diff --git a/front/package.json b/front/package.json index fb31411fa..8cb599ff1 100644 --- a/front/package.json +++ b/front/package.json @@ -40,6 +40,7 @@ "react-datepicker": "^4.11.0", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", + "react-error-boundary": "^4.0.11", "react-helmet-async": "^1.3.0", "react-hook-form": "^7.45.1", "react-hotkeys-hook": "^4.4.0", @@ -176,4 +177,4 @@ "msw": { "workerDirectory": "public" } -} \ No newline at end of file +} diff --git a/front/src/index.tsx b/front/src/index.tsx index 4080957a6..cb89d3bc5 100644 --- a/front/src/index.tsx +++ b/front/src/index.tsx @@ -7,6 +7,8 @@ import { RecoilRoot } from 'recoil'; import { ApolloProvider } from '@/apollo/components/ApolloProvider'; import { ClientConfigProvider } from '@/client-config/components/ClientConfigProvider'; import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserver'; +import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; +import { PromiseRejectionEffect } from '@/error-handler/components/PromiseRejectionEffect'; import { ApolloMetadataClientProvider } from '@/object-metadata/components/ApolloMetadataClientProvider'; import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager'; @@ -16,12 +18,11 @@ import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/Sn import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider'; import { ThemeType } from '@/ui/theme/constants/theme'; import { UserProvider } from '@/users/components/UserProvider'; +import { App } from '~/App'; +import { PageChangeEffect } from '~/effect-components/PageChangeEffect'; import '@emotion/react'; -import { PageChangeEffect } from './effect-components/PageChangeEffect'; -import { App } from './App'; - import './index.css'; import 'react-loading-skeleton/dist/skeleton.css'; @@ -31,35 +32,38 @@ const root = ReactDOM.createRoot( root.render( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , ); diff --git a/front/src/modules/activities/components/ActivityComments.tsx b/front/src/modules/activities/components/ActivityComments.tsx index 9ade1a605..f5eb54ffc 100644 --- a/front/src/modules/activities/components/ActivityComments.tsx +++ b/front/src/modules/activities/components/ActivityComments.tsx @@ -67,7 +67,7 @@ export const ActivityComments = ({ const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const { records: comments } = useFindManyRecords({ - objectNamePlural: 'comments', + objectNameSingular: 'comment', filter: { activityId: { eq: activity?.id ?? '', diff --git a/front/src/modules/activities/files/hooks/useAttachments.tsx b/front/src/modules/activities/files/hooks/useAttachments.tsx index 7aa2fd158..530bc16dc 100644 --- a/front/src/modules/activities/files/hooks/useAttachments.tsx +++ b/front/src/modules/activities/files/hooks/useAttachments.tsx @@ -5,7 +5,7 @@ import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity'; export const useAttachments = (entity: ActivityTargetableEntity) => { const { records: attachments } = useFindManyRecords({ - objectNamePlural: 'attachments', + objectNameSingular: 'attachment', filter: { [entity.type === 'Company' ? 'companyId' : 'personId']: { eq: entity.id }, }, diff --git a/front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx b/front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx index 76bfde04d..db695c443 100644 --- a/front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx +++ b/front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx @@ -87,7 +87,7 @@ export const ActivityTargetInlineCellEditMode = ({ orderByField: 'createdAt', mappingFunction: (record: any) => identifiersMapper?.(record, 'person'), selectedIds: initialPeopleIds, - objectNamePlural: 'people', + objectNameSingular: 'person', limit: 3, }); @@ -102,7 +102,7 @@ export const ActivityTargetInlineCellEditMode = ({ orderByField: 'createdAt', mappingFunction: (record: any) => identifiersMapper?.(record, 'company'), selectedIds: initialCompanyIds, - objectNamePlural: 'companies', + objectNameSingular: 'company', limit: 3, }); diff --git a/front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx index 50b22074e..1fa2d066d 100644 --- a/front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx +++ b/front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx @@ -28,7 +28,7 @@ export const ActivityTargetsInlineCell = ({ ) ?? []; const { records: activityTargets } = useFindManyRecords({ - objectNamePlural: 'activityTargets', + objectNameSingular: 'activityTarget', filter: { id: { in: activityTargetIds } }, }); diff --git a/front/src/modules/activities/notes/hooks/useNotes.ts b/front/src/modules/activities/notes/hooks/useNotes.ts index de3bdf4b0..264ea63e1 100644 --- a/front/src/modules/activities/notes/hooks/useNotes.ts +++ b/front/src/modules/activities/notes/hooks/useNotes.ts @@ -5,7 +5,7 @@ import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity'; export const useNotes = (entity: ActivityTargetableEntity) => { const { records: activityTargets } = useFindManyRecords({ - objectNamePlural: 'activityTargets', + objectNameSingular: 'activityTarget', filter: { [entity.type === 'Company' ? 'companyId' : 'personId']: { eq: entity.id }, }, @@ -23,7 +23,7 @@ export const useNotes = (entity: ActivityTargetableEntity) => { const { records: notes } = useFindManyRecords({ skip: !activityTargets?.length, - objectNamePlural: 'activities', + objectNameSingular: 'activity', filter, orderBy, }); diff --git a/front/src/modules/activities/tasks/components/TaskRow.tsx b/front/src/modules/activities/tasks/components/TaskRow.tsx index 7cbbad99f..e7246cf5d 100644 --- a/front/src/modules/activities/tasks/components/TaskRow.tsx +++ b/front/src/modules/activities/tasks/components/TaskRow.tsx @@ -82,7 +82,7 @@ export const TaskRow = ({ ) ?? []; const { records: activityTargets } = useFindManyRecords({ - objectNamePlural: 'activityTargets', + objectNameSingular: 'activityTarget', filter: { id: { in: activityTargetIds } }, }); diff --git a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts index d136191bd..b313ef654 100644 --- a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts +++ b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts @@ -9,7 +9,7 @@ export const useCurrentUserTaskCount = () => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const { records: tasks } = useFindManyRecords({ - objectNamePlural: 'activities', + objectNameSingular: 'activity', filter: { type: { eq: 'Task' }, completedAt: { is: 'NULL' }, diff --git a/front/src/modules/activities/tasks/hooks/useTasks.ts b/front/src/modules/activities/tasks/hooks/useTasks.ts index 2c7dfcbd2..6ae79ebd4 100644 --- a/front/src/modules/activities/tasks/hooks/useTasks.ts +++ b/front/src/modules/activities/tasks/hooks/useTasks.ts @@ -22,7 +22,7 @@ export const useTasks = (props?: UseTasksProps) => { }); const { records: activityTargets } = useFindManyRecords({ - objectNamePlural: 'activityTargets', + objectNameSingular: 'activityTarget', filter: isDefined(entity) ? { [entity?.type === 'Company' ? 'companyId' : 'personId']: { @@ -33,7 +33,7 @@ export const useTasks = (props?: UseTasksProps) => { }); const { records: completeTasksData } = useFindManyRecords({ - objectNamePlural: 'activities', + objectNameSingular: 'activity', skip: !entity && !selectedFilter, filter: { completedAt: { is: 'NOT_NULL' }, @@ -57,7 +57,7 @@ export const useTasks = (props?: UseTasksProps) => { }); const { records: incompleteTaskData } = useFindManyRecords({ - objectNamePlural: 'activities', + objectNameSingular: 'activity', skip: !entity && !selectedFilter, filter: { completedAt: { is: 'NULL' }, diff --git a/front/src/modules/activities/timeline/components/Timeline.tsx b/front/src/modules/activities/timeline/components/Timeline.tsx index 2197db360..4b61bf6eb 100644 --- a/front/src/modules/activities/timeline/components/Timeline.tsx +++ b/front/src/modules/activities/timeline/components/Timeline.tsx @@ -49,7 +49,7 @@ const StyledEmptyTimelineSubTitle = styled.div` export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => { const { records: activityTargets, loading } = useFindManyRecords({ - objectNamePlural: 'activityTargets', + objectNameSingular: 'activityTarget', filter: { [entity.type === 'Company' ? 'companyId' : 'personId']: { eq: entity.id }, }, @@ -57,7 +57,7 @@ export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => { const { records: activities } = useFindManyRecords({ skip: !activityTargets?.length, - objectNamePlural: 'activities', + objectNameSingular: 'activity', filter: { id: { in: activityTargets?.map((activityTarget) => activityTarget.activityId), diff --git a/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts b/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts index bf53263fc..465b83386 100644 --- a/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts +++ b/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts @@ -12,6 +12,7 @@ import { useObjectMetadataItem, } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { optimisticEffectState } from '../states/optimisticEffectState'; import { OptimisticEffect } from '../types/internal/OptimisticEffect'; @@ -19,10 +20,9 @@ import { OptimisticEffectDefinition } from '../types/OptimisticEffectDefinition' export const useOptimisticEffect = ({ objectNameSingular, -}: { - objectNameSingular: string | undefined; -}) => { +}: ObjectMetadataItemIdentifier) => { const apolloClient = useApolloClient(); + const { findManyRecordsQuery } = useObjectMetadataItem({ objectNameSingular, }); diff --git a/front/src/modules/auth/hooks/useAuth.ts b/front/src/modules/auth/hooks/useAuth.ts index 2d0b24e7b..36a43b146 100644 --- a/front/src/modules/auth/hooks/useAuth.ts +++ b/front/src/modules/auth/hooks/useAuth.ts @@ -28,6 +28,7 @@ export const useAuth = () => { const setCurrentWorkspaceMember = useSetRecoilState( currentWorkspaceMemberState, ); + const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); const setIsVerifyPendingState = useSetRecoilState(isVerifyPendingState); diff --git a/front/src/modules/command-menu/components/CommandMenu.tsx b/front/src/modules/command-menu/components/CommandMenu.tsx index 19d192d63..5f765750b 100644 --- a/front/src/modules/command-menu/components/CommandMenu.tsx +++ b/front/src/modules/command-menu/components/CommandMenu.tsx @@ -116,7 +116,7 @@ export const CommandMenu = () => { const { records: people } = useFindManyRecords({ skip: !isCommandMenuOpened, - objectNamePlural: 'people', + objectNameSingular: 'person', filter: { or: [ { name: { firstName: { ilike: `%${search}%` } } }, @@ -128,7 +128,7 @@ export const CommandMenu = () => { const { records: companies } = useFindManyRecords({ skip: !isCommandMenuOpened, - objectNamePlural: 'companies', + objectNameSingular: 'company', filter: { name: { ilike: `%${search}%` }, }, @@ -137,7 +137,7 @@ export const CommandMenu = () => { const { records: activities } = useFindManyRecords({ skip: !isCommandMenuOpened, - objectNamePlural: 'activities', + objectNameSingular: 'activity', filter: { or: [ { title: { like: `%${search}%` } }, diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx index 6d32886d1..b29e2962d 100644 --- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx +++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx @@ -61,7 +61,7 @@ export const HooksCompanyBoardEffect = ({ const currentViewSorts = useRecoilValue(currentViewSortsState); const { objectMetadataItem } = useObjectMetadataItem({ - objectNamePlural: 'opportunities', + objectNameSingular: 'opportunity', }); const { columnDefinitions, filterDefinitions, sortDefinitions } = @@ -85,7 +85,7 @@ export const HooksCompanyBoardEffect = ({ ); useFindManyRecords({ - objectNamePlural: 'pipelineSteps', + objectNameSingular: 'pipelineStep', filter: {}, onCompleted: useCallback( (data: PaginatedRecordTypeResults) => { @@ -107,7 +107,7 @@ export const HooksCompanyBoardEffect = ({ const { fetchMoreRecords: fetchMoreOpportunities } = useFindManyRecords({ skip: !pipelineSteps.length, - objectNamePlural: 'opportunities', + objectNameSingular: 'opportunity', filter: filter, orderBy: orderBy, onCompleted: useCallback( @@ -132,7 +132,7 @@ export const HooksCompanyBoardEffect = ({ const { fetchMoreRecords: fetchMoreCompanies } = useFindManyRecords({ skip: !opportunities.length, - objectNamePlural: 'companies', + objectNameSingular: 'company', filter: { id: { in: opportunities.map((opportunity) => opportunity.companyId || ''), diff --git a/front/src/modules/companies/components/NewOpportunityButton.tsx b/front/src/modules/companies/components/NewOpportunityButton.tsx index 93702383c..69a6b2e96 100644 --- a/front/src/modules/companies/components/NewOpportunityButton.tsx +++ b/front/src/modules/companies/components/NewOpportunityButton.tsx @@ -78,7 +78,7 @@ export const NewOpportunityButton = () => { orderByField: 'createdAt', selectedIds: [], mappingFunction: (record: any) => identifiersMapper?.(record, 'company'), - objectNamePlural: 'companies', + objectNameSingular: 'company', }); return ( diff --git a/front/src/modules/companies/components/OpportunityPicker.tsx b/front/src/modules/companies/components/OpportunityPicker.tsx index 571653480..1950d6c62 100644 --- a/front/src/modules/companies/components/OpportunityPicker.tsx +++ b/front/src/modules/companies/components/OpportunityPicker.tsx @@ -54,7 +54,7 @@ export const OpportunityPicker = ({ orderByField: 'createdAt', selectedIds: [], mappingFunction: (record: any) => identifiersMapper?.(record, 'company'), - objectNamePlural: 'companies', + objectNameSingular: 'company', }); const [isProgressSelectionUnfolded, setIsProgressSelectionUnfolded] = diff --git a/front/src/modules/error-handler/components/AppErrorBoundary.tsx b/front/src/modules/error-handler/components/AppErrorBoundary.tsx new file mode 100644 index 000000000..ecd37e8e2 --- /dev/null +++ b/front/src/modules/error-handler/components/AppErrorBoundary.tsx @@ -0,0 +1,19 @@ +import { ErrorInfo, ReactNode } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; + +import { GenericErrorFallback } from '@/error-handler/components/GenericErrorFallback'; + +export const AppErrorBoundary = ({ children }: { children: ReactNode }) => { + const handleError = (_error: Error, _info: ErrorInfo) => { + // TODO: log error to Sentry + }; + + return ( + + {children} + + ); +}; diff --git a/front/src/modules/error-handler/components/GenericErrorFallback.tsx b/front/src/modules/error-handler/components/GenericErrorFallback.tsx new file mode 100644 index 000000000..17d29da53 --- /dev/null +++ b/front/src/modules/error-handler/components/GenericErrorFallback.tsx @@ -0,0 +1,26 @@ +import { FallbackProps } from 'react-error-boundary'; + +type GenericErrorFallbackProps = FallbackProps; + +export const GenericErrorFallback = ({ + error, + resetErrorBoundary, +}: GenericErrorFallbackProps) => { + return ( +
+
{error.message}
+ +
+ ); +}; diff --git a/front/src/modules/error-handler/components/PromiseRejectionEffect.tsx b/front/src/modules/error-handler/components/PromiseRejectionEffect.tsx new file mode 100644 index 000000000..7dc75ac6c --- /dev/null +++ b/front/src/modules/error-handler/components/PromiseRejectionEffect.tsx @@ -0,0 +1,39 @@ +import React, { useCallback, useEffect } from 'react'; + +import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError'; +import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; + +export const PromiseRejectionEffect = () => { + const { enqueueSnackBar } = useSnackBar(); + + const handlePromiseRejection = useCallback( + (event: PromiseRejectionEvent) => { + const error = event.reason; + + // TODO: connect Sentry here + if (error instanceof ObjectMetadataItemNotFoundError) { + enqueueSnackBar( + `Error with custom object that cannot be found : ${event.reason}`, + { + variant: 'error', + }, + ); + } else { + enqueueSnackBar(`Error: ${event.reason}`, { + variant: 'error', + }); + } + }, + [enqueueSnackBar], + ); + + useEffect(() => { + window.addEventListener('unhandledrejection', handlePromiseRejection); + + return () => { + window.removeEventListener('unhandledrejection', handlePromiseRejection); + }; + }, [handlePromiseRejection]); + + return <>; +}; diff --git a/front/src/modules/favorites/hooks/useFavorites.ts b/front/src/modules/favorites/hooks/useFavorites.ts index e2ac47efd..5092f632e 100644 --- a/front/src/modules/favorites/hooks/useFavorites.ts +++ b/front/src/modules/favorites/hooks/useFavorites.ts @@ -8,6 +8,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { Favorite } from '@/favorites/types/Favorite'; import { mapFavorites } from '@/favorites/utils/mapFavorites'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults'; @@ -18,7 +19,7 @@ import { favoritesState } from '../states/favoritesState'; export const useFavorites = ({ objectNamePlural, }: { - objectNamePlural: string | undefined; + objectNamePlural: string; }) => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); @@ -30,7 +31,7 @@ export const useFavorites = ({ deleteOneRecordMutation: deleteOneFavoriteMutation, objectMetadataItem: favoriteObjectMetadataItem, } = useObjectMetadataItem({ - objectNamePlural: 'favorites', + objectNameSingular: 'favorite', }); const { registerOptimisticEffect, triggerOptimisticEffects } = @@ -39,15 +40,19 @@ export const useFavorites = ({ }); const { performOptimisticEvict } = useOptimisticEvict(); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + const { objectMetadataItem: favoriteTargetObjectMetadataItem } = useObjectMetadataItem({ - objectNamePlural, + objectNameSingular, }); const apolloClient = useApolloClient(); useFindManyRecords({ - objectNamePlural: 'favorites', + objectNameSingular: 'favorite', onCompleted: useRecoilCallback( ({ snapshot, set }) => async (data: PaginatedRecordTypeResults>) => { diff --git a/front/src/modules/object-metadata/components/ApolloMetadataClientProvider.tsx b/front/src/modules/object-metadata/components/ApolloMetadataClientProvider.tsx index b3eb9db9b..3b19d5564 100644 --- a/front/src/modules/object-metadata/components/ApolloMetadataClientProvider.tsx +++ b/front/src/modules/object-metadata/components/ApolloMetadataClientProvider.tsx @@ -14,7 +14,6 @@ export const ApolloMetadataClientProvider = ({ children: React.ReactNode; }) => { const [tokenPair] = useRecoilState(tokenPairState); - const apolloMetadataClient = useMemo(() => { if (tokenPair?.accessToken.token) { return new ApolloClient({ diff --git a/front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx b/front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx new file mode 100644 index 000000000..a0100ca58 --- /dev/null +++ b/front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx @@ -0,0 +1,7 @@ +import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems'; + +export const ObjectMetadataItemsLoadEffect = () => { + useFindManyObjectMetadataItems(); + + return <>; +}; diff --git a/front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx b/front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx index 5744c8d34..31d393d93 100644 --- a/front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx +++ b/front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx @@ -1,14 +1,21 @@ +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect'; -import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RelationPickerScope } from '@/ui/input/components/internal/relation-picker/scopes/RelationPickerScope'; export const ObjectMetadataItemsProvider = ({ children, }: React.PropsWithChildren) => { - const { loading } = useFindManyObjectMetadataItems(); + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + const currentWorkspace = useRecoilValue(currentWorkspaceState); - return loading ? ( - <> + return objectMetadataItems.length < 1 && currentWorkspace ? ( + <> + + ) : ( <> diff --git a/front/src/modules/object-metadata/errors/ObjectMetadataNotFoundError.ts b/front/src/modules/object-metadata/errors/ObjectMetadataNotFoundError.ts new file mode 100644 index 000000000..b56080fa2 --- /dev/null +++ b/front/src/modules/object-metadata/errors/ObjectMetadataNotFoundError.ts @@ -0,0 +1,13 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export class ObjectMetadataItemNotFoundError extends Error { + constructor(objectName: string, objectMetadataItems: ObjectMetadataItem[]) { + const message = `Object metadata item "${objectName}" cannot be found in an array of ${ + objectMetadataItems?.length ?? 0 + } elements`; + + super(message); + + Object.setPrototypeOf(this, ObjectMetadataItemNotFoundError.prototype); + } +} diff --git a/front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts b/front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts index 0c8d8e074..2503893cc 100644 --- a/front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts +++ b/front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts @@ -1,7 +1,11 @@ import { gql } from '@apollo/client'; import { useRecoilValue } from 'recoil'; +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError'; import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; import { useGenerateCreateOneRecordMutation } from '@/object-record/hooks/useGenerateCreateOneRecordMutation'; import { useGenerateFindManyRecordsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsQuery'; import { useGenerateFindOneRecordQuery } from '@/object-record/hooks/useGenerateFindOneRecordQuery'; @@ -26,17 +30,36 @@ export const EMPTY_MUTATION = gql` `; export const useObjectMetadataItem = ( - { objectNamePlural, objectNameSingular }: ObjectMetadataItemIdentifier, + { objectNameSingular }: ObjectMetadataItemIdentifier, depth?: number, ) => { - const objectMetadataItem = useRecoilValue( + const currentWorkspace = useRecoilValue(currentWorkspaceState); + const mockObjectMetadataItems = getObjectMetadataItemsMock(); + + let objectMetadataItem = useRecoilValue( objectMetadataItemFamilySelector({ - objectNamePlural, - objectNameSingular, + objectName: objectNameSingular, + objectNameType: 'singular', }), ); - const objectMetadataItemNotFound = !isDefined(objectMetadataItem); + let objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + if (!currentWorkspace) { + objectMetadataItem = + mockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ) ?? null; + objectMetadataItems = mockObjectMetadataItems; + } + + if (!isDefined(objectMetadataItem)) { + throw new ObjectMetadataItemNotFoundError( + objectNameSingular, + objectMetadataItems, + ); + } const getRecordFromCache = useGetRecordFromCache({ objectMetadataItem, @@ -68,17 +91,16 @@ export const useObjectMetadataItem = ( objectMetadataItem, }); - const labelIdentifierFieldMetadataId = objectMetadataItem?.fields.find( + const labelIdentifierFieldMetadataId = objectMetadataItem.fields.find( ({ name }) => name === 'name', )?.id; - const basePathToShowPage = `/object/${objectMetadataItem?.nameSingular}/`; + const basePathToShowPage = `/object/${objectMetadataItem.nameSingular}/`; return { labelIdentifierFieldMetadataId, basePathToShowPage, objectMetadataItem, - objectMetadataItemNotFound, getRecordFromCache, modifyRecordFromCache, findManyRecordsQuery, diff --git a/front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts b/front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts new file mode 100644 index 000000000..470664a91 --- /dev/null +++ b/front/src/modules/object-metadata/hooks/useObjectNamePluralFromSingular.ts @@ -0,0 +1,38 @@ +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { isDefined } from '~/utils/isDefined'; + +export const useObjectNamePluralFromSingular = ({ + objectNameSingular, +}: { + objectNameSingular: string; +}) => { + const currentWorkspace = useRecoilValue(currentWorkspaceState); + const mockObjectMetadataItems = getObjectMetadataItemsMock(); + + let objectMetadataItem = useRecoilValue( + objectMetadataItemFamilySelector({ + objectName: objectNameSingular, + objectNameType: 'singular', + }), + ); + + if (!currentWorkspace) { + objectMetadataItem = + mockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ) ?? null; + } + + if (!isDefined(objectMetadataItem)) { + throw new Error( + `Object metadata item not found for ${objectNameSingular} object`, + ); + } + + return { objectNamePlural: objectMetadataItem.namePlural }; +}; diff --git a/front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts b/front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts new file mode 100644 index 000000000..2c9d0c1f6 --- /dev/null +++ b/front/src/modules/object-metadata/hooks/useObjectNameSingularFromPlural.ts @@ -0,0 +1,38 @@ +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { isDefined } from '~/utils/isDefined'; + +export const useObjectNameSingularFromPlural = ({ + objectNamePlural, +}: { + objectNamePlural: string; +}) => { + const currentWorkspace = useRecoilValue(currentWorkspaceState); + const mockObjectMetadataItems = getObjectMetadataItemsMock(); + + let objectMetadataItem = useRecoilValue( + objectMetadataItemFamilySelector({ + objectName: objectNamePlural, + objectNameType: 'plural', + }), + ); + + if (!currentWorkspace) { + objectMetadataItem = + mockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.namePlural === objectNamePlural, + ) ?? null; + } + + if (!isDefined(objectMetadataItem)) { + throw new Error( + `Object metadata item not found for ${objectNamePlural} object`, + ); + } + + return { objectNameSingular: objectMetadataItem.nameSingular }; +}; diff --git a/front/src/modules/object-metadata/states/objectMetadataItemFamilySelector.ts b/front/src/modules/object-metadata/states/objectMetadataItemFamilySelector.ts index fbfe2e33c..b264758fb 100644 --- a/front/src/modules/object-metadata/states/objectMetadataItemFamilySelector.ts +++ b/front/src/modules/object-metadata/states/objectMetadataItemFamilySelector.ts @@ -3,27 +3,37 @@ import { selectorFamily } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +type ObjectMetadataItemSelector = { + objectName: string; + objectNameType: 'singular' | 'plural'; +}; + export const objectMetadataItemFamilySelector = selectorFamily< ObjectMetadataItem | null, - { objectNameSingular?: string; objectNamePlural?: string } + ObjectMetadataItemSelector >({ key: 'objectMetadataItemFamilySelector', get: - ({ - objectNameSingular, - objectNamePlural, - }: { - objectNameSingular?: string; - objectNamePlural?: string; - }) => + ({ objectNameType, objectName }: ObjectMetadataItemSelector) => ({ get }) => { const objectMetadataItems = get(objectMetadataItemsState); - return ( - objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === objectNameSingular || - objectMetadataItem.namePlural === objectNamePlural, - ) ?? null - ); + + if (objectNameType === 'singular') { + return ( + objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectName, + ) ?? null + ); + } else if (objectNameType === 'plural') { + return ( + objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.namePlural === objectName, + ) ?? null + ); + } + + return null; }, }); diff --git a/front/src/modules/object-metadata/types/ObjectMetadataItemIdentifier.ts b/front/src/modules/object-metadata/types/ObjectMetadataItemIdentifier.ts index 0c4d0cbea..5ecaa343c 100644 --- a/front/src/modules/object-metadata/types/ObjectMetadataItemIdentifier.ts +++ b/front/src/modules/object-metadata/types/ObjectMetadataItemIdentifier.ts @@ -1,4 +1,3 @@ export type ObjectMetadataItemIdentifier = { - objectNamePlural?: string; - objectNameSingular?: string; + objectNameSingular: string; }; diff --git a/front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts b/front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts new file mode 100644 index 000000000..d6b0c4350 --- /dev/null +++ b/front/src/modules/object-metadata/utils/getObjectMetadataItemsMock.ts @@ -0,0 +1,3676 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export const getObjectMetadataItemsMock = () => { + const mockArray = [ + { + __typename: 'object', + id: '20202020-ddee-40de-9c9b-5f82a3503360', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'webhook', + namePlural: 'webhooks', + labelSingular: 'Webhook', + labelPlural: 'Webhooks', + description: 'A webhook', + icon: 'IconRobot', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [], + }, + { + __typename: 'object', + id: '20202020-d8d0-4c2d-a370-5499b2181d02', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'apiKey', + namePlural: 'apiKeys', + labelSingular: 'Api Key', + labelPlural: 'Api Keys', + description: 'An api key', + icon: 'IconRobot', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-a092-41e2-940e-e17cd0403aa7', + type: 'DATE_TIME', + name: 'expiresAt', + label: 'Expiration date', + description: 'ApiKey expiration date', + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-435c-4133-93c0-df5709d1694d', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-ecd6-479f-8368-5032fdee43b3', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7222-45ee-b5c4-c30eba68566f', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1dfa-4ef3-8d19-51e82c28677a', + type: 'TEXT', + name: 'name', + label: 'Name', + description: 'ApiKey name', + icon: 'IconLink', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-da41-436e-8498-b1a99c23b275', + type: 'DATE_TIME', + name: 'revokedAt', + label: 'Revocation date', + description: 'ApiKey revocation date', + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.251Z', + updatedAt: '2023-11-30T11:13:15.251Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-cf28-41dd-b98b-d6e1f5b3a251', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewSort', + namePlural: 'viewSorts', + labelSingular: 'View Sort', + labelPlural: 'View Sorts', + description: '(System) View Sorts', + icon: 'IconArrowsSort', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-077e-4451-b1d8-e602c956ebd2', + type: 'TEXT', + name: 'direction', + label: 'Direction', + description: 'View Sort direction', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-cb2c-4c8f-a289-c9851b23d064', + type: 'UUID', + name: 'fieldMetadataId', + label: 'Field Metadata Id', + description: 'View Sort target field', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5870-4665-92a6-a39b7f53352d', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7677-4955-8ffe-06481534d12c', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-16ec-4074-a54b-c8f7f1178cf6', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f5d0-467f-a3d8-395ba16b8ebf', + type: 'UUID', + name: 'viewId', + label: 'View Id', + description: 'View Sort related view', + icon: 'IconLayoutCollage', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.361Z', + updatedAt: '2023-11-30T11:13:15.361Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '89f2d604-2372-41ac-b822-8feae0ea31ee', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-767f-473f-8fd0-6cdbefbf8dbe', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'view', + namePlural: 'views', + }, + fromFieldMetadataId: '20202020-3011-4d5c-8133-c01134e733df', + }, + }, + ], + }, + { + __typename: 'object', + id: '20202020-cae9-4ff4-9579-f7d9fe44c937', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'opportunity', + namePlural: 'opportunities', + labelSingular: 'Opportunity', + labelPlural: 'Opportunities', + description: 'An opportunity', + icon: 'IconTargetArrow', + isCustom: false, + isActive: true, + isSystem: false, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-0655-41df-b938-15d71e589d3e', + type: 'UUID', + name: 'personId', + label: 'Person ID (foreign key)', + description: 'Foreign key for person', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-618e-42da-b3c3-bcd7af76e4c2', + type: 'UUID', + name: 'pointOfContactId', + label: 'Point of Contact ID (foreign key)', + description: 'Foreign key for point of contact', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-437b-4fd7-98bd-00cb91204329', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-31d5-4af5-b016-c61c1c265706', + type: 'RELATION', + name: 'company', + label: 'Company', + description: 'Opportunity company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '34b27cf4-b706-4466-824b-bdd1745cf04d', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + fromFieldMetadataId: '20202020-e3fc-46ff-b552-3e757843f06e', + }, + }, + { + __typename: 'field', + id: '20202020-31d5-4af5-b016-c61c1c2657b9', + type: 'UUID', + name: 'companyId', + label: 'Company ID (foreign key)', + description: 'Foreign key for company', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0a2e-4676-8011-3fdb2c30d7f8', + type: 'UUID', + name: 'pipelineStepId', + label: 'Pipeline Step ID (foreign key)', + description: 'Foreign key for pipeline step', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3b9c-4e58-a3d2-c617d3b596b1', + type: 'TEXT', + name: 'probability', + label: 'Probability', + description: 'Opportunity probability', + icon: 'IconProgressCheck', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0a2e-4676-8011-3fdb2c30c258', + type: 'RELATION', + name: 'pipelineStep', + label: 'Pipeline Step', + description: 'Opportunity pipeline step', + icon: 'IconKanban', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'dfb44970-3e09-49f2-9f1d-51c8c451b8f5', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-1029-4661-9e91-83bad932bdcd', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'pipelineStep', + namePlural: 'pipelineSteps', + }, + fromFieldMetadataId: '20202020-22c4-443a-b114-43c97dda5867', + }, + }, + { + __typename: 'field', + id: '20202020-de52-4e7b-a298-db7a7553500f', + type: 'DATE_TIME', + name: 'closeDate', + label: 'Close date', + description: 'Opportunity close date', + icon: 'IconCalendarEvent', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8c1f-4c83-9a89-7843e586564d', + type: 'CURRENCY', + name: 'amount', + label: 'Amount', + description: 'Opportunity amount', + icon: 'IconCurrencyDollar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-16ef-476c-8eac-d439b84024cb', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-a39d-4ea9-994f-28d1ebd15904', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-618e-42da-b3c3-bcd7af76e355', + type: 'RELATION', + name: 'pointOfContact', + label: 'Point of Contact', + description: 'Opportunity point of contact', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '5e4c2e1a-ee54-4987-917a-d79142d69bd3', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + fromFieldMetadataId: '20202020-2c2e-418e-ba2d-d28434ff02a6', + }, + }, + { + __typename: 'field', + id: '20202020-0655-41df-b938-15d71e589307', + type: 'RELATION', + name: 'person', + label: 'Person', + description: 'Opportunity person', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.308Z', + updatedAt: '2023-11-30T11:13:15.308Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'e7c6b729-3f52-422c-8452-aedea5753c96', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + fromFieldMetadataId: '20202020-6bc4-4905-a9d3-4f8d616a19e1', + }, + }, + ], + }, + { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + labelSingular: 'Person', + labelPlural: 'People', + description: 'A person', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-6bc4-4905-a9d3-4f8d616a19e1', + type: 'RELATION', + name: 'opportunities', + label: 'Opportunities', + description: 'Opportunities linked to the contact.', + icon: 'IconTargetArrow', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'e7c6b729-3f52-422c-8452-aedea5753c96', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-cae9-4ff4-9579-f7d9fe44c937', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'opportunity', + namePlural: 'opportunities', + }, + toFieldMetadataId: '20202020-0655-41df-b938-15d71e589307', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-a3a7-4f63-9303-10226f6055be', + type: 'LINK', + name: 'xLink', + label: 'X', + description: 'Contact’s X/Twitter account', + icon: 'IconBrandX', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-03cd-4cd0-9afc-92077b69f24f', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2c2e-418e-ba2d-d28434ff02a6', + type: 'RELATION', + name: 'pointOfContactForOpportunities', + label: 'POC for Opportunities', + description: 'Point of Contact for Opportuniites', + icon: 'IconTargetArrow', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: { + __typename: 'relation', + id: '5e4c2e1a-ee54-4987-917a-d79142d69bd3', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-cae9-4ff4-9579-f7d9fe44c937', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'opportunity', + namePlural: 'opportunities', + }, + toFieldMetadataId: '20202020-618e-42da-b3c3-bcd7af76e355', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-bec0-4cf0-bf1c-8b2ed21f027a', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-64e1-4080-b6ad-db03c3809885', + type: 'RELATION', + name: 'company', + label: 'Company', + description: 'Contact’s company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '8bb4535e-fd80-4ad8-af6d-06b02b83da32', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + fromFieldMetadataId: '20202020-68b4-4c8e-af19-738eba2a42a5', + }, + }, + { + __typename: 'field', + id: '20202020-78f8-4b4c-90ff-86adf77590f5', + type: 'TEXT', + name: 'city', + label: 'City', + description: 'Contact’s city', + icon: 'IconMap', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8a96-4e4b-86fd-ea126530e0c1', + type: 'EMAIL', + name: 'email', + label: 'Email', + description: 'Contact’s Email', + icon: 'IconMail', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f285-4115-a46c-116522986b29', + type: 'RELATION', + name: 'activityTargets', + label: 'Activities', + description: 'Activities tied to the contact', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: { + __typename: 'relation', + id: '1c515eae-14e8-4042-9af4-50ee725b6de5', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-439a-4a41-83a3-3cda03d01d38', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activityTarget', + namePlural: 'activityTargets', + }, + toFieldMetadataId: '20202020-e56c-43e6-8fce-5619d8c2293a', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3b86-413e-ab56-0ebd1a583ff3', + type: 'TEXT', + name: 'jobTitle', + label: 'Job Title', + description: 'Contact’s job title', + icon: 'IconBriefcase', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-6268-4165-8774-9aaf45db2b25', + type: 'RELATION', + name: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the contact', + icon: 'IconHeart', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: { + __typename: 'relation', + id: '175b312c-956c-47c4-95f9-1aa0289ba794', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-90e4-4701-a350-8ab75e23e3b8', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'favorite', + namePlural: 'favorites', + }, + toFieldMetadataId: '20202020-0876-4735-8974-ff4d51aafa07', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5883-4bb3-a308-65271901a1d4', + type: 'RELATION', + name: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the contact.', + icon: 'IconFileImport', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: { + __typename: 'relation', + id: '264dce1c-24da-444c-af1f-4e0b90d06b0b', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-5f98-4317-915d-3779bb821be2', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'attachment', + namePlural: 'attachments', + }, + toFieldMetadataId: '20202020-f67c-4cc5-893c-c6b615527473', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-9b56-4888-bfe3-f6f59aa999e3', + type: 'FULL_NAME', + name: 'name', + label: 'Name', + description: 'Contact’s name', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-486f-45f9-bbdf-aac18b1831c0', + type: 'TEXT', + name: 'phone', + label: 'Phone', + description: 'Contact’s phone number', + icon: 'IconPhone', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-dcf6-445a-b543-37e55de43c25', + type: 'LINK', + name: 'linkedinLink', + label: 'Linkedin', + description: 'Contact’s Linkedin account', + icon: 'IconBrandLinkedin', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2bf4-42b8-8718-a3e852bfa6a6', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-bb05-45cb-aa2a-71b58d49dd23', + type: 'TEXT', + name: 'avatarUrl', + label: 'Avatar', + description: 'Contact’s avatar', + icon: 'IconFileUpload', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-64e1-4080-b6ad-db03c3809f8b', + type: 'UUID', + name: 'companyId', + label: 'Company ID (foreign key)', + description: 'Foreign key for company', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.331Z', + updatedAt: '2023-11-30T11:13:15.331Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + labelSingular: 'Workspace Member', + labelPlural: 'Workspace Members', + description: 'A workspace member', + icon: 'IconUserCircle', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-83f2-4c5f-96b0-0c51ecc160e3', + type: 'TEXT', + name: 'colorScheme', + label: 'Color Scheme', + description: 'Preferred color scheme', + icon: 'IconColorSwatch', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8c37-4163-ba06-1dada334ce3e', + type: 'FULL_NAME', + name: 'name', + label: 'Name', + description: 'Workspace member name', + icon: 'IconCircleUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-10f6-4df9-8d6f-a760b65bd800', + type: 'TEXT', + name: 'locale', + label: 'Language', + description: 'Preferred language', + icon: 'IconLanguage', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f2c1-4ca1-9ca5-7b9d5cc87eb0', + type: 'UUID', + name: 'userId', + label: 'User Id', + description: 'Associated User Id', + icon: 'IconCircleUsers', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5ecb-405b-8712-171bb8916b96', + type: 'RELATION', + name: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the workspace member', + icon: 'IconHeart', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: '71f35744-ab2e-4311-922e-0488aa55b3c5', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-90e4-4701-a350-8ab75e23e3b8', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'favorite', + namePlural: 'favorites', + }, + toFieldMetadataId: '20202020-1138-4e93-bbff-917a68161abf', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7ba6-40d5-934b-17146183a212', + type: 'TEXT', + name: 'avatarUrl', + label: 'Avatar Url', + description: 'Workspace member avatar', + icon: 'IconFileUpload', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-37a0-4db4-9c9f-fd3e3f4e47fc', + type: 'RELATION', + name: 'authoredActivities', + label: 'Authored activities', + description: 'Activities created by the workspace member', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'fa043ecd-792d-4ece-bc98-24c81fd8daf7', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + }, + toFieldMetadataId: '20202020-3acb-46bb-b993-0dc49fa2a48c', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1cbf-4b32-8c33-fbfedcd9afa8', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7238-4e2a-9ccf-d2c8f604933a', + type: 'RELATION', + name: 'authoredComments', + label: 'Authored comments', + description: 'Authored comments', + icon: 'IconComment', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'f7ebb0a5-c9d6-4d53-9a70-1d736000468a', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-4de3-4e65-ac60-b40b8e08d7d6', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'comment', + namePlural: 'comments', + }, + toFieldMetadataId: '20202020-2c70-40c2-bba6-893780b25d41', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1ba3-4c24-b2cd-b0789633e8d4', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-678e-4702-a535-2549ef07f1ca', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-ac05-44b9-9526-764dd5ce14e2', + type: 'RELATION', + name: 'assignedActivities', + label: 'Assigned activities', + description: 'Activities assigned to the workspace member', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: '5fd21f44-4025-4574-8f58-fed08a4c04f1', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + }, + toFieldMetadataId: '20202020-4694-4ec6-9084-8d932ebb3065', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7e0c-4dc4-be49-37de4396349e', + type: 'RELATION', + name: 'authoredAttachments', + label: 'Authored attachments', + description: 'Attachments created by the workspace member', + icon: 'IconFileImport', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: '4b113dcf-d33b-408b-ae1a-3db7a928ce5f', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-5f98-4317-915d-3779bb821be2', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'attachment', + namePlural: 'attachments', + }, + toFieldMetadataId: '20202020-7831-43c2-827f-bc78289b7398', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-41bb-4c17-8979-40fa915df9e1', + type: 'RELATION', + name: 'accountOwnerForCompanies', + label: 'Account Owner For Companies', + description: 'Account owner for companies', + icon: 'IconBriefcase', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.392Z', + updatedAt: '2023-11-30T11:13:15.392Z', + fromRelationMetadata: { + __typename: 'relation', + id: '35e9f9d0-07ee-4ef9-9ec2-3059b3e76df5', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + toFieldMetadataId: '20202020-0739-495d-8e70-c0807f6b2268', + }, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-90e4-4701-a350-8ab75e23e3b8', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'favorite', + namePlural: 'favorites', + labelSingular: 'Favorite', + labelPlural: 'Favorites', + description: 'A favorite', + icon: 'IconHeart', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-7d1d-46c7-8c09-8e8c73e30042', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-09e1-4384-ae3e-45e79563d528', + type: 'UUID', + name: 'companyId', + label: 'Company ID (foreign key)', + description: 'Foreign key for company', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-a0f4-443c-a63d-2776a842d024', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0876-4735-9473-ff4d51aa4e7b', + type: 'UUID', + name: 'personId', + label: 'Person ID (foreign key)', + description: 'Foreign key for person', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0876-4735-8974-ff4d51aafa07', + type: 'RELATION', + name: 'person', + label: 'Person', + description: 'Favorite person', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '175b312c-956c-47c4-95f9-1aa0289ba794', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + fromFieldMetadataId: '20202020-6268-4165-8774-9aaf45db2b25', + }, + }, + { + __typename: 'field', + id: '20202020-dd6d-4f67-94aa-22cc83eb0a2e', + type: 'NUMBER', + name: 'position', + label: 'Position', + description: 'Favorite position', + icon: 'IconList', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0f4c-4b9a-9b9a-917a68161a4f', + type: 'UUID', + name: 'workspaceMemberId', + label: 'Workspace Member ID (foreign key)', + description: 'Foreign key for workspace member', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1138-4e93-bbff-917a68161abf', + type: 'RELATION', + name: 'workspaceMember', + label: 'Workspace Member', + description: 'Favorite workspace member', + icon: 'IconCircleUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '71f35744-ab2e-4311-922e-0488aa55b3c5', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-5ecb-405b-8712-171bb8916b96', + }, + }, + { + __typename: 'field', + id: '20202020-09e1-4384-ae3e-39e7956396ff', + type: 'RELATION', + name: 'company', + label: 'Company', + description: 'Favorite company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '88dd058c-a955-4de9-a41d-f870ef072360', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + fromFieldMetadataId: '20202020-e7c8-4771-8cc4-ce0e8c36a3c0', + }, + }, + { + __typename: 'field', + id: '20202020-273a-41bc-babf-f58f0b2ba2ec', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.300Z', + updatedAt: '2023-11-30T11:13:15.300Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + labelSingular: 'Activity', + labelPlural: 'Activities', + description: 'An activity', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-65a2-4d9c-b640-bac54007a14d', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-cd46-44f4-bf22-b0aa20d009da', + type: 'DATE_TIME', + name: 'reminderAt', + label: 'Reminder Date', + description: 'Activity reminder date', + icon: 'IconCalendarEvent', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3acb-46bb-b993-0dc49fa2a48d', + type: 'UUID', + name: 'authorId', + label: 'Author id (foreign key)', + description: 'Activity author id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-4694-4ec6-9084-8d932ebb3065', + type: 'RELATION', + name: 'assignee', + label: 'Assignee', + description: + 'Acitivity assignee. This is the workspace member assigned to the activity ', + icon: 'IconUserCircle', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '5fd21f44-4025-4574-8f58-fed08a4c04f1', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-ac05-44b9-9526-764dd5ce14e2', + }, + }, + { + __typename: 'field', + id: '20202020-ec1d-4ffe-8bd2-a85c23ae0037', + type: 'RELATION', + name: 'activityTargets', + label: 'Targets', + description: 'Activity targets', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: { + __typename: 'relation', + id: '04eb67c8-3525-436f-b26b-c08acf48d12e', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-439a-4a41-83a3-3cda03d01d38', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activityTarget', + namePlural: 'activityTargets', + }, + toFieldMetadataId: '20202020-cb21-42c9-bba8-347f7cb02b84', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2584-4797-95a8-5cc90d48c040', + type: 'TEXT', + name: 'title', + label: 'Title', + description: 'Activity title', + icon: 'IconNotes', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0924-48f0-a8c2-d2dd4e2098e2', + type: 'DATE_TIME', + name: 'completedAt', + label: 'Completion Date', + description: 'Activity completion date', + icon: 'IconCheck', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3acb-46bb-b993-0dc49fa2a48c', + type: 'RELATION', + name: 'author', + label: 'Author', + description: + 'Activity author. This is the person who created the activity', + icon: 'IconUserCircle', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'fa043ecd-792d-4ece-bc98-24c81fd8daf7', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-37a0-4db4-9c9f-fd3e3f4e47fc', + }, + }, + { + __typename: 'field', + id: '20202020-88df-4202-bf82-6a06c6963280', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-9755-43a8-b621-f94df0f6b839', + type: 'RELATION', + name: 'attachments', + label: 'Attachments', + description: 'Activity attachments', + icon: 'IconFileImport', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: { + __typename: 'relation', + id: '18560266-e8d2-4306-8182-87da1c7c5fee', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-5f98-4317-915d-3779bb821be2', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'attachment', + namePlural: 'attachments', + }, + toFieldMetadataId: '20202020-f5a9-46ec-b39a-eda906f00804', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-aff0-4961-be8a-0e5c2598b9a6', + type: 'TEXT', + name: 'body', + label: 'Body', + description: 'Activity body', + icon: 'IconList', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-c85c-47f2-bbe4-6b36c26f9247', + type: 'RELATION', + name: 'comments', + label: 'Comments', + description: 'Activity comments', + icon: 'IconComment', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: { + __typename: 'relation', + id: '3970abf3-c0bf-4a3a-a02a-81aac69a4073', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-4de3-4e65-ac60-b40b8e08d7d6', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'comment', + namePlural: 'comments', + }, + toFieldMetadataId: '20202020-a9ac-4294-9462-db0f690da906', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-20e1-4366-b386-750bdca2dfe3', + type: 'DATE_TIME', + name: 'dueAt', + label: 'Due Date', + description: 'Activity due date', + icon: 'IconCalendarEvent', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-a243-4b94-a4b4-25705af86be2', + type: 'TEXT', + name: 'type', + label: 'Type', + description: 'Activity type', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f695-419c-b928-c488323d6df3', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-4694-4ec6-9084-8d932ebb3066', + type: 'UUID', + name: 'assigneeId', + label: 'Assignee id (foreign key)', + description: 'Acitivity assignee id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.244Z', + updatedAt: '2023-11-30T11:13:15.244Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-767f-473f-8fd0-6cdbefbf8dbe', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'view', + namePlural: 'views', + labelSingular: 'View', + labelPlural: 'Views', + description: '(System) Views', + icon: 'IconLayoutCollage', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-2957-4431-b3b5-879b5e687c6e', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2c69-46f0-9cf2-1a4f9869d560', + type: 'UUID', + name: 'objectMetadataId', + label: 'Object Metadata Id', + description: 'View target object', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3011-4d5c-8133-c01134e733df', + type: 'RELATION', + name: 'viewSorts', + label: 'View Sorts', + description: 'View Sorts', + icon: 'IconArrowsSort', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: { + __typename: 'relation', + id: '89f2d604-2372-41ac-b822-8feae0ea31ee', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-cf28-41dd-b98b-d6e1f5b3a251', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewSort', + namePlural: 'viewSorts', + }, + toFieldMetadataId: '20202020-f5d0-467f-a3d8-395ba16b8ebf', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2c70-46f0-9cf2-1a4f9869d591', + type: 'TEXT', + name: 'type', + label: 'Type', + description: 'View type', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-ad91-42b0-b654-cbd981ddb5bf', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-afe8-40bc-9a81-9b33e45131d9', + type: 'RELATION', + name: 'viewFilters', + label: 'View Filters', + description: 'View Filters', + icon: 'IconFilterBolt', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: { + __typename: 'relation', + id: '962649c6-745a-476a-a4c8-de7794e9a04e', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-4461-4e2d-bf9e-9b47e68846d3', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewFilter', + namePlural: 'viewFilters', + }, + toFieldMetadataId: '20202020-65e5-4082-829d-8c634c20e7b5', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-e10e-4346-8690-b2e582ebc03c', + type: 'TEXT', + name: 'name', + label: 'Name', + description: 'View name', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-d288-4df4-9548-7b5c5747f623', + type: 'RELATION', + name: 'viewFields', + label: 'View Fields', + description: 'View Fields', + icon: 'IconTag', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'fd72ef3b-fdf6-4d2a-8735-4a996f214f5a', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-485c-4c48-a22e-0d9a164f9647', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewField', + namePlural: 'viewFields', + }, + toFieldMetadataId: '20202020-8788-4508-b771-719807b60e61', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-b4e6-4044-8f6e-886c6eb2a67c', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.343Z', + updatedAt: '2023-11-30T11:13:15.343Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-5f98-4317-915d-3779bb821be2', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'attachment', + namePlural: 'attachments', + labelSingular: 'Attachment', + labelPlural: 'Attachments', + description: 'An attachment', + icon: 'IconFileImport', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-f67c-4cc5-893c-c6b615527473', + type: 'RELATION', + name: 'person', + label: 'Person', + description: 'Attachment person', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '264dce1c-24da-444c-af1f-4e0b90d06b0b', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + fromFieldMetadataId: '20202020-5883-4bb3-a308-65271901a1d4', + }, + }, + { + __typename: 'field', + id: '20202020-7831-43c2-827f-bc78289b7398', + type: 'RELATION', + name: 'author', + label: 'Author', + description: 'Attachment author', + icon: 'IconCircleUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '4b113dcf-d33b-408b-ae1a-3db7a928ce5f', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-7e0c-4dc4-be49-37de4396349e', + }, + }, + { + __typename: 'field', + id: '20202020-7f29-490d-a3e1-9c3015524057', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5463-4d03-9124-1775b9b7f955', + type: 'RELATION', + name: 'company', + label: 'Company', + description: 'Attachment company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'de5f7a45-b00b-47a1-8ebc-2beca661a410', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + fromFieldMetadataId: '20202020-61af-4ffd-b79b-baed6db8ad11', + }, + }, + { + __typename: 'field', + id: '20202020-839b-4cbb-a1be-1a0cb85524a4', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5683-4c80-8590-255321ece692', + type: 'TEXT', + name: 'name', + label: 'Name', + description: 'Attachment name', + icon: 'IconFileUpload', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f67c-4cc5-893c-c6b615527474', + type: 'UUID', + name: 'personId', + label: 'Person id (foreign key)', + description: 'Attachment person id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f5a9-46ec-b39a-eda906f00805', + type: 'UUID', + name: 'activityId', + label: 'Activity id (foreign key)', + description: 'Attachment activity id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-f5a9-46ec-b39a-eda906f00804', + type: 'RELATION', + name: 'activity', + label: 'Activity', + description: 'Attachment activity', + icon: 'IconNotes', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '18560266-e8d2-4306-8182-87da1c7c5fee', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + }, + fromFieldMetadataId: '20202020-9755-43a8-b621-f94df0f6b839', + }, + }, + { + __typename: 'field', + id: '20202020-5463-4d03-9124-1775b9b7f956', + type: 'UUID', + name: 'companyId', + label: 'Company id (foreign key)', + description: 'Attachment company id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0544-432b-8f96-84c4d6a94d50', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7831-43c2-827f-bc78289b7399', + type: 'UUID', + name: 'authorId', + label: 'Author id (foreign key)', + description: 'Attachment author id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8dfa-492f-92d1-56d5fb18cbb7', + type: 'TEXT', + name: 'type', + label: 'Type', + description: 'Attachment type', + icon: 'IconList', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-bb72-4644-b255-afb4ebb83b66', + type: 'TEXT', + name: 'fullPath', + label: 'Full path', + description: 'Attachment full path', + icon: 'IconLink', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.261Z', + updatedAt: '2023-11-30T11:13:15.261Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-4de3-4e65-ac60-b40b8e08d7d6', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'comment', + namePlural: 'comments', + labelSingular: 'Comment', + labelPlural: 'Comments', + description: 'A comment', + icon: 'IconMessageCircle', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202021-a9ac-4294-9462-db0f690da907', + type: 'UUID', + name: 'activityId', + label: 'Activity id (foreign key)', + description: 'Activity id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-a9ac-4294-9462-db0f690da906', + type: 'RELATION', + name: 'activity', + label: 'Activity', + description: 'Comment activity', + icon: 'IconNotes', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '3970abf3-c0bf-4a3a-a02a-81aac69a4073', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + }, + fromFieldMetadataId: '20202020-c85c-47f2-bbe4-6b36c26f9247', + }, + }, + { + __typename: 'field', + id: '20202020-2899-42fa-ba07-1f4dad7ae28f', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-354b-4f10-9425-fa3eb8fddc51', + type: 'TEXT', + name: 'body', + label: 'Body', + description: 'Comment body', + icon: 'IconLink', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-63dd-4426-abad-9973fece49ed', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-88fd-4db2-9fcb-b5f4f5955cf2', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2c70-40c2-bba6-893780b25d41', + type: 'RELATION', + name: 'author', + label: 'Author', + description: 'Comment author', + icon: 'IconCircleUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'f7ebb0a5-c9d6-4d53-9a70-1d736000468a', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-7238-4e2a-9ccf-d2c8f604933a', + }, + }, + { + __typename: 'field', + id: '20202021-2c70-40c2-bba6-893780b25d42', + type: 'UUID', + name: 'authorId', + label: 'Author id (foreign key)', + description: 'Comment author id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.281Z', + updatedAt: '2023-11-30T11:13:15.281Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-485c-4c48-a22e-0d9a164f9647', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewField', + namePlural: 'viewFields', + labelSingular: 'View Field', + labelPlural: 'View Fields', + description: '(System) View Fields', + icon: 'IconTag', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-8788-4508-b771-719807b60e61', + type: 'RELATION', + name: 'view', + label: 'View Id', + description: 'View Field related view', + icon: 'IconLayoutCollage', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: 'fd72ef3b-fdf6-4d2a-8735-4a996f214f5a', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-767f-473f-8fd0-6cdbefbf8dbe', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'view', + namePlural: 'views', + }, + fromFieldMetadataId: '20202020-d288-4df4-9548-7b5c5747f623', + }, + }, + { + __typename: 'field', + id: '20202020-a4bb-440a-add2-81dbd9a74517', + type: 'NUMBER', + name: 'position', + label: 'Position', + description: 'View Field position', + icon: 'IconList', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-3aa9-42db-a74d-0fd6b7cb7c4a', + type: 'BOOLEAN', + name: 'isVisible', + label: 'Visible', + description: 'View Field visibility', + icon: 'IconEye', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1a5e-4ac1-9530-c7fff8481b79', + type: 'UUID', + name: 'fieldMetadataId', + label: 'Field Metadata Id', + description: 'View Field target field', + icon: 'IconTag', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-c852-4c28-b13a-07788c845d6a', + type: 'UUID', + name: 'viewId', + label: 'View ID (foreign key)', + description: 'Foreign key for view', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-64f2-4ecf-b4c5-45daf154756a', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-b9a1-4c2e-a5af-3a6b4fef4af6', + type: 'NUMBER', + name: 'size', + label: 'Size', + description: 'View Field size', + icon: 'IconEye', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-e137-4e59-b417-a134c050936c', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-17ff-4585-9f3b-cd9ee9523448', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.349Z', + updatedAt: '2023-11-30T11:13:15.349Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + labelSingular: 'Company', + labelPlural: 'Companies', + description: 'A company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-46e3-479a-b8f4-77137c74daa6', + type: 'LINK', + name: 'xLink', + label: 'X', + description: 'The company Twitter/X account', + icon: 'IconBrandX', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0739-495d-8e70-c0807f6b2268', + type: 'RELATION', + name: 'accountOwner', + label: 'Account Owner', + description: + 'Your team member responsible for managing the company account', + icon: 'IconUserCircle', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '35e9f9d0-07ee-4ef9-9ec2-3059b3e76df5', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-b550-40bb-a96b-9ab54b664753', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + }, + fromFieldMetadataId: '20202020-41bb-4c17-8979-40fa915df9e1', + }, + }, + { + __typename: 'field', + id: '20202020-a61d-4b78-b998-3fd88b4f73a1', + type: 'LINK', + name: 'linkedinLink', + label: 'Linkedin', + description: 'The company Linkedin account', + icon: 'IconBrandLinkedin', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-61af-4ffd-b79b-baed6db8ad11', + type: 'RELATION', + name: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the company.', + icon: 'IconFileImport', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'de5f7a45-b00b-47a1-8ebc-2beca661a410', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-5f98-4317-915d-3779bb821be2', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'attachment', + namePlural: 'attachments', + }, + toFieldMetadataId: '20202020-5463-4d03-9124-1775b9b7f955', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5e4e-4007-a630-8a2617914889', + type: 'TEXT', + name: 'domainName', + label: 'Domain Name', + description: + 'The company website URL. We use this url to fetch the company icon', + icon: 'IconLink', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-e3fc-46ff-b552-3e757843f06e', + type: 'RELATION', + name: 'opportunities', + label: 'Opportunities', + description: 'Opportunities linked to the company.', + icon: 'IconTargetArrow', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: { + __typename: 'relation', + id: '34b27cf4-b706-4466-824b-bdd1745cf04d', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-cae9-4ff4-9579-f7d9fe44c937', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'opportunity', + namePlural: 'opportunities', + }, + toFieldMetadataId: '20202020-31d5-4af5-b016-c61c1c265706', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-4a5a-466f-92d9-c3870d9502a9', + type: 'CURRENCY', + name: 'annualRecurringRevenue', + label: 'ARR', + description: + 'Annual Recurring Revenue: The actual or estimated annual revenue of the company', + icon: 'IconMoneybag', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-4dc2-47c9-bb15-6e6f19ba9e46', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-ad10-4117-a039-3f04b7a5f939', + type: 'TEXT', + name: 'address', + label: 'Address', + description: 'The company address', + icon: 'IconMap', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-64b8-41bf-a01c-be6a806e8b70', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-4a2e-4b41-8562-279963e8947e', + type: 'RELATION', + name: 'activityTargets', + label: 'Activities', + description: 'Activities tied to the company', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: { + __typename: 'relation', + id: '311bf27d-3710-4776-8b8d-b4cfba8c0ae8', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-439a-4a41-83a3-3cda03d01d38', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activityTarget', + namePlural: 'activityTargets', + }, + toFieldMetadataId: '20202020-9408-4cc0-9fe1-51467edb530b', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-e7c8-4771-8cc4-ce0e8c36a3c0', + type: 'RELATION', + name: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the company', + icon: 'IconHeart', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: { + __typename: 'relation', + id: '88dd058c-a955-4de9-a41d-f870ef072360', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-90e4-4701-a350-8ab75e23e3b8', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'favorite', + namePlural: 'favorites', + }, + toFieldMetadataId: '20202020-09e1-4384-ae3e-39e7956396ff', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-68b4-4c8e-af19-738eba2a42a5', + type: 'RELATION', + name: 'people', + label: 'People', + description: 'People linked to the company.', + icon: 'IconUsers', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: { + __typename: 'relation', + id: '8bb4535e-fd80-4ad8-af6d-06b02b83da32', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + toFieldMetadataId: '20202020-64e1-4080-b6ad-db03c3809885', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-6d30-4111-9f40-b4301906fd3c', + type: 'TEXT', + name: 'name', + label: 'Name', + description: 'The company name', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-0b9e-4b9e-8b0a-5b0b5b0b5b0b', + type: 'UUID', + name: 'accountOwnerId', + label: 'Account Owner ID (foreign key)', + description: 'Foreign key for account owner', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7fbd-41ad-b64d-25a15ff62f04', + type: 'NUMBER', + name: 'employees', + label: 'Employees', + description: 'Number of employees in the company', + icon: 'IconUsers', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8169-44a3-9e0b-6bad1ac50f87', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-9e9f-4235-98b2-c76f3e2d281e', + type: 'BOOLEAN', + name: 'idealCustomerProfile', + label: 'ICP', + description: + 'Ideal Customer Profile: Indicates whether the company is the most suitable and valuable customer for you', + icon: 'IconTarget', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.292Z', + updatedAt: '2023-11-30T11:13:15.292Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-4461-4e2d-bf9e-9b47e68846d3', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'viewFilter', + namePlural: 'viewFilters', + labelSingular: 'View Filter', + labelPlural: 'View Filters', + description: '(System) View Filters', + icon: 'IconFilterBolt', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-da57-452d-9671-ab3ccac2a9da', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-96c9-4cf1-87b4-8a009c591a16', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-1d12-465d-ab2c-8af008182730', + type: 'TEXT', + name: 'operand', + label: 'Operand', + description: 'View Filter operand', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-ed89-4892-83fa-d2b2929c6d52', + type: 'TEXT', + name: 'displayValue', + label: 'Display Value', + description: 'View Filter Display Value', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-65e5-4082-829d-8c634c20e7b5', + type: 'UUID', + name: 'viewId', + label: 'View Id', + description: 'View Filter related view', + icon: 'IconLayoutCollage', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '962649c6-745a-476a-a4c8-de7794e9a04e', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-767f-473f-8fd0-6cdbefbf8dbe', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'view', + namePlural: 'views', + }, + fromFieldMetadataId: '20202020-afe8-40bc-9a81-9b33e45131d9', + }, + }, + { + __typename: 'field', + id: '20202020-78bb-4f2b-a052-260bc8efd694', + type: 'UUID', + name: 'fieldMetadataId', + label: 'Field Metadata Id', + description: 'View Filter target field', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-8b37-46ae-86b8-14287ec06802', + type: 'TEXT', + name: 'value', + label: 'Value', + description: 'View Filter value', + icon: null, + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-353c-4fb0-9011-1ad8e1dd67f9', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.355Z', + updatedAt: '2023-11-30T11:13:15.355Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + { + __typename: 'object', + id: '20202020-439a-4a41-83a3-3cda03d01d38', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activityTarget', + namePlural: 'activityTargets', + labelSingular: 'Activity Target', + labelPlural: 'Activity Targets', + description: 'An activity target', + icon: 'IconCheckbox', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-4cf0-4478-8c68-62a855622a99', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-585f-48fa-a4b6-97cf7f86315e', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-9408-4cc0-9fe1-51467edb530b', + type: 'RELATION', + name: 'company', + label: 'Company', + description: 'ActivityTarget company', + icon: 'IconBuildingSkyscraper', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '311bf27d-3710-4776-8b8d-b4cfba8c0ae8', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-480c-434e-b4c7-e22408b97047', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'company', + namePlural: 'companies', + }, + fromFieldMetadataId: '20202020-4a2e-4b41-8562-279963e8947e', + }, + }, + { + __typename: 'field', + id: '20202020-4c5d-4b5e-8d6e-3b2a4d5f6a7b', + type: 'UUID', + name: 'personId', + label: 'Person id (foreign key)', + description: 'ActivityTarget person id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2b1a-4c6a-9c0a-1b9f5b7c9b1a', + type: 'UUID', + name: 'activityId', + label: 'Activity id (foreign key)', + description: 'ActivityTarget activity id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-9408-4cc0-9fe1-51467edb530c', + type: 'UUID', + name: 'companyId', + label: 'Company id (foreign key)', + description: 'ActivityTarget company id foreign key', + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: true, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-7db7-4dac-8093-ea0a12e9466f', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-cb21-42c9-bba8-347f7cb02b84', + type: 'RELATION', + name: 'activity', + label: 'Activity', + description: 'ActivityTarget activity', + icon: 'IconNotes', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '04eb67c8-3525-436f-b26b-c08acf48d12e', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'activity', + namePlural: 'activities', + }, + fromFieldMetadataId: '20202020-ec1d-4ffe-8bd2-a85c23ae0037', + }, + }, + { + __typename: 'field', + id: '20202020-e56c-43e6-8fce-5619d8c2293a', + type: 'RELATION', + name: 'person', + label: 'Person', + description: 'ActivityTarget person', + icon: 'IconUser', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.231Z', + updatedAt: '2023-11-30T11:13:15.231Z', + fromRelationMetadata: null, + toRelationMetadata: { + __typename: 'relation', + id: '1c515eae-14e8-4042-9af4-50ee725b6de5', + relationType: 'ONE_TO_MANY', + fromObjectMetadata: { + __typename: 'object', + id: '20202020-c64b-44bc-bd2c-502c99f49dca', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'person', + namePlural: 'people', + }, + fromFieldMetadataId: '20202020-f285-4115-a46c-116522986b29', + }, + }, + ], + }, + { + __typename: 'object', + id: '20202020-1029-4661-9e91-83bad932bdcd', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'pipelineStep', + namePlural: 'pipelineSteps', + labelSingular: 'Pipeline Step', + labelPlural: 'Pipeline Steps', + description: 'A pipeline step', + icon: 'IconLayoutKanban', + isCustom: false, + isActive: true, + isSystem: true, + createdAt: '2023-11-30T11:13:15.206Z', + updatedAt: '2023-11-30T11:13:15.206Z', + fields: [ + { + __typename: 'field', + id: '20202020-f294-430e-b800-3a411fc05ad3', + type: 'TEXT', + name: 'name', + label: 'Name', + description: 'Pipeline Step name', + icon: 'IconCurrencyDollar', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-039a-4fbd-b4c1-66dfa9e4bd3f', + type: 'UUID', + name: 'id', + label: 'Id', + description: null, + icon: null, + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-816f-4861-9b36-4a2f8ae2791c', + type: 'DATE_TIME', + name: 'createdAt', + label: 'Creation date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-22c4-443a-b114-43c97dda5867', + type: 'RELATION', + name: 'opportunities', + label: 'Opportunities', + description: 'Opportunities linked to the step.', + icon: 'IconTargetArrow', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: true, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: { + __typename: 'relation', + id: 'dfb44970-3e09-49f2-9f1d-51c8c451b8f5', + relationType: 'ONE_TO_MANY', + toObjectMetadata: { + __typename: 'object', + id: '20202020-cae9-4ff4-9579-f7d9fe44c937', + dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', + nameSingular: 'opportunity', + namePlural: 'opportunities', + }, + toFieldMetadataId: '20202020-0a2e-4676-8011-3fdb2c30c258', + }, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-6296-4cab-aafb-121ef5822b13', + type: 'NUMBER', + name: 'position', + label: 'Position', + description: 'Pipeline Step position', + icon: 'IconHierarchy2', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-5b93-4b28-8c45-7988ea68f91b', + type: 'TEXT', + name: 'color', + label: 'Color', + description: 'Pipeline Step color', + icon: 'IconColorSwatch', + isCustom: false, + isActive: true, + isSystem: false, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + { + __typename: 'field', + id: '20202020-2d73-4829-b774-522c2f5627d7', + type: 'DATE_TIME', + name: 'updatedAt', + label: 'Update date', + description: null, + icon: 'IconCalendar', + isCustom: false, + isActive: true, + isSystem: true, + isNullable: false, + createdAt: '2023-11-30T11:13:15.337Z', + updatedAt: '2023-11-30T11:13:15.337Z', + fromRelationMetadata: null, + toRelationMetadata: null, + }, + ], + }, + ]; + + // Todo fix typing here (the backend is not in sync with the frontend) + return mockArray as ObjectMetadataItem[]; +}; diff --git a/front/src/modules/object-record/components/RecordShowPage.tsx b/front/src/modules/object-record/components/RecordShowPage.tsx index b67f7db07..e431d0a30 100644 --- a/front/src/modules/object-record/components/RecordShowPage.tsx +++ b/front/src/modules/object-record/components/RecordShowPage.tsx @@ -37,6 +37,10 @@ export const RecordShowPage = () => { objectRecordId: string; }>(); + if (!objectNameSingular) { + throw new Error(`Object name is not defined`); + } + const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); @@ -44,7 +48,7 @@ export const RecordShowPage = () => { const { identifiersMapper } = useRelationPicker(); const { favorites, createFavorite, deleteFavorite } = useFavorites({ - objectNamePlural: objectMetadataItem?.namePlural, + objectNamePlural: objectMetadataItem.namePlural, }); const [, setEntityFields] = useRecoilState( diff --git a/front/src/modules/object-record/components/RecordTableContainer.tsx b/front/src/modules/object-record/components/RecordTableContainer.tsx index 981477221..267d4e886 100644 --- a/front/src/modules/object-record/components/RecordTableContainer.tsx +++ b/front/src/modules/object-record/components/RecordTableContainer.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { RecordTable } from '@/ui/object/record-table/components/RecordTable'; import { TableOptionsDropdownId } from '@/ui/object/record-table/constants/TableOptionsDropdownId'; import { useRecordTable } from '@/ui/object/record-table/hooks/useRecordTable'; @@ -29,17 +30,19 @@ export const RecordTableContainer = ({ objectNamePlural: string; createRecord: () => void; }) => { - const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( - { - objectNamePlural, - }, - ); - const { columnDefinitions } = useColumnDefinitionsFromFieldMetadata( - foundObjectMetadataItem, - ); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const { columnDefinitions } = + useColumnDefinitionsFromFieldMetadata(objectMetadataItem); const { updateOneRecord } = useUpdateOneRecord({ - objectNameSingular: foundObjectMetadataItem?.nameSingular, + objectNameSingular, }); const recordTableId = objectNamePlural ?? ''; diff --git a/front/src/modules/object-record/components/RecordTableEffect.tsx b/front/src/modules/object-record/components/RecordTableEffect.tsx index 7e5027ec6..523a92023 100644 --- a/front/src/modules/object-record/components/RecordTableEffect.tsx +++ b/front/src/modules/object-record/components/RecordTableEffect.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries'; import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns'; import { useRecordTable } from '@/ui/object/record-table/hooks/useRecordTable'; @@ -16,18 +17,23 @@ export const RecordTableEffect = ({ viewBarId: string; }) => { const { + // Todo: do not infer objectNamePlural from recordTableId scopeId: objectNamePlural, setAvailableTableColumns, setOnEntityCountChange, setObjectMetadataConfig, } = useRecordTable({ recordTableScopeId: recordTableId }); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + const { objectMetadataItem, basePathToShowPage, labelIdentifierFieldMetadataId, } = useObjectMetadataItem({ - objectNamePlural, + objectNameSingular, }); const { columnDefinitions, filterDefinitions, sortDefinitions } = diff --git a/front/src/modules/object-record/components/RecordTablePage.tsx b/front/src/modules/object-record/components/RecordTablePage.tsx index 9f6bb37b5..c57625a3e 100644 --- a/front/src/modules/object-record/components/RecordTablePage.tsx +++ b/front/src/modules/object-record/components/RecordTablePage.tsx @@ -1,11 +1,11 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; +import { isNonEmptyString } from '@sniptt/guards'; import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { IconBuildingSkyscraper } from '@/ui/display/icon'; import { PageAddButton } from '@/ui/layout/page/PageAddButton'; import { PageBody } from '@/ui/layout/page/PageBody'; @@ -25,18 +25,12 @@ const StyledTableContainer = styled.div` width: 100%; `; -export type RecordTablePageProps = Pick< - ObjectMetadataItemIdentifier, - 'objectNamePlural' ->; - export const RecordTablePage = () => { const objectNamePlural = useParams().objectNamePlural ?? ''; - const { objectMetadataItemNotFound, objectMetadataItem } = - useObjectMetadataItem({ - objectNamePlural, - }); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); const onboardingStatus = useOnboardingStatus(); @@ -44,15 +38,15 @@ export const RecordTablePage = () => { useEffect(() => { if ( - objectMetadataItemNotFound && + !isNonEmptyString(objectNamePlural) && onboardingStatus === OnboardingStatus.Completed ) { navigate('/'); } - }, [objectMetadataItemNotFound, navigate, onboardingStatus]); + }, [objectNamePlural, navigate, onboardingStatus]); const { createOneRecord: createOneObject } = useCreateOneRecord({ - objectNameSingular: objectMetadataItem?.nameSingular, + objectNameSingular, }); const handleAddButtonClick = async () => { diff --git a/front/src/modules/object-record/hooks/useCreateOneRecord.ts b/front/src/modules/object-record/hooks/useCreateOneRecord.ts index f75a84a33..66192b4ef 100644 --- a/front/src/modules/object-record/hooks/useCreateOneRecord.ts +++ b/front/src/modules/object-record/hooks/useCreateOneRecord.ts @@ -8,42 +8,39 @@ import { capitalize } from '~/utils/string/capitalize'; export const useCreateOneRecord = ({ objectNameSingular, -}: Pick) => { +}: ObjectMetadataItemIdentifier) => { const { triggerOptimisticEffects } = useOptimisticEffect({ objectNameSingular, }); - const { - objectMetadataItem, - objectMetadataItemNotFound, - createOneRecordMutation, - } = useObjectMetadataItem({ - objectNameSingular, - }); + const { objectMetadataItem, createOneRecordMutation } = useObjectMetadataItem( + { + objectNameSingular, + }, + ); // TODO: type this with a minimal type at least with Record const [mutate] = useMutation(createOneRecordMutation); const createOneRecord = async (input: Record) => { - if (!objectMetadataItem || !objectNameSingular) { - return null; - } - - const createdRecord = await mutate({ + const createdObject = await mutate({ variables: { input: { ...input, id: v4() }, }, }); triggerOptimisticEffects( - `${capitalize(objectNameSingular)}Edge`, - createdRecord.data[`create${capitalize(objectNameSingular)}`], + `${capitalize(objectMetadataItem.nameSingular)}Edge`, + createdObject.data[ + `create${capitalize(objectMetadataItem.nameSingular)}` + ], ); - return createdRecord.data[`create${capitalize(objectNameSingular)}`] as T; + return createdObject.data[ + `create${capitalize(objectMetadataItem.nameSingular)}` + ] as T; }; return { createOneRecord, - objectMetadataItemNotFound, }; }; diff --git a/front/src/modules/object-record/hooks/useDeleteOneRecord.ts b/front/src/modules/object-record/hooks/useDeleteOneRecord.ts index e071e70d3..023e06f02 100644 --- a/front/src/modules/object-record/hooks/useDeleteOneRecord.ts +++ b/front/src/modules/object-record/hooks/useDeleteOneRecord.ts @@ -8,41 +8,40 @@ import { capitalize } from '~/utils/string/capitalize'; export const useDeleteOneRecord = ({ objectNameSingular, -}: Pick) => { +}: ObjectMetadataItemIdentifier) => { const { performOptimisticEvict } = useOptimisticEvict(); - const { - objectMetadataItem, - objectMetadataItemNotFound, - deleteOneRecordMutation, - } = useObjectMetadataItem({ - objectNameSingular, - }); + const { objectMetadataItem, deleteOneRecordMutation } = useObjectMetadataItem( + { + objectNameSingular, + }, + ); // TODO: type this with a minimal type at least with Record const [mutate] = useMutation(deleteOneRecordMutation); const deleteOneRecord = useCallback( async (idToDelete: string) => { - if (!objectMetadataItem || !objectNameSingular) { - return null; - } - const deletedRecord = await mutate({ variables: { idToDelete, }, }); - performOptimisticEvict(capitalize(objectNameSingular), 'id', idToDelete); + performOptimisticEvict( + capitalize(objectMetadataItem.nameSingular), + 'id', + idToDelete, + ); - return deletedRecord.data[`create${capitalize(objectNameSingular)}`] as T; + return deletedRecord.data[ + `create${capitalize(objectMetadataItem.nameSingular)}` + ] as T; }, - [performOptimisticEvict, objectMetadataItem, mutate, objectNameSingular], + [performOptimisticEvict, objectMetadataItem, mutate], ); return { deleteOneRecord, - objectMetadataItemNotFound, }; }; diff --git a/front/src/modules/object-record/hooks/useFindManyRecords.ts b/front/src/modules/object-record/hooks/useFindManyRecords.ts index 1a0beb6fd..81e504795 100644 --- a/front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -2,9 +2,10 @@ import { useCallback, useMemo } from 'react'; import { useQuery } from '@apollo/client'; import { isNonEmptyArray } from '@apollo/client/utilities'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition'; @@ -27,13 +28,13 @@ import { mapPaginatedRecordsToRecords } from '../utils/mapPaginatedRecordsToReco export const useFindManyRecords = < RecordType extends { id: string } & Record, >({ - objectNamePlural, + objectNameSingular, filter, orderBy, limit = DEFAULT_SEARCH_REQUEST_LIMIT, onCompleted, skip, -}: Pick & { +}: ObjectMetadataItemIdentifier & { filter?: any; orderBy?: any; limit?: number; @@ -41,7 +42,10 @@ export const useFindManyRecords = < skip?: boolean; }) => { const findManyQueryStateIdentifier = - objectNamePlural + JSON.stringify(filter) + JSON.stringify(orderBy) + limit; + objectNameSingular + + JSON.stringify(filter) + + JSON.stringify(orderBy) + + limit; const [lastCursor, setLastCursor] = useRecoilState( cursorFamilyState(findManyQueryStateIdentifier), @@ -55,24 +59,21 @@ export const useFindManyRecords = < isFetchingMoreRecordsFamilyState(findManyQueryStateIdentifier), ); - const { - objectMetadataItem, - objectMetadataItemNotFound, - findManyRecordsQuery, - } = useObjectMetadataItem({ - objectNamePlural, + const { objectMetadataItem, findManyRecordsQuery } = useObjectMetadataItem({ + objectNameSingular, }); const { registerOptimisticEffect } = useOptimisticEffect({ - objectNameSingular: objectMetadataItem?.nameSingular, + objectNameSingular, }); const { enqueueSnackBar } = useSnackBar(); + const currentWorkspace = useRecoilValue(currentWorkspaceState); const { data, loading, error, fetchMore } = useQuery< PaginatedRecordType >(findManyRecordsQuery, { - skip: skip || !objectMetadataItem || !objectNamePlural, + skip: skip || !objectMetadataItem || !currentWorkspace, variables: { filter: filter ?? {}, limit: limit, @@ -92,21 +93,24 @@ export const useFindManyRecords = < }); } - if (objectNamePlural) { - onCompleted?.(data[objectNamePlural]); + onCompleted?.(data[objectMetadataItem.namePlural]); - if (objectNamePlural && data?.[objectNamePlural]) { - setLastCursor(data?.[objectNamePlural]?.pageInfo.endCursor); - setHasNextPage(data?.[objectNamePlural]?.pageInfo.hasNextPage); - } + if (data?.[objectMetadataItem.namePlural]) { + setLastCursor( + data?.[objectMetadataItem.namePlural]?.pageInfo.endCursor, + ); + setHasNextPage( + data?.[objectMetadataItem.namePlural]?.pageInfo.hasNextPage, + ); } }, onError: (error) => { logError( - `useFindManyObjectRecords for "${objectNamePlural}" error : ` + error, + `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + + error, ); enqueueSnackBar( - `Error during useFindManyObjectRecords for "${objectNamePlural}", ${error.message}`, + `Error during useFindManyRecords for "${objectMetadataItem.namePlural}", ${error.message}`, { variant: 'error', }, @@ -115,7 +119,7 @@ export const useFindManyRecords = < }); const fetchMoreRecords = useCallback(async () => { - if (objectNamePlural && hasNextPage) { + if (hasNextPage) { setIsFetchingMoreObjects(true); try { @@ -126,33 +130,38 @@ export const useFindManyRecords = < lastCursor: isNonEmptyString(lastCursor) ? lastCursor : undefined, }, updateQuery: (prev, { fetchMoreResult }) => { - const previousEdges = prev?.[objectNamePlural]?.edges; - const nextEdges = fetchMoreResult?.[objectNamePlural]?.edges; + const previousEdges = prev?.[objectMetadataItem.namePlural]?.edges; + const nextEdges = + fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; let newEdges: PaginatedRecordTypeEdge[] = []; if (isNonEmptyArray(previousEdges) && isNonEmptyArray(nextEdges)) { newEdges = filterUniqueRecordEdgesByCursor([ - ...prev?.[objectNamePlural]?.edges, - ...fetchMoreResult?.[objectNamePlural]?.edges, + ...prev?.[objectMetadataItem.namePlural]?.edges, + ...fetchMoreResult?.[objectMetadataItem.namePlural]?.edges, ]); } return Object.assign({}, prev, { - [objectNamePlural]: { + [objectMetadataItem.namePlural]: { __typename: `${capitalize( - objectMetadataItem?.nameSingular ?? '', + objectMetadataItem.nameSingular, )}Connection`, edges: newEdges, - pageInfo: fetchMoreResult?.[objectNamePlural].pageInfo, + pageInfo: + fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, }, } as PaginatedRecordType); }, }); } catch (error) { - logError(`fetchMoreObjects for "${objectNamePlural}" error : ` + error); + logError( + `fetchMoreObjects for "${objectMetadataItem.namePlural}" error : ` + + error, + ); enqueueSnackBar( - `Error during fetchMoreObjects for "${objectNamePlural}", ${error}`, + `Error during fetchMoreObjects for "${objectMetadataItem.namePlural}", ${error}`, { variant: 'error', }, @@ -162,7 +171,6 @@ export const useFindManyRecords = < } } }, [ - objectNamePlural, lastCursor, fetchMore, filter, @@ -175,13 +183,11 @@ export const useFindManyRecords = < const records = useMemo( () => - objectNamePlural - ? mapPaginatedRecordsToRecords({ - pagedRecords: data, - objectNamePlural, - }) - : [], - [data, objectNamePlural], + mapPaginatedRecordsToRecords({ + pagedRecords: data, + objectNamePlural: objectMetadataItem.namePlural, + }), + [data, objectMetadataItem], ); return { @@ -189,7 +195,6 @@ export const useFindManyRecords = < records, loading, error, - objectMetadataItemNotFound, fetchMoreRecords, }; }; diff --git a/front/src/modules/object-record/hooks/useFindOneRecord.ts b/front/src/modules/object-record/hooks/useFindOneRecord.ts index 97ba25442..6fb6d2a13 100644 --- a/front/src/modules/object-record/hooks/useFindOneRecord.ts +++ b/front/src/modules/object-record/hooks/useFindOneRecord.ts @@ -11,19 +11,18 @@ export const useFindOneRecord = < onCompleted, depth, skip, -}: Pick & { +}: ObjectMetadataItemIdentifier & { objectRecordId: string | undefined; onCompleted?: (data: ObjectType) => void; skip?: boolean; depth?: number; }) => { - const { objectMetadataItem, objectMetadataItemNotFound, findOneRecordQuery } = - useObjectMetadataItem( - { - objectNameSingular, - }, - depth, - ); + const { objectMetadataItem, findOneRecordQuery } = useObjectMetadataItem( + { + objectNameSingular, + }, + depth, + ); const { data, loading, error } = useQuery< { [nameSingular: string]: ObjectType }, @@ -34,19 +33,17 @@ export const useFindOneRecord = < objectRecordId: objectRecordId ?? '', }, onCompleted: (data) => { - if (onCompleted && objectNameSingular) { + if (onCompleted) { onCompleted(data[objectNameSingular]); } }, }); - const record = - objectNameSingular && data ? data[objectNameSingular] : undefined; + const record = data ? data[objectNameSingular] : undefined; return { record, loading, error, - objectMetadataItemNotFound, }; }; diff --git a/front/src/modules/object-record/hooks/useGenerateCreateOneRecordMutation.ts b/front/src/modules/object-record/hooks/useGenerateCreateOneRecordMutation.ts index e3809d142..507e17d46 100644 --- a/front/src/modules/object-record/hooks/useGenerateCreateOneRecordMutation.ts +++ b/front/src/modules/object-record/hooks/useGenerateCreateOneRecordMutation.ts @@ -8,7 +8,7 @@ import { capitalize } from '~/utils/string/capitalize'; export const useGenerateCreateOneRecordMutation = ({ objectMetadataItem, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; }) => { const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); diff --git a/front/src/modules/object-record/hooks/useGenerateFindManyRecordsQuery.ts b/front/src/modules/object-record/hooks/useGenerateFindManyRecordsQuery.ts index 6d6ceb6a1..c8d2e48d1 100644 --- a/front/src/modules/object-record/hooks/useGenerateFindManyRecordsQuery.ts +++ b/front/src/modules/object-record/hooks/useGenerateFindManyRecordsQuery.ts @@ -9,7 +9,7 @@ export const useGenerateFindManyRecordsQuery = ({ objectMetadataItem, depth, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; depth?: number; }) => { const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); diff --git a/front/src/modules/object-record/hooks/useGenerateFindOneRecordQuery.ts b/front/src/modules/object-record/hooks/useGenerateFindOneRecordQuery.ts index 6b9ade87d..c40f6aa7b 100644 --- a/front/src/modules/object-record/hooks/useGenerateFindOneRecordQuery.ts +++ b/front/src/modules/object-record/hooks/useGenerateFindOneRecordQuery.ts @@ -8,7 +8,7 @@ export const useGenerateFindOneRecordQuery = ({ objectMetadataItem, depth, }: { - objectMetadataItem: ObjectMetadataItem | null | undefined; + objectMetadataItem: ObjectMetadataItem; depth?: number; }) => { const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); diff --git a/front/src/modules/object-record/hooks/useGenerateUpdateOneRecordMutation.ts b/front/src/modules/object-record/hooks/useGenerateUpdateOneRecordMutation.ts index d9454aad4..19343a593 100644 --- a/front/src/modules/object-record/hooks/useGenerateUpdateOneRecordMutation.ts +++ b/front/src/modules/object-record/hooks/useGenerateUpdateOneRecordMutation.ts @@ -16,7 +16,7 @@ export const getUpdateOneRecordMutationGraphQLField = ({ export const useGenerateUpdateOneRecordMutation = ({ objectMetadataItem, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; }) => { const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); diff --git a/front/src/modules/object-record/hooks/useGetRecordFromCache.ts b/front/src/modules/object-record/hooks/useGetRecordFromCache.ts index 80283c681..49c8085b7 100644 --- a/front/src/modules/object-record/hooks/useGetRecordFromCache.ts +++ b/front/src/modules/object-record/hooks/useGetRecordFromCache.ts @@ -8,7 +8,7 @@ import { capitalize } from '~/utils/string/capitalize'; export const useGetRecordFromCache = ({ objectMetadataItem, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; }) => { const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); const apolloClient = useApolloClient(); @@ -31,7 +31,7 @@ export const useGetRecordFromCache = ({ const cache = apolloClient.cache; const cachedRecordId = cache.identify({ - __typename: capitalize(objectMetadataItem?.nameSingular ?? ''), + __typename: capitalize(objectMetadataItem.nameSingular), id: recordId, }); diff --git a/front/src/modules/object-record/hooks/useModifyRecordFromCache.ts b/front/src/modules/object-record/hooks/useModifyRecordFromCache.ts index 3ac695e4f..8a39edf45 100644 --- a/front/src/modules/object-record/hooks/useModifyRecordFromCache.ts +++ b/front/src/modules/object-record/hooks/useModifyRecordFromCache.ts @@ -8,7 +8,7 @@ import { capitalize } from '~/utils/string/capitalize'; export const useModifyRecordFromCache = ({ objectMetadataItem, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; }) => { const apolloClient = useApolloClient(); @@ -19,7 +19,7 @@ export const useModifyRecordFromCache = ({ const cache = apolloClient.cache; const cachedRecordId = cache.identify({ - __typename: capitalize(objectMetadataItem?.nameSingular ?? ''), + __typename: capitalize(objectMetadataItem.nameSingular), id: recordId, }); diff --git a/front/src/modules/object-record/hooks/useObjectRecordTable.ts b/front/src/modules/object-record/hooks/useObjectRecordTable.ts index 7bdf8bf83..1a2c6a05d 100644 --- a/front/src/modules/object-record/hooks/useObjectRecordTable.ts +++ b/front/src/modules/object-record/hooks/useObjectRecordTable.ts @@ -2,6 +2,7 @@ import { useRecoilValue } from 'recoil'; import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { turnFiltersIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClause'; import { turnSortsIntoOrderBy } from '@/ui/object/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { useRecordTableScopedStates } from '@/ui/object/record-table/hooks/internal/useRecordTableScopedStates'; @@ -14,14 +15,18 @@ import { useFindManyRecords } from './useFindManyRecords'; export const useObjectRecordTable = () => { const { scopeId: objectNamePlural, setRecordTableData } = useRecordTable(); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( { - objectNamePlural, + objectNameSingular, }, ); const { registerOptimisticEffect } = useOptimisticEffect({ - objectNameSingular: foundObjectMetadataItem?.nameSingular, + objectNameSingular, }); const { tableFiltersState, tableSortsState } = useRecordTableScopedStates(); @@ -39,7 +44,7 @@ export const useObjectRecordTable = () => { ); const { records, loading, fetchMoreRecords } = useFindManyRecords({ - objectNamePlural, + objectNameSingular, filter, orderBy, onCompleted: (data) => { diff --git a/front/src/modules/object-record/hooks/useRecordTableContextMenuEntries.tsx b/front/src/modules/object-record/hooks/useRecordTableContextMenuEntries.tsx index 676249684..7a51a25b2 100644 --- a/front/src/modules/object-record/hooks/useRecordTableContextMenuEntries.tsx +++ b/front/src/modules/object-record/hooks/useRecordTableContextMenuEntries.tsx @@ -3,7 +3,7 @@ import { isNonEmptyString } from '@sniptt/guards'; import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil'; import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { IconHeart, IconHeartOff, IconTrash } from '@/ui/display/icon'; import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState'; @@ -38,7 +38,7 @@ export const useRecordTableContextMenuEntries = ( recordTableScopeId: scopeId, }); - const { objectMetadataItem } = useObjectMetadataItem({ + const { objectNameSingular } = useObjectNameSingularFromPlural({ objectNamePlural, }); @@ -67,7 +67,7 @@ export const useRecordTableContextMenuEntries = ( }); const { deleteOneRecord } = useDeleteOneRecord({ - objectNameSingular: objectMetadataItem?.nameSingular, + objectNameSingular, }); const handleDeleteClick = useRecoilCallback(({ snapshot }) => async () => { diff --git a/front/src/modules/object-record/hooks/useUpdateOneRecord.ts b/front/src/modules/object-record/hooks/useUpdateOneRecord.ts index 4ec82bd65..35613c44a 100644 --- a/front/src/modules/object-record/hooks/useUpdateOneRecord.ts +++ b/front/src/modules/object-record/hooks/useUpdateOneRecord.ts @@ -7,10 +7,9 @@ import { capitalize } from '~/utils/string/capitalize'; export const useUpdateOneRecord = ({ objectNameSingular, -}: Pick) => { +}: ObjectMetadataItemIdentifier) => { const { objectMetadataItem, - objectMetadataItemNotFound, updateOneRecordMutation, getRecordFromCache, findManyRecordsQuery, @@ -29,10 +28,6 @@ export const useUpdateOneRecord = ({ input: Record; forceRefetch?: boolean; }) => { - if (!objectMetadataItem || !objectNameSingular) { - return null; - } - const cachedRecord = getRecordFromCache(idToUpdate); const updatedRecord = await mutateUpdateOneRecord({ @@ -43,7 +38,7 @@ export const useUpdateOneRecord = ({ }, }, optimisticResponse: { - [`update${capitalize(objectNameSingular)}`]: { + [`update${capitalize(objectMetadataItem.nameSingular)}`]: { ...(cachedRecord ?? {}), ...input, }, @@ -54,11 +49,12 @@ export const useUpdateOneRecord = ({ awaitRefetchQueries: forceRefetch, }); - return updatedRecord.data[`update${capitalize(objectNameSingular)}`] as T; + return updatedRecord.data[ + `update${capitalize(objectMetadataItem.nameSingular)}` + ] as T; }; return { updateOneRecord, - objectMetadataItemNotFound, }; }; diff --git a/front/src/modules/object-record/types/PaginatedRecordTypeResults.ts b/front/src/modules/object-record/types/PaginatedRecordTypeResults.ts index c2b400b48..f0fb2350e 100644 --- a/front/src/modules/object-record/types/PaginatedRecordTypeResults.ts +++ b/front/src/modules/object-record/types/PaginatedRecordTypeResults.ts @@ -1,9 +1,13 @@ -export type PaginatedRecordTypeEdge = { +export type PaginatedRecordTypeEdge< + RecordType extends { id: string } & Record, +> = { node: RecordType; cursor: string; }; -export type PaginatedRecordTypeResults = { +export type PaginatedRecordTypeResults< + RecordType extends { id: string } & Record, +> = { __typename?: string; edges: PaginatedRecordTypeEdge[]; pageInfo: { diff --git a/front/src/modules/object-record/utils/generateDeleteOneRecordMutation.ts b/front/src/modules/object-record/utils/generateDeleteOneRecordMutation.ts index 6ba52adae..1ca8bd6d5 100644 --- a/front/src/modules/object-record/utils/generateDeleteOneRecordMutation.ts +++ b/front/src/modules/object-record/utils/generateDeleteOneRecordMutation.ts @@ -7,13 +7,13 @@ import { capitalize } from '~/utils/string/capitalize'; export const generateDeleteOneRecordMutation = ({ objectMetadataItem, }: { - objectMetadataItem: ObjectMetadataItem | undefined | null; + objectMetadataItem: ObjectMetadataItem; }) => { if (!objectMetadataItem) { return EMPTY_MUTATION; } - const capitalizedObjectName = capitalize(objectMetadataItem?.nameSingular); + const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular); return gql` mutation DeleteOne${capitalizedObjectName}($idToDelete: ID!) { diff --git a/front/src/modules/people/components/PeopleCard.tsx b/front/src/modules/people/components/PeopleCard.tsx index e030a240b..59a18d6b2 100644 --- a/front/src/modules/people/components/PeopleCard.tsx +++ b/front/src/modules/people/components/PeopleCard.tsx @@ -107,7 +107,6 @@ export const PeopleCard = ({ setIsOptionsOpen(!isOptionsOpen); }; - // TODO: refactor with useObjectMetadataItem V2 with typed hooks const { findManyRecordsQuery, updateOneRecordMutation, diff --git a/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts b/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts index ce1babc01..a79a034d5 100644 --- a/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts +++ b/front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts @@ -1,6 +1,7 @@ import { QueryHookOptions, QueryResult } from '@apollo/client'; import { isNonEmptyString } from '@sniptt/guards'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { mapPaginatedRecordsToRecords } from '@/object-record/utils/mapPaginatedRecordsToRecords'; import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; @@ -30,7 +31,7 @@ export const useFilteredSearchEntityQuery = ({ mappingFunction, limit, excludeEntityIds = [], - objectNamePlural, + objectNameSingular, }: { queryHook: ( queryOptions?: QueryHookOptions, @@ -42,8 +43,12 @@ export const useFilteredSearchEntityQuery = ({ mappingFunction: (entity: any) => EntityForSelect | undefined; limit?: number; excludeEntityIds?: string[]; - objectNamePlural: string; + objectNameSingular: string; }): EntitiesForMultipleEntitySelect => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + const { loading: selectedEntitiesLoading, data: selectedEntitiesData } = queryHook({ variables: { @@ -138,19 +143,19 @@ export const useFilteredSearchEntityQuery = ({ return { selectedEntities: mapPaginatedRecordsToRecords({ - objectNamePlural: objectNamePlural, + objectNamePlural: objectMetadataItem.namePlural, pagedRecords: selectedEntitiesData, }) .map(mappingFunction) .filter(assertNotNull), filteredSelectedEntities: mapPaginatedRecordsToRecords({ - objectNamePlural: objectNamePlural, + objectNamePlural: objectMetadataItem.namePlural, pagedRecords: filteredSelectedEntitiesData, }) .map(mappingFunction) .filter(assertNotNull), entitiesToSelect: mapPaginatedRecordsToRecords({ - objectNamePlural: objectNamePlural, + objectNamePlural: objectMetadataItem.namePlural, pagedRecords: entitiesToSelectData, }) .map(mappingFunction) diff --git a/front/src/modules/settings/data-model/hooks/useFieldPreview.ts b/front/src/modules/settings/data-model/hooks/useFieldPreview.ts index 9ea639d3c..799383f9a 100644 --- a/front/src/modules/settings/data-model/hooks/useFieldPreview.ts +++ b/front/src/modules/settings/data-model/hooks/useFieldPreview.ts @@ -31,7 +31,7 @@ export const useFieldPreview = ({ const { value: firstRecordFieldValue } = useFieldPreviewValue({ fieldName: fieldName || '', - objectNamePlural: objectMetadataItem?.namePlural || '', + objectNamePlural: objectMetadataItem?.namePlural ?? '', skip: !fieldName || !objectMetadataItem || diff --git a/front/src/modules/settings/data-model/hooks/useFieldPreviewValue.ts b/front/src/modules/settings/data-model/hooks/useFieldPreviewValue.ts index 1e372b079..55186d4e9 100644 --- a/front/src/modules/settings/data-model/hooks/useFieldPreviewValue.ts +++ b/front/src/modules/settings/data-model/hooks/useFieldPreviewValue.ts @@ -1,3 +1,4 @@ +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { assertNotNull } from '~/utils/assert'; @@ -10,8 +11,12 @@ export const useFieldPreviewValue = ({ objectNamePlural: string; skip?: boolean; }) => { - const { records } = useFindManyRecords({ + const { objectNameSingular } = useObjectNameSingularFromPlural({ objectNamePlural, + }); + + const { records } = useFindManyRecords({ + objectNameSingular, skip, }); diff --git a/front/src/modules/settings/data-model/hooks/useRelationFieldPreviewValue.ts b/front/src/modules/settings/data-model/hooks/useRelationFieldPreviewValue.ts index 07ba1509b..ca11ebf87 100644 --- a/front/src/modules/settings/data-model/hooks/useRelationFieldPreviewValue.ts +++ b/front/src/modules/settings/data-model/hooks/useRelationFieldPreviewValue.ts @@ -10,12 +10,13 @@ export const useRelationFieldPreviewValue = ({ }) => { const { findObjectMetadataItemById } = useObjectMetadataItemForSettings(); + // TODO: make this impossible to be undefined const relationObjectMetadataItem = relationObjectMetadataId ? findObjectMetadataItemById(relationObjectMetadataId) : undefined; const { records: relationObjects } = useFindManyRecords({ - objectNamePlural: relationObjectMetadataItem?.namePlural, + objectNameSingular: relationObjectMetadataItem?.nameSingular ?? '', skip: skip || !relationObjectMetadataItem, }); diff --git a/front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx b/front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx index d93d06857..4c66109fb 100644 --- a/front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx +++ b/front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx @@ -37,7 +37,7 @@ export const SettingsObjectItemTableRow = ({ const theme = useTheme(); const { records } = useFindManyRecords({ - objectNamePlural: objectItem.namePlural, + objectNameSingular: objectItem.nameSingular, }); const { Icon } = useLazyLoadIcon(objectItem.icon ?? ''); diff --git a/front/src/modules/settings/profile/components/NameFields.tsx b/front/src/modules/settings/profile/components/NameFields.tsx index 12fc9a869..c855da025 100644 --- a/front/src/modules/settings/profile/components/NameFields.tsx +++ b/front/src/modules/settings/profile/components/NameFields.tsx @@ -40,7 +40,7 @@ export const NameFields = ({ currentWorkspaceMember?.name?.lastName ?? '', ); - const { updateOneRecord, objectMetadataItemNotFound } = useUpdateOneRecord({ + const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular: 'workspaceMember', }); @@ -58,9 +58,6 @@ export const NameFields = ({ } if (autoSave) { - if (!updateOneRecord || objectMetadataItemNotFound) { - throw new Error('Object not found in metadata'); - } await updateOneRecord({ idToUpdate: currentWorkspaceMember?.id, input: { diff --git a/front/src/modules/settings/profile/components/ProfilePictureUploader.tsx b/front/src/modules/settings/profile/components/ProfilePictureUploader.tsx index 5861f0bbb..390a297af 100644 --- a/front/src/modules/settings/profile/components/ProfilePictureUploader.tsx +++ b/front/src/modules/settings/profile/components/ProfilePictureUploader.tsx @@ -19,7 +19,7 @@ export const ProfilePictureUploader = () => { useState(null); const [errorMessage, setErrorMessage] = useState(null); - const { updateOneRecord, objectMetadataItemNotFound } = useUpdateOneRecord({ + const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular: 'workspaceMember', }); @@ -54,9 +54,7 @@ export const ProfilePictureUploader = () => { if (!avatarUrl) { throw new Error('Avatar URL not found'); } - if (!updateOneRecord || objectMetadataItemNotFound) { - throw new Error('Object not found in metadata'); - } + await updateOneRecord({ idToUpdate: currentWorkspaceMember?.id, input: { @@ -80,12 +78,10 @@ export const ProfilePictureUploader = () => { }; const handleRemove = async () => { - if (!updateOneRecord || objectMetadataItemNotFound) { - throw new Error('Object not found in metadata'); - } if (!currentWorkspaceMember?.id) { throw new Error('User is not logged in'); } + await updateOneRecord({ idToUpdate: currentWorkspaceMember?.id, input: { diff --git a/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx b/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx index c3024071f..3bad2ac6a 100644 --- a/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx +++ b/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx @@ -14,8 +14,8 @@ const StyledContainer = styled.div` `; export const SignInBackgroundMockContainer = () => { - const recordTableId = 'sign-in-background-mock-table'; - const viewBarId = 'sign-in-background-mock-view'; + const recordTableId = 'companies'; + const viewBarId = 'companies-mock'; return ( diff --git a/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx b/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx index aefb680b7..32938bde5 100644 --- a/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx +++ b/front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries'; import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns'; import { signInBackgroundMockCompanies } from '@/sign-in-background-mock/constants/signInBackgroundMockCompanies'; @@ -35,10 +36,14 @@ export const SignInBackgroundMockContainerEffect = ({ recordTableScopeId: recordTableId, }); - const { objectMetadataItem } = useObjectMetadataItem({ + const { objectNameSingular } = useObjectNameSingularFromPlural({ objectNamePlural, }); + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + const { setAvailableSortDefinitions, setAvailableFilterDefinitions, @@ -49,7 +54,7 @@ export const SignInBackgroundMockContainerEffect = ({ } = useViewBar({ viewBarId: viewId }); useEffect(() => { - setViewObjectMetadataId?.('company-mock-object-metadata-id'); + setViewObjectMetadataId?.(objectMetadataItem.id); setViewType?.(ViewType.Table); setAvailableSortDefinitions?.(signInBackgroundMockSortDefinitions); diff --git a/front/src/modules/sign-in-background-mock/constants/signInBackgroundMockMetadataItems.ts b/front/src/modules/sign-in-background-mock/constants/signInBackgroundMockMetadataItems.ts deleted file mode 100644 index 00e7cf7b5..000000000 --- a/front/src/modules/sign-in-background-mock/constants/signInBackgroundMockMetadataItems.ts +++ /dev/null @@ -1,400 +0,0 @@ -export const metadataItem = { - __typename: 'object', - id: '20202020-480c-434e-b4c7-e22408b97047', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'company', - namePlural: 'companies', - labelSingular: 'Company', - labelPlural: 'Companies', - description: 'A company', - icon: 'IconBuildingSkyscraper', - isCustom: false, - isActive: true, - isSystem: false, - createdAt: '2023-11-23T15:38:02.187Z', - updatedAt: '2023-11-23T15:38:02.187Z', - fields: [ - { - __typename: 'field', - id: '20202020-5e4e-4007-a630-8a2617914889', - type: 'TEXT', - name: 'domainName', - label: 'Domain Name', - description: - 'The company website URL. We use this url to fetch the company icon', - icon: 'IconLink', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-64b8-41bf-a01c-be6a806e8b70', - type: 'DATE_TIME', - name: 'updatedAt', - label: 'Update date', - description: null, - icon: 'IconCalendar', - isCustom: false, - isActive: true, - isSystem: true, - isNullable: false, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-7fbd-41ad-b64d-25a15ff62f04', - type: 'NUMBER', - name: 'employees', - label: 'Employees', - description: 'Number of employees in the company', - icon: 'IconUsers', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-6d30-4111-9f40-b4301906fd3c', - type: 'TEXT', - name: 'name', - label: 'Name', - description: 'The company name', - icon: 'IconBuildingSkyscraper', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-e7c8-4771-8cc4-ce0e8c36a3c0', - type: 'RELATION', - name: 'favorites', - label: 'Favorites', - description: 'Favorites linked to the company', - icon: 'IconHeart', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: { - __typename: 'relation', - id: '73d9610a-a196-4186-b5b2-9a1da2d3bede', - relationType: 'ONE_TO_MANY', - toObjectMetadata: { - __typename: 'object', - id: '20202020-90e4-4701-a350-8ab75e23e3b8', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'favorite', - namePlural: 'favorites', - }, - toFieldMetadataId: '20202020-09e1-4384-ae3e-39e7956396ff', - }, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-ad10-4117-a039-3f04b7a5f939', - type: 'TEXT', - name: 'address', - label: 'Address', - description: 'The company address', - icon: 'IconMap', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-0739-495d-8e70-c0807f6b2268', - type: 'RELATION', - name: 'accountOwner', - label: 'Account Owner', - description: - 'Your team member responsible for managing the company account', - icon: 'IconUserCircle', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: { - __typename: 'relation', - id: '729283e1-8134-494d-9df5-24a44e92c38b', - relationType: 'ONE_TO_MANY', - fromObjectMetadata: { - __typename: 'object', - id: '20202020-b550-40bb-a96b-9ab54b664753', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'workspaceMember', - namePlural: 'workspaceMembers', - }, - fromFieldMetadataId: '20202020-41bb-4c17-8979-40fa915df9e1', - }, - }, - { - __typename: 'field', - id: '20202020-68b4-4c8e-af19-738eba2a42a5', - type: 'RELATION', - name: 'people', - label: 'People', - description: 'People linked to the company.', - icon: 'IconUsers', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: { - __typename: 'relation', - id: '8256c11a-710d-48b5-bc86-f607895abec4', - relationType: 'ONE_TO_MANY', - toObjectMetadata: { - __typename: 'object', - id: '20202020-c64b-44bc-bd2c-502c99f49dca', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'person', - namePlural: 'people', - }, - toFieldMetadataId: '20202020-64e1-4080-b6ad-db03c3809885', - }, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-61af-4ffd-b79b-baed6db8ad11', - type: 'RELATION', - name: 'attachments', - label: 'Attachments', - description: 'Attachments linked to the company.', - icon: 'IconFileImport', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: { - __typename: 'relation', - id: '54c7c707-09f8-4ce0-b2f6-0161443fffa8', - relationType: 'ONE_TO_MANY', - toObjectMetadata: { - __typename: 'object', - id: '20202020-5f98-4317-915d-3779bb821be2', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'attachment', - namePlural: 'attachments', - }, - toFieldMetadataId: '20202020-5463-4d03-9124-1775b9b7f955', - }, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-4dc2-47c9-bb15-6e6f19ba9e46', - type: 'DATE_TIME', - name: 'createdAt', - label: 'Creation date', - description: null, - icon: 'IconCalendar', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: false, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-9e9f-4235-98b2-c76f3e2d281e', - type: 'BOOLEAN', - name: 'idealCustomerProfile', - label: 'ICP', - description: - 'Ideal Customer Profile: Indicates whether the company is the most suitable and valuable customer for you', - icon: 'IconTarget', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-8169-44a3-9e0b-6bad1ac50f87', - type: 'UUID', - name: 'id', - label: 'Id', - description: null, - icon: null, - isCustom: false, - isActive: true, - isSystem: true, - isNullable: false, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-a61d-4b78-b998-3fd88b4f73a1', - type: 'LINK', - name: 'linkedinLink', - label: 'Linkedin', - description: 'The company Linkedin account', - icon: 'IconBrandLinkedin', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-e3fc-46ff-b552-3e757843f06e', - type: 'RELATION', - name: 'opportunities', - label: 'Opportunities', - description: 'Opportunities linked to the company.', - icon: 'IconTargetArrow', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: { - __typename: 'relation', - id: '831b6b14-125c-4563-83a3-99d5e07c0a85', - relationType: 'ONE_TO_MANY', - toObjectMetadata: { - __typename: 'object', - id: '20202020-cae9-4ff4-9579-f7d9fe44c937', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'opportunity', - namePlural: 'opportunities', - }, - toFieldMetadataId: '20202020-31d5-4af5-b016-c61c1c265706', - }, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-0b9e-4b9e-8b0a-5b0b5b0b5b0b', - type: 'UUID', - name: 'accountOwnerId', - label: 'Account Owner ID (foreign key)', - description: 'Foreign key for account owner', - icon: null, - isCustom: false, - isActive: true, - isSystem: true, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-46e3-479a-b8f4-77137c74daa6', - type: 'LINK', - name: 'xLink', - label: 'X', - description: 'The company Twitter/X account', - icon: 'IconBrandX', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-4a2e-4b41-8562-279963e8947e', - type: 'RELATION', - name: 'activityTargets', - label: 'Activities', - description: 'Activities tied to the company', - icon: 'IconCheckbox', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: { - __typename: 'relation', - id: '56e2ab44-4718-4c05-b61c-a7f978d7bdd1', - relationType: 'ONE_TO_MANY', - toObjectMetadata: { - __typename: 'object', - id: '20202020-439a-4a41-83a3-3cda03d01d38', - dataSourceId: '20202020-7f63-47a9-b1b3-6c7290ca9fb1', - nameSingular: 'activityTarget', - namePlural: 'activityTargets', - }, - toFieldMetadataId: '20202020-9408-4cc0-9fe1-51467edb530b', - }, - toRelationMetadata: null, - }, - { - __typename: 'field', - id: '20202020-4a5a-466f-92d9-c3870d9502a9', - type: 'CURRENCY', - name: 'annualRecurringRevenue', - label: 'ARR', - description: - 'Annual Recurring Revenue: The actual or estimated annual revenue of the company', - icon: 'IconMoneybag', - isCustom: false, - isActive: true, - isSystem: false, - isNullable: true, - createdAt: '2023-11-23T15:38:02.292Z', - updatedAt: '2023-11-23T15:38:02.292Z', - fromRelationMetadata: null, - toRelationMetadata: null, - }, - ], -}; diff --git a/front/src/modules/ui/input/components/internal/relation-picker/components/RelationPicker.tsx b/front/src/modules/ui/input/components/internal/relation-picker/components/RelationPicker.tsx index ae237d392..976309ba7 100644 --- a/front/src/modules/ui/input/components/internal/relation-picker/components/RelationPicker.tsx +++ b/front/src/modules/ui/input/components/internal/relation-picker/components/RelationPicker.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; import { useQuery } from '@apollo/client'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; import { IconForbid } from '@/ui/display/icon'; import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker'; @@ -49,6 +50,12 @@ export const RelationPicker = ({ const { identifiersMapper, searchQuery } = useRelationPicker(); + const { objectNameSingular: relationObjectNameSingular } = + useObjectNameSingularFromPlural({ + objectNamePlural: + fieldDefinition.metadata.relationObjectMetadataNamePlural, + }); + const records = useFilteredSearchEntityQuery({ queryHook: useFindManyQuery, filters: [ @@ -68,7 +75,7 @@ export const RelationPicker = ({ ), selectedIds: recordId ? [recordId] : [], excludeEntityIds: excludeRecordIds, - objectNamePlural: fieldDefinition.metadata.relationObjectMetadataNamePlural, + objectNameSingular: relationObjectNameSingular, }); const handleEntitySelected = async (selectedUser: any | null | undefined) => { diff --git a/front/src/modules/ui/layout/page/DefaultLayout.tsx b/front/src/modules/ui/layout/page/DefaultLayout.tsx index b390e677f..a3ead82ba 100644 --- a/front/src/modules/ui/layout/page/DefaultLayout.tsx +++ b/front/src/modules/ui/layout/page/DefaultLayout.tsx @@ -6,6 +6,7 @@ import { AuthModal } from '@/auth/components/Modal'; import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; import { CommandMenu } from '@/command-menu/components/CommandMenu'; +import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; import { KeyboardShortcutMenu } from '@/keyboard-shortcut-menu/components/KeyboardShortcutMenu'; import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage'; import { NavbarAnimatedContainer } from '@/ui/navigation/navbar/components/NavbarAnimatedContainer'; @@ -74,7 +75,7 @@ export const DefaultLayout = ({ children }: DefaultLayoutProps) => { ) : ( - <>{children} + {children} )} diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySelect.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySelect.tsx index e0e20543e..a946d2cbc 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySelect.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySelect.tsx @@ -16,9 +16,6 @@ export const ObjectFilterDropdownEntitySelect = () => { const objectMetadataNameSingular = filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular ?? ''; - const objectMetadataNamePlural = - filterDefinitionUsedInDropdown?.relationObjectMetadataNamePlural ?? ''; - // TODO: refactor useFilteredSearchEntityQuery const { findManyRecordsQuery } = useObjectMetadataItem({ objectNameSingular: objectMetadataNameSingular, @@ -44,7 +41,7 @@ export const ObjectFilterDropdownEntitySelect = () => { : [], mappingFunction: (record: any) => identifiersMapper?.(record, objectMetadataNameSingular), - objectNamePlural: objectMetadataNamePlural, + objectNameSingular: objectMetadataNameSingular, }); if (filterDefinitionUsedInDropdown?.type !== 'RELATION') { diff --git a/front/src/modules/ui/object/record-table/components/RecordTableBody.tsx b/front/src/modules/ui/object/record-table/components/RecordTableBody.tsx index 2e335d0e8..fbcbbc177 100644 --- a/front/src/modules/ui/object/record-table/components/RecordTableBody.tsx +++ b/front/src/modules/ui/object/record-table/components/RecordTableBody.tsx @@ -3,6 +3,7 @@ import { useInView } from 'react-intersection-observer'; import { useRecoilState, useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useObjectRecordTable } from '@/object-record/hooks/useObjectRecordTable'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { isDefined } from '~/utils/isDefined'; @@ -22,9 +23,13 @@ export const RecordTableBody = () => { const { scopeId: objectNamePlural } = useRecordTable(); + const { objectNameSingular } = useObjectNameSingularFromPlural({ + objectNamePlural, + }); + const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( { - objectNamePlural, + objectNameSingular, }, ); diff --git a/front/src/modules/ui/theme/components/AppThemeProvider.tsx b/front/src/modules/ui/theme/components/AppThemeProvider.tsx index 947825f9a..41afd6dd7 100644 --- a/front/src/modules/ui/theme/components/AppThemeProvider.tsx +++ b/front/src/modules/ui/theme/components/AppThemeProvider.tsx @@ -16,6 +16,7 @@ export const AppThemeProvider = ({ children }: AppThemeProviderProps) => { const computedColorScheme = colorScheme === 'System' ? systemColorScheme : colorScheme; + const theme = computedColorScheme === 'Dark' ? darkTheme : lightTheme; return {children}; diff --git a/front/src/modules/views/components/ViewBarEffect.tsx b/front/src/modules/views/components/ViewBarEffect.tsx index 68299a473..e70f97998 100644 --- a/front/src/modules/views/components/ViewBarEffect.tsx +++ b/front/src/modules/views/components/ViewBarEffect.tsx @@ -32,7 +32,7 @@ export const ViewBarEffect = () => { useFindManyRecords({ skip: !viewObjectMetadataId, - objectNamePlural: 'views', + objectNameSingular: 'view', filter: { type: { eq: viewType }, objectMetadataId: { eq: viewObjectMetadataId }, diff --git a/front/src/modules/views/hooks/internal/useViews.ts b/front/src/modules/views/hooks/internal/useViews.ts index 98ed360e7..96be0038f 100644 --- a/front/src/modules/views/hooks/internal/useViews.ts +++ b/front/src/modules/views/hooks/internal/useViews.ts @@ -14,6 +14,7 @@ export const useViews = (scopeId: string) => { } = useObjectMetadataItem({ objectNameSingular: 'view', }); + const apolloClient = useApolloClient(); const createView = useRecoilCallback( diff --git a/front/src/pages/auth/CreateProfile.tsx b/front/src/pages/auth/CreateProfile.tsx index 92c81a6a4..8aada94e0 100644 --- a/front/src/pages/auth/CreateProfile.tsx +++ b/front/src/pages/auth/CreateProfile.tsx @@ -62,10 +62,9 @@ export const CreateProfile = () => { currentWorkspaceMemberState, ); - const { updateOneRecord, objectMetadataItemNotFound } = - useUpdateOneRecord({ - objectNameSingular: 'workspaceMember', - }); + const { updateOneRecord } = useUpdateOneRecord({ + objectNameSingular: 'workspaceMember', + }); // Form const { @@ -91,9 +90,6 @@ export const CreateProfile = () => { if (!data.firstName || !data.lastName) { throw new Error('First name or last name is missing'); } - if (!updateOneRecord || objectMetadataItemNotFound) { - throw new Error('Object not found in metadata'); - } await updateOneRecord({ idToUpdate: currentWorkspaceMember?.id, @@ -127,7 +123,6 @@ export const CreateProfile = () => { currentWorkspaceMember?.id, enqueueSnackBar, navigate, - objectMetadataItemNotFound, setCurrentWorkspaceMember, updateOneRecord, ], diff --git a/front/src/pages/settings/SettingsWorkspaceMembers.tsx b/front/src/pages/settings/SettingsWorkspaceMembers.tsx index 79b9f50da..575620b4f 100644 --- a/front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -35,7 +35,7 @@ export const SettingsWorkspaceMembers = () => { >(); const { records: workspaceMembers } = useFindManyRecords({ - objectNamePlural: 'workspaceMembers', + objectNameSingular: 'workspaceMember', }); const { deleteOneRecord: deleteOneWorkspaceMember } = useDeleteOneRecord({ diff --git a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx index 1963e25c5..29e0b94af 100644 --- a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx @@ -79,7 +79,7 @@ export const SettingsObjectNewFieldStep2 = () => { }); useFindManyRecords({ - objectNamePlural: 'views', + objectNameSingular: 'view', filter: { type: { eq: ViewType.Table }, objectMetadataId: { eq: activeObjectMetadataItem?.id }, @@ -94,7 +94,7 @@ export const SettingsObjectNewFieldStep2 = () => { }); useFindManyRecords({ - objectNamePlural: 'views', + objectNameSingular: 'view', skip: !formValues.relation?.objectMetadataId, filter: { type: { eq: ViewType.Table }, diff --git a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx index 4b3313106..df38e453c 100644 --- a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx +++ b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx @@ -43,8 +43,9 @@ export const SettingsDevelopersApiKeys = () => { const [apiKeys, setApiKeys] = useState>([]); const filter = { revokedAt: { is: 'NULL' } }; + useFindManyRecords({ - objectNamePlural: 'apiKeys', + objectNameSingular: 'apiKey', filter, orderBy: {}, onCompleted: (data) => { diff --git a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index 61300e8b8..173c90f00 100644 --- a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx +++ b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -33,6 +33,7 @@ export const SettingsDevelopersApiKeysNew = () => { const { createOneRecord: createOneApiKey } = useCreateOneRecord({ objectNameSingular: 'apiKey', }); + const onSave = async () => { const expiresAt = DateTime.now() .plus({ days: formValues.expirationDate ?? 30 }) diff --git a/front/src/utils/string/capitalize.ts b/front/src/utils/string/capitalize.ts index 3e3d732af..9953f3751 100644 --- a/front/src/utils/string/capitalize.ts +++ b/front/src/utils/string/capitalize.ts @@ -2,5 +2,6 @@ import { isNonEmptyString } from '@sniptt/guards'; export const capitalize = (stringToCapitalize: string) => { if (!isNonEmptyString(stringToCapitalize)) return ''; + return stringToCapitalize[0].toUpperCase() + stringToCapitalize.slice(1); }; diff --git a/front/yarn.lock b/front/yarn.lock index bd9cba08f..53db88d4a 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -16476,6 +16476,13 @@ react-element-to-jsx-string@^15.0.0: is-plain-object "5.0.0" react-is "18.1.0" +react-error-boundary@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.11.tgz#36bf44de7746714725a814630282fee83a7c9a1c" + integrity sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw== + dependencies: + "@babel/runtime" "^7.12.5" + react-error-overlay@^6.0.11: version "6.0.11" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"