mirror of
https://github.com/System-End/nephthys.git
synced 2026-04-19 16:28:16 +00:00
App home improvements! (#133)
* Show an error message if the views_publish call fails This means that if our Block Kit has a syntax error and Slack API returns en error for it, a fallback screen is shown instead of indefinite loading * Include nav buttons in the header * Fix header formatting error I think this was a GH Copilot hallucination that I accepted bc it looked very similar to the OG code :( * Show header on the loading screen * Make clicking on a button during the loading phase work * Delete views/home/apps.py I don't think this view is used anywhere * Use the new header style everywhere * Remove buttons.py (no longer used) * Show "dashboard" tab as selected during first load This means that the "default" virtual view name no longer exists, but we have a DEFAULT_VIEW constant now * Add at least some sort of return type to get_header() * Make the helper and assigned views non-helper-friendly * Allow non-helpers to access the app home * Remove useless `or` statement * Extract error_screen to a component * Gate the tags view to only helpers * Make the tags view non-helper-friendly * Make the stats view non-helper-friendly * Make the error text a bit nicer * Fix type error * Make the infinite loading situation less likely This could happen if you spam-clicked one of the buttons (I tested with assigned tickets). I think the problem existed before but was made worse by the new `user_last_requested_view` logic - now it's back to normal and the issue is very hard to recreate. * Remove "unknown user" view and transcripts * Remove commented code block * Remove comment the second * Fix timezone fetching and add more logs
This commit is contained in:
parent
8791e3ec54
commit
43967cf289
16 changed files with 170 additions and 314 deletions
|
|
@ -3,6 +3,7 @@ import traceback
|
|||
from typing import Any
|
||||
|
||||
from prometheus_client import Histogram
|
||||
from slack_sdk.errors import SlackApiError
|
||||
from slack_sdk.web.async_client import AsyncWebClient
|
||||
|
||||
from nephthys.utils.env import env
|
||||
|
|
@ -14,12 +15,13 @@ from nephthys.views.home.helper import get_helper_view
|
|||
from nephthys.views.home.loading import get_loading_view
|
||||
from nephthys.views.home.stats import get_stats_view
|
||||
from nephthys.views.home.tags import get_manage_tags_view
|
||||
from nephthys.views.home.unknown_user import get_unknown_user_view
|
||||
|
||||
DEFAULT_VIEW = "dashboard"
|
||||
|
||||
|
||||
async def on_app_home_opened(event: dict[str, Any], client: AsyncWebClient):
|
||||
user_id = event["user"]
|
||||
await open_app_home("default", client, user_id)
|
||||
await open_app_home(DEFAULT_VIEW, client, user_id)
|
||||
|
||||
|
||||
APP_HOME_RENDER_DURATION = Histogram(
|
||||
|
|
@ -29,43 +31,40 @@ APP_HOME_RENDER_DURATION = Histogram(
|
|||
)
|
||||
|
||||
|
||||
# Map of the last-requested view for each Slack user
|
||||
# This prevents a view that took a while to render overwriting the view you want
|
||||
# Entries are deleted once the view is published
|
||||
last_requested_views: dict[str, str] = {}
|
||||
|
||||
|
||||
async def open_app_home(home_type: str, client: AsyncWebClient, user_id: str):
|
||||
last_requested_views[user_id] = home_type
|
||||
try:
|
||||
await client.views_publish(view=get_loading_view(), user_id=user_id)
|
||||
await client.views_publish(view=get_loading_view(home_type), user_id=user_id)
|
||||
|
||||
user = await env.db.user.find_unique(where={"slackId": user_id})
|
||||
|
||||
if not user or not user.helper:
|
||||
user_info = await client.users_info(user=user_id) or {}
|
||||
name = (
|
||||
user_info.get("user", {}).get("profile", {}).get("display_name")
|
||||
or user_info.get("user", {}).get("profile", {}).get("real_name")
|
||||
or "person"
|
||||
)
|
||||
view = get_unknown_user_view(name)
|
||||
else:
|
||||
logging.info(f"Opening {home_type} for {user_id}")
|
||||
async with perf_timer(
|
||||
f"Rendering app home (type={home_type})",
|
||||
APP_HOME_RENDER_DURATION,
|
||||
home_type=home_type,
|
||||
):
|
||||
match home_type:
|
||||
case "default" | "dashboard":
|
||||
view = await get_helper_view(user)
|
||||
case "assigned-tickets":
|
||||
view = await get_assigned_tickets_view(user)
|
||||
case "tags":
|
||||
view = await get_manage_tags_view(user)
|
||||
case "my-stats":
|
||||
view = await get_stats_view(user)
|
||||
case _:
|
||||
await send_heartbeat(
|
||||
f"Attempted to load unknown app home type {home_type} for <@{user_id}>"
|
||||
)
|
||||
view = get_error_view(
|
||||
f"This shouldn't happen, please tell <@{env.slack_maintainer_id}> that app home case `_` was hit with home type `{home_type}`"
|
||||
)
|
||||
logging.info(f"Opening {home_type} for {user_id}")
|
||||
async with perf_timer(
|
||||
f"Rendering app home (type={home_type})",
|
||||
APP_HOME_RENDER_DURATION,
|
||||
home_type=home_type,
|
||||
):
|
||||
match home_type:
|
||||
case "dashboard":
|
||||
view = await get_helper_view(slack_user=user_id, db_user=user)
|
||||
case "assigned-tickets":
|
||||
view = await get_assigned_tickets_view(user)
|
||||
case "tags":
|
||||
view = await get_manage_tags_view(user)
|
||||
case "my-stats":
|
||||
view = await get_stats_view(user)
|
||||
case _:
|
||||
await send_heartbeat(
|
||||
f"Attempted to load unknown app home type {home_type} for <@{user_id}>"
|
||||
)
|
||||
view = get_error_view(
|
||||
f"This shouldn't happen, please tell <@{env.slack_maintainer_id}> that app home case `_` was hit with home type `{home_type}`"
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error(f"Error opening app home: {e}")
|
||||
tb = traceback.format_exception(e)
|
||||
|
|
@ -82,4 +81,20 @@ async def open_app_home(home_type: str, client: AsyncWebClient, user_id: str):
|
|||
messages=[f"```{tb_str}```", f"cc <@{env.slack_maintainer_id}>"],
|
||||
)
|
||||
|
||||
await client.views_publish(user_id=user_id, view=view)
|
||||
user_last_requested_view = last_requested_views.get(user_id)
|
||||
if user_last_requested_view:
|
||||
if user_last_requested_view != home_type:
|
||||
logging.info(f"Ignoring stale view request ({user_id}, {home_type})")
|
||||
return
|
||||
del last_requested_views[user_id]
|
||||
|
||||
try:
|
||||
await client.views_publish(user_id=user_id, view=view)
|
||||
except SlackApiError as e:
|
||||
logging.error(f"Error publishing app home view: {e}")
|
||||
await client.views_publish(
|
||||
user_id=user_id,
|
||||
view=get_error_view(
|
||||
f"A Slack API error occurred while opening the app home:\n{e}",
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -95,15 +95,6 @@ class Transcript(BaseModel):
|
|||
description="Message to be sent when the ship cert queue macro is used (only applies to SoM)",
|
||||
)
|
||||
|
||||
home_unknown_user_title: str = Field(
|
||||
default=":upside-down_orpheus: woah, stop right there {name}!",
|
||||
description="Title for unknown user on home page",
|
||||
)
|
||||
|
||||
home_unknown_user_text: str = Field(
|
||||
default="", description="Text for unknown user on home page"
|
||||
)
|
||||
|
||||
not_allowed_channel: str = Field(
|
||||
default="", description="Message for unauthorized channel access"
|
||||
)
|
||||
|
|
@ -158,9 +149,6 @@ if your question has been answered, please hit the button below to mark it as re
|
|||
if not self.identity_macro:
|
||||
self.identity_macro = f"hey, (user)! please could you ask questions about identity verification in <#{self.identity_help_channel}>? :rac_cute:\n\nit helps the verification team keep track of questions easier!"
|
||||
|
||||
if not self.home_unknown_user_text:
|
||||
self.home_unknown_user_text = f"heyyyy, heidi here! it looks like i'm not allowed to show ya this. sorry! if you think this is a mistake, please reach out to <@{self.program_owner}> and she'll lmk what to do!"
|
||||
|
||||
if not self.not_allowed_channel:
|
||||
self.not_allowed_channel = f"heya, it looks like you're not supposed to be in that channel, pls talk to <@{self.program_owner}> if that's wrong"
|
||||
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ Someone from the team will reply shortly with next steps.
|
|||
ticket_resolve: str = f"""
|
||||
Nice — this ticket was marked resolved by <@{{user_id}}>.
|
||||
If you need additional changes or the issue returns, send a message in <#{help_channel}> and we'll take another look.
|
||||
"""
|
||||
|
||||
home_unknown_user_title: str = ":wrench: whoa — access limited"
|
||||
home_unknown_user_text: str = """
|
||||
_Checking permissions_
|
||||
|
||||
Hey {name}, it looks like you don't have access to this page right now.
|
||||
If that's a mistake, please ask <@{program_owner}> to grant access and include a short note about why you need it.
|
||||
"""
|
||||
|
||||
not_allowed_channel: str = f"Oops — you don't have permission for that channel. If you think this is wrong, ask <@{program_owner}> to check your access."
|
||||
|
|
|
|||
|
|
@ -47,16 +47,6 @@ Hi (user), would you mind directing any fraud related queries to <@U091HC53CE8>?
|
|||
It'll keep your case confidential and make it easier for the fraud team to keep track of!
|
||||
|
||||
_I've marked this thread as resolved_
|
||||
"""
|
||||
|
||||
home_unknown_user_title: str = ":upside-down_orpheus: woah, wait one sec!"
|
||||
home_unknown_user_text: str = """
|
||||
_checks records_
|
||||
|
||||
heyy {name}, it doesn't look like you're on the list of people allowed to access this page – sorry!
|
||||
|
||||
If you think this isn't right, ask <@{program_owner}> and they'll check for you! I'm still new to this \
|
||||
fancy "role-based access" stuff :P
|
||||
"""
|
||||
|
||||
not_allowed_channel: str = f"hey, it looks like you're not supposed to be in that channel, pls talk to <@{program_owner}> if that's wrong"
|
||||
|
|
|
|||
|
|
@ -23,9 +23,4 @@ if your question has been answered, please hit the button below to mark it as re
|
|||
resolve_ticket_button: str = "i get it now"
|
||||
ticket_resolve: str = f"oh, oh! it looks like this post has been marked as resolved by <@{{user_id}}>! if you have any more questions, please make a new post in <#{help_channel}> and someone'll be happy to help you out! not me though, i'm just a silly racoon ^-^"
|
||||
|
||||
home_unknown_user_title: str = (
|
||||
":upside-down_orpheus: woah, stop right there {name}!"
|
||||
)
|
||||
home_unknown_user_text: str = f"heyyyy, heidi here! it looks like i'm not allowed to show ya this. sorry! if you think this is a mistake, please reach out to <@{program_owner}> and she'll lmk what to do!"
|
||||
|
||||
not_allowed_channel: str = f"heya, it looks like you're not supposed to be in that channel, pls talk to <@{program_owner}> if that's wrong"
|
||||
|
|
|
|||
|
|
@ -27,16 +27,6 @@ class Midnight(Transcript):
|
|||
ticket_resolve: str = f"""
|
||||
Aha, this post has just been marked as resolved by <@{{user_id}}>! I'll head back to my castle now, \
|
||||
but if you need any more help, just send another message in <#{help_channel}> and I'll be right back o/
|
||||
"""
|
||||
|
||||
home_unknown_user_title: str = ":upside-down_orpheus: chat give me a min"
|
||||
home_unknown_user_text: str = """
|
||||
_checks records_
|
||||
|
||||
heyy {name}, it doesn't look like you're on the list of people allowed to access this page - sorry!
|
||||
|
||||
If you think this isn't right, ask <@{program_owner}> and they'll check for you! I'm still new to this \
|
||||
fancy "role-based access" stuff :P
|
||||
"""
|
||||
|
||||
not_allowed_channel: str = f"hey, it looks like you're not supposed to be in that channel, pls talk to <@{program_owner}> if that's wrong"
|
||||
|
|
|
|||
|
|
@ -27,9 +27,4 @@ if your question has been answered, please hit the button below to mark it as re
|
|||
"hi (user)! unfortunately, there is a backlog of projects awaiting ship certification; please be patient. \n\n *pssst... voting more will move your project further towards the front of the queue.*"
|
||||
)
|
||||
|
||||
home_unknown_user_title: str = (
|
||||
":upside-down_orpheus: woah, stop right there {name}!"
|
||||
)
|
||||
home_unknown_user_text: str = f"heyyyy, heidi here! it looks like i'm not allowed to show ya this. sorry! if you think this is a mistake, please reach out to <@{program_owner}> and she'll lmk what to do!"
|
||||
|
||||
not_allowed_channel: str = f"heya, it looks like you're not supposed to be in that channel, pls talk to <@{program_owner}> if that's wrong"
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
import logging
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.views.home.components.buttons import get_buttons
|
||||
from prisma.models import User
|
||||
|
||||
|
||||
async def get_manage_tags_view(user: User) -> dict:
|
||||
btns = get_buttons(user, "tags")
|
||||
|
||||
tags = await env.db.tag.find_many(include={"userSubscriptions": True})
|
||||
|
||||
blocks = []
|
||||
|
||||
if not tags:
|
||||
blocks.append(
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": f":rac_nooo: i couldn't scrounge up any tags{', you can make a new one below though' if user.admin else ''}",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
for tag in tags:
|
||||
logging.info(f"Tag {tag.name} with id {tag.id} found in the database")
|
||||
logging.info(
|
||||
f"Tag {tag.name} has {len(tag.userSubscriptions) if tag.userSubscriptions else 0} subscriptions"
|
||||
)
|
||||
if tag.userSubscriptions:
|
||||
subIds = [user.userId for user in tag.userSubscriptions]
|
||||
|
||||
subUsers = await env.db.user.find_many(where={"id": {"in": subIds}})
|
||||
|
||||
subs = [user.slackId for user in subUsers]
|
||||
else:
|
||||
subs = []
|
||||
stringified_subs = [f"<@{user}>" for user in subs]
|
||||
blocks.append(
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": f"*{tag.name}* - {''.join(stringified_subs) if stringified_subs else ':rac_nooo: no subscriptions'}",
|
||||
},
|
||||
"accessory": {
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f":rac_cute: {'subscribe' if user.id not in subs else 'unsubscribe'}",
|
||||
"emoji": True,
|
||||
},
|
||||
"action_id": "tag-subscribe",
|
||||
"value": f"{tag.id};{tag.name}",
|
||||
"style": "primary" if user.id not in subs else "danger",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
view = {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_info: Apps",
|
||||
"emoji": True,
|
||||
},
|
||||
},
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": ":rac_thumbs: here you can manage tags and your subscriptions"
|
||||
if user.admin
|
||||
else ":rac_thumbs: here you can manage your tag subscriptions",
|
||||
},
|
||||
},
|
||||
{"type": "divider"},
|
||||
*blocks,
|
||||
],
|
||||
}
|
||||
|
||||
if user.admin:
|
||||
view["blocks"].append(
|
||||
{
|
||||
"type": "actions",
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_cute: add a tag?",
|
||||
"emoji": True,
|
||||
},
|
||||
"action_id": "create-tag",
|
||||
"style": "primary",
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
return view
|
||||
|
|
@ -1,59 +1,47 @@
|
|||
import pytz
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.views.home.components.buttons import get_buttons
|
||||
from nephthys.views.home.components.error_screen import error_screen
|
||||
from nephthys.views.home.components.header import get_header
|
||||
from prisma.enums import TicketStatus
|
||||
from prisma.models import User
|
||||
|
||||
|
||||
async def get_assigned_tickets_view(user: User):
|
||||
header = get_header()
|
||||
btns = get_buttons(user, "assigned-tickets")
|
||||
async def get_assigned_tickets_view(user: User | None):
|
||||
header = get_header(user, "assigned-tickets")
|
||||
|
||||
tickets = (
|
||||
await env.db.ticket.find_many(
|
||||
where={"assignedToId": user.id, "NOT": [{"status": TicketStatus.CLOSED}]},
|
||||
include={"openedBy": True},
|
||||
if not user or not user.helper:
|
||||
return error_screen(
|
||||
header,
|
||||
":rac_info: you're not a helper!",
|
||||
":rac_believes_in_theory_about_green_lizards_and_space_lasers: only helpers can be assigned to tickets, so you have none - zero responsibility!",
|
||||
)
|
||||
or []
|
||||
|
||||
tickets = await env.db.ticket.find_many(
|
||||
where={"assignedToId": user.id, "NOT": [{"status": TicketStatus.CLOSED}]},
|
||||
include={"openedBy": True},
|
||||
)
|
||||
|
||||
if not tickets:
|
||||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_cute: no assigned tickets",
|
||||
"emoji": True,
|
||||
},
|
||||
},
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": ":rac_believes_in_theory_about_green_lizards_and_space_lasers: you don't have any assigned tickets right now!",
|
||||
"emoji": True,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
return error_screen(
|
||||
header,
|
||||
":rac_cute: no assigned tickets",
|
||||
":rac_believes_in_theory_about_green_lizards_and_space_lasers: you don't have any assigned tickets right now!",
|
||||
)
|
||||
|
||||
ticket_blocks = []
|
||||
for ticket in tickets:
|
||||
unix_ts = int(ticket.createdAt.timestamp())
|
||||
time_ago_str = f"<!date^{unix_ts}^opened {{ago}}|at {ticket.createdAt.astimezone(pytz.timezone('Europe/London')).strftime('%H:%M %Z')}>"
|
||||
opened_by_str = (
|
||||
f"<@{ticket.openedBy.slackId}>" if ticket.openedBy else "unknown user"
|
||||
)
|
||||
ticket_blocks.append(
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": f"*{ticket.title}*\n _from <@{ticket.openedBy.slackId}>. {time_ago_str}_",
|
||||
"text": f"*{ticket.title}*\n _from {opened_by_str}. {time_ago_str}_",
|
||||
},
|
||||
"accessory": {
|
||||
"type": "button",
|
||||
|
|
@ -73,9 +61,7 @@ async def get_assigned_tickets_view(user: User):
|
|||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
header,
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
*header,
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
from prisma.models import User
|
||||
|
||||
|
||||
def get_buttons(user: User, current: str = "dashboard"):
|
||||
buttons = []
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Dashboard", "emoji": True},
|
||||
"action_id": "dashboard",
|
||||
**({"style": "primary"} if current != "dashboard" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Assigned Tickets", "emoji": True},
|
||||
"action_id": "assigned-tickets",
|
||||
**({"style": "primary"} if current != "assigned-tickets" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Tags", "emoji": True},
|
||||
"action_id": "tags",
|
||||
**({"style": "primary"} if current != "tags" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "My Stats", "emoji": True},
|
||||
"action_id": "my-stats",
|
||||
**({"style": "primary"} if current != "my-stats" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
blocks = {"type": "actions", "elements": buttons}
|
||||
return blocks
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
from nephthys.utils.env import env
|
||||
|
||||
|
||||
def get_unknown_user_view(name: str):
|
||||
def error_screen(header: list[dict], title: str, message: str) -> dict:
|
||||
"""A basic error screen that can be rendered as a view if permissions are missing, or something like that"""
|
||||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
*header,
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": env.transcript.home_unknown_user_title.format(name=name),
|
||||
"text": title,
|
||||
"emoji": True,
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": env.transcript.home_unknown_user_text,
|
||||
"type": "plain_text",
|
||||
"text": message,
|
||||
"emoji": True,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -1,7 +1,51 @@
|
|||
from nephthys.utils.env import env
|
||||
from prisma.models import User
|
||||
|
||||
|
||||
def get_header():
|
||||
def header_buttons(current_view: str):
|
||||
buttons = []
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Dashboard", "emoji": True},
|
||||
"action_id": "dashboard",
|
||||
**({"style": "primary"} if current_view != "dashboard" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Assigned Tickets", "emoji": True},
|
||||
"action_id": "assigned-tickets",
|
||||
**({"style": "primary"} if current_view != "assigned-tickets" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "Tags", "emoji": True},
|
||||
"action_id": "tags",
|
||||
**({"style": "primary"} if current_view != "tags" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
buttons.append(
|
||||
{
|
||||
"type": "button",
|
||||
"text": {"type": "plain_text", "text": "My Stats", "emoji": True},
|
||||
"action_id": "my-stats",
|
||||
**({"style": "primary"} if current_view != "my-stats" else {}),
|
||||
}
|
||||
)
|
||||
|
||||
blocks = {"type": "actions", "elements": buttons}
|
||||
return blocks
|
||||
|
||||
|
||||
def title_line():
|
||||
return {
|
||||
"type": "header",
|
||||
"text": {
|
||||
|
|
@ -10,3 +54,11 @@ def get_header():
|
|||
"emoji": True,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def get_header(user: User | None, current: str = "dashboard") -> list[dict]:
|
||||
return [
|
||||
title_line(),
|
||||
header_buttons(current),
|
||||
{"type": "divider"},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import logging
|
||||
|
||||
import pytz
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.utils.performance import perf_timer
|
||||
from nephthys.views.home.components.buttons import get_buttons
|
||||
from nephthys.views.home.components.header import get_header
|
||||
from nephthys.views.home.components.leaderboards import get_leaderboard_view
|
||||
from nephthys.views.home.components.ticket_status_pie import get_ticket_status_pie_chart
|
||||
|
|
@ -10,14 +11,19 @@ from nephthys.views.home.error import get_error_view
|
|||
from prisma.models import User
|
||||
|
||||
|
||||
async def get_helper_view(user: User):
|
||||
async def get_helper_view(slack_user: str, db_user: User | None):
|
||||
async with perf_timer("Fetching user info"):
|
||||
user_info = await env.slack_client.users_info(user=user.slackId)
|
||||
if not user_info or not (slack_user := user_info.get("user")):
|
||||
user_info_response = await env.slack_client.users_info(user=slack_user)
|
||||
user_info = user_info_response.get("user")
|
||||
if not user_info:
|
||||
logging.error(f"Failed to fetch user={slack_user}: {user_info_response}")
|
||||
return get_error_view(
|
||||
":rac_freaking: oops, i couldn't find your info! try again in a bit?"
|
||||
)
|
||||
tz_string = slack_user.get("tz", "Europe/London")
|
||||
tz_string = user_info.get("tz")
|
||||
if not tz_string:
|
||||
logging.warning(f"No timezone found user={slack_user}")
|
||||
tz_string = "Europe/London"
|
||||
tz = pytz.timezone(tz_string)
|
||||
|
||||
async with perf_timer("Rendering pie chart (total time)"):
|
||||
|
|
@ -26,15 +32,12 @@ async def get_helper_view(user: User):
|
|||
async with perf_timer("Generating leaderboard"):
|
||||
leaderboard = await get_leaderboard_view()
|
||||
|
||||
header = get_header()
|
||||
btns = get_buttons(user, "dashboard")
|
||||
header = get_header(db_user, "dashboard")
|
||||
|
||||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
header,
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
*header,
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
def get_loading_view():
|
||||
from nephthys.views.home.components.header import get_header
|
||||
|
||||
|
||||
def get_loading_view(home_type: str):
|
||||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
*get_header(user=None, current=home_type),
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
|
|
@ -9,9 +13,6 @@ def get_loading_view():
|
|||
"text": ":hourglass_flowing_sand: loading...",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "divider",
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"image_url": "https://hc-cdn.hel1.your-objectstorage.com/s/v3/1c1fc5fb03b8bf46c6ab047c97f962ed930616f0_loading-hugs.gif",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
from nephthys.views.home.components.buttons import get_buttons
|
||||
from nephthys.views.home.components.header import get_header
|
||||
from prisma.models import User
|
||||
|
||||
|
||||
async def get_stats_view(user: User):
|
||||
btns = get_buttons(user, "my-stats")
|
||||
|
||||
async def get_stats_view(user: User | None):
|
||||
return {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
*get_header(user, "my-stats"),
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
|
|
@ -16,8 +15,6 @@ async def get_stats_view(user: User):
|
|||
"emoji": True,
|
||||
},
|
||||
},
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import logging
|
||||
|
||||
from nephthys.utils.env import env
|
||||
from nephthys.views.home.components.buttons import get_buttons
|
||||
from nephthys.views.home.components.header import get_header
|
||||
from prisma.models import User
|
||||
|
||||
|
||||
async def get_manage_tags_view(user: User) -> dict:
|
||||
btns = get_buttons(user, "tags")
|
||||
|
||||
async def get_manage_tags_view(user: User | None) -> dict:
|
||||
header = get_header(user, "tags")
|
||||
is_admin = bool(user and user.admin)
|
||||
is_helper = bool(user and user.helper)
|
||||
tags = await env.db.tag.find_many(include={"userSubscriptions": True})
|
||||
|
||||
blocks = []
|
||||
|
||||
if not tags:
|
||||
|
|
@ -18,7 +18,7 @@ async def get_manage_tags_view(user: User) -> dict:
|
|||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": f":rac_nooo: i couldn't scrounge up any tags{', you can make a new one below though' if user.admin else ''}",
|
||||
"text": f":rac_nooo: i couldn't scrounge up any tags{', you can make a new one below though' if is_admin else ''}",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
@ -54,13 +54,16 @@ async def get_manage_tags_view(user: User) -> dict:
|
|||
"action_id": "tag-subscribe",
|
||||
"value": f"{tag.id};{tag.name}",
|
||||
"style": "primary" if user.id not in subs else "danger",
|
||||
},
|
||||
}
|
||||
if user and is_helper
|
||||
else {},
|
||||
}
|
||||
)
|
||||
|
||||
view = {
|
||||
"type": "home",
|
||||
"blocks": [
|
||||
*header,
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
|
|
@ -69,23 +72,23 @@ async def get_manage_tags_view(user: User) -> dict:
|
|||
"emoji": True,
|
||||
},
|
||||
},
|
||||
btns,
|
||||
{"type": "divider"},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": ":rac_thumbs: here you can manage tags and your subscriptions"
|
||||
if user.admin
|
||||
else ":rac_thumbs: here you can manage your tag subscriptions",
|
||||
if is_admin
|
||||
else ":rac_thumbs: here you can manage your tag subscriptions"
|
||||
if is_helper
|
||||
else ":rac_thumbs: note: you're not a helper, so you can only view tags",
|
||||
},
|
||||
},
|
||||
{"type": "divider"},
|
||||
{"type": "section", "text": {"type": "plain_text", "text": " "}},
|
||||
*blocks,
|
||||
],
|
||||
}
|
||||
|
||||
if user.admin:
|
||||
if is_admin:
|
||||
view["blocks"].append(
|
||||
{
|
||||
"type": "actions",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue