Skip to content

DEVPROD-26582: Remove notifyOnNetworkStatusChange: false at global apollo client level#1482

Open
sophiayangDB wants to merge 16 commits intoevergreen-ci:mainfrom
sophiayangDB:DEVPROD-26582
Open

DEVPROD-26582: Remove notifyOnNetworkStatusChange: false at global apollo client level#1482
sophiayangDB wants to merge 16 commits intoevergreen-ci:mainfrom
sophiayangDB:DEVPROD-26582

Conversation

@sophiayangDB
Copy link
Copy Markdown
Contributor

DEVPROD-26582

Description

notifyOnNetworkStatusChange has a new default for Apollo

@sophiayangDB sophiayangDB marked this pull request as ready for review March 26, 2026 17:53
@sophiayangDB sophiayangDB requested a review from a team as a code owner March 26, 2026 17:53
Copy link
Copy Markdown
Contributor

@minnakt minnakt left a comment

Choose a reason for hiding this comment

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

Nice; but the test failures are likely real failures that need to be fixed

@minnakt minnakt changed the title DEVPROD-26582: Consider removing notifyOnNetworkStatusChange: false at global apollo client level DEVPROD-26582: Remove notifyOnNetworkStatusChange: false at global apollo client level Mar 26, 2026
Comment on lines +19 to +21
return null;
}
// if (loading || !userSettings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The NotificationsTab renders nothing if user settings fail to load, causing the tab content to disappear without any error or loading state.
Severity: MEDIUM

Suggested Fix

Update the conditional logic in NotificationsTab to show a CardSkeleton or an error state when userSettings is null, even after the initial load has completed. This ensures the user always sees a meaningful UI state instead of a blank component.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/NotificationsTab.tsx#L19-L21

Potential issue: In the `NotificationsTab` component, if the `useUserSettings` query
completes but returns `null` for `userSettings` (e.g., due to a network error or if the
backend returns no settings), the component will return `null`. This causes the entire
content of the notifications tab to disappear silently without displaying a loading
indicator or an error message to the user. This behavior is inconsistent with the
`ProfileTab`, which shows a skeleton, and is likely unintended as it provides a poor
user experience during data fetch failures.

Did we get this right? 👍 / 👎 to inform future reviews.

const awsRegions = awsRegionData?.awsRegions || [];

if (loading) {
if (awsRegionsLoading || userSettingsLoading || !userSettings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The ProfileTab shows a loading skeleton indefinitely if fetching user settings completes with no data, because the !userSettings check does not account for the loading state.
Severity: MEDIUM

Suggested Fix

Modify the conditional logic in ProfileTab to distinguish between an initial loading state and a completed-but-empty/error state. For example, use a condition like const isInitialLoading = userSettingsLoading && userSettings === null; and only show the skeleton when isInitialLoading is true.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/ProfileTab.tsx#L15

Potential issue: In the `ProfileTab` component, the loading condition `!userSettings`
causes a perpetual loading skeleton to be displayed. If the data fetch completes
(`userSettingsLoading` is `false`) but the `userSettings` data is `null` (due to a query
error or empty data), the `!userSettings` condition remains true. As a result, the
component will show a `CardSkeleton` indefinitely, misleading the user into thinking the
content is still loading when the request has already finished.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +11 to +13
const isInitialLoading = loading && userSettings === null;

if (isInitialLoading) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: When saving notification settings, if the subsequent data refetch fails, the UI silently displays stale data without any error indication, making the save appear successful.
Severity: HIGH

Suggested Fix

Ensure the useUserSettings hook properly handles and exposes error states from Apollo Client's useQuery. Set notifyOnNetworkStatusChange: true for the query to ensure the loading state is updated on refetches. Implement UI to display an error message to the user when a refetch fails, preventing stale data from being shown.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/NotificationsTab.tsx#L11-L13

Potential issue: In the `NotificationsTab` component, after a user submits the form, a
refetch of `UserSettings` is triggered. Due to the Apollo Client configuration
(`notifyOnNetworkStatusChange` being effectively `false`), the `loading` state is not
updated during this refetch. If the refetch fails due to a network error, the component
will not receive an error state or a loading indicator. As a result, it will continue to
display the stale data from the cache, misleading the user into believing their changes
were successfully saved when they were not.

const { notifications, slackMemberId, slackUsername } = userSettings ?? {};

if (loading || !userSettings) {
if (loading && !userSettings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The conditional logic for the loading skeleton at loading && !userSettings will always be false, preventing the skeleton from ever rendering during data fetching.
Severity: MEDIUM

Suggested Fix

The conditional check for the loading skeleton should be simplified to if (loading). This will correctly display the skeleton while the user settings are being fetched and loading is true.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/NotificationsTab.tsx#L11

Potential issue: The `useUserSettings` hook is designed to always return a truthy value
for `userSettings`, defaulting to an empty object `{}`. The conditional logic for
displaying the loading skeleton was changed to `loading && !userSettings`. Because
`!userSettings` will always evaluate to `false`, the entire condition is always `false`.
This prevents the loading skeleton from ever being displayed, even when data is being
fetched. As a result, users will see a flash of an empty form before their settings are
populated, which is a degradation of the user experience.

const { notifications, slackMemberId, slackUsername } = userSettings ?? {};

if (loading || !userSettings) {
if (loading && !userSettings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The condition if (loading && !userSettings) will always be false because userSettings is always a truthy object, preventing the loading skeleton from ever rendering.
Severity: CRITICAL

Suggested Fix

The conditional logic should be updated to correctly show the loading state. A simple if (loading) check would be sufficient, as is done in similar components. Alternatively, reverting to the previous logic if (loading || !userSettings) would also work.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/NotificationsTab.tsx#L11

Potential issue: The `useUserSettings` hook returns `userSettings` as `user?.settings ??
{}`, which guarantees it is always at least an empty, truthy object. Because of this,
the `!userSettings` part of the conditional `if (loading && !userSettings)` will always
evaluate to `false`. This makes the entire condition `false`, regardless of the
`loading` state. As a result, the loading skeleton will never be rendered, and users
will see a broken UI with empty values while data is being fetched.

Comment thread apps/spruce/src/gql/client/useCreateGQLClient/index.ts
const { notifications, slackMemberId, slackUsername } = userSettings ?? {};

if (loading || !userSettings) {
if (loading && !userSettings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The condition to show the loading skeleton was changed to if (loading && !userSettings). Since userSettings is always truthy, the skeleton will never render.
Severity: MEDIUM

Suggested Fix

Revert the conditional logic to if (loading || !userSettings), or simplify it to if (loading) to correctly display the loading skeleton when data is being fetched. This aligns with the pattern used in other similar components.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/spruce/src/pages/preferences/preferencesTabs/NotificationsTab.tsx#L11

Potential issue: The conditional logic for displaying the loading skeleton in the
Notifications tab was changed from `if (loading || !userSettings)` to `if (loading &&
!userSettings)`. The `useUserSettings` hook ensures `userSettings` is always a truthy
object (defaulting to `{}`), which makes the `!userSettings` part of the condition
always `false`. As a result, the entire expression `loading && false` is always `false`,
and the loading skeleton is never rendered. This will cause the component to attempt
rendering with empty or undefined data during initial page loads or data refetches,
instead of showing the expected loading state.

Comment thread apps/spruce/cypress/integration/projectSettings/defaulting_to_repo.ts Outdated
Comment thread apps/spruce/src/gql/client/useCreateGQLClient/index.ts Outdated
Comment on lines +54 to +55
cy.contains("button", "Delete").click();
cy.contains("button", "Delete").click();
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.

Sorry I didn't pick up on your question from before. Clicking the button twice probably isn't what we intend to do; ideally, we should mimic real situations where the button would be clicked once.

Maybe it will help to assert that the delete-project-modal is visible first

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Tried that no luck :(

.find("button")
.contains("Attach")
.parent()
.click();
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.

is there a reason why we don't attach to repo anymore? We are likely checking that the project can be deleted even if it is attached to a repo

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No :( In theory once the refresh problem is actually fixed this would pass, I was being lazy

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