refactor(cms-180): migrate studio admin data fetching to TanStack Query#113
Conversation
Replaces the last three raw useEffect+useState data-fetching sites in the Studio admin runtime with TanStack Query hooks, matching the pattern established in CMS-132: - admin/page.tsx (dashboard) now fetches loadDashboardData through a new useDashboardData hook; the 200ms skeleton-delay is preserved via a single local effect. - admin/layout.tsx is split into an outer QueryClientProvider wrapper and an inner component whose capabilities, session, and environments are driven by useQuery. The token-mode capability failure promotion to session.status=token-error is preserved through a derived memo. - pages/content-page.tsx now consumes loadStudioContentOverviewState through a new useStudioContentOverview hook. No external contracts or behaviors change; all existing layout, content-page, dashboard-data, and content-overview-state tests pass.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRefactors admin UI to use TanStack React Query for capabilities, session, and environments; splits AdminLayout into an outer QueryClientProvider and AdminLayoutInner; adds Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AdminLayout
participant QueryClient
participant CapabilitiesAPI
participant SessionAPI
participant EnvironmentsAPI
Client->>AdminLayout: render children
AdminLayout->>QueryClient: provide React Query context
AdminLayout->>CapabilitiesAPI: useQuery(capabilities) [keyed on project/env/server/auth]
AdminLayout->>SessionAPI: useQuery(session) [cookie-only or token-derived state]
AdminLayout->>EnvironmentsAPI: useQuery(environments) [enabled when inputs present]
CapabilitiesAPI-->>AdminLayout: capabilities / error
SessionAPI-->>AdminLayout: session / error
EnvironmentsAPI-->>AdminLayout: environments / error
AdminLayout->>AdminLayout: derive permissions & sessionState (uses extractStatusCode)
AdminLayout->>QueryClient: invalidateQueries(["studio"]) on token rotation
AdminLayout->>Client: redirect if unauthenticated and not token mode
Client->>AdminLayout: render inner UI with fetched data
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
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 `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 272-283: The query key for capabilitiesQuery currently embeds the
raw bearer token via capabilitiesLoadInput.auth.token—remove any token or
sensitive auth fields from the queryKey (keep project, environment, serverUrl,
auth.mode only) and instead store the token in memory/context and inject it
inside the queryFn using a custom fetch wrapper that reads the token from that
secure store; update any other queries that used the token in keys (same pattern
at the other occurrences) and implement token refresh handling by wiring
QueryCache.onError to detect 401 responses, refresh the token, and call
queryClient.invalidateQueries() so queries re-run with the new token.
In `@packages/studio/src/lib/runtime-ui/hooks/use-content-overview.ts`:
- Around line 13-18: The query key returned by getContentOverviewQueryKey is
missing discriminators (apiBaseUrl, supportedLocales, auth) that affect
loadInput and thus the query result; update getContentOverviewQueryKey to
include the current apiBaseUrl, supportedLocales, and auth (or a stable auth
identifier) alongside project and environment so TanStack Query v5 correctly
caches/invalidation, and ensure any other usage of this key (the hook that calls
loadInput and related functions) uses the expanded key so changes to apiBaseUrl,
supportedLocales or auth will refetch rather than reuse stale data.
In `@packages/studio/src/lib/runtime-ui/hooks/use-dashboard-data.ts`:
- Around line 15-20: getDashboardDataQueryKey currently only includes project
and environment so React Query can return stale dashboard data when the API host
changes; update the getDashboardDataQueryKey function to accept and include
apiBaseUrl (and optionally a non-sensitive auth discriminator) in the returned
tuple (i.e., ["studio","dashboard", project, environment, apiBaseUrl]) so
different API targets produce distinct keys; additionally, ensure callers that
build the apis memo or change auth either pass a lightweight, non-sensitive auth
discriminator into this key or call
queryClient.invalidateQueries(getDashboardDataQueryKey(...)) when credentials
rotate.
🪄 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: 822c0535-c998-4a48-909b-ee5ef013eeee
📒 Files selected for processing (5)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsxpackages/studio/src/lib/runtime-ui/app/admin/page.tsxpackages/studio/src/lib/runtime-ui/hooks/use-content-overview.tspackages/studio/src/lib/runtime-ui/hooks/use-dashboard-data.tspackages/studio/src/lib/runtime-ui/pages/content-page.tsx
- Drop raw auth.token from the three admin-layout query keys (capabilities, session, environments). Keep auth.mode as the auth discriminator, matching the pattern already used by use-user-list.ts, use-content-type-list.ts, and use-create-document.ts. Tokens still flow to requests via the API factory options, not via the query cache. - Expand getDashboardDataQueryKey to include apiBaseUrl and auth.mode so a host-URL or auth-mode change produces a distinct cache entry. - Expand getContentOverviewQueryKey to include apiBaseUrl, auth.mode, and supportedLocales; the last one flows into entries[i].locales inside loadStudioContentOverviewState, so it must be part of the cache key.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx (1)
272-289:⚠️ Potential issue | 🟠 MajorInvalidate Studio queries when the bearer token changes.
Now that the key only discriminates on
auth.mode, a host-side token refresh or user switch can leave this query,environmentsQuery, and childstudio/*queries pinned to the previous cache/error state until they go stale. In the bad case, an old 401/403 here keepssessionStatestuck in"token-error"even after the host supplies a fresh token. Add an auth-change invalidation/removal path at the layout level so the shared query client refetches with the new credentials. Based on learnings: Studio must be embedded in a host React application and rendered in a catch-all route.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 272 - 289, The capabilities query only keys on auth.mode so token changes aren't triggering refetch; add logic at the layout level to invalidate or remove all "studio" queries when the auth credentials change (watch capabilitiesLoadInput!.auth, e.g. the bearer token) so capabilitiesQuery, environmentsQuery and child "studio/*" queries refetch with new credentials; use the shared react-query client to call invalidateQueries or removeQueries for the "studio" namespace (or specific keys used) when the auth token (not just auth.mode) is updated, ensuring createStudioCurrentPrincipalCapabilitiesApi and dependent queries refetch and sessionState can recover from prior 401/403.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 392-399: The current code treats missing capabilitiesQuery.data as
"no permissions" by defaulting each boolean to false; instead, stop collapsing
absent data into false and either (A) gate UI on capabilitiesQuery.isPending /
capabilitiesQuery.isError so the app shows loading/error state rather than
hiding features, or (B) preserve the last successful capabilities set and use
that until a new successful fetch arrives. Concretely, stop using expressions
like capabilities?.schema.read ?? false; read nested fields safely (e.g.
capabilities?.schema?.read) and if undefined use a preservedLastCapabilities
state/ref (updated only on successful fetch) or short-circuit rendering when
capabilitiesQuery.isPending/error; update uses of canReadSchema,
canCreateContent, canPublishContent, canUnpublishContent, canDeleteContent,
canManageUsers, and canManageSettings to rely on these non-defaulted values so
network/500 errors are not mistaken for an authorization denial.
---
Duplicate comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 272-289: The capabilities query only keys on auth.mode so token
changes aren't triggering refetch; add logic at the layout level to invalidate
or remove all "studio" queries when the auth credentials change (watch
capabilitiesLoadInput!.auth, e.g. the bearer token) so capabilitiesQuery,
environmentsQuery and child "studio/*" queries refetch with new credentials; use
the shared react-query client to call invalidateQueries or removeQueries for the
"studio" namespace (or specific keys used) when the auth token (not just
auth.mode) is updated, ensuring createStudioCurrentPrincipalCapabilitiesApi and
dependent queries refetch and sessionState can recover from prior 401/403.
🪄 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: 347e0eb7-7b13-4cea-89d1-5a733cedbb13
📒 Files selected for processing (3)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsxpackages/studio/src/lib/runtime-ui/hooks/use-content-overview.tspackages/studio/src/lib/runtime-ui/hooks/use-dashboard-data.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/studio/src/lib/runtime-ui/hooks/use-content-overview.ts
…switch TanStack Query v5 resets query.data to undefined when the queryKey changes and no cache entry exists for the new key. That made the capability flags and the environments list briefly collapse to default values during an environment switch — the sidebar would flash "no permissions" until the new fetch resolved. The pre-refactor useEffect only called the setters inside .then/.catch, so old flags persisted until the new response arrived. Restore that continuity by adding placeholderData: keepPreviousData to both queries. The sessionQuery does not need this — its key is keyed on serverUrl and auth.mode, neither of which changes mid-session.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx (2)
276-298:⚠️ Potential issue | 🟠 MajorInvalidate the auth-scoped queries when the token changes.
Lines 276-298 and 378-402 remove the bearer token from the key, which is correct, but there is no replacement invalidation path when
context.auth.tokenchanges. With the samequeryKey, TanStack Query will keep the existing cache/error state, so a refreshed or corrected token can leave capabilities/environments stuck until a reload or unrelated refetch.Possible fix
-import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { QueryClientProvider, keepPreviousData, useQuery, + useQueryClient, } from "@tanstack/react-query"; @@ function AdminLayoutInner({ @@ }) { + const queryClient = useQueryClient(); const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const previousTokenRef = useRef(context.auth.token); @@ + useEffect(() => { + if (context.auth.mode !== "token") { + previousTokenRef.current = context.auth.token; + return; + } + + if (previousTokenRef.current === context.auth.token) { + return; + } + + previousTokenRef.current = context.auth.token; + + void queryClient.invalidateQueries({ queryKey: ["studio", "capabilities"] }); + void queryClient.invalidateQueries({ queryKey: ["studio", "environments"] }); + }, [queryClient, context.auth.mode, context.auth.token]);Also applies to: 378-402
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 276 - 298, The query key was intentionally made token-agnostic, but you must invalidate the auth-scoped queries when the bearer token changes so stale cached results don't persist; add a useEffect that watches the auth token (e.g. capabilitiesLoadInput?.auth.token or context.auth.token) and calls queryClient.invalidateQueries with the same key shape used by capabilitiesQuery (["studio","capabilities", capabilitiesLoadInput?.config.project, capabilitiesLoadInput?.config.environment, capabilitiesLoadInput?.config.serverUrl, capabilitiesLoadInput?.auth.mode]) to force refetch on token change; apply the same pattern for the analogous environments query (the other block around lines 378-402) using its query key.
404-413:⚠️ Potential issue | 🟠 MajorDon’t treat missing capability data as “no permissions.”
Lines 404-413 still collapse
undefinedcapability data intofalsefor every permission, so first-load and non-auth failures silently hide features instead of surfacing the outage. Also, reads likecapabilities?.schema.readare still unsafe if a nested section is omitted; that needscapabilities?.schema?.read.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 404 - 413, The current code collapses missing capabilities into false and uses unsafe nested property access; update the permissions logic so you do not coerce undefined capability data into false and use safe optional chaining for nested fields: read capabilities from capabilitiesQuery.data (keep it undefined/null when missing) and set canReadSchema = capabilities?.schema?.read, canCreateContent = capabilities?.content?.write, canPublishContent = capabilities?.content?.publish, canUnpublishContent = capabilities?.content?.unpublish, canDeleteContent = capabilities?.content?.delete, canManageUsers = capabilities?.users?.manage, and canManageSettings = capabilities?.settings?.manage (no default to false), then handle undefined permissions elsewhere (e.g., show loading/error state) so outages aren’t silently treated as “no permissions.”
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 276-298: The query key was intentionally made token-agnostic, but
you must invalidate the auth-scoped queries when the bearer token changes so
stale cached results don't persist; add a useEffect that watches the auth token
(e.g. capabilitiesLoadInput?.auth.token or context.auth.token) and calls
queryClient.invalidateQueries with the same key shape used by capabilitiesQuery
(["studio","capabilities", capabilitiesLoadInput?.config.project,
capabilitiesLoadInput?.config.environment,
capabilitiesLoadInput?.config.serverUrl, capabilitiesLoadInput?.auth.mode]) to
force refetch on token change; apply the same pattern for the analogous
environments query (the other block around lines 378-402) using its query key.
- Around line 404-413: The current code collapses missing capabilities into
false and uses unsafe nested property access; update the permissions logic so
you do not coerce undefined capability data into false and use safe optional
chaining for nested fields: read capabilities from capabilitiesQuery.data (keep
it undefined/null when missing) and set canReadSchema =
capabilities?.schema?.read, canCreateContent = capabilities?.content?.write,
canPublishContent = capabilities?.content?.publish, canUnpublishContent =
capabilities?.content?.unpublish, canDeleteContent =
capabilities?.content?.delete, canManageUsers = capabilities?.users?.manage, and
canManageSettings = capabilities?.settings?.manage (no default to false), then
handle undefined permissions elsewhere (e.g., show loading/error state) so
outages aren’t silently treated as “no permissions.”
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 71806741-648d-41ab-81ab-fd29add4ccc3
📒 Files selected for processing (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx
The previous round dropped the bearer token from query keys to keep secrets out of the TanStack Query cache. Pre-refactor, the capabilities/session/ environments useEffects tracked context.auth.token as a dependency and re-fetched when the host rotated the token. After removing the token from keys, that reactivity was lost — a new token would reuse the previous token's cached response until the cache expired. Add a single useEffect inside AdminLayoutInner that invalidates every query under the "studio" prefix whenever context.auth.token changes. That covers capabilities, session, environments, dashboard, and content overview in one place. The token still never enters a query key.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx (1)
416-423:⚠️ Potential issue | 🟠 MajorCapabilities still collapse fetch absence/error into “no permissions.”
Defaulting every flag to
falsehere still makes pending/error states look like authorization denial. That can silently hide features during outages. Handle pending/error explicitly (or gate rendering), then map permissions from successful data only. Also prefer nested optional access (?.schema?.read, etc.) for resilience to partial payloads.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 416 - 423, The code is collapsing fetch pending/error into “no permissions” by defaulting flags to false; update the mapping so you only derive canReadSchema/canCreateContent/canPublishContent/canUnpublishContent/canDeleteContent/canManageUsers/canManageSettings from capabilitiesQuery.data when the query is successful (e.g., check capabilitiesQuery.isSuccess or Boolean(capabilitiesQuery.data)) and otherwise leave them undefined or handle loading/error states upstream to gate rendering; also use nested optional chaining when reading properties (capabilities?.schema?.read, capabilities?.content?.write, etc.) to avoid crashes on partial payloads and ensure UI shows loading/error rather than silently hiding features.
🧹 Nitpick comments (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx (1)
261-263: Avoid invalidating allstudioqueries on first mount.This effect runs once on mount (not only on rotation), so it can trigger unnecessary refetch churn. Invalidate only when the token actually changes from a previous value.
♻️ Proposed adjustment
+import { useRef } from "react"; + const queryClient = useQueryClient(); + const previousTokenRef = useRef<string | undefined>(context.auth.token); + useEffect(() => { - void queryClient.invalidateQueries({ queryKey: ["studio"] }); + const previousToken = previousTokenRef.current; + const nextToken = context.auth.token; + if (previousToken !== nextToken) { + void queryClient.invalidateQueries({ queryKey: ["studio"] }); + previousTokenRef.current = nextToken; + } }, [queryClient, context.auth.token]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 261 - 263, The effect currently invalidates all "studio" queries on first mount because it runs whenever the component mounts; update the useEffect that calls queryClient.invalidateQueries({ queryKey: ["studio"] }) so it only invalidates when context.auth.token actually changes from a previous value: track the previous token (e.g., with a ref) inside the effect and only call queryClient.invalidateQueries when prevToken.current exists and prevToken.current !== context.auth.token, then set prevToken.current = context.auth.token; keep the effect dependencies as [queryClient, context.auth.token].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 416-423: The code is collapsing fetch pending/error into “no
permissions” by defaulting flags to false; update the mapping so you only derive
canReadSchema/canCreateContent/canPublishContent/canUnpublishContent/canDeleteContent/canManageUsers/canManageSettings
from capabilitiesQuery.data when the query is successful (e.g., check
capabilitiesQuery.isSuccess or Boolean(capabilitiesQuery.data)) and otherwise
leave them undefined or handle loading/error states upstream to gate rendering;
also use nested optional chaining when reading properties
(capabilities?.schema?.read, capabilities?.content?.write, etc.) to avoid
crashes on partial payloads and ensure UI shows loading/error rather than
silently hiding features.
---
Nitpick comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 261-263: The effect currently invalidates all "studio" queries on
first mount because it runs whenever the component mounts; update the useEffect
that calls queryClient.invalidateQueries({ queryKey: ["studio"] }) so it only
invalidates when context.auth.token actually changes from a previous value:
track the previous token (e.g., with a ref) inside the effect and only call
queryClient.invalidateQueries when prevToken.current exists and
prevToken.current !== context.auth.token, then set prevToken.current =
context.auth.token; keep the effect dependencies as [queryClient,
context.auth.token].
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 14f43652-4711-48ee-83bd-c1643bb5f563
📒 Files selected for processing (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx
Guard the bearer-token invalidation effect with a useRef so it only fires when the token actually changes from a previous value. On first mount the queries are in the middle of registering their initial fetch; invalidating them would mark them stale and trigger a redundant refetch once the first fetch settles.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx (1)
419-426:⚠️ Potential issue | 🟠 MajorDon’t map missing/failed capabilities to hard “no permissions,” and fix unsafe nested access.
Line 420–426 still collapses unavailable capability data into
false, so first-load/network/server failures are indistinguishable from real authorization denial. Also, expressions likecapabilities?.schema.readare not fully safe ifschemais absent.Suggested fix
- const capabilities = capabilitiesQuery.data?.capabilities; - const canReadSchema = capabilities?.schema.read ?? false; - const canCreateContent = capabilities?.content.write ?? false; - const canPublishContent = capabilities?.content.publish ?? false; - const canUnpublishContent = capabilities?.content.unpublish ?? false; - const canDeleteContent = capabilities?.content.delete ?? false; - const canManageUsers = capabilities?.users.manage ?? false; - const canManageSettings = capabilities?.settings.manage ?? false; + const capabilities = capabilitiesQuery.data?.capabilities; + + if (!capabilities && (capabilitiesQuery.isPending || capabilitiesQuery.isError)) { + return ( + <div className="flex min-h-screen items-center justify-center bg-background"> + <div className="text-foreground-muted text-sm"> + {capabilitiesQuery.isError + ? "Capabilities could not be loaded." + : "Loading capabilities..."} + </div> + </div> + ); + } + + const canReadSchema = capabilities?.schema?.read ?? false; + const canCreateContent = capabilities?.content?.write ?? false; + const canPublishContent = capabilities?.content?.publish ?? false; + const canUnpublishContent = capabilities?.content?.unpublish ?? false; + const canDeleteContent = capabilities?.content?.delete ?? false; + const canManageUsers = capabilities?.users?.manage ?? false; + const canManageSettings = capabilities?.settings?.manage ?? false;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx` around lines 419 - 426, The code currently coerces missing/failed capability data into false and uses unsafe nested access; change each capability binding (canReadSchema, canCreateContent, canPublishContent, canUnpublishContent, canDeleteContent, canManageUsers, canManageSettings) to preserve undefined when data is absent and use safe optional chaining into nested objects (e.g., capabilities?.schema?.read instead of capabilities?.schema.read ?? false), removing the "?? false" so callers can distinguish unknown vs explicit false and handle capabilitiesQuery errors/loading separately.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/studio/src/lib/runtime-ui/app/admin/layout.tsx`:
- Around line 419-426: The code currently coerces missing/failed capability data
into false and uses unsafe nested access; change each capability binding
(canReadSchema, canCreateContent, canPublishContent, canUnpublishContent,
canDeleteContent, canManageUsers, canManageSettings) to preserve undefined when
data is absent and use safe optional chaining into nested objects (e.g.,
capabilities?.schema?.read instead of capabilities?.schema.read ?? false),
removing the "?? false" so callers can distinguish unknown vs explicit false and
handle capabilitiesQuery errors/loading separately.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d8d54742-c559-403f-b861-0ddd7a15ca7b
📒 Files selected for processing (1)
packages/studio/src/lib/runtime-ui/app/admin/layout.tsx
Summary
Finishes the TanStack Query migration in the Studio runtime that CMS-132 started. The last three raw
useEffect+useStatedata-fetching sites inpackages/studioare replaced withuseQuery-based hooks:admin/page.tsx) fetchesloadDashboardDatathrough a newuseDashboardDatahook. The 200 ms skeleton-delay behavior is preserved with a single local effect so fast responses still avoid a loading flash.admin/layout.tsx) is split into an outerQueryClientProviderwrapper and an innerAdminLayoutInner. Inside the provider, capabilities / session / environments are driven byuseQuery. The token-mode capability-failure promotion tosession.status = "token-error"is preserved through a derived memo.pages/content-page.tsx) consumesloadStudioContentOverviewStatethrough a newuseStudioContentOverviewhook.Pure orchestration functions (
loadDashboardData,loadStudioContentOverviewState) are untouched — the refactor is confined to the React data-fetching boundary. No external contracts change.Jira: https://blazity.atlassian.net/browse/CMS-180
Test plan
bun run format:checkcleanbun run check(Nx build + typecheck for all 6 projects) greenlayout.test.tsx,content-page.test.tsx,content-overview-state.test.ts,dashboard-data.test.ts(33/33)button.test.tsxon the working tree, not introduced by this PR)Summary by CodeRabbit
Refactor
New Features
Bug Fixes