Skip to content

fix(cluster): update cached resetPassword before navigating after admin setup - #1599

Open
Devin-Holland wants to merge 1 commit into
stagefrom
fix/finish-setup-redirect-race
Open

fix(cluster): update cached resetPassword before navigating after admin setup#1599
Devin-Holland wants to merge 1 commit into
stagefrom
fix/finish-setup-redirect-race

Conversation

@Devin-Holland

Copy link
Copy Markdown
Member

What

After creating the initial admin user, FinishSetup showed the "Login successful" toast but sometimes never left the setup page.

Why

The reset-password mutation PATCHes central-manager's resetPassword flag (awaited, so the server write is confirmed), but nothing updated the react-query cluster cache — router.invalidate() only re-runs route loaders. The subsequent navigate('../') landed on ClusterHome, which routes on cluster.resetPassword from the same [clusterId] query — still cached true until the next 10s poll tick — so its guard bounced the user straight back to finish-setup. Intermittent by poll timing, which is why it reproduced only sometimes.

Change

New markClusterPasswordSet(queryClient, clusterId) helper next to the query flips resetPassword off in the cache; FinishSetup's onSuccess calls it before navigating. Not an optimistic update — the CM write has already succeeded by the time onSuccess runs.

Verification

  • 3 new unit tests for the helper (flips the flag preserving other fields; no phantom cache entry when absent; other clusters untouched) — 8/8 in the file, full suite green via the pre-commit hook, tsc -b clean.
  • Traced the post-fix interaction with FinishSetup's own !resetPassword guard: both possible destinations (../ and ../sign-in) resolve to the cluster home for a now-connected user, so no new dead-end.

— devain (Claude)

…in setup

The reset-password mutation PATCHes central-manager, but nothing updated
the react-query cluster cache — router.invalidate() only re-runs route
loaders. Navigating to ClusterHome then read the same [clusterId] query
with a stale resetPassword: true (10s poll), and its guard bounced the
user straight back to finish-setup. Intermittent by poll timing.

Set the cached flag synchronously in onSuccess (not optimistic: the CM
write is awaited inside the mutation before it succeeds).
@Devin-Holland
Devin-Holland requested a review from a team as a code owner August 5, 2026 14:50

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a markClusterPasswordSet utility to synchronously update the cached cluster's resetPassword state to false upon successful setup completion, preventing navigation bounces caused by stale polling data. Unit tests have been added to verify this cache update behavior. The feedback suggests explicitly typing the setQueryData call with the Cluster generic to maintain strict type safety and prevent potential TypeScript compilation errors.

Comment on lines +18 to +21
queryClient.setQueryData(
getClusterInfoQueryOptions(clusterId).queryKey,
(cluster) => cluster && { ...cluster, resetPassword: false },
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To preserve type safety and prevent TypeScript from inferring cluster as unknown (which can cause compilation errors under strict mode when spreading or accessing properties), explicitly type the setQueryData call with the Cluster generic.

Suggested change
queryClient.setQueryData(
getClusterInfoQueryOptions(clusterId).queryKey,
(cluster) => cluster && { ...cluster, resetPassword: false },
);
queryClient.setQueryData<Cluster>(
getClusterInfoQueryOptions(clusterId).queryKey,
(cluster) => cluster && { ...cluster, resetPassword: false },
);

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 54.27% 6431 / 11849
🔵 Statements 54.9% 6926 / 12614
🔵 Functions 45.91% 1562 / 3402
🔵 Branches 47.96% 4423 / 9221
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/features/cluster/FinishSetup.tsx 0% 0% 0% 0% 29-185
src/features/cluster/queries/getClusterInfoQuery.ts 50% 100% 60% 50% 7-8, 27
Generated in workflow #1669 for commit d594bfe by the Vitest Coverage Report Action

@kriszyp kriszyp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One codex suggestion

🤖 Reviewed with Codex

* finish-setup bounces straight back to it.
*/
export function markClusterPasswordSet(queryClient: QueryClient, clusterId: string) {
queryClient.setQueryData(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

An already-running 10-second poll can still complete after setQueryData and replace this value with its stale resetPassword: true response. That recreates the redirect loop when ClusterHome renders. Please cancel the exact cluster query before applying the cache update (make this helper async and await queryClient.cancelQueries({ queryKey, exact: true }), then call setQueryData) and await the helper before navigating. A deferred-query test where the old response resolves after the update would cover the failure scenario.

— KrAIs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants