From 032d201ffaea100c1f36c37f631d568135c1e64e Mon Sep 17 00:00:00 2001 From: Jacob Date: Thu, 4 Jun 2026 09:31:32 -0600 Subject: [PATCH 1/3] refactor: turned TA view into a component --- bot.py | 15 ++++- ui/views/ta_view.py | 138 ++++++++++++++++++++++++-------------------- 2 files changed, 88 insertions(+), 65 deletions(-) diff --git a/bot.py b/bot.py index cf914aa..ef21cf5 100644 --- a/bot.py +++ b/bot.py @@ -3,7 +3,7 @@ from discord.utils import get from help_queue import HelpQueue from ui.views.queue_view import QueueView -from ui.views.ta_view import TAView +from ui.views.ta_view import TAView, TAQueueControls, TAQueueManagement, TAQueueInformation from ui.helpers.constants import HELP_CHANNEL_NAME, TA_TEXT_CHANNEL_NAME, TA_VOICE_CHANNEL_NAME from ui.helpers.discord_helpers import update_queue_messages from records import QueueEntry @@ -221,9 +221,20 @@ async def queue_panel(interaction: discord.Interaction): @bot.tree.command(name="ta") async def ta_panel(interaction: discord.Interaction): await interaction.response.send_message( - "TA Panel", view=TAView() ) + # await interaction.channel.send( + # "Queue Controls", + # view=TAQueueControls() + # ) + # await interaction.channel.send( + # "Queue Management", + # view=TAQueueManagement() + # ) + # await interaction.channel.send( + # "Queue Information", + # view=TAQueueInformation() + # ) token: str = os.getenv("TOKEN") bot.run(token) \ No newline at end of file diff --git a/ui/views/ta_view.py b/ui/views/ta_view.py index 331491a..7c577b5 100644 --- a/ui/views/ta_view.py +++ b/ui/views/ta_view.py @@ -8,58 +8,11 @@ from ui.helpers.utils import fixed_width from ui.helpers.discord_helpers import get_channel, get_role, move_to_breakout, safe_dm_user, notify_next_if_changed, update_queue_messages +class BaseLayoutView(discord.ui.LayoutView): + pass - -class TAView(discord.ui.View): - - def __init__(self): - super().__init__(timeout=None) - - - @discord.ui.button(label="Open Queue", style=discord.ButtonStyle.green, custom_id="open_queue", emoji="🔓") - async def open(self, interaction: discord.Interaction, button: discord.Button): - if not interaction.client.queue.is_open: - interaction.client.queue.is_open = True - await interaction.response.send_message(QUEUE_OPENED, ephemeral=True, delete_after=DEFAULT_TIMEOUT) - await update_queue_messages(interaction.client) - return - else: - await interaction.response.send_message(QUEUE_ALREADY_OPEN, ephemeral=True, delete_after=SHORT_TIMEOUT) - - @discord.ui.button(label="Close Queue", style=discord.ButtonStyle.red, custom_id="close_queue", emoji="🔏") - async def close(self, interaction: discord.Interaction, button): - if interaction.client.queue.is_open: - interaction.client.queue.is_open = False - await interaction.response.send_message(QUEUE_CLOSED, ephemeral=True, delete_after=DEFAULT_TIMEOUT) - await update_queue_messages(interaction.client) - return - else: - await interaction.response.send_message(QUEUE_ALREADY_CLOSED, ephemeral=True, delete_after=SHORT_TIMEOUT) - - @discord.ui.button(label="Days Since Last Incident", style=discord.ButtonStyle.secondary, custom_id="days_since_incident", emoji="⚠️") - async def days_since_incident_btn(self, interaction: discord.Interaction, button): - days, issue_text = get_last_incident_info() - if days is None: - message = "No incidents have been reported yet." - elif days == 1: - message = f"1 day since last incident. Description: {issue_text or 'No description provided.'}" - else: - message = f"{days} days since last incident. Description: {issue_text or 'No description provided.'}" - - await interaction.response.send_message(message, ephemeral=True, delete_after=DEFAULT_TIMEOUT) - - @discord.ui.button(label="Student Info", style=discord.ButtonStyle.secondary, custom_id="student_info", emoji="📝") - async def student_info(self, interaction: discord.Interaction, button): - headers, rows = get_student_info() - width = STUDENT_INFO_WIDTH - def row_to_line(items): - return "| ".join(fixed_width(str(x), width) for x in items) - - divider = "-" * (width * len(headers) + 3 * (len(headers)-1)) - body = "\n".join(row_to_line(r) for r in rows) - builder = f"```Student Info:\n{row_to_line(headers)}\n{divider}\n{body}```" - await interaction.response.send_message(builder, ephemeral=True, delete_after=LONG_TIMEOUT) - +class TAQueueControls(discord.ui.ActionRow[discord.ui.LayoutView]): + view: "TAView" @discord.ui.button(label="Next", style=discord.ButtonStyle.blurple, custom_id="next", emoji="➡️") async def next(self, interaction: discord.Interaction, button): entry: Optional[QueueEntry] = await interaction.client.queue.next() @@ -108,7 +61,6 @@ async def next_online(self, interaction: discord.Interaction, button: discord.ui delete_after=DEFAULT_TIMEOUT ) - @discord.ui.button(label="Next Passoff", style=discord.ButtonStyle.blurple, custom_id="next_passoff", emoji="✅") async def next_passoff(self, interaction: discord.Interaction, button: discord.ui.Button): # Get who was at front before removal @@ -131,7 +83,6 @@ async def next_passoff(self, interaction: discord.Interaction, button: discord.u delete_after=DEFAULT_TIMEOUT ) - @discord.ui.button(label="Next Online Passoff", style=discord.ButtonStyle.blurple, custom_id="next_online_passoff", emoji="☑️") async def next_online_passoff(self, interaction: discord.Interaction, button: discord.ui.Button): # Get who was at front before removal @@ -153,16 +104,6 @@ async def next_online_passoff(self, interaction: discord.Interaction, button: di delete_after=DEFAULT_TIMEOUT ) - - - @discord.ui.button(label="Clear Queue", style=discord.ButtonStyle.danger, custom_id="clear_queue", emoji="💥") - async def clear_queue(self, interaction: discord.Interaction, button): - await interaction.response.send_modal(ClearConfirmModal()) - - @discord.ui.button(label="Remove Student", style=discord.ButtonStyle.danger, custom_id="remove_from_queue", emoji="🗑️") - async def remove_from_queue(self, interaction: discord.Interaction, button): - await interaction.response.send_modal(RemoveConfirmModal()) - @discord.ui.button(label="Finish", style=discord.ButtonStyle.green, custom_id="finish", emoji="🔚") async def finish_button(self, interaction: discord.Interaction, button): online_ta_vc: discord.VoiceChannel = get_channel(interaction, TA_VOICE_CHANNEL_NAME) @@ -188,8 +129,79 @@ async def finish_button(self, interaction: discord.Interaction, button): await interaction.user.move_to(online_ta_vc) await interaction.response.defer(thinking=False) +class TAQueueManagement(discord.ui.ActionRow[discord.ui.LayoutView]): + view: "TAView" + @discord.ui.button(label="Open Queue", style=discord.ButtonStyle.green, custom_id="open_queue", emoji="🔓") + async def open(self, interaction: discord.Interaction, button: discord.Button): + if not interaction.client.queue.is_open: + interaction.client.queue.is_open = True + await interaction.response.send_message(QUEUE_OPENED, ephemeral=True, delete_after=DEFAULT_TIMEOUT) + await update_queue_messages(interaction.client) + return + else: + await interaction.response.send_message(QUEUE_ALREADY_OPEN, ephemeral=True, delete_after=SHORT_TIMEOUT) + + @discord.ui.button(label="Close Queue", style=discord.ButtonStyle.red, custom_id="close_queue", emoji="🔏") + async def close(self, interaction: discord.Interaction, button): + if interaction.client.queue.is_open: + interaction.client.queue.is_open = False + await interaction.response.send_message(QUEUE_CLOSED, ephemeral=True, delete_after=DEFAULT_TIMEOUT) + await update_queue_messages(interaction.client) + return + else: + await interaction.response.send_message(QUEUE_ALREADY_CLOSED, ephemeral=True, delete_after=SHORT_TIMEOUT) + + @discord.ui.button(label="Clear Queue", style=discord.ButtonStyle.danger, custom_id="clear_queue", emoji="💥") + async def clear_queue(self, interaction: discord.Interaction, button): + await interaction.response.send_modal(ClearConfirmModal()) + + @discord.ui.button(label="Remove Student", style=discord.ButtonStyle.danger, custom_id="remove_from_queue", emoji="🗑️") + async def remove_from_queue(self, interaction: discord.Interaction, button): + await interaction.response.send_modal(RemoveConfirmModal()) + +class TAQueueInformation(discord.ui.ActionRow[discord.ui.LayoutView]): + view: "TAView" + @discord.ui.button(label="Days Since Last Incident", style=discord.ButtonStyle.secondary, custom_id="days_since_incident", emoji="⚠️") + async def days_since_incident_btn(self, interaction: discord.Interaction, button): + days, issue_text = get_last_incident_info() + if days is None: + message = "No incidents have been reported yet." + elif days == 1: + message = f"1 day since last incident. Description: {issue_text or 'No description provided.'}" + else: + message = f"{days} days since last incident. Description: {issue_text or 'No description provided.'}" + + await interaction.response.send_message(message, ephemeral=True, delete_after=DEFAULT_TIMEOUT) + + @discord.ui.button(label="Student Info", style=discord.ButtonStyle.secondary, custom_id="student_info", emoji="📝") + async def student_info(self, interaction: discord.Interaction, button): + headers, rows = get_student_info() + width = STUDENT_INFO_WIDTH + def row_to_line(items): + return "| ".join(fixed_width(str(x), width) for x in items) + + divider = "-" * (width * len(headers) + 3 * (len(headers)-1)) + body = "\n".join(row_to_line(r) for r in rows) + builder = f"```Student Info:\n{row_to_line(headers)}\n{divider}\n{body}```" + await interaction.response.send_message(builder, ephemeral=True, delete_after=LONG_TIMEOUT) + @discord.ui.button(label="Edit Hours", style=discord.ButtonStyle.secondary, custom_id="edit_hours", emoji="🕐") async def edit_queue_hours(self, interaction: discord.Interaction, button: discord.ui.Button): from ui.modals import EditQueueHoursModal await interaction.response.send_modal(EditQueueHoursModal()) +class TAView(discord.ui.LayoutView): + + def __init__(self): + super().__init__(timeout=None) + container = discord.ui.Container[discord.ui.LayoutView]( + discord.ui.Section( + "## Queue Controls", + accessory=discord.ui.Thumbnail["TAView"]("https://brightspotcdn.byu.edu/8e/28/7bcd62fe4b2b9517b74f783decfe/1-monogram-378w.svg") + ), + TAQueueControls(), + TAQueueManagement(), + TAQueueInformation() + ) + row: discord.ui.ActionRow[TAView] = discord.ui.ActionRow() + self.add_item(container) From 9601ac3a84ac2eb4876e11a7078ab1a63e4b98d8 Mon Sep 17 00:00:00 2001 From: Jacob Date: Thu, 4 Jun 2026 10:31:26 -0600 Subject: [PATCH 2/3] refactor: turned queue_view into a component and cleaned up TA view --- bot.py | 15 +-------------- ui/views/queue_view.py | 24 ++++++++++++++++++------ ui/views/ta_view.py | 37 ++++++++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/bot.py b/bot.py index ef21cf5..f5f09a3 100644 --- a/bot.py +++ b/bot.py @@ -3,7 +3,7 @@ from discord.utils import get from help_queue import HelpQueue from ui.views.queue_view import QueueView -from ui.views.ta_view import TAView, TAQueueControls, TAQueueManagement, TAQueueInformation +from ui.views.ta_view import TAView from ui.helpers.constants import HELP_CHANNEL_NAME, TA_TEXT_CHANNEL_NAME, TA_VOICE_CHANNEL_NAME from ui.helpers.discord_helpers import update_queue_messages from records import QueueEntry @@ -214,7 +214,6 @@ async def queue_handler(self, interaction: discord.Interaction, question, is_pas @bot.tree.command(name="queue") async def queue_panel(interaction: discord.Interaction): await interaction.response.send_message( - "Queue Panel", view=QueueView() ) @@ -223,18 +222,6 @@ async def ta_panel(interaction: discord.Interaction): await interaction.response.send_message( view=TAView() ) - # await interaction.channel.send( - # "Queue Controls", - # view=TAQueueControls() - # ) - # await interaction.channel.send( - # "Queue Management", - # view=TAQueueManagement() - # ) - # await interaction.channel.send( - # "Queue Information", - # view=TAQueueInformation() - # ) token: str = os.getenv("TOKEN") bot.run(token) \ No newline at end of file diff --git a/ui/views/queue_view.py b/ui/views/queue_view.py index 35fc58b..8c42ddd 100644 --- a/ui/views/queue_view.py +++ b/ui/views/queue_view.py @@ -5,11 +5,7 @@ from ui.helpers.constants import DEFAULT_TIMEOUT, SHORT_TIMEOUT from ui.helpers.discord_helpers import update_queue_messages - -class QueueView(discord.ui.View): - def __init__(self): - super().__init__(timeout=None) - +class QueueRequests(discord.ui.ActionRow[discord.ui.LayoutView]): @discord.ui.button(label="Need Help", style=discord.ButtonStyle.primary, custom_id="need_help", emoji="🙏") async def help_btn(self, interaction: discord.Interaction, button): ok = await require_queue_open_and_not_in_queue(interaction) @@ -52,7 +48,23 @@ async def position_btn(self, interaction: discord.Interaction, button): ephemeral=True, delete_after=DEFAULT_TIMEOUT, ) - +class EsotericCommands(discord.ui.ActionRow[discord.ui.LayoutView]): @discord.ui.button(label="Report Bot Problem", style=discord.ButtonStyle.secondary, custom_id="report_bot_problem", emoji="☢️") async def report_bot_problem_btn(self, interaction: discord.Interaction, button): await interaction.response.send_modal(BotIssueModal()) + +class QueueView(discord.ui.LayoutView): + def __init__(self): + super().__init__(timeout=None) + + + container = discord.ui.Container[discord.ui.LayoutView]( + discord.ui.TextDisplay("## Queue Requests"), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), + QueueRequests(), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), + EsotericCommands(), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), + ) + + self.add_item(container) diff --git a/ui/views/ta_view.py b/ui/views/ta_view.py index 7c577b5..3bffdb6 100644 --- a/ui/views/ta_view.py +++ b/ui/views/ta_view.py @@ -11,9 +11,9 @@ class BaseLayoutView(discord.ui.LayoutView): pass -class TAQueueControls(discord.ui.ActionRow[discord.ui.LayoutView]): +class TAQueueControls1(discord.ui.ActionRow[discord.ui.LayoutView]): view: "TAView" - @discord.ui.button(label="Next", style=discord.ButtonStyle.blurple, custom_id="next", emoji="➡️") + @discord.ui.button(label="Next Student", style=discord.ButtonStyle.blurple, custom_id="next", emoji="➡️") async def next(self, interaction: discord.Interaction, button): entry: Optional[QueueEntry] = await interaction.client.queue.next() @@ -36,7 +36,7 @@ async def next(self, interaction: discord.Interaction, button): if not interaction.response.is_done(): await interaction.response.send_message(NOW_HELPING_TEMPLATE.format(ta=interaction.user.display_name, student=entry.username), delete_after=DEFAULT_TIMEOUT) - @discord.ui.button(label="Next Online", style=discord.ButtonStyle.blurple, custom_id="next_online", emoji="💻") + @discord.ui.button(label="Next Student (Online)", style=discord.ButtonStyle.blurple, custom_id="next_online", emoji="💻") async def next_online(self, interaction: discord.Interaction, button: discord.ui.Button): # Get who was at front before removal front_before = await interaction.client.queue.get_front() @@ -61,6 +61,9 @@ async def next_online(self, interaction: discord.Interaction, button: discord.ui delete_after=DEFAULT_TIMEOUT ) + + +class TAQueueControls2(discord.ui.ActionRow[discord.ui.LayoutView]): @discord.ui.button(label="Next Passoff", style=discord.ButtonStyle.blurple, custom_id="next_passoff", emoji="✅") async def next_passoff(self, interaction: discord.Interaction, button: discord.ui.Button): # Get who was at front before removal @@ -83,7 +86,7 @@ async def next_passoff(self, interaction: discord.Interaction, button: discord.u delete_after=DEFAULT_TIMEOUT ) - @discord.ui.button(label="Next Online Passoff", style=discord.ButtonStyle.blurple, custom_id="next_online_passoff", emoji="☑️") + @discord.ui.button(label="Next Passoff (Online)", style=discord.ButtonStyle.blurple, custom_id="next_online_passoff", emoji="☑️") async def next_online_passoff(self, interaction: discord.Interaction, button: discord.ui.Button): # Get who was at front before removal front_before = await interaction.client.queue.get_front() @@ -104,7 +107,8 @@ async def next_online_passoff(self, interaction: discord.Interaction, button: di delete_after=DEFAULT_TIMEOUT ) - @discord.ui.button(label="Finish", style=discord.ButtonStyle.green, custom_id="finish", emoji="🔚") +class TAQueueControls3(discord.ui.ActionRow[discord.ui.LayoutView]): + @discord.ui.button(label="Finish Helping Student", style=discord.ButtonStyle.green, custom_id="finish", emoji="🔚") async def finish_button(self, interaction: discord.Interaction, button): online_ta_vc: discord.VoiceChannel = get_channel(interaction, TA_VOICE_CHANNEL_NAME) @@ -195,13 +199,24 @@ class TAView(discord.ui.LayoutView): def __init__(self): super().__init__(timeout=None) container = discord.ui.Container[discord.ui.LayoutView]( - discord.ui.Section( - "## Queue Controls", - accessory=discord.ui.Thumbnail["TAView"]("https://brightspotcdn.byu.edu/8e/28/7bcd62fe4b2b9517b74f783decfe/1-monogram-378w.svg") - ), - TAQueueControls(), + discord.ui.TextDisplay("## Queue Controls"), + # discord.ui.Section( + # "## Queue Controls", + # accessory=discord.ui.Thumbnail["TAView"]("https://images.seeklogo.com/logo-png/30/1/byu-brigham-young-university-logo-png_seeklogo-306722.png") + # ), + discord.ui.Separator(visible=False, spacing=discord.SeparatorSpacing.large), + discord.ui.TextDisplay("### Basic Controls"), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), + TAQueueControls1(), + TAQueueControls2(), + TAQueueControls3(), + discord.ui.Separator(visible=False, spacing=discord.SeparatorSpacing.large), + discord.ui.TextDisplay("### Queue Management"), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), TAQueueManagement(), + discord.ui.Separator(visible=False, spacing=discord.SeparatorSpacing.large), + discord.ui.TextDisplay("### Information/Upkeep"), + discord.ui.Separator(visible=True, spacing=discord.SeparatorSpacing.small), TAQueueInformation() ) - row: discord.ui.ActionRow[TAView] = discord.ui.ActionRow() self.add_item(container) From 1a8568f5c1d633abf5ce93d9be2aef261433bd93 Mon Sep 17 00:00:00 2001 From: Jacob Date: Thu, 4 Jun 2026 13:49:16 -0600 Subject: [PATCH 3/3] fix: remove unused BaseLayoutView --- ui/views/ta_view.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/views/ta_view.py b/ui/views/ta_view.py index 3bffdb6..cd1bcf3 100644 --- a/ui/views/ta_view.py +++ b/ui/views/ta_view.py @@ -8,9 +8,6 @@ from ui.helpers.utils import fixed_width from ui.helpers.discord_helpers import get_channel, get_role, move_to_breakout, safe_dm_user, notify_next_if_changed, update_queue_messages -class BaseLayoutView(discord.ui.LayoutView): - pass - class TAQueueControls1(discord.ui.ActionRow[discord.ui.LayoutView]): view: "TAView" @discord.ui.button(label="Next Student", style=discord.ButtonStyle.blurple, custom_id="next", emoji="➡️")