fix(web): show all guild categories in dashboard selector#477
fix(web): show all guild categories in dashboard selector#477BillChirico wants to merge 17 commits intomainfrom
Conversation
|
|
🚅 Deployed to the volvox-bot-pr-477 environment in volvox-bot
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 58 minutes and 29 seconds. ⌛ 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: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughReplaces two-way guild partitioning with three categories (infrastructure, addBot, community); adds Changes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 48afc4a3dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Updates the web dashboard guild selector to surface all user guilds, classify them into actionable categories (installed/manageable vs inviteable vs community/read-only), and adds test coverage for the new invite/community flows.
Changes:
- Return all user guilds from the Discord directory API and annotate each with
botPresent. - Update the ServerSelector UI to split guilds into “Infrastructure Hubs”, “Add Bot”, and “Community Hubs”, with an invite flow that can preselect a guild.
- Add/adjust unit + component tests for the new invite URL builder, permission gating, and selector behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/lib/discord.server.ts | Changes getMutualGuilds() to return all user guilds and set botPresent based on bot guild membership. |
| web/src/lib/discord.ts | Enhances getBotInviteUrl() to optionally preselect a guild via OAuth parameters. |
| web/src/hooks/use-guild-role.ts | Adds canInviteBot() helper to determine whether the user can invite the bot to a guild. |
| web/src/components/layout/server-selector.tsx | Refactors selector UI into three categories with updated loading/empty states and invite/community actions. |
| web/tests/lib/discord.test.ts | Adds tests for getBotInviteUrl() and updates mutual guild expectations to include botPresent=false rows. |
| web/tests/hooks/use-guild-role.test.ts | Adds tests for canInviteBot() behavior. |
| web/tests/components/layout/server-selector.test.tsx | Updates/extends tests to cover the new categorized selector behavior and invite/community flows. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/src/components/layout/server-selector.tsx`:
- Around line 147-149: The "community" bucket currently includes any guild not
in infrastructureIds or addBotIds, which surfaces private/member-only servers;
update the guilds.filter used for the community key so it also checks the same
community-page eligibility predicate used by the community route. Concretely,
modify the filter in the community assignment (the guilds.filter expression) to
include the community-route eligibility check (e.g., the same function or
boolean used elsewhere such as isCommunityPageEligible(guild) or
canViewCommunityPage(guild)) in addition to the existing
!infrastructureIds.has(guild.id) and !addBotIds.has(guild.id) checks so only
guilds that actually support a public community page are included.
- Around line 377-404: The addBot rows (rendered from addBot and using
getBotInviteUrl, GuildRow and Button) are currently plain divs inside
DropdownMenuContent so they aren't in the menu's focus model; wrap each invite
row in a DropdownMenuItem (use the asChild prop) so the Button/anchor or
SectionBadge becomes the menu item and keyboard/arrow navigation can reach them,
and for unavailable invites wrap the SectionBadge in a DropdownMenuItem with
disabled or aria-disabled to preserve focusability and semantics.
- Around line 136-143: The current partitioning collapses unknown bot presence
into the Add Bot flow; update the filters so they explicitly check
guild.botPresent === true for infrastructureGuilds and guild.botPresent ===
false for addBotGuilds (treat undefined as "unknown" and exclude those guilds
from both install-based sets), and ensure downstream code (infrastructureIds,
addBotIds, and UI logic in server-selector.tsx) handles the unknown state
gracefully; also note getMutualGuilds() may return botPresent undefined so make
this explicit in the filtering logic to skip the install-based split when
presence couldn't be resolved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2ec31b6a-aeb7-4c53-b0d8-fb6f3190c9f7
📒 Files selected for processing (7)
web/src/components/layout/server-selector.tsxweb/src/hooks/use-guild-role.tsweb/src/lib/discord.server.tsweb/src/lib/discord.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Agent
- GitHub Check: Greptile Review
- GitHub Check: Cursor Bugbot
- GitHub Check: Test
- GitHub Check: Docker Build Validation
- GitHub Check: E2E Tests (2/2)
- GitHub Check: E2E Tests (1/2)
- GitHub Check: Typecheck & Build
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{js,ts,tsx}: Use single quotes for strings (except in JSON files); no double quotes
Always include semicolons at the end of statements
Use 2-space indentation (spaces, not tabs)
Always include trailing commas in multi-line arrays, objects, and function parameters
Maintain a maximum line width of 100 characters
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use
console.*methods in web dashboard code; use appropriate logging mechanisms for React applications
web/src/**/*.{ts,tsx}: New dashboard routes need title wiring in web/src/lib/page-titles.ts; use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation
Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Recharts dashboard views should use web/src/components/ui/stable-responsive-container.tsx; raw ResponsiveContainer mounts can spam width(-1)/height(-1) warnings when panels render before layout settles
Any visual dashboard or landing page change must be verified with Chrome DevTools MCP before calling it done; take a screenshot after the change
Check both light and dark themes if colors or theming changed
Check responsive behavior on mobile, tablet, and desktop if layout changed
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
**/*.{js,ts,jsx,tsx,mjs,mts}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only; do not use CommonJS
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use src/logger.js; do not use console.*
Use the safe Discord messaging helpers in src/utils/safeSend.js instead of raw reply/send/edit calls
Use parameterized SQL only; do not use string concatenation for SQL queries
Community features should be gated behind config..enabled; moderation commands are the exception
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Welcome-message variables use double braces only, like {{user}}; single braces are plain text and should not be documented, inserted, or parsed as variables
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
web/src/**/*.{ts,tsx,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Follow the design system when making changes to the UI/UX; see DESIGN.md for the design system and color palette
Files:
web/src/lib/discord.server.tsweb/src/hooks/use-guild-role.tsweb/src/components/layout/server-selector.tsxweb/src/lib/discord.ts
web/tests/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
web/tests/**/*.test.{ts,tsx}: Write web dashboard tests using Vitest 4 with thejsdomenvironment and React Testing Library, matching theweb/src/structure
Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
Files:
web/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.ts
🧠 Learnings (6)
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Applied to files:
web/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/commands/**/*.js : Guild owners should be explicitly exempted from role hierarchy restrictions in command handlers to match Discord permission model expectations
Applied to files:
web/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/components/layout/server-selector.test.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/tests/**/*.test.{ts,tsx} : Write web dashboard tests using Vitest 4 with the `jsdom` environment and React Testing Library, matching the `web/src/` structure
Applied to files:
web/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to tests/**/*.test.js : Write bot tests using Vitest 4 with the `node` environment, matching the `src/` structure in the `tests/` directory
Applied to files:
web/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to web/src/components/layout/dashboard-shell.tsx : Dashboard page titles should sync with route changes using DashboardTitleSync component mounted in dashboard-shell.tsx and canonical title string 'Volvox.Bot - AI Powered Discord Bot'
Applied to files:
web/tests/components/layout/server-selector.test.tsx
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to web/src/app/api/**/route.ts : Include guildId in signed WebSocket ticket payload when issuing tickets from dashboard endpoints
Applied to files:
web/src/lib/discord.ts
🔇 Additional comments (1)
web/src/lib/discord.ts (1)
22-36: Nice use ofURL/searchParams.This keeps the invite query construction encoded and avoids the usual string-concatenation mistakes around optional
guild_idparameters.
|
| Filename | Overview |
|---|---|
| web/src/app/api/guilds/route.ts | Switched to getUserGuildDirectory (all guilds with bot-presence annotation); applyAccessLevels correctly limits bot API queries to guilds where botPresent===true and batches in 100-guild chunks. |
| web/src/lib/discord.server.ts | New getUserGuildDirectory returns all user guilds annotated with botPresent; getUserGuilds (for auth) is unchanged and still filters to mutual-only; both degrade gracefully when the bot API is unavailable. |
| web/src/components/layout/server-selector.tsx | Three-bucket layout (Infrastructure Hubs / Add Bot / Community Hubs) is well-structured; one unused parameter in an onSelect callback that Biome will flag. |
| web/src/hooks/use-guild-role.ts | canInviteBot deliberately relies on Discord permission bits rather than the API access field; explicitly tested and intentional. |
| web/src/components/layout/guild-directory-context.tsx | isUserGuild validator accepts botPresent as undefined (unknown status) or boolean; context now surfaces all user guilds to the selector. |
| web/tests/lib/discord.test.ts | Imports updated to getUserGuildDirectory and getUserGuilds (previously flagged getMutualGuilds issue is resolved); new describe blocks cover happy-path and degraded-bot-API scenarios. |
| web/tests/hooks/use-guild-role.test.ts | Type renamed from MutualGuild to UserGuild (previously flagged issue resolved); canInviteBot and isGuildManageable tests cover both permission-bit and API-access-field paths. |
| web/tests/components/layout/server-selector.test.tsx | Comprehensive rendering tests for all three bucket states; popup-blocker fix verified via window.open spy; localStorage restore and broadcast-deduplication paths covered. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[GET /api/guilds] --> B[getUserGuildDirectory]
B --> C{Bot API available?}
C -->|Yes| D[All user guilds\nbotPresent: true / false]
C -->|No| E[All user guilds\nbotPresent: undefined]
D --> F[applyAccessLevels\nfor botPresent===true guilds]
E --> G[Return as-is\nskip access lookup]
F --> H[Guild list to client]
G --> H
H --> I[GuildDirectoryContext]
I --> J[ServerSelector useMemo]
J --> K{Classify each guild}
K -->|botPresent true/undefined & isGuildManageable| L[Infrastructure Hubs]
K -->|botPresent false & canInviteBot| M[Add Bot]
K -->|everything else| N[Community Hubs]
subgraph Auth Proxy
O[Protected route] --> P[getUserGuilds mutual only]
P --> Q{Bot API available?}
Q -->|Yes| R[Filter: bot in guild]
Q -->|No| S[Fallback: all user guilds botPresent: true]
end
Prompt To Fix All With AI
This is a comment left during a code review.
Path: web/src/components/layout/server-selector.tsx
Line: 352-355
Comment:
**Unused `e` parameter in `onSelect` callback**
The `e` parameter is declared but never referenced. Biome's `noUnusedVariables` rule will flag this.
```suggestion
onSelect={() => {
if (selectedGuild?.id === guild.id) return;
selectGuild(guild);
}}
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (10): Last reviewed commit: "fix: update test imports for UserGuild r..." | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/layout/guild-directory-context.tsx (1)
23-31: 🛠️ Refactor suggestion | 🟠 MajorValidate the fields the selector now branches on.
GuildDirectoryProvideris the only runtime boundary before these objects are treated asMutualGuild. With this PR, downstream logic now relies onowner,permissions,features, andaccess, butisMutualGuild()still admits anything that only hasid,name, andbotPresent. A partial/api/guildspayload can therefore misbucket guilds or blow up later in the invite/community flows.♻️ Suggested hardening
function isMutualGuild(value: unknown): value is MutualGuild { const g = value as Record<string, unknown>; return ( typeof value === 'object' && value !== null && typeof g.id === 'string' && typeof g.name === 'string' && + typeof g.icon === 'string' || g.icon === null && + typeof g.owner === 'boolean' && + typeof g.permissions === 'string' && + Array.isArray(g.features) && + (g.access === undefined || + g.access === 'owner' || + g.access === 'admin' || + g.access === 'moderator' || + g.access === 'viewer' || + g.access === 'bot-owner') && (g.botPresent === undefined || typeof g.botPresent === 'boolean') ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/layout/guild-directory-context.tsx` around lines 23 - 31, The type-guard isMutualGuild currently only checks id, name, and botPresent, but downstream code in GuildDirectoryProvider and invite/community flows expects owner, permissions, features, and access; update isMutualGuild to validate those fields too by ensuring (when present) owner is a boolean, permissions is the expected primitive (string or number as used elsewhere in the codebase), features is an array of strings, and access is the expected string enum/primitive; adjust the predicate to return false for partial/invalid shapes so GuildDirectoryProvider doesn't misbucket or pass malformed guild objects downstream.
♻️ Duplicate comments (1)
web/src/components/layout/server-selector.tsx (1)
149-151:⚠️ Potential issue | 🟠 MajorOnly include public, enabled community guilds in this bucket.
Right now
communityis the catch-all for every guild that is neitherinfrastructurenoraddBot, so private/member-only leftovers andbotPresent === undefinedcases still get a/community/${guild.id}link. That doesn't match the PR objective for Community Hubs, which is limited to guilds with a public community page, and it also surfaces community navigation even when the feature is disabled. Reuse the same community-page eligibility check andconfig.<feature>.enabledgate that the community route uses before adding a guild here.As per coding guidelines, "Community features should be gated behind config..enabled; moderation commands are the exception."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/layout/server-selector.tsx` around lines 149 - 151, The community bucket currently includes every guild not in infrastructureIds or addBotIds; restrict it to only public, enabled community guilds by reusing the same eligibility predicate and feature gate the community route uses: replace the guilds.filter callback for the community key with a check that ensures config.community.enabled (or the relevant config.<feature>.enabled) is true and that the guild passes the community-page eligibility function used elsewhere (e.g., isCommunityPageEligible / communityPageEligibility which checks public/communityPage and botPresent/member-only rules), while still excluding infrastructureIds and addBotIds.
🤖 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/src/hooks/use-guild-role.ts`:
- Around line 71-92: The function canInviteBot contains dead branches checking
guild.access values; remove the access comparisons (guild.access === 'owner' |
'bot-owner' | 'admin') and only use guild.owner and the permission-bit checks on
BigInt(guild.permissions) (using ADMINISTRATOR and MANAGE_GUILD) to decide
invite eligibility in canInviteBot; keep the try/catch around BigInt conversion
and return false on failure.
In `@web/src/lib/discord.server.ts`:
- Around line 301-355: The current getUserGuildsWithBotPresence swallows all
errors from fetchBotGuilds and treats them as "bot unavailable", which
incorrectly converts aborts/timeouts into degraded data; change the catch to
rethrow AbortError/timeouts and only degrade for non-abort failures. Concretely,
inside getUserGuildsWithBotPresence replace the fetchBotGuilds.catch handler so
it checks the thrown error (e.g., if err.name === 'AbortError' or err instanceof
DOMException && err.name === 'AbortError') and rethrows in that case; otherwise
log the warning and return { available: false, guilds: [] } as BotGuildResult.
This preserves the existing behavior for getUserGuildDirectory and
getMutualGuilds while ensuring aborts propagate out of
getUserGuildsWithBotPresence.
---
Outside diff comments:
In `@web/src/components/layout/guild-directory-context.tsx`:
- Around line 23-31: The type-guard isMutualGuild currently only checks id,
name, and botPresent, but downstream code in GuildDirectoryProvider and
invite/community flows expects owner, permissions, features, and access; update
isMutualGuild to validate those fields too by ensuring (when present) owner is a
boolean, permissions is the expected primitive (string or number as used
elsewhere in the codebase), features is an array of strings, and access is the
expected string enum/primitive; adjust the predicate to return false for
partial/invalid shapes so GuildDirectoryProvider doesn't misbucket or pass
malformed guild objects downstream.
---
Duplicate comments:
In `@web/src/components/layout/server-selector.tsx`:
- Around line 149-151: The community bucket currently includes every guild not
in infrastructureIds or addBotIds; restrict it to only public, enabled community
guilds by reusing the same eligibility predicate and feature gate the community
route uses: replace the guilds.filter callback for the community key with a
check that ensures config.community.enabled (or the relevant
config.<feature>.enabled) is true and that the guild passes the community-page
eligibility function used elsewhere (e.g., isCommunityPageEligible /
communityPageEligibility which checks public/communityPage and
botPresent/member-only rules), while still excluding infrastructureIds and
addBotIds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 654ec729-c525-4164-819d-db1a2ac33460
📒 Files selected for processing (10)
web/src/app/api/guilds/route.tsweb/src/components/layout/guild-directory-context.tsxweb/src/components/layout/server-selector.tsxweb/src/hooks/use-guild-role.tsweb/src/lib/discord.server.tsweb/src/types/discord.tsweb/tests/api/guilds.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: CodeQL
- GitHub Check: Agent
- GitHub Check: Greptile Review
- GitHub Check: Cursor Bugbot
- GitHub Check: E2E Tests (2/2)
- GitHub Check: Docker Build Validation
- GitHub Check: E2E Tests (1/2)
- GitHub Check: Test
- GitHub Check: Typecheck & Build
- GitHub Check: Analyze (actions)
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{js,ts,tsx}: Use single quotes for strings (except in JSON files); no double quotes
Always include semicolons at the end of statements
Use 2-space indentation (spaces, not tabs)
Always include trailing commas in multi-line arrays, objects, and function parameters
Maintain a maximum line width of 100 characters
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsxweb/tests/lib/discord.test.ts
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use
console.*methods in web dashboard code; use appropriate logging mechanisms for React applications
web/src/**/*.{ts,tsx}: New dashboard routes need title wiring in web/src/lib/page-titles.ts; use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation
Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Recharts dashboard views should use web/src/components/ui/stable-responsive-container.tsx; raw ResponsiveContainer mounts can spam width(-1)/height(-1) warnings when panels render before layout settles
Any visual dashboard or landing page change must be verified with Chrome DevTools MCP before calling it done; take a screenshot after the change
Check both light and dark themes if colors or theming changed
Check responsive behavior on mobile, tablet, and desktop if layout changed
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/src/lib/discord.server.tsweb/src/components/layout/server-selector.tsx
**/*.{js,ts,jsx,tsx,mjs,mts}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only; do not use CommonJS
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsxweb/tests/lib/discord.test.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use src/logger.js; do not use console.*
Use the safe Discord messaging helpers in src/utils/safeSend.js instead of raw reply/send/edit calls
Use parameterized SQL only; do not use string concatenation for SQL queries
Community features should be gated behind config..enabled; moderation commands are the exception
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsxweb/tests/lib/discord.test.ts
**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Welcome-message variables use double braces only, like {{user}}; single braces are plain text and should not be documented, inserted, or parsed as variables
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsxweb/tests/lib/discord.test.ts
web/src/**/*.{ts,tsx,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Follow the design system when making changes to the UI/UX; see DESIGN.md for the design system and color palette
Files:
web/src/types/discord.tsweb/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/src/lib/discord.server.tsweb/src/components/layout/server-selector.tsx
web/tests/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
web/tests/**/*.test.{ts,tsx}: Write web dashboard tests using Vitest 4 with thejsdomenvironment and React Testing Library, matching theweb/src/structure
Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
Files:
web/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/tests/components/layout/server-selector.test.tsxweb/tests/lib/discord.test.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/commands/**/*.js : Guild owners should be explicitly exempted from role hierarchy restrictions in command handlers to match Discord permission model expectations
Applied to files:
web/src/types/discord.tsweb/src/app/api/guilds/route.tsweb/src/hooks/use-guild-role.tsweb/tests/hooks/use-guild-role.test.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Applied to files:
web/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.tsweb/tests/components/layout/server-selector.test.tsxweb/src/components/layout/server-selector.tsxweb/tests/lib/discord.test.ts
📚 Learning: 2026-03-11T17:18:17.626Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T17:18:17.626Z
Learning: Applies to src/**/{startup,command-register,reload}*.{js,ts} : Remove process.env.GUILD_ID runtime reads from bot startup and reload command registration
Applied to files:
web/src/components/layout/guild-directory-context.tsx
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to src/api/routes/*.js : Add adaptDeleteGuildIdParam in API route handlers to enforce guild moderation checks on DELETE requests without losing record id
Applied to files:
web/src/components/layout/guild-directory-context.tsxweb/src/app/api/guilds/route.tsweb/tests/api/guilds.test.tsweb/src/lib/discord.server.ts
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to web/src/app/api/**/route.ts : Include guildId in signed WebSocket ticket payload when issuing tickets from dashboard endpoints
Applied to files:
web/src/app/api/guilds/route.tsweb/src/lib/discord.server.ts
📚 Learning: 2026-03-10T23:29:51.063Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:29:51.063Z
Learning: Applies to src/api/routes/*.js : Apply requireGuildModerator authorization check to DELETE endpoints that modify guild-scoped resources
Applied to files:
web/src/app/api/guilds/route.tsweb/src/lib/discord.server.ts
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to src/api/ws/**/*.js : Enforce tenant scoping on WebSocket handlers: reject mismatched guildId in filters and require entry.guild_id === ws.guildId for broadcast matching
Applied to files:
web/src/app/api/guilds/route.tsweb/tests/api/guilds.test.ts
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/commands/reactionrole.js : Enforce invoker role hierarchy check in /reactionrole add command to prevent non-owner users from configuring roles at or above their highest role
Applied to files:
web/src/hooks/use-guild-role.ts
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/tests/**/*.test.{ts,tsx} : Write web dashboard tests using Vitest 4 with the `jsdom` environment and React Testing Library, matching the `web/src/` structure
Applied to files:
web/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to tests/**/*.test.js : Write bot tests using Vitest 4 with the `node` environment, matching the `src/` structure in the `tests/` directory
Applied to files:
web/tests/hooks/use-guild-role.test.tsweb/tests/lib/discord.test.ts
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/api/ws/*.js : Bind audit-log WebSocket auth tickets to guild context by including nonce.expiry.guildId.hmac in ticket validation
Applied to files:
web/src/lib/discord.server.ts
📚 Learning: 2026-04-03T00:05:30.740Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-03T00:05:30.740Z
Learning: Do not persist GUILD_ID as a shared environment variable for multi-guild deployments; preserve dev-only guild-scoped deploy support via CLI flag instead
Applied to files:
web/src/lib/discord.server.ts
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Community features should be gated behind config.<feature>.enabled; moderation commands are the exception
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to config.json : All community features in `config.json` should be gated behind a `config.<feature>.enabled` flag; moderation commands are always available regardless of config settings
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/tests/**/*.test.{ts,tsx} : Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
Applied to files:
web/tests/lib/discord.test.ts
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to tests/**/*.test.js : Maintain test coverage thresholds: statements 85%, branches 82%, functions 85%, lines 85%; never lower thresholds—add tests to cover new code instead
Applied to files:
web/tests/lib/discord.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d262fd0b6b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/tests/components/layout/server-selector.test.tsx (1)
253-261: 🧹 Nitpick | 🔵 TrivialTest approach is fragile.
The test relies on the last occurrence of "Default Server" text being the menu item. This assumption could break if the UI structure changes (e.g., additional labels or badges containing the server name).
Consider using a more specific selector targeting the menuitem role directly after the dropdown opens.
♻️ Suggested: More robust selector
await user.click( screen.getByRole("button", { name: /Default Server/i }), ); - const entries = await screen.findAllByText('Default Server'); - await user.click(entries[entries.length - 1]); + const menuItem = await screen.findByRole('menuitem', { name: /Default Server/i }); + await user.click(menuItem); expect(mockBroadcastSelectedGuild).toHaveBeenCalledTimes(1);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/tests/components/layout/server-selector.test.tsx` around lines 253 - 261, The test is brittle because it selects the last text node 'Default Server' instead of the specific dropdown item; after opening the dropdown (the click on the button returned by screen.getByRole("button", { name: /Default Server/i })), query for the menu item role for the option itself (e.g., use screen.findByRole or screen.findAllByRole("menuitem", { name: /Default Server/i }) and pick the specific item) and click that element instead of entries[entries.length - 1]; update the assertions to still expect mockBroadcastSelectedGuild and fetchSpy calls after clicking the menuitem.
🤖 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/src/components/layout/server-selector.tsx`:
- Around line 440-454: The DropdownMenuItem click handler uses
window.location.href causing a full reload; replace it with Next.js client-side
navigation by importing and using useRouter (or next/navigation's useRouter) and
call router.push(`/community/${guild.id}`) inside the onSelect callback of the
DropdownMenuItem (where GuildRow is rendered) to perform SPA-style navigation;
if you prefer prefetching or want an anchor, wrap the content with Next's Link
to `/community/${guild.id}` instead—ensure you update the import and handler in
server-selector.tsx where DropdownMenuItem and GuildRow are defined.
---
Outside diff comments:
In `@web/tests/components/layout/server-selector.test.tsx`:
- Around line 253-261: The test is brittle because it selects the last text node
'Default Server' instead of the specific dropdown item; after opening the
dropdown (the click on the button returned by screen.getByRole("button", { name:
/Default Server/i })), query for the menu item role for the option itself (e.g.,
use screen.findByRole or screen.findAllByRole("menuitem", { name: /Default
Server/i }) and pick the specific item) and click that element instead of
entries[entries.length - 1]; update the assertions to still expect
mockBroadcastSelectedGuild and fetchSpy calls after clicking the menuitem.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: e47b6fcf-96b1-4260-91a6-f76c99a7134b
📒 Files selected for processing (2)
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: Agent
- GitHub Check: Greptile Review
- GitHub Check: Cursor Bugbot
- GitHub Check: Typecheck & Build
- GitHub Check: Docker Build Validation
- GitHub Check: E2E Tests (2/2)
- GitHub Check: Test
- GitHub Check: E2E Tests (1/2)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (actions)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{js,ts,tsx}: Use single quotes for strings (except in JSON files); no double quotes
Always include semicolons at the end of statements
Use 2-space indentation (spaces, not tabs)
Always include trailing commas in multi-line arrays, objects, and function parameters
Maintain a maximum line width of 100 characters
Files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use
console.*methods in web dashboard code; use appropriate logging mechanisms for React applications
web/src/**/*.{ts,tsx}: New dashboard routes need title wiring in web/src/lib/page-titles.ts; use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation
Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Recharts dashboard views should use web/src/components/ui/stable-responsive-container.tsx; raw ResponsiveContainer mounts can spam width(-1)/height(-1) warnings when panels render before layout settles
Any visual dashboard or landing page change must be verified with Chrome DevTools MCP before calling it done; take a screenshot after the change
Check both light and dark themes if colors or theming changed
Check responsive behavior on mobile, tablet, and desktop if layout changed
Files:
web/src/components/layout/server-selector.tsx
**/*.{js,ts,jsx,tsx,mjs,mts}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only; do not use CommonJS
Files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use src/logger.js; do not use console.*
Use the safe Discord messaging helpers in src/utils/safeSend.js instead of raw reply/send/edit calls
Use parameterized SQL only; do not use string concatenation for SQL queries
Community features should be gated behind config..enabled; moderation commands are the exception
Files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Welcome-message variables use double braces only, like {{user}}; single braces are plain text and should not be documented, inserted, or parsed as variables
Files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
web/src/**/*.{ts,tsx,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Follow the design system when making changes to the UI/UX; see DESIGN.md for the design system and color palette
Files:
web/src/components/layout/server-selector.tsx
web/tests/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
web/tests/**/*.test.{ts,tsx}: Write web dashboard tests using Vitest 4 with thejsdomenvironment and React Testing Library, matching theweb/src/structure
Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
Files:
web/tests/components/layout/server-selector.test.tsx
🧠 Learnings (8)
📓 Common learnings
Learnt from: BillChirico
Repo: VolvoxLLC/volvox-bot PR: 477
File: web/src/components/layout/server-selector.tsx:136-153
Timestamp: 2026-04-11T22:42:46.710Z
Learning: In `web/src/components/layout/server-selector.tsx`, the community feature is intentionally NOT gated behind a global config flag. The `ServerSelector` renders a full guild directory across all guilds a user belongs to; community eligibility is per-guild, so gating each community entry would require N extra config fetches (one per guild). Per-guild community gating is handled instead in the selected-guild config surface (e.g. ConfigProvider), where the selected guild's config is already available.
📚 Learning: 2026-04-11T22:42:46.710Z
Learnt from: BillChirico
Repo: VolvoxLLC/volvox-bot PR: 477
File: web/src/components/layout/server-selector.tsx:136-153
Timestamp: 2026-04-11T22:42:46.710Z
Learning: In `web/src/components/layout/server-selector.tsx`, the community feature is intentionally NOT gated behind a global config flag. The `ServerSelector` renders a full guild directory across all guilds a user belongs to; community eligibility is per-guild, so gating each community entry would require N extra config fetches (one per guild). Per-guild community gating is handled instead in the selected-guild config surface (e.g. ConfigProvider), where the selected guild's config is already available.
Applied to files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to web/src/components/layout/dashboard-shell.tsx : Dashboard page titles should sync with route changes using DashboardTitleSync component mounted in dashboard-shell.tsx and canonical title string 'Volvox.Bot - AI Powered Discord Bot'
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Community features should be gated behind config.<feature>.enabled; moderation commands are the exception
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to config.json : All community features in `config.json` should be gated behind a `config.<feature>.enabled` flag; moderation commands are always available regardless of config settings
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/commands/**/*.js : Guild owners should be explicitly exempted from role hierarchy restrictions in command handlers to match Discord permission model expectations
Applied to files:
web/src/components/layout/server-selector.tsxweb/tests/components/layout/server-selector.test.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Any visual dashboard or landing page change must be verified with Chrome DevTools MCP before calling it done; take a screenshot after the change
Applied to files:
web/tests/components/layout/server-selector.test.tsx
🔇 Additional comments (17)
web/src/components/layout/server-selector.tsx (10)
1-20: LGTM!Imports are clean and well-organized. The component properly uses
GuildDirectoryProvidercontext as per the coding guidelines for dashboard clients needing the guild list.
53-79: LGTM!Well-structured
SectionBadgecomponent with proper tone variants that align with the design system. The use ofReadonly<>for props is a good practice.
81-133: LGTM!The helper components (
CategoryHeader,CategoryEmptyState,LoadingCategory) provide a consistent structure for the three-category layout. The loading skeleton now properly shows all three categories during load, which aligns with the new UI.
139-157: LGTM!The three-bucket categorization logic correctly handles the unknown bot status case by including
botPresent === undefinedin the infrastructure bucket when the guild is manageable. This addresses the prior concern about losing dashboard access during bot API outages. The separation is clear:
infrastructure: manageable guilds where bot is present OR status unknownaddBot: explicitlybotPresent === falseAND can invitecommunity: everything else
159-182: LGTM!The
accessSummarynow includes the unknown status count for user transparency, and the trigger logic properly cascades through the three categories with sensible fallbacks.
189-221: LGTM!The selection persistence logic correctly scopes to the
infrastructurebucket only, ensuring that restored selections are valid dashboard-accessible guilds. The fallback toinfrastructure[0]when no saved selection exists is appropriate.
223-235: LGTM!Loading state now properly displays skeleton loaders for all three categories, providing a clear preview of the upcoming content structure.
252-275: LGTM!The empty state properly handles both scenarios: when the Discord client ID is available (showing invite button) and when it's missing (showing helpful instruction text).
348-381: LGTM!Infrastructure hubs section properly:
- Uses
DropdownMenuItemfor keyboard accessibility- Shows distinct "Live" vs "Status unknown" badges
- Prevents re-selection of the already selected guild (Line 353)
- Displays selection indicator for current guild
389-429: LGTM!The Add Bot section properly:
- Uses
DropdownMenuItemfor keyboard accessibility (addressing prior review)- Opens invite URLs in new tabs via
window.open- Handles unavailable invite URLs with disabled state
- The
getBotInviteUrl(guild.id)correctly pre-selects the guild in Discord's OAuth flowweb/tests/components/layout/server-selector.test.tsx (7)
1-77: LGTM!Test setup is comprehensive:
- Proper mocking of
next/imageandbroadcastSelectedGuild- Animation mock handles jsdom limitations
- Environment variable cleanup in
afterEachprevents test pollution
79-86: LGTM!The loading state test correctly verifies the new three-category structure with "Infrastructure Hubs", "Add Bot", and "Community Hubs" labels.
320-371: LGTM!This test properly:
- Uses
try/finallyto ensurewindow.locationrestoration (addressing prior review)- Verifies community hub UI and navigation behavior
- Confirms
broadcastSelectedGuildis not called for community navigation
373-422: LGTM!Comprehensive test for the add bot flow:
- Properly mocks and restores
window.open- Verifies invite URL contains
guild_idanddisable_guild_select=true- Confirms
broadcastSelectedGuildis not called for invite actions
473-500: LGTM!This test correctly verifies that explicit
access: "moderator"makes a guild manageable regardless of Discord permission bits, which is important for the role hierarchy system.
502-532: LGTM!Good defensive test ensuring invalid guild records from the API don't crash the component or pollute the UI.
424-471: The test is correct. A guild withpermissions: '32'(MANAGE_GUILD) andowner: falseis properly placed in the infrastructure bucket because:
- The guild has
botPresent === undefined(unset)MANAGE_GUILDpermission maps to the'moderator'dashboard role viagetGuildDashboardRole()isGuildManageable()returnstruefor'moderator'role- The bucketing logic includes guilds where
(botPresent === true || botPresent === undefined) && isGuildManageable(guild)— both conditions are satisfiedThe test expectations match the actual implementation.
> Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 057bdfb. Configure here.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/src/components/layout/server-selector.tsx`:
- Around line 159-171: The useMemo for accessSummary incorrectly lists
infrastructure.filter in its dependency array; update the dependency array to
depend on the actual data used (e.g., infrastructure) instead of the
Array.prototype method so the memo invalidates when infrastructure contents
change—specifically, in the accessSummary useMemo, replace infrastructure.filter
with infrastructure and keep the other dependencies (addBot.length,
community.length, infrastructure.length or just infrastructure) so that
formatServerCount and formatUnknownStatusCount results recompute correctly when
infrastructure changes.
- Line 389: The Add Bot section wrapper uses className "space-y-1.5 px-2" which
causes inconsistent horizontal padding versus the Infrastructure and Community
sections; update the layout in server-selector.tsx so padding is consistent
across sections by either removing "px-2" from the Add Bot container (the div
with className "space-y-1.5 px-2") or adding the same "px-2" wrapper to the
Infrastructure and Community section containers to match their horizontal
spacing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: acf3fdee-b7b1-4d4e-8900-9a53c842b53b
📒 Files selected for processing (1)
web/src/components/layout/server-selector.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Greptile Review
- GitHub Check: Cursor Bugbot
- GitHub Check: E2E Tests (2/2)
- GitHub Check: Typecheck & Build
- GitHub Check: Test
- GitHub Check: E2E Tests (1/2)
- GitHub Check: Docker Build Validation
- GitHub Check: Analyze (actions)
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{js,ts,tsx}: Use single quotes for strings (except in JSON files); no double quotes
Always include semicolons at the end of statements
Use 2-space indentation (spaces, not tabs)
Always include trailing commas in multi-line arrays, objects, and function parameters
Maintain a maximum line width of 100 characters
Files:
web/src/components/layout/server-selector.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use
console.*methods in web dashboard code; use appropriate logging mechanisms for React applications
web/src/**/*.{ts,tsx}: New dashboard routes need title wiring in web/src/lib/page-titles.ts; use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation
Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Recharts dashboard views should use web/src/components/ui/stable-responsive-container.tsx; raw ResponsiveContainer mounts can spam width(-1)/height(-1) warnings when panels render before layout settles
Any visual dashboard or landing page change must be verified with Chrome DevTools MCP before calling it done; take a screenshot after the change
Check both light and dark themes if colors or theming changed
Check responsive behavior on mobile, tablet, and desktop if layout changed
Files:
web/src/components/layout/server-selector.tsx
**/*.{js,ts,jsx,tsx,mjs,mts}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only; do not use CommonJS
Files:
web/src/components/layout/server-selector.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use src/logger.js; do not use console.*
Use the safe Discord messaging helpers in src/utils/safeSend.js instead of raw reply/send/edit calls
Use parameterized SQL only; do not use string concatenation for SQL queries
Community features should be gated behind config..enabled; moderation commands are the exception
Files:
web/src/components/layout/server-selector.tsx
**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Welcome-message variables use double braces only, like {{user}}; single braces are plain text and should not be documented, inserted, or parsed as variables
Files:
web/src/components/layout/server-selector.tsx
web/src/**/*.{ts,tsx,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Follow the design system when making changes to the UI/UX; see DESIGN.md for the design system and color palette
Files:
web/src/components/layout/server-selector.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: BillChirico
Repo: VolvoxLLC/volvox-bot PR: 477
File: web/src/components/layout/server-selector.tsx:136-153
Timestamp: 2026-04-11T22:42:46.710Z
Learning: In `web/src/components/layout/server-selector.tsx`, the community feature is intentionally NOT gated behind a global config flag. The `ServerSelector` renders a full guild directory across all guilds a user belongs to; community eligibility is per-guild, so gating each community entry would require N extra config fetches (one per guild). Per-guild community gating is handled instead in the selected-guild config surface (e.g. ConfigProvider), where the selected guild's config is already available.
📚 Learning: 2026-04-11T22:42:46.710Z
Learnt from: BillChirico
Repo: VolvoxLLC/volvox-bot PR: 477
File: web/src/components/layout/server-selector.tsx:136-153
Timestamp: 2026-04-11T22:42:46.710Z
Learning: In `web/src/components/layout/server-selector.tsx`, the community feature is intentionally NOT gated behind a global config flag. The `ServerSelector` renders a full guild directory across all guilds a user belongs to; community eligibility is per-guild, so gating each community entry would require N extra config fetches (one per guild). Per-guild community gating is handled instead in the selected-guild config surface (e.g. ConfigProvider), where the selected guild's config is already available.
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : Dashboard clients that need the guild list should consume GuildDirectoryProvider; do not stack extra /api/guilds fetch loops in leaf components
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to web/src/components/layout/dashboard-shell.tsx : Dashboard page titles should sync with route changes using DashboardTitleSync component mounted in dashboard-shell.tsx and canonical title string 'Volvox.Bot - AI Powered Discord Bot'
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Community features should be gated behind config.<feature>.enabled; moderation commands are the exception
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to config.json : All community features in `config.json` should be gated behind a `config.<feature>.enabled` flag; moderation commands are always available regardless of config settings
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to src/commands/**/*.js : Guild owners should be explicitly exempted from role hierarchy restrictions in command handlers to match Discord permission model expectations
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-04-09T20:31:03.263Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-09T20:31:03.263Z
Learning: Applies to web/src/**/*.{ts,tsx} : New dashboard routes need title wiring in web/src/lib/page-titles.ts; use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation
Applied to files:
web/src/components/layout/server-selector.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/src/app/dashboard/**/*.tsx : For dashboard routes, add a matcher entry to `dashboardTitleMatchers` in `web/src/lib/page-titles.ts`: use exact equality for leaf routes (`pathname === '/dashboard/my-route'`) and subtree checks (`pathname.startsWith('/dashboard/my-route/')`); export `metadata` using `createPageMetadata(title)` for SSR entry points
Applied to files:
web/src/components/layout/server-selector.tsx
🔇 Additional comments (1)
web/src/components/layout/server-selector.tsx (1)
440-454: Community navigation still uses full page reload.A past review suggested using Next.js
useRouterfor client-side navigation instead ofwindow.location.href. This remains unchanged—if/community/${guild.id}shares the same layout/providers as the dashboard, switching torouter.push()would provide smoother SPA navigation. However, if a full reload is intentional (e.g., different page structure), this is acceptable.
- accessSummary useMemo: depend on array references instead of .length so content changes trigger recalculation - Add Bot section: remove extra px-2 for consistent padding - window.location.href in dropdown: kept as-is — full navigation is acceptable for cross-route dropdown selection
|
Note Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it. Generating unit tests... This may take up to 20 minutes. |
|
✅ Created PR with unit tests: #537 |
- server-selector: use onSelect instead of onClick on DropdownMenuItem - discord.ts: rename MutualGuild to UserGuild for accurate semantics
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d5ceaabba
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- discord.test.ts: getMutualGuilds → getUserGuilds - use-guild-role.test.ts: MutualGuild → UserGuild - server-selector: use onClick for window.open to avoid popup blocker (onSelect fires via setTimeout which browsers block for window.open)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7109a00964
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".



Summary
Testing
Closes #426