feat(dashboard): add operator commands panel to dashboard#360
Conversation
Expose bot operator commands in the dashboard via two expanded tabs: Operator Dashboard now has 3 sub-tabs: - Health — existing health metrics (unchanged) - Bot Permissions — per-guild permission check table with subscribe/unsubscribe toggle for missing-permission DM notifications on bot restart - Error Control — error throttle status, suppress (with duration input), resume, and debug logging toggle Operator Modules now has 2 sub-tabs: - Modules — existing load/unload UI (unchanged) - Command Sync — sync slash commands with Discord API; supports global, local, copy-global-to-guild, and clear-guild modes Backend: - 6 new Valkey commands: bot_permissions, error_status, error_suppress, error_resume, debug_toggle, sync_commands - 8 new FastAPI endpoints under /operator/ - New Pydantic schemas for all new request/response types - New TypeScript interfaces in api/types.ts - EN + DE i18n keys for all new UI strings Co-Authored-By: Claude <noreply@anthropic.com>
- Extract inline compound @click expressions to simple tab switches; a single watch(activeTab) watcher now handles all lazy-load logic - Initialize debugEnabled from the error_status response instead of waiting for the first toggle (adds debug_enabled field to valkey handler, Pydantic schema, and TS type) - Replace hard-coded "N missing" badge text with i18n key (permissions_missing in both en + de locales) - Remove redundant fetchGuilds() call on sync tab button click; the existing watch(activeTab) watcher already handles it Co-Authored-By: Claude <noreply@anthropic.com>
Add fixture data and resolver routes for all endpoints introduced in this branch so test mode works without a live bot: - /operator/bot-permissions (+ subscriptions CRUD) - /operator/error-status, error-suppress, error-resume - /operator/debug-toggle (stateful toggle) - /operator/sync-commands - /operator/recipe-sync, recipe-sync/status, recipe-cache Suppress/resume and debug-toggle are stateful within the browser session; subscriptions are also mutated in-memory. Co-Authored-By: Claude <noreply@anthropic.com>
valkey.py: - Cache required_permissions_for() result; invalidate on module load/unload so the per-request recompute is eliminated OperatorDashboardTab.vue: - Replace !permissions.length lazy-load guard with permFetched boolean so navigating back to an empty-guild bot doesn't re-fetch on every tab switch - Remove redundant debugEnabled ref; derive state directly from errorStatus.debug_enabled and update it optimistically after toggle - Disable the Debug Toggle button until error status has loaded resolver.ts (dev mode): - Fix error-resume mock to check suppression state before clearing, matching real backend behavior (returns already_active when not suppressed) - Document parseDurationSecs single-unit limitation vs backend pytimeparse2 Co-Authored-By: Claude <noreply@anthropic.com>
…ponent Removes byte-for-byte duplicate .subtab-bar/.subtab-btn scoped CSS from OperatorDashboardTab, OperatorModulesTab, and OperatorRecipeSyncTab. Uses Vue 3 :slotted() to style slot-projected buttons from the parent. Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds operator tooling: bot-permissions inspection and subscription management, error-throttling controls (status/suppress/resume), debug toggle, and slash-command sync. Implements Valkey command handlers and cache invalidation, backend API routes and Pydantic schemas, frontend types/fixtures/mocks, i18n keys, a SubTabBar component, and multi-tab operator UIs. Changes
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…key_command Python requires the global statement to appear before any assignment to the name in the same function scope — the compiler rejects it at parse time regardless of runtime branch ordering. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
NerdyPy/utils/valkey.py (1)
316-319:⚠️ Potential issue | 🔴 CriticalSyntax error:
globaldeclaration must precede all assignments.The
global _required_permissionson line 316 conflicts with the assignments on lines 122 and 134. Python requires theglobalstatement before any assignment to that variable within the function scope.🐛 Fix: Move global declaration to top of function
Add the global declaration at the start of
handle_valkey_command, after the docstring:async def handle_valkey_command(bot, command: str, payload: dict) -> dict: """ Dispatches Valkey pub/sub commands... """ + global _required_permissions + if command == "health":Then remove the redundant
global _required_permissionsfrom line 316:elif command == "bot_permissions": from utils.permissions import check_guild_permissions, required_permissions_for - global _required_permissions if _required_permissions is None:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@NerdyPy/utils/valkey.py` around lines 316 - 319, Move the "global _required_permissions" declaration to the top of the handle_valkey_command function (immediately after its docstring) so the variable is declared global before any assignments in that function, and remove the later redundant "global _required_permissions" use near the block that sets _required_permissions (the assignment block that calls required_permissions_for and assigns required); ensure all references in handle_valkey_command now rely on the single global declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/routes/operator.py`:
- Around line 386-391: The ErrorStatusResponse returned by the handler is
missing the debug_enabled field; update the return construction to include
debug_enabled=result.get("debug_enabled") (or .get("debug_enabled", None)) so
the response uses the actual bot debug state provided by the valkey
'error_status' (see valkey.py where debug_enabled is set); modify the
dict-to-ErrorStatusResponse mapping in the current handler to pass debug_enabled
through alongside is_suppressed, suppressed_remaining, throttle_window, and
buckets.
---
Duplicate comments:
In `@NerdyPy/utils/valkey.py`:
- Around line 316-319: Move the "global _required_permissions" declaration to
the top of the handle_valkey_command function (immediately after its docstring)
so the variable is declared global before any assignments in that function, and
remove the later redundant "global _required_permissions" use near the block
that sets _required_permissions (the assignment block that calls
required_permissions_for and assigns required); ensure all references in
handle_valkey_command now rely on the single global declaration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: c5c8a609-7e55-4be1-9f9f-6f3ad03c4cb7
📒 Files selected for processing (12)
NerdyPy/utils/valkey.pyweb/frontend/src/api/types.tsweb/frontend/src/components/SubTabBar.vueweb/frontend/src/dev/fixtures.tsweb/frontend/src/dev/resolver.tsweb/frontend/src/i18n/locales/de.tsweb/frontend/src/i18n/locales/en.tsweb/frontend/src/views/guild/tabs/OperatorDashboardTab.vueweb/frontend/src/views/guild/tabs/OperatorModulesTab.vueweb/frontend/src/views/guild/tabs/OperatorRecipeSyncTab.vueweb/routes/operator.pyweb/schemas.py
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@NerdyPy/utils/valkey.py`:
- Around line 370-371: The error message is inconsistent with the variable name:
update the return error text that currently says "guild_id required for this
mode" to refer to "guild_ids" (e.g., "guild_ids required for this mode" or
"guild_ids are required for this mode") so it matches the variable name
guild_ids used in the surrounding code (locate the check using guild_ids and
adjust the string returned).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2de9a454-64a2-4806-87ef-5e81cee4958a
📒 Files selected for processing (1)
NerdyPy/utils/valkey.py
…ror message typo - operator.py: ErrorStatusResponse was missing debug_enabled from the valkey result dict, causing it to always return null to the frontend - valkey.py: error message "guild_id required" → "guild_ids required" to match the guild_ids parameter name Co-Authored-By: Claude <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
/api/operator/…) for all operator actions: health, bot permissions with guild subscriptions, error status/suppress/resume, debug toggle, command sync, recipe sync, and recipe cache browsing.subtab-bar/.subtab-btnCSS from three operator tab components into a reusableSubTabBar.vuecomponent using Vue 3:slotted()— removes ~110 lines of duplicate CSSrequired_permissionslookup invalkey.pyacross requests; invalidates on module load/unloadTest plan
npm run buildpasses with no type errors🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores