diff --git a/bot/lib/BotClient.ts b/bot/lib/BotClient.ts index da1a868..d347f08 100644 --- a/bot/lib/BotClient.ts +++ b/bot/lib/BotClient.ts @@ -8,7 +8,7 @@ import { EventLoader } from "@lib/loaders/EventLoader"; export class Client extends DiscordClient { commands: Collection; - knownCommands: Set; + knownCommands: Map; lastCommandTimestamp: number | null = null; maintenanceMode: boolean = false; private commandLoader: CommandLoader; @@ -17,7 +17,7 @@ export class Client extends DiscordClient { constructor({ intents }: { intents: number[] }) { super({ intents }); this.commands = new Collection(); - this.knownCommands = new Set(); + this.knownCommands = new Map(); this.commandLoader = new CommandLoader(this); this.eventLoader = new EventLoader(this); } diff --git a/bot/lib/loaders/CommandLoader.ts b/bot/lib/loaders/CommandLoader.ts index 3264ca2..0fe8a5f 100644 --- a/bot/lib/loaders/CommandLoader.ts +++ b/bot/lib/loaders/CommandLoader.ts @@ -72,7 +72,7 @@ export class CommandLoader { command.category = category; // Track all known commands regardless of enabled status - this.client.knownCommands.add(command.data.name); + this.client.knownCommands.set(command.data.name, category); const isEnabled = config.commands[command.data.name] !== false; diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index fb5bb3e..cacbf5d 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -12,7 +12,7 @@ interface ChannelOption { id: string; name: string; type: number; } interface SettingsMeta { roles: RoleOption[]; channels: ChannelOption[]; - commands: string[]; + commands: { name: string; category: string }[]; } import { type GameConfigType } from "@shared/lib/config"; @@ -400,29 +400,43 @@ export function Settings() { {activeTab === "system" && (
-
- {meta.commands.map(cmd => ( -
-
- /{cmd} - - {config?.commands?.[cmd] === false ? "Disabled" : "Enabled"} - + + {meta.commands.length === 0 ? ( +
+ No commands found in metadata. +
+ ) : ( + Object.entries( + meta.commands.reduce((acc, cmd) => { + const cat = cmd.category || 'Uncategorized'; + if (!acc[cat]) acc[cat] = []; + acc[cat].push(cmd); + return acc; + }, {} as Record) + ).sort(([a], [b]) => a.localeCompare(b)).map(([category, commands]) => ( +
+

{category}

+
+ {commands.map(cmd => ( +
+
+ /{cmd.name} + + {config?.commands?.[cmd.name] === false ? "Disabled" : "Enabled"} + +
+ updateConfig(`commands.${cmd.name}`, e.target.checked)} + className="h-4 w-4 rounded border-white/10 bg-white/5 accent-primary cursor-pointer" + /> +
+ ))}
- updateConfig(`commands.${cmd}`, e.target.checked)} - className="h-4 w-4 rounded border-white/10 bg-white/5 accent-primary" - />
- ))} - {meta.commands.length === 0 && ( -
- No commands found in metadata. -
- )} -
+ )) + )}
)} diff --git a/web/src/server.settings.test.ts b/web/src/server.settings.test.ts index a14ec38..3289e41 100644 --- a/web/src/server.settings.test.ts +++ b/web/src/server.settings.test.ts @@ -62,7 +62,11 @@ mock.module("../../bot/lib/BotClient", () => ({ commands: [ { data: { name: "ping" } } ], - knownCommands: new Set(["ping", "help", "disabled-cmd"]) + knownCommands: new Map([ + ["ping", "utility"], + ["help", "utility"], + ["disabled-cmd", "admin"] + ]) } })); @@ -156,6 +160,11 @@ describe("Settings API", () => { expect(data.roles).toHaveLength(2); expect(data.roles[0]).toEqual({ id: "role1", name: "Admin", color: "#ffffff" }); expect(data.channels[0]).toEqual({ id: "chan1", name: "general", type: 0 }); - expect(data.commands).toContain("ping"); + + // Check new commands structure + expect(data.commands).toBeArray(); + expect(data.commands.length).toBeGreaterThan(0); + expect(data.commands[0]).toHaveProperty("name"); + expect(data.commands[0]).toHaveProperty("category"); }); }); diff --git a/web/src/server.ts b/web/src/server.ts index 8e90764..0e89989 100644 --- a/web/src/server.ts +++ b/web/src/server.ts @@ -226,7 +226,12 @@ export async function createWebServer(config: WebServerConfig = {}): Promise ({ id: c.id, name: c.name, type: c.type })); - const commands = Array.from(AuroraClient.knownCommands).sort(); + const commands = Array.from(AuroraClient.knownCommands.entries()) + .map(([name, category]) => ({ name, category })) + .sort((a, b) => { + if (a.category !== b.category) return a.category.localeCompare(b.category); + return a.name.localeCompare(b.name); + }); return Response.json({ roles, channels, commands }); } catch (error) {