Skip to content
This repository was archived by the owner on Apr 6, 2026. It is now read-only.

feat(dashboard): add operator commands panel to dashboard#360

Merged
karaktaka merged 7 commits into
mainfrom
feat/operator-dashboard-commands
Mar 18, 2026
Merged

feat(dashboard): add operator commands panel to dashboard#360
karaktaka merged 7 commits into
mainfrom
feat/operator-dashboard-commands

Conversation

@karaktaka
Copy link
Copy Markdown
Contributor

@karaktaka karaktaka commented Mar 18, 2026

Summary

  • Exposes bot operator controls (health, permissions, error throttle, debug toggle, command sync) as sub-tabs inside the existing Bot Health and Modules dashboard pages — no new sidebar entries needed
  • Adds FastAPI routes (/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
  • Adds test-mode mock resolver routes and fixture data for all new endpoints so the mockup toolbar works without a live bot
  • Extracts shared .subtab-bar/.subtab-btn CSS from three operator tab components into a reusable SubTabBar.vue component using Vue 3 :slotted() — removes ~110 lines of duplicate CSS
  • Caches the required_permissions lookup in valkey.py across requests; invalidates on module load/unload

Test plan

  • Open dashboard in test mode (MockupToolbar) — Bot Health and Modules tabs both show sub-tab bars without console errors
  • Sub-tabs navigate correctly: health / permissions / error control in Bot Health; modules / sync in Modules
  • Permissions tab lazy-loads on first visit; does not re-fetch on re-navigation
  • Error suppress/resume buttons toggle state correctly in test mode
  • Debug toggle updates state optimistically; button disabled while request is in-flight
  • Command sync modal sends correct mode and guild IDs
  • Recipe sync tab: cache stats load, sync button queues a job, browse tab filters work
  • npm run build passes with no type errors

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Bot Permissions dashboard: per-guild permission status with subscribe/unsubscribe for missing-permission notifications.
    • Error Control panel: view error throttling, suppress/resume notifications, and toggle debug logging.
    • Command Sync UI: sync commands with global/local/copy/clear modes and optional guild selection.
    • Operator UI reorganized into sub-tabs (Health, Permissions, Error Control, Modules/Sync) with a reusable SubTabBar.
  • Chores

    • Added English/German translations, dev fixtures and mock endpoints for operator features.

karaktaka and others added 5 commits March 18, 2026 20:54
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>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

Warning

Rate limit exceeded

@karaktaka has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 49 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1bf2ba33-d581-45c5-becc-245e984d8ba6

📥 Commits

Reviewing files that changed from the base of the PR and between a407aa3 and 37ecff9.

📒 Files selected for processing (2)
  • NerdyPy/utils/valkey.py
  • web/routes/operator.py
📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Backend operator commands & API
NerdyPy/utils/valkey.py, web/routes/operator.py, web/schemas.py
Added module-level cache for required permissions and new Valkey command handling (permissions check, error throttle control, debug toggle, sync commands). New API endpoints for bot-permissions (list/subscribe/unsubscribe), error control (status/suppress/resume), debug toggle, and command sync. New Pydantic request/response models. Watch cache invalidation and HTTP error mapping.
Frontend types & dev mocks
web/frontend/src/api/types.ts, web/frontend/src/dev/fixtures.ts, web/frontend/src/dev/resolver.ts
Declared TypeScript interfaces for permissions, error status/actions, debug toggle, and sync requests/responses. Added fixtures for operator data and extended mock resolver with subscription endpoints, error-status/suppress/resume, debug-toggle, and sync endpoints. Includes parseDurationSecs and in-memory subscription state—verify parity with backend semantics.
Frontend reusable component
web/frontend/src/components/SubTabBar.vue
New presentational SubTabBar component used to replace duplicated sub-tab markup across operator views.
Frontend i18n
web/frontend/src/i18n/locales/en.ts, web/frontend/src/i18n/locales/de.ts
Added extensive localization keys for operator modules, command sync UI, bot permissions, and error-control/dashboard texts. Ensure all new UI strings are covered.
Frontend operator views
web/frontend/src/views/guild/tabs/OperatorDashboardTab.vue, web/frontend/src/views/guild/tabs/OperatorModulesTab.vue, web/frontend/src/views/guild/tabs/OperatorRecipeSyncTab.vue
OperatorDashboard refactored into three subtabs (health, permissions, error_control) with per-tab loading/error states, lazy fetching, permission subscription toggles, error suppression form, and debug toggle. OperatorModulesTab adds a Command Sync tab (modes: global/local/copy/clear) with guild selection. Recipe sync tab updated to use SubTabBar. Review async flows, state isolation, and user-facing messages from sync/error APIs.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly summarizes the main change: adding operator commands/controls to the dashboard via new sub-tabs and API routes.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread NerdyPy/utils/valkey.py Fixed
Comment thread NerdyPy/utils/valkey.py Fixed
…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>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
NerdyPy/utils/valkey.py (1)

316-319: ⚠️ Potential issue | 🔴 Critical

Syntax error: global declaration must precede all assignments.

The global _required_permissions on line 316 conflicts with the assignments on lines 122 and 134. Python requires the global statement 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_permissions from 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

📥 Commits

Reviewing files that changed from the base of the PR and between 699f7b1 and f865705.

📒 Files selected for processing (12)
  • NerdyPy/utils/valkey.py
  • web/frontend/src/api/types.ts
  • web/frontend/src/components/SubTabBar.vue
  • web/frontend/src/dev/fixtures.ts
  • web/frontend/src/dev/resolver.ts
  • web/frontend/src/i18n/locales/de.ts
  • web/frontend/src/i18n/locales/en.ts
  • web/frontend/src/views/guild/tabs/OperatorDashboardTab.vue
  • web/frontend/src/views/guild/tabs/OperatorModulesTab.vue
  • web/frontend/src/views/guild/tabs/OperatorRecipeSyncTab.vue
  • web/routes/operator.py
  • web/schemas.py

Comment thread web/routes/operator.py
Comment thread NerdyPy/utils/valkey.py Dismissed
Comment thread NerdyPy/utils/valkey.py Dismissed
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between f865705 and a407aa3.

📒 Files selected for processing (1)
  • NerdyPy/utils/valkey.py

Comment thread NerdyPy/utils/valkey.py Outdated
…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>
@karaktaka
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@karaktaka karaktaka merged commit ec8d71a into main Mar 18, 2026
13 checks passed
@karaktaka karaktaka deleted the feat/operator-dashboard-commands branch March 18, 2026 21:43
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant