From 43967cf2896b02d68ce5257b3fd6975f6ddd954e Mon Sep 17 00:00:00 2001 From: Mish Date: Mon, 8 Dec 2025 11:54:00 +0000 Subject: [PATCH] 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 --- nephthys/events/app_home_opened.py | 87 ++++++++------ nephthys/transcripts/transcript.py | 12 -- nephthys/transcripts/transcripts/construct.py | 8 -- .../transcripts/transcripts/flavortown.py | 10 -- nephthys/transcripts/transcripts/identity.py | 5 - nephthys/transcripts/transcripts/midnight.py | 10 -- .../transcripts/summer_of_making.py | 5 - nephthys/views/home/apps.py | 107 ------------------ nephthys/views/home/assigned.py | 58 ++++------ nephthys/views/home/components/buttons.py | 44 ------- .../error_screen.py} | 14 +-- nephthys/views/home/components/header.py | 54 ++++++++- nephthys/views/home/helper.py | 23 ++-- nephthys/views/home/loading.py | 9 +- nephthys/views/home/stats.py | 9 +- nephthys/views/home/tags.py | 29 ++--- 16 files changed, 170 insertions(+), 314 deletions(-) delete mode 100644 nephthys/views/home/apps.py delete mode 100644 nephthys/views/home/components/buttons.py rename nephthys/views/home/{unknown_user.py => components/error_screen.py} (50%) diff --git a/nephthys/events/app_home_opened.py b/nephthys/events/app_home_opened.py index bcab4b9..128bff8 100644 --- a/nephthys/events/app_home_opened.py +++ b/nephthys/events/app_home_opened.py @@ -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}", + ), + ) diff --git a/nephthys/transcripts/transcript.py b/nephthys/transcripts/transcript.py index 6c6a7e3..d539dc9 100644 --- a/nephthys/transcripts/transcript.py +++ b/nephthys/transcripts/transcript.py @@ -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" diff --git a/nephthys/transcripts/transcripts/construct.py b/nephthys/transcripts/transcripts/construct.py index fa421df..cec6102 100644 --- a/nephthys/transcripts/transcripts/construct.py +++ b/nephthys/transcripts/transcripts/construct.py @@ -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." diff --git a/nephthys/transcripts/transcripts/flavortown.py b/nephthys/transcripts/transcripts/flavortown.py index 5791dda..518d9f4 100644 --- a/nephthys/transcripts/transcripts/flavortown.py +++ b/nephthys/transcripts/transcripts/flavortown.py @@ -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" diff --git a/nephthys/transcripts/transcripts/identity.py b/nephthys/transcripts/transcripts/identity.py index 21da253..95863f5 100644 --- a/nephthys/transcripts/transcripts/identity.py +++ b/nephthys/transcripts/transcripts/identity.py @@ -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" diff --git a/nephthys/transcripts/transcripts/midnight.py b/nephthys/transcripts/transcripts/midnight.py index 086220e..b79aa75 100644 --- a/nephthys/transcripts/transcripts/midnight.py +++ b/nephthys/transcripts/transcripts/midnight.py @@ -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" diff --git a/nephthys/transcripts/transcripts/summer_of_making.py b/nephthys/transcripts/transcripts/summer_of_making.py index 938a7e5..c8ef1a8 100644 --- a/nephthys/transcripts/transcripts/summer_of_making.py +++ b/nephthys/transcripts/transcripts/summer_of_making.py @@ -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" diff --git a/nephthys/views/home/apps.py b/nephthys/views/home/apps.py deleted file mode 100644 index e0f7ea4..0000000 --- a/nephthys/views/home/apps.py +++ /dev/null @@ -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 diff --git a/nephthys/views/home/assigned.py b/nephthys/views/home/assigned.py index 9aedae6..080d057 100644 --- a/nephthys/views/home/assigned.py +++ b/nephthys/views/home/assigned.py @@ -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"" + 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": { diff --git a/nephthys/views/home/components/buttons.py b/nephthys/views/home/components/buttons.py deleted file mode 100644 index 1ffbc29..0000000 --- a/nephthys/views/home/components/buttons.py +++ /dev/null @@ -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 diff --git a/nephthys/views/home/unknown_user.py b/nephthys/views/home/components/error_screen.py similarity index 50% rename from nephthys/views/home/unknown_user.py rename to nephthys/views/home/components/error_screen.py index 44155df..fc1e5c4 100644 --- a/nephthys/views/home/unknown_user.py +++ b/nephthys/views/home/components/error_screen.py @@ -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, }, }, ], diff --git a/nephthys/views/home/components/header.py b/nephthys/views/home/components/header.py index 2114eba..795f7a2 100644 --- a/nephthys/views/home/components/header.py +++ b/nephthys/views/home/components/header.py @@ -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"}, + ] diff --git a/nephthys/views/home/helper.py b/nephthys/views/home/helper.py index 8669e52..bb8a9c7 100644 --- a/nephthys/views/home/helper.py +++ b/nephthys/views/home/helper.py @@ -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": { diff --git a/nephthys/views/home/loading.py b/nephthys/views/home/loading.py index 5c10704..b9ca3d4 100644 --- a/nephthys/views/home/loading.py +++ b/nephthys/views/home/loading.py @@ -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", diff --git a/nephthys/views/home/stats.py b/nephthys/views/home/stats.py index 0247aa4..d2dfd5f 100644 --- a/nephthys/views/home/stats.py +++ b/nephthys/views/home/stats.py @@ -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": { diff --git a/nephthys/views/home/tags.py b/nephthys/views/home/tags.py index 217c33d..dac854d 100644 --- a/nephthys/views/home/tags.py +++ b/nephthys/views/home/tags.py @@ -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",