Skip to content

Commit d2b5042

Browse files
sebkuiplorenzo132
andauthored
Added submenu functionality to threadmenu. Fixes #3403 (#3404)
* Threadmenu now supports submenus * Fix a small issue with path not resetting after main menu. * Fix copilot suggestions * Black formatting * Fix undeclared vars * threadmenu: submenu navigation fixes Signed-off-by: lorenzo132 <50767078+lorenzo132@users.noreply.github.com> * threadmenu: submenu navigation fixes Refactor thread creation menu handling to improve path management and submenu navigation. Signed-off-by: lorenzo132 <50767078+lorenzo132@users.noreply.github.com> * Fix formatting according to black --------- Signed-off-by: lorenzo132 <50767078+lorenzo132@users.noreply.github.com> Co-authored-by: lorenzo132 <50767078+lorenzo132@users.noreply.github.com>
1 parent cfedecb commit d2b5042

File tree

2 files changed

+94
-17
lines changed

2 files changed

+94
-17
lines changed

cogs/threadmenu.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ def typecheck(m):
178178
if label.lower() == "cancel":
179179
return await ctx.send("Cancelled.")
180180

181+
if label.lower() == "main menu":
182+
return await ctx.send("You cannot use that label.")
183+
181184
if sanitized_label in conf["options"]:
182185
await ctx.send("That option already exists. Use `threadmenu edit` to edit it.")
183186
return

