fix: post-merge settings bugs — SCIM duplication, crash, error boundary#77
fix: post-merge settings bugs — SCIM duplication, crash, error boundary#77TerrifiedBug merged 2 commits intomainfrom
Conversation
…gs crash, error boundary navigation - Remove inline ScimSettings from auth-settings page (now has dedicated /settings/scim route) - Add throwOnError/retry guards to settings.get query in team-settings (requires super-admin, crashes for team admins) - Add componentDidUpdate to ErrorBoundary to reset error state on navigation
…ne for global metrics - Show "—" for condition, threshold, and duration on binary metrics (pipeline_crashed, node_unreachable) in the rules table - Hide pipeline dropdown for metrics that aren't pipeline-scopable (node_unreachable, new_version_available, scim_sync_failed, backup_failed, certificate_expiring, node_joined, node_left) - Move metric selector before pipeline dropdown so the pipeline field reacts to metric selection - Clear pipelineId when switching to a global metric - Show "Notifications will be sent when this event occurs" for binary metrics in the form
Greptile SummaryThis PR fixes three post-merge regressions across settings and navigation: it removes the duplicate inline Key changes:
Confidence Score: 4/5
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Team Admin navigates to Team Settings] --> B{settings.get query}
B -- "FORBIDDEN (non-super-admin)" --> C["throwOnError: false\nretry: false\n→ settingsQuery.data = undefined"]
B -- "Success (super-admin)" --> D[settingsQuery.data populated]
C --> E["oidcConfigured = false\nSSO link button hidden\nSCIM/OIDC banner hidden"]
D --> F["oidcConfigured = true\nSSO link button shown\nSCIM/OIDC banner shown"]
G[User navigates to /settings/auth] --> H[AuthSettings renders]
H --> I[No inline ScimSettings]
J[User navigates to /settings/scim] --> K[ScimSettings renders standalone]
L[Error thrown in page] --> M[ErrorBoundary shows fallback]
M --> N{children ref change?\nprevProps.children !== props.children}
N -- "Yes (parent re-render OR navigation)" --> O[Reset error state\nRe-render children]
N -- No --> M
Last reviewed commit: 6606bfe |
|
|
||
| componentDidUpdate(prevProps: Props) { | ||
| // Reset error state when children change (e.g. route navigation) | ||
| if (this.state.hasError && prevProps.children !== this.props.children) { |
There was a problem hiding this comment.
Children comparison triggers on every parent re-render, not just navigation
prevProps.children !== this.props.children compares JSX element object identity. Because JSX creates a new object on every render, this condition will be true on any parent re-render — not only on route navigation.
If a parent component re-renders while the error fallback is visible (e.g. a polling query fires, or any context update occurs above the boundary), the sequence becomes:
- Error thrown → fallback shown
- Parent re-renders (new children object reference) →
componentDidUpdateresets error state - Crashed children re-render → same error thrown again →
getDerivedStateFromErrorsetshasError: true - Back to showing the fallback
This produces a visible flash/retry loop whenever a parent re-renders during an error state.
The canonical fix is to drive resets via a stable identity such as the current route pathname. The simplest approach is for callers to pass the current route as a key to the boundary — when the key changes on navigation, React unmounts and remounts the component, clearing error state without any componentDidUpdate logic. Alternatively, accept an explicit resetKey prop and compare that instead of children.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/error-boundary.tsx
Line: 29
Comment:
**Children comparison triggers on every parent re-render, not just navigation**
`prevProps.children !== this.props.children` compares JSX element object identity. Because JSX creates a **new object on every render**, this condition will be `true` on any parent re-render — not only on route navigation.
If a parent component re-renders while the error fallback is visible (e.g. a polling query fires, or any context update occurs above the boundary), the sequence becomes:
1. Error thrown → fallback shown
2. Parent re-renders (new children object reference) → `componentDidUpdate` resets error state
3. Crashed children re-render → same error thrown again → `getDerivedStateFromError` sets `hasError: true`
4. Back to showing the fallback
This produces a visible flash/retry loop whenever a parent re-renders during an error state.
The canonical fix is to drive resets via a stable identity such as the current route pathname. The simplest approach is for callers to pass the current route as a `key` to the boundary — when the key changes on navigation, React unmounts and remounts the component, clearing error state without any `componentDidUpdate` logic. Alternatively, accept an explicit `resetKey` prop and compare that instead of `children`.
How can I resolve this? If you propose a fix, please make it concise.|
@greptile review |
Summary
<ScimSettings />from the Authentication page — SCIM now lives exclusively at/settings/scimsettings.getrequires super-admin butTeamSettingscalls it unconditionally. AddedthrowOnError: false+retry: falseso team admins degrade gracefully instead of crashingErrorBoundarydidn't reset on navigation, so one page's error broke all subsequent pages. AddedcomponentDidUpdateto reset when children changeTest plan
/settings/scim— SCIM settings should still work independently