b470cb21a1
## 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>
95 lines
4.7 KiB
TypeScript
95 lines
4.7 KiB
TypeScript
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultCompanyRecordPageLayout';
|
|
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultCompanyRecordPageLayoutId';
|
|
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultNoteRecordPageLayout';
|
|
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultNoteRecordPageLayoutId';
|
|
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultOpportunityRecordPageLayout';
|
|
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultOpportunityRecordPageLayoutId';
|
|
import { DEFAULT_PERSON_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultPersonRecordPageLayout';
|
|
import { DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPersonRecordPageLayoutId';
|
|
import { DEFAULT_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultRecordPageLayout';
|
|
import { DEFAULT_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultRecordPageLayoutId';
|
|
import { DEFAULT_TASK_RECORD_PAGE_LAYOUT } from '@/page-layout/constants/DefaultTaskRecordPageLayout';
|
|
import { DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultTaskRecordPageLayoutId';
|
|
import { DEFAULT_WORKFLOW_PAGE_LAYOUT } from '@/page-layout/constants/DefaultWorkflowPageLayout';
|
|
import { DEFAULT_WORKFLOW_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowPageLayoutId';
|
|
import { DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT } from '@/page-layout/constants/DefaultWorkflowRunPageLayout';
|
|
import { DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowRunPageLayoutId';
|
|
import { DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT } from '@/page-layout/constants/DefaultWorkflowVersionPageLayout';
|
|
import { DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowVersionPageLayoutId';
|
|
import { recordPageLayoutFromIdFamilySelector } from '@/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector';
|
|
import { type PageLayout } from '@/page-layout/types/PageLayout';
|
|
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
|
|
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
|
|
import { useQuery } from '@apollo/client/react';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import { FindOnePageLayoutDocument } from '~/generated-metadata/graphql';
|
|
|
|
const getDefaultLayoutById = (layoutId: string): PageLayout => {
|
|
switch (layoutId) {
|
|
case DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID:
|
|
return DEFAULT_COMPANY_RECORD_PAGE_LAYOUT;
|
|
case DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID:
|
|
return DEFAULT_PERSON_RECORD_PAGE_LAYOUT;
|
|
case DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID:
|
|
return DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT;
|
|
case DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID:
|
|
return DEFAULT_NOTE_RECORD_PAGE_LAYOUT;
|
|
case DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID:
|
|
return DEFAULT_TASK_RECORD_PAGE_LAYOUT;
|
|
case DEFAULT_WORKFLOW_PAGE_LAYOUT_ID:
|
|
return DEFAULT_WORKFLOW_PAGE_LAYOUT;
|
|
case DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID:
|
|
return DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT;
|
|
case DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID:
|
|
return DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT;
|
|
case DEFAULT_RECORD_PAGE_LAYOUT_ID:
|
|
default:
|
|
return DEFAULT_RECORD_PAGE_LAYOUT;
|
|
}
|
|
};
|
|
|
|
const isDefaultLayoutId = (layoutId: string): boolean =>
|
|
layoutId === DEFAULT_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_WORKFLOW_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID ||
|
|
layoutId === DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID;
|
|
|
|
export const useBasePageLayout = (
|
|
pageLayoutId: string,
|
|
): PageLayout | undefined => {
|
|
const isDefaultLayout = isDefaultLayoutId(pageLayoutId);
|
|
|
|
const cachedRecordPageLayout = useAtomFamilySelectorValue(
|
|
recordPageLayoutFromIdFamilySelector,
|
|
{ pageLayoutId },
|
|
);
|
|
|
|
const shouldSkipQuery = isDefaultLayout || isDefined(cachedRecordPageLayout);
|
|
|
|
const { data } = useQuery(FindOnePageLayoutDocument, {
|
|
variables: {
|
|
id: pageLayoutId,
|
|
},
|
|
skip: shouldSkipQuery,
|
|
});
|
|
|
|
if (isDefaultLayout) {
|
|
return getDefaultLayoutById(pageLayoutId);
|
|
}
|
|
|
|
if (isDefined(cachedRecordPageLayout)) {
|
|
return cachedRecordPageLayout;
|
|
}
|
|
|
|
if (isDefined(data?.getPageLayout)) {
|
|
return transformPageLayout(data.getPageLayout);
|
|
}
|
|
|
|
return undefined;
|
|
};
|