core/thread.py

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -849,11 +849,9 @@ async def send_genesis_message():
849849
if getattr(self, "_selected_thread_creation_menu_option", None) and self.bot.config.get(
850850
"thread_creation_menu_selection_log"
851851
):
852-
opt = self._selected_thread_creation_menu_option
852+
path = self._selected_thread_creation_menu_option
853853
try:
854-
log_txt = f"Selected menu option: {opt.get('label')} ({opt.get('type')})"
855-
if opt.get("type") == "command":
856-
log_txt += f" -> {opt.get('callback')}"
854+
log_txt = f"Selected menu path: {' -> '.join(path)}"
857855
await channel.send(embed=discord.Embed(description=log_txt, color=self.bot.mod_color))
858856
except Exception:
859857
logger.warning(
@@ -2659,29 +2657,44 @@ async def create(
26592657
placeholder = "Select an option to contact the staff team."
26602658
timeout = 20
26612659

2662-
options = self.bot.config.get("thread_creation_menu_options") or {}
2663-
submenus = self.bot.config.get("thread_creation_menu_submenus") or {}
2664-
26652660
# Minimal inline view implementation (avoid importing plugin code)
26662661

26672662
thread.ready = False # not ready yet
26682663

26692664
class _ThreadCreationMenuSelect(discord.ui.Select):
2670-
def __init__(self, outer_thread: Thread):
2665+
def __init__(
2666+
self,
2667+
bot,
2668+
outer_thread: Thread,
2669+
option_data: dict,
2670+
menu_msg: discord.Message,
2671+
path: list,
2672+
is_home: bool = True,
2673+
):
2674+
self.bot = bot
26712675
self.outer_thread = outer_thread
2672-
opts = [
2676+
self.option_data = option_data
2677+
self.menu_msg = menu_msg
2678+
self.path = path
2679+
options = [
26732680
discord.SelectOption(
26742681
label=o["label"],
26752682
description=o["description"],
26762683
emoji=o["emoji"],
26772684
)
2678-
for o in options.values()
2685+
for o in option_data.values()
26792686
]
2687+
if not is_home:
2688+
options.append(
2689+
discord.SelectOption(
2690+
label="main menu", description="Return to the main menu", emoji="🏠"
2691+
)
2692+
)
26802693
super().__init__(
26812694
placeholder=placeholder,
26822695
min_values=1,
26832696
max_values=1,
2684-
options=opts,
2697+
options=options,
26852698
)
26862699

26872700
async def callback(self, interaction: discord.Interaction):
@@ -2696,8 +2709,45 @@ async def callback(self, interaction: discord.Interaction):
26962709
chosen_label = self.values[0]
26972710
# Resolve option key
26982711
key = chosen_label.lower().replace(" ", "_")
2699-
selected = options.get(key)
2700-
self.outer_thread._selected_thread_creation_menu_option = selected
2712+
if key == "main_menu":
2713+
option_data = self.bot.config.get("thread_creation_menu_options") or {}
2714+
new_view = _ThreadCreationMenuView(
2715+
self.bot,
2716+
self.outer_thread,
2717+
option_data,
2718+
self.menu_msg,
2719+
path=[],
2720+
is_home=True,
2721+
)
2722+
return await self.menu_msg.edit(view=new_view)
2723+
selected: dict = self.option_data.get(key, {})
2724+
next_path = [*self.path, chosen_label]
2725+
if selected.get("type", "command") == "submenu":
2726+
submenu_data = self.bot.config.get("thread_creation_menu_submenus") or {}
2727+
submenu_key = selected.get("callback", key)
2728+
option_data = submenu_data.get(submenu_key, {})
2729+
if not option_data:
2730+
home_options = self.bot.config.get("thread_creation_menu_options") or {}
2731+
new_view = _ThreadCreationMenuView(
2732+
self.bot,
2733+
self.outer_thread,
2734+
home_options,
2735+
self.menu_msg,
2736+
path=[],
2737+
is_home=True,
2738+
)
2739+
return await self.menu_msg.edit(view=new_view)
2740+
new_view = _ThreadCreationMenuView(
2741+
self.bot,
2742+
self.outer_thread,
2743+
option_data,
2744+
self.menu_msg,
2745+
path=next_path,
2746+
is_home=False,
2747+
)
2748+
return await self.menu_msg.edit(view=new_view)
2749+
2750+
self.outer_thread._selected_thread_creation_menu_option = next_path
27012751
# Reflect the selection in the original DM by editing the embed/body
27022752
try:
27032753
msg = getattr(interaction, "message", None)
@@ -2936,10 +2986,30 @@ async def callback(self, interaction: discord.Interaction):
29362986
ctx_.command.checks = old_checks
29372987

29382988
class _ThreadCreationMenuView(discord.ui.View):
2939-
def __init__(self, outer_thread: Thread):
2989+
def __init__(
2990+
self,
2991+
bot,
2992+
outer_thread: Thread,
2993+
option_data: dict,
2994+
menu_msg: discord.Message,
2995+
path: list,
2996+
is_home: bool = True,
2997+
):
29402998
super().__init__(timeout=timeout)
29412999
self.outer_thread = outer_thread
2942-
self.add_item(_ThreadCreationMenuSelect(outer_thread))
3000+
self.path = path
3001+
self.menu_msg = menu_msg
3002+
self.option_data = option_data
3003+
self.add_item(
3004+
_ThreadCreationMenuSelect(
3005+
bot,
3006+
outer_thread,
3007+
option_data=option_data,
3008+
menu_msg=menu_msg,
3009+
path=self.path,
3010+
is_home=is_home,
3011+
)
3012+
)
29433013

29443014
async def on_timeout(self):
29453015
# Timeout -> abort thread creation
@@ -3061,8 +3131,12 @@ async def on_timeout(self):
30613131
embed.set_thumbnail(url=embed_thumb)
30623132
except Exception as e:
30633133
logger.debug("Thumbnail set failed (ignored): %s", e)
3064-
menu_view = _ThreadCreationMenuView(thread)
3065-
menu_msg = await recipient.send(embed=embed, view=menu_view)
3134+
menu_msg = await recipient.send(embed=embed)
3135+
option_data = self.bot.config.get("thread_creation_menu_options") or {}
3136+
menu_view = _ThreadCreationMenuView(
3137+
self.bot, thread, option_data, menu_msg, path=[], is_home=True
3138+
)
3139+
menu_msg = await menu_msg.edit(view=menu_view)
30663140
# mark thread as pending menu selection
30673141
thread._pending_menu = True
30683142
# Explicitly attach the message to the view for safety in callbacks

0 commit comments

Comments
 (0)