fix(dashboard): render code-tabs lines as blocks + auto-activate sole org#391
Conversation
… org
Two landing/dashboard fixes:
- code-tabs: each highlighted code line was an inline <span> with no newline
between siblings, so inside <pre> the whole snippet collapsed onto one
horizontal row. Render each line as a block. Also rewrite the active-tab
style selectors — Astro <style> is static CSS, so the `${uid}` selectors
never interpolated and the active tab never highlighted; use :nth-of-type
correlation instead.
- app-shell: a user who belongs to exactly one org still starts on Clerk's
personal account (no `o_id` claim), so the session resolves to
`personal:<userId>` and the dashboard renders empty while the org's data
sits intact under the real org. Auto-activate the sole org when none is
active, guarded by sessionStorage so the post-activation reload can't loop.
Co-Authored-By: Duyet Le <me@duyet.net>
Co-Authored-By: duyetbot <bot@duyet.net>
Reviewer's GuideThis PR fixes two user-facing issues: code tabs on the landing hero now render each highlighted line as a block and correctly highlight the active tab via static CSS, and the dashboard auto-activates a user’s sole organization when no org is active, ensuring they land on org-scoped data instead of an empty personal scope. Sequence diagram for auto-activating a sole organization in the dashboardsequenceDiagram
actor User
participant Clerk
participant SidebarOrgScope
participant sessionStorage
participant window
User->>Clerk: Authenticate
Clerk-->>SidebarOrgScope: isLoaded, organizations, activeOrg, setActive
SidebarOrgScope->>SidebarOrgScope: useEffect
alt [isLoaded && setActive && !activeOrg && organizations.length === 1]
SidebarOrgScope->>sessionStorage: getItem(agentstate:auto-activated-org)
alt [no guard item]
SidebarOrgScope->>sessionStorage: setItem(agentstate:auto-activated-org, 1)
SidebarOrgScope->>Clerk: setActive({ organization: organizations[0].id })
Clerk-->>SidebarOrgScope: Promise resolved
SidebarOrgScope->>window: location.reload()
window-->>User: Reloaded dashboard with active org scope
else [guard already set]
SidebarOrgScope-->>User: Dashboard remains in current scope
end
else [conditions not met]
SidebarOrgScope-->>User: No auto-activation
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Review limit reached
Next review available in: 46 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR adds automatic activation for a user’s only organization when no active organization exists, and updates code tab line markup and active-tab CSS selectors. ChangesOrganization scope activation
Code tab rendering
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant SidebarOrgScope
participant ClerkSession
participant sessionStorage
participant Browser
SidebarOrgScope->>ClerkSession: Check organization state
SidebarOrgScope->>sessionStorage: Check activation guard
SidebarOrgScope->>ClerkSession: Activate sole organization
SidebarOrgScope->>Browser: Reload dashboard
Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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.
Hey - I've left some high level feedback:
- The
:nth-of-typeselectors incode-tabs.astrohard-code support for five tabs and assume the inputs and labels remain in strict positional sync; consider deriving these rules from the tabs array or using a class-based correlation to avoid breakage if the number or order of tabs changes. - The auto-activation side effect in
SidebarOrgScoperuns a fullwindow.location.reload()after setting the active org; you might want to guard against unnecessary reloads when the active org is already correct or handle failures fromsetActivemore explicitly (e.g., clearing the sessionStorage guard) to avoid leaving users stuck in an unexpected state.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `:nth-of-type` selectors in `code-tabs.astro` hard-code support for five tabs and assume the inputs and labels remain in strict positional sync; consider deriving these rules from the tabs array or using a class-based correlation to avoid breakage if the number or order of tabs changes.
- The auto-activation side effect in `SidebarOrgScope` runs a full `window.location.reload()` after setting the active org; you might want to guard against unnecessary reloads when the active org is already correct or handle failures from `setActive` more explicitly (e.g., clearing the sessionStorage guard) to avoid leaving users stuck in an unexpected state.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request introduces auto-activation of a single organization on Clerk session start to prevent rendering an empty dashboard, and fixes Astro static CSS interpolation in code-tabs.astro by using :nth-of-type selectors. Feedback was provided on the useEffect in app-shell.tsx regarding an unstable dependency array (organizations) and potential infinite reload loops or crashes if sessionStorage is blocked (e.g., in private browsing). A refactored version using a stable primitive dependency and a try-catch block was suggested.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| useEffect(() => { | ||
| if (!isLoaded || !setActive || activeOrg || organizations.length !== 1) return; | ||
| const GUARD = "agentstate:auto-activated-org"; | ||
| if (sessionStorage.getItem(GUARD)) return; | ||
| sessionStorage.setItem(GUARD, "1"); | ||
| void setActive({ organization: organizations[0].id }).then(() => { | ||
| window.location.reload(); | ||
| }); | ||
| }, [isLoaded, setActive, activeOrg, organizations]); |
There was a problem hiding this comment.
There are two issues with this useEffect implementation:
- Unstable Dependency Array / Performance: The
organizationsarray returned byuseOrganizationsList()is computed dynamically on every render (via.map()and.filter()), meaning its reference identity changes constantly. This causes theuseEffectto execute on every single render of theSidebarOrgScopecomponent. - Robustness / Potential Infinite Loop: Accessing
sessionStoragecan throw aSecurityErrororDOMExceptionin environments where storage is disabled or blocked (e.g., strict private browsing modes). If it throws, the app shell will crash on mount. Furthermore, if we simply catch the error and proceed withsetActiveandwindow.location.reload(), the page will reload and run the effect again, leading to an infinite reload loop.
Recommendation:
- Extract a stable primitive dependency like
singleOrgId(which is a string or null) to prevent unnecessary effect runs. - Wrap the
sessionStorageoperations in atry-catchblock, and if it throws, return early to safely prevent both crashes and infinite reload loops.
const singleOrgId = organizations.length === 1 ? organizations[0].id : null;
useEffect(() => {
if (!isLoaded || !setActive || activeOrg || !singleOrgId) return;
const GUARD = "agentstate:auto-activated-org";
try {
if (sessionStorage.getItem(GUARD)) return;
sessionStorage.setItem(GUARD, "1");
} catch {
// If sessionStorage is unavailable (e.g., private mode or blocked cookies),
// do not auto-activate to prevent an infinite reload loop.
return;
}
void setActive({ organization: singleOrgId }).then(() => {
window.location.reload();
});
}, [isLoaded, setActive, activeOrg, singleOrgId]);
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/dashboard/src/components/app-shell.tsx`:
- Around line 282-290: Update the auto-activation useEffect around setActive so
it only proceeds when activeOrg is explicitly null, not undefined, preserving
the loading-state distinction. Handle setActive failures with a catch, clear the
"agentstate:auto-activated-org" sessionStorage guard on rejection, and retain
the existing reload behavior on success.
🪄 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: fc57b97e-e41d-44ee-a5f0-dba79f078c2d
📒 Files selected for processing (2)
packages/dashboard/src/components/app-shell.tsxpackages/dashboard/src/components/home/code-tabs.astro
Harden the sole-org auto-activation effect per CodeRabbit/Gemini review: - Gate on useOrganization().isLoaded and check activeOrg === null via the loaded flag, so the effect no longer fires during the `undefined` loading window (fixes the race where the org list loads before the active org and triggers a spurious reload). - Depend on a derived stable `soleOrgId` primitive instead of the `organizations` array whose reference changes every render. - Wrap sessionStorage access in try/catch (throws in private mode) and add a .catch() to setActive that clears the guard and skips the reload on failure. Co-Authored-By: Duyet Le <me@duyet.net> Co-Authored-By: duyetbot <bot@duyet.net>
Summary
Two user-reported fixes, both deployed to production already.
1. Landing hero code block collapsed to one line
Each highlighted code line was an inline
<span>with no newline between siblings, so inside<pre>the whole snippet flowed onto a single horizontal row (see the broken TypeScript/Vercel AI/LangGraph tabs). Each line now renders as a block.While here, the active-tab highlight was also dead: Astro
<style>blocks are static CSS, so the${uid}selectors never interpolated. Rewrote them with:nth-of-typecorrelation (no uid needed).2. Dashboard shows no data for a user's org
A user who belongs to exactly one org still starts on Clerk's personal account (no
o_idclaim), soverifyDashboardSessionresolves topersonal:<userId>— an org with no row — and the dashboard renders empty while the org's projects sit intact under the real org id. This matches theorg-tenancy-modelhistory (#387/#389).Fix: auto-activate the sole org when none is active, guarded by
sessionStorageso the post-activationwindow.location.reload()can't loop if the active org fails to persist.Verification
bun run build(dashboard) ✓/,/api,/dashboard/all return 200class="block"spans present in production landing HTMLNotes
The data was never lost — 9 projects / 101 conversations remain under org
eHyHEJ4YQnplY5WHvJJjP(Clerkorg_3B0cAAPs5mwolujADLk7UdIWHuI). This makes single-org users land on their data instead of an empty personal scope.Co-Authored-By: Duyet Le me@duyet.net
Co-Authored-By: duyetbot bot@duyet.net
Summary by Sourcery
Fix landing page code tabs rendering and improve dashboard org activation behavior for single-org users.
Bug Fixes:
Summary by CodeRabbit
New Features
Bug Fixes