chore(studio): react-doctor cleanup (66 → 84/100)#146
Conversation
Internal-only cleanup of `@mdcms/studio` against the react-doctor ruleset. No published-surface contract change beyond an internal rename (`renderReadyMdxPropsEditor` → `ReadyMdxPropsEditor`, not in `src/index.ts`). - ES2023 lib bump so `Array#toSorted` compiles workspace-wide - React 19 `use()` migration for context reads - Hydration handling on the API-keys table (client-mounted badge + date helper) - Render-in-render extractions (ContentCardGrid, RouteContent, RowActions, …) - Mirror-prop bug fix in proposal-card.tsx (local-override OR rejecting) - Knip config describing the runtime-ui build-time bundling (drops ~117 false-positive warnings) - Mechanical sweeps: toSorted, flatMap-over-map+filter, length-check shape, module-level EMPTY_*, SVG d-attr decimal truncation, label htmlFor, …
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ 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: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR refactors the ChangesReact 19 & ES2023 Modernization Cleanup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/studio/src/lib/runtime-ui/app/admin/settings-page.tsx`:
- Around line 39-45: The badge's "now" value is captured once at mount (useState
now + useEffect that calls setNow once), so ApiKeyStatusBadge's isExpired
(computed from now, expiresAt) never updates; change the useEffect in the
component (the code that declares now, setNow, setNow(Date.now()), and
isExpired) to start a timer (setInterval) that updates now periodically (e.g.,
every 1s or 1m depending on required granularity), compute isExpired from that
updated now, and clear the interval in the effect cleanup to avoid leaks.
In `@packages/studio/src/lib/runtime-ui/components/api-key-create-dialog.tsx`:
- Around line 110-116: The effect that computes todayMinDate runs only on mount
(useEffect with []); change it to recompute whenever the create dialog is opened
by adding the dialog open state (e.g., open or isOpen) to the effect dependency
array and only computing/setTodayMinDate when that state is true; update the
useEffect that sets todayMinDate (and any other place setting the min value,
e.g., where todayMinDate is used at lines ~254-255) so the min date is
recalculated each time the dialog opens instead of only once on mount.
In `@packages/studio/src/lib/runtime-ui/components/layout/page-header.tsx`:
- Line 113: Breadcrumb keys using "crumb.href ?? crumb.label" can collide when
multiple crumbs share the same label and no href; update the key to include a
collision-safe suffix (e.g., append the map index or a unique identifier) where
the crumbs are rendered in the PageHeader component (the crumbs.map callback
that produces elements using key={crumb.href ?? crumb.label}) so that keys
become unique like `${crumb.href ?? crumb.label}-${index}` or use a unique id
field on the crumb objects.
In `@packages/studio/src/lib/studio-component.tsx`:
- Around line 723-726: The comment for the SHELL_THEME_INLINE_SCRIPT constant is
outdated: it says the script reads theme preference from a cookie while the
implementation actually reads from window.localStorage; update the inline
comment near the SHELL_THEME_INLINE_SCRIPT declaration in studio-component.tsx
to state that it reads the dark/light preference from localStorage (not
cookies), that it applies the theme class before hydration to prevent FOUC, and
that the payload contains no user input and does not touch network data.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e977daab-945f-4352-9c1c-d415e24f032f
📒 Files selected for processing (53)
.changeset/react-doctor-studio-cleanup.mdpackages/studio/knip.jsonpackages/studio/src/lib/build-runtime.test.tspackages/studio/src/lib/build-runtime.tspackages/studio/src/lib/content-overview-state.tspackages/studio/src/lib/document-route-schema.test.tspackages/studio/src/lib/document-route-schema.tspackages/studio/src/lib/document-version-diff.tspackages/studio/src/lib/mdx-component-extension.tspackages/studio/src/lib/mdx-props-editor-host.test.tsxpackages/studio/src/lib/mdx-props-editor-host.tsxpackages/studio/src/lib/remote-studio-app.tsxpackages/studio/src/lib/runtime-registry.tspackages/studio/src/lib/runtime-ui/adapters/next-themes.tsxpackages/studio/src/lib/runtime-ui/app/admin/capabilities-context.tsxpackages/studio/src/lib/runtime-ui/app/admin/content/[type]/page.tsxpackages/studio/src/lib/runtime-ui/app/admin/environments-page.tsxpackages/studio/src/lib/runtime-ui/app/admin/layout.tsxpackages/studio/src/lib/runtime-ui/app/admin/login-page.tsxpackages/studio/src/lib/runtime-ui/app/admin/mount-info-context.tsxpackages/studio/src/lib/runtime-ui/app/admin/page.tsxpackages/studio/src/lib/runtime-ui/app/admin/schema-page.tsxpackages/studio/src/lib/runtime-ui/app/admin/session-context.tsxpackages/studio/src/lib/runtime-ui/app/admin/settings-page.tsxpackages/studio/src/lib/runtime-ui/app/admin/trash-page.tsxpackages/studio/src/lib/runtime-ui/app/admin/users-page.tsxpackages/studio/src/lib/runtime-ui/app/invite/invite-accept-page.tsxpackages/studio/src/lib/runtime-ui/components/api-key-create-dialog.tsxpackages/studio/src/lib/runtime-ui/components/assistant/assistant-context.tsxpackages/studio/src/lib/runtime-ui/components/assistant/assistant-panel.tsxpackages/studio/src/lib/runtime-ui/components/assistant/proposal-card.tsxpackages/studio/src/lib/runtime-ui/components/assistant/send-stop-button.tsxpackages/studio/src/lib/runtime-ui/components/coming-soon.tsxpackages/studio/src/lib/runtime-ui/components/create-document-dialog.tsxpackages/studio/src/lib/runtime-ui/components/editor/inline-ai-bubble.tsxpackages/studio/src/lib/runtime-ui/components/editor/inline-ai-panel.test.tsxpackages/studio/src/lib/runtime-ui/components/editor/inline-ai-panel.tsxpackages/studio/src/lib/runtime-ui/components/editor/mdx-component-collapse.tsxpackages/studio/src/lib/runtime-ui/components/editor/mdx-component-node-view.tsxpackages/studio/src/lib/runtime-ui/components/editor/mdx-component-picker.tsxpackages/studio/src/lib/runtime-ui/components/editor/tiptap-editor.tsxpackages/studio/src/lib/runtime-ui/components/layout/app-sidebar.tsxpackages/studio/src/lib/runtime-ui/components/layout/page-header.tsxpackages/studio/src/lib/runtime-ui/components/mdcms-logo.tsxpackages/studio/src/lib/runtime-ui/components/toast.tsxpackages/studio/src/lib/runtime-ui/components/ui/pagination.tsxpackages/studio/src/lib/runtime-ui/navigation.tsxpackages/studio/src/lib/runtime-ui/pages/content-document-page.tsxpackages/studio/src/lib/runtime-ui/pages/content-page.tsxpackages/studio/src/lib/studio-component.tsxpackages/studio/src/lib/studio-loader.test.tspackages/studio/tsconfig.lib.jsontsconfig.base.json
💤 Files with no reviewable changes (3)
- packages/studio/src/lib/runtime-ui/app/invite/invite-accept-page.tsx
- packages/studio/src/lib/runtime-ui/components/create-document-dialog.tsx
- packages/studio/src/lib/runtime-ui/components/ui/pagination.tsx
- ApiKeyStatusBadge refreshes `now` every 60s so a key crossing its expiry while the page is open flips Active→Expired without a reload. - api-key-create-dialog recomputes `todayMinDate` on each dialog open so the date input's `min` doesn't get stuck on the first-mount day. - BreadcrumbTrail key now includes the index suffix (`href ?? label`-`index`) to disambiguate breadcrumbs that share a label and have no href. - SHELL_THEME_INLINE_SCRIPT JSX comment corrected: the script reads from `window.localStorage`, not a cookie.
Summary
@mdcms/studioagainst the react-doctor ruleset: score 66 → 84, 302 → 76 warnings, 1 → 0 errors.renderReadyMdxPropsEditor→ReadyMdxPropsEditor(not re-exported fromsrc/index.ts, only used inside the package and its tests).packages/studio/knip.jsonteaches knip about the two-tier runtime architecture (theruntime-ui/**tree is bundled at build-time bybuild-runtime.tsvia dynamic string imports), dropping ~117 false-positive warnings.Highlights
tsconfig.base.jsonbumpedtarget/libto ES2023 (enablesArray#toSorted, etc.).use()migration across context modules (session-context,mount-info-context,next-themes,toast,navigation,capabilities-context,mdx-component-collapse,assistant-context).proposal-card.tsx: removed the prop-mirroringuseState/useEffectpattern in 5 sub-cards; reject panel now opens viarejecting || openLocally.settings-page.tsxAPI-keys table:formatClientDatehelper + client-mountedApiKeyStatusBadgeto avoid SSR/CSR locale and clock hydration mismatches.api-key-create-dialog.tsx:mindate attr set after mount.ContentCardGrid/ContentTypeCard,RetryButton,SchemaKindChip/SchemaConstraintFlags,ReadyMdxPropsEditor/AutoFormFieldControl,RouteContent,RowActions,TrashRowActions.setStateeffect.studio-component.tsx+mdx-component-node-view.tsx: documented the two intentionaldangerouslySetInnerHTMLsites inline.toSorted,flatMapovermap().filter(), ES2023 length-check shape, hoistedEMPTY_BREADCRUMBS, SVGddecimal truncation, labelhtmlForassociations, redundantrole="navigation"removed,Promise.allfor independent awaits,gap-yoverspace-yon flex children, action-named button labels, stable list keys,autoFocusremoved from non-critical surfaces,useEffectEventon the save shortcut.Documented skips
react-compiler-destructure-method(8): React Compiler not installed; rule is moot until adopted.react/no-children-prop(4): all in test fixtures.async-await-in-loop(9): all sequential by design (retry, deterministic hash, ordered file copy, pagination).prefer-useReducer(4),no-giant-component(9),no-cascading-set-state(most): substantial design-level refactors. Better as a focused follow-up so individual components can be reviewed in isolation.no-prevent-default,no-dynamic-import-path,nextjs-no-client-side-redirect,nextjs-no-native-script,async-defer-await,rendering-usetransition-loading,query-mutation-missing-invalidation,rerender-state-only-in-handlers: per-site false-positives; rationale in the plan file under.ai/plans/.Test plan
bun run check(build + typecheck across 6 projects) — green locally.bun test --cwd packages/studio— 603 pass, 1 pre-existing unrelated failure in untrackedbutton.test.tsx(not part of this PR).bun run ci:requiredto be run in CI.proposal-card.tsx).<div onClick>withonClickonToolbarButton).Summary by CodeRabbit
Release Notes
Bug Fixes
New Features
Refactor
Style