Upgrade Apollo Client to v4 and refactor error handling (#18584)

## Summary
This PR upgrades Apollo Client from v3.10.0 to v4 and refactors error
handling patterns across the codebase to use a new centralized
`useSnackBarOnQueryError` hook.

## Key Changes

- **Dependency Update**: Upgraded `@apollo/client` from `^3.10.0` to
`^3.11.0` in root package.json
- **New Hook**: Added `useSnackBarOnQueryError` hook for centralized
Apollo query error handling with snack bar notifications
- **Error Handling Refactor**: Updated 100+ files to use the new error
handling pattern:
  - Removed direct `ApolloError` imports where no longer needed
- Replaced manual error handling logic with `useSnackBarOnQueryError`
hook
- Simplified error handling in hooks and components across multiple
modules
- **GraphQL Codegen**: Updated codegen configuration files to work with
Apollo Client v3.11.0
- **Type Definitions**: Added TypeScript declaration file for
`apollo-upload-client` module
- **Test Updates**: Updated test files to reflect new error handling
patterns

## Notable Implementation Details

- The new `useSnackBarOnQueryError` hook provides a consistent way to
handle Apollo query errors with automatic snack bar notifications
- Changes span across multiple feature areas: auth, object records,
settings, workflows, billing, and more
- All changes maintain backward compatibility while improving code
maintainability and reducing duplication
- Jest configuration updated to work with the new Apollo Client version

https://claude.ai/code/session_019WGZ6Rd7sEHuBg9sTrXRqJ

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Félix Malfait
2026-03-13 14:59:46 +01:00
committed by GitHub
parent 172bbd01bc
commit b470cb21a1
386 changed files with 3482 additions and 13593 deletions
@@ -1,9 +1,12 @@
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import { renderHook } from '@testing-library/react';
import { type ComputeStepOutputSchemaInput } from '~/generated/graphql';
import { useComputeStepOutputSchema } from '@/workflow/hooks/useComputeStepOutputSchema';
jest.mock('@apollo/client');
jest.mock('@apollo/client/react', () => ({
...jest.requireActual('@apollo/client/react'),
useMutation: jest.fn(),
}));
jest.mock('@/object-metadata/hooks/useApolloCoreClient', () => ({
useApolloCoreClient: () => ({}),
}));
@@ -16,7 +19,7 @@ describe('useComputeStepOutputSchema', () => {
};
const mockMutate = jest.fn().mockResolvedValue(mockResponse);
(useMutation as jest.Mock).mockReturnValue([mockMutate]);
(useMutation as unknown as jest.Mock).mockReturnValue([mockMutate]);
const { result } = renderHook(() => useComputeStepOutputSchema());
const response = await result.current.computeStepOutputSchema(
@@ -1,4 +1,4 @@
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
@@ -64,15 +64,18 @@ export const useActivateWorkflowVersion = () => {
},
});
const cacheSnapshot = apolloCoreClient.cache.extract();
const cacheSnapshot = apolloCoreClient.cache.extract() as Record<
string,
Record<string, unknown>
>;
const allWorkflowVersions: Array<WorkflowVersion> = Object.values(
cacheSnapshot,
const allWorkflowVersions = (
Object.values(cacheSnapshot) as Array<Record<string, unknown>>
).filter(
(item) =>
item.__typename === 'WorkflowVersion' &&
item.workflowId === workflowId,
);
) as Array<WorkflowVersion>;
const previousActiveWorkflowVersions = allWorkflowVersions.filter(
(version) =>
@@ -1,6 +1,6 @@
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
import { COMPUTE_STEP_OUTPUT_SCHEMA } from '@/workflow/graphql/mutations/computeStepOutputSchema';
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import {
type ComputeStepOutputSchemaInput,
type ComputeStepOutputSchemaMutation,
@@ -1,15 +1,16 @@
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import { useMutation } from '@apollo/client/react';
import {
type CreateDraftFromWorkflowVersionInput,
useCreateDraftFromWorkflowVersionMutation,
CreateDraftFromWorkflowVersionDocument,
} from '~/generated/graphql';
export const useCreateDraftFromWorkflowVersion = () => {
const apolloCoreClient = useApolloCoreClient();
const [mutate] = useCreateDraftFromWorkflowVersionMutation({
const [mutate] = useMutation(CreateDraftFromWorkflowVersionDocument, {
client: apolloCoreClient,
});
@@ -1,4 +1,4 @@
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
@@ -62,14 +62,17 @@ export const useDeactivateWorkflowVersion = () => {
},
});
const cacheSnapshot = apolloCoreClient.cache.extract();
const workflowVersion: WorkflowVersion | undefined = Object.values(
cacheSnapshot,
const cacheSnapshot = apolloCoreClient.cache.extract() as Record<
string,
Record<string, unknown>
>;
const workflowVersion = (
Object.values(cacheSnapshot) as Array<Record<string, unknown>>
).find(
(item) =>
item.__typename === 'WorkflowVersion' &&
item.id === workflowVersionId,
);
) as WorkflowVersion | undefined;
if (!isDefined(workflowVersion)) {
return;
@@ -1,7 +1,7 @@
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import {
type DuplicateWorkflowInput,
type WorkflowVersionDto,
@@ -19,7 +19,7 @@ import { RUN_WORKFLOW_VERSION } from '@/workflow/graphql/mutations/runWorkflowVe
import { type WorkflowRun } from '@/workflow/types/Workflow';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useCallback } from 'react';
import { useMutation } from '@apollo/client';
import { useMutation } from '@apollo/client/react';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import {
@@ -2,11 +2,12 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { dispatchObjectRecordOperationBrowserEvent } from '@/browser-event/utils/dispatchObjectRecordOperationBrowserEvent';
import { useStopWorkflowRunMutation } from '~/generated/graphql';
import { useMutation } from '@apollo/client/react';
import { StopWorkflowRunDocument } from '~/generated/graphql';
export const useStopWorkflowRun = () => {
const apolloCoreClient = useApolloCoreClient();
const [mutate] = useStopWorkflowRunMutation({
const [mutate] = useMutation(StopWorkflowRunDocument, {
client: apolloCoreClient,
});