From dff00e813c7d46f42bd25cacae8c05a31a21c879 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 25 Aug 2025 15:49:21 +0200 Subject: [PATCH] Add coreView state in FE (#14034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: bosiraphael Co-authored-by: Raphaƫl Bosi <71827178+bosiraphael@users.noreply.github.com> --- .../src/generated-metadata/graphql.ts | 85 +++++++++---------- .../twenty-front/src/generated/graphql.ts | 75 ++++++++++------ ...wIdFromObjectMetadataItemFamilySelector.ts | 7 +- .../prefetchViewFromViewIdFamilySelector.ts | 7 +- ...IdsFromObjectMetadataItemFamilySelector.ts | 7 +- .../prefetchViewLengthFamilySelector.ts | 7 +- ...ewsFromObjectMetadataItemFamilySelector.ts | 16 ++-- .../users/components/UserProviderEffect.tsx | 24 +++++- .../graphql/fragments/userQueryFragment.ts | 25 ------ .../ViewBarFilterDropdown.stories.tsx | 35 +++----- .../views/graphql/fragments/viewFragment.ts | 26 ++++++ ...GroupsToCurrentRecordFilterGroups.test.tsx | 55 +++++++----- ...ViewFiltersToCurrentRecordFilters.test.tsx | 85 ++++++++++++------- ...rentViewSortsToCurrentRecordSorts.test.tsx | 25 +++++- .../hooks/useCreateViewFromCurrentView.ts | 35 +++++++- .../views/hooks/useMapViewFiltersToFilters.ts | 5 +- .../src/modules/views/states/coreViewState.ts | 7 ++ .../views/utils/mapViewFiltersToFilters.ts | 20 ++++- .../hooks/useCreateViewFromCurrentState.ts | 13 ++- .../src/testing/mock-data/views.ts | 85 +++++++++++++++++++ packages/twenty-ui/package.json | 1 + 21 files changed, 441 insertions(+), 204 deletions(-) create mode 100644 packages/twenty-front/src/modules/views/states/coreViewState.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 1e5b72f041..bae19bdf1c 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -4653,7 +4653,7 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: st export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }; -export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null }; +export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }> }; export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }; @@ -4664,7 +4664,7 @@ export type CreateCoreViewMutationVariables = Exact<{ }>; -export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } }; +export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }> } }; export type CreateCoreViewFieldMutationVariables = Exact<{ input: CreateViewFieldInput; @@ -4791,7 +4791,7 @@ export type UpdateCoreViewMutationVariables = Exact<{ }>; -export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } }; +export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }> } }; export type UpdateCoreViewFieldMutationVariables = Exact<{ id: Scalars['String']; @@ -4873,14 +4873,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{ }>; -export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null }> }; +export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }> }> }; export type FindOneCoreViewQueryVariables = Exact<{ id: Scalars['String']; }>; -export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } | null }; +export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string }> } | null }; export type FindOneCoreViewFieldQueryVariables = Exact<{ id: Scalars['String']; @@ -5256,24 +5256,6 @@ export const RoleFragmentFragmentDoc = gql` canDestroyAllObjectRecords } `; -export const ViewFragmentFragmentDoc = gql` - fragment ViewFragment on CoreView { - id - name - objectMetadataId - type - key - icon - position - isCompact - openRecordIn - kanbanAggregateOperation - kanbanAggregateOperationFieldMetadataId - createdAt - updatedAt - anyFieldFilterValue -} - `; export const ViewFieldFragmentFragmentDoc = gql` fragment ViewFieldFragment on CoreViewField { id @@ -5334,6 +5316,43 @@ export const ViewGroupFragmentFragmentDoc = gql` updatedAt } `; +export const ViewFragmentFragmentDoc = gql` + fragment ViewFragment on CoreView { + id + name + objectMetadataId + type + key + icon + position + isCompact + openRecordIn + kanbanAggregateOperation + kanbanAggregateOperationFieldMetadataId + createdAt + updatedAt + anyFieldFilterValue + viewFields { + ...ViewFieldFragment + } + viewFilters { + ...ViewFilterFragment + } + viewFilterGroups { + ...ViewFilterGroupFragment + } + viewSorts { + ...ViewSortFragment + } + viewGroups { + ...ViewGroupFragment + } +} + ${ViewFieldFragmentFragmentDoc} +${ViewFilterFragmentFragmentDoc} +${ViewFilterGroupFragmentFragmentDoc} +${ViewSortFragmentFragmentDoc} +${ViewGroupFragmentFragmentDoc}`; export const AvailableWorkspaceFragmentFragmentDoc = gql` fragment AvailableWorkspaceFragment on AvailableWorkspace { id @@ -5454,21 +5473,6 @@ export const UserQueryFragmentFragmentDoc = gql` isTwoFactorAuthenticationEnforced views { ...ViewFragment - viewFields { - ...ViewFieldFragment - } - viewFilters { - ...ViewFilterFragment - } - viewFilterGroups { - ...ViewFilterGroupFragment - } - viewSorts { - ...ViewSortFragment - } - viewGroups { - ...ViewGroupFragment - } } } availableWorkspaces { @@ -5482,11 +5486,6 @@ ${ObjectPermissionFragmentFragmentDoc} ${WorkspaceUrlsFragmentFragmentDoc} ${RoleFragmentFragmentDoc} ${ViewFragmentFragmentDoc} -${ViewFieldFragmentFragmentDoc} -${ViewFilterFragmentFragmentDoc} -${ViewFilterGroupFragmentFragmentDoc} -${ViewSortFragmentFragmentDoc} -${ViewGroupFragmentFragmentDoc} ${AvailableWorkspacesFragmentFragmentDoc}`; export const AssignRoleToAgentDocument = gql` mutation AssignRoleToAgent($agentId: UUID!, $roleId: UUID!) { diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 15e0a80e30..94c463f54e 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -3596,7 +3596,7 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: an export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }; -export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null }; +export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> }; export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }; @@ -3607,7 +3607,7 @@ export type CreateCoreViewMutationVariables = Exact<{ }>; -export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } }; +export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } }; export type CreateCoreViewFieldMutationVariables = Exact<{ input: CreateViewFieldInput; @@ -3734,7 +3734,7 @@ export type UpdateCoreViewMutationVariables = Exact<{ }>; -export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } }; +export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } }; export type UpdateCoreViewFieldMutationVariables = Exact<{ id: Scalars['String']; @@ -3816,14 +3816,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{ }>; -export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null }> }; +export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> }> }; export type FindOneCoreViewQueryVariables = Exact<{ id: Scalars['String']; }>; -export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null } | null }; +export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, createdAt: string, updatedAt: string, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any, createdAt: string, updatedAt: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any, createdAt: string, updatedAt: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string }> } | null }; export type FindOneCoreViewFieldQueryVariables = Exact<{ id: Scalars['String']; @@ -3898,6 +3898,28 @@ export const ViewFilterGroupFragmentFragmentDoc = gql` updatedAt } `; +export const ViewSortFragmentFragmentDoc = gql` + fragment ViewSortFragment on CoreViewSort { + id + fieldMetadataId + direction + viewId + createdAt + updatedAt +} + `; +export const ViewGroupFragmentFragmentDoc = gql` + fragment ViewGroupFragment on CoreViewGroup { + id + fieldMetadataId + isVisible + fieldValue + position + viewId + createdAt + updatedAt +} + `; export const ViewFragmentFragmentDoc = gql` fragment ViewFragment on CoreView { id @@ -3914,30 +3936,27 @@ export const ViewFragmentFragmentDoc = gql` createdAt updatedAt anyFieldFilterValue + viewFields { + ...ViewFieldFragment + } + viewFilters { + ...ViewFilterFragment + } + viewFilterGroups { + ...ViewFilterGroupFragment + } + viewSorts { + ...ViewSortFragment + } + viewGroups { + ...ViewGroupFragment + } } - `; -export const ViewGroupFragmentFragmentDoc = gql` - fragment ViewGroupFragment on CoreViewGroup { - id - fieldMetadataId - isVisible - fieldValue - position - viewId - createdAt - updatedAt -} - `; -export const ViewSortFragmentFragmentDoc = gql` - fragment ViewSortFragment on CoreViewSort { - id - fieldMetadataId - direction - viewId - createdAt - updatedAt -} - `; + ${ViewFieldFragmentFragmentDoc} +${ViewFilterFragmentFragmentDoc} +${ViewFilterGroupFragmentFragmentDoc} +${ViewSortFragmentFragmentDoc} +${ViewGroupFragmentFragmentDoc}`; export const SearchDocument = gql` query Search($searchInput: String!, $limit: Int!, $after: String, $excludedObjectNameSingulars: [String!], $includedObjectNameSingulars: [String!], $filter: ObjectRecordFilterInput) { search( diff --git a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector.ts b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector.ts index 9399d602a1..876560e2a8 100644 --- a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector.ts +++ b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector.ts @@ -1,5 +1,6 @@ -import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; import { ViewKey } from '@/views/types/ViewKey'; +import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { selectorFamily } from 'recoil'; export const prefetchIndexViewIdFromObjectMetadataItemFamilySelector = @@ -8,7 +9,9 @@ export const prefetchIndexViewIdFromObjectMetadataItemFamilySelector = get: ({ objectMetadataItemId }) => ({ get }) => { - const views = get(prefetchViewsState); + const coreViews = get(coreViewsState); + + const views = coreViews.map(convertCoreViewToView); return views?.find( (view) => view.objectMetadataId === objectMetadataItemId && diff --git a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewFromViewIdFamilySelector.ts b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewFromViewIdFamilySelector.ts index 8f235ea092..11fb3782df 100644 --- a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewFromViewIdFamilySelector.ts +++ b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewFromViewIdFamilySelector.ts @@ -1,5 +1,6 @@ -import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; import { type View } from '@/views/types/View'; +import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { selectorFamily } from 'recoil'; export const prefetchViewFromViewIdFamilySelector = selectorFamily< @@ -10,7 +11,9 @@ export const prefetchViewFromViewIdFamilySelector = selectorFamily< get: ({ viewId }) => ({ get }) => { - const views = get(prefetchViewsState); + const coreViews = get(coreViewsState); + + const views = coreViews.map(convertCoreViewToView); return views?.find((view) => view.id === viewId); }, }); diff --git a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewIdsFromObjectMetadataItemFamilySelector.ts b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewIdsFromObjectMetadataItemFamilySelector.ts index 30277752c4..ef563c2a6d 100644 --- a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewIdsFromObjectMetadataItemFamilySelector.ts +++ b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewIdsFromObjectMetadataItemFamilySelector.ts @@ -1,4 +1,5 @@ -import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { selectorFamily } from 'recoil'; export const prefetchViewIdsFromObjectMetadataItemFamilySelector = @@ -7,7 +8,9 @@ export const prefetchViewIdsFromObjectMetadataItemFamilySelector = get: ({ objectMetadataItemId }) => ({ get }) => { - const views = get(prefetchViewsState); + const coreViews = get(coreViewsState); + + const views = coreViews.map(convertCoreViewToView); return views .filter((view) => view.objectMetadataId === objectMetadataItemId) .map((view) => view.id); diff --git a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewLengthFamilySelector.ts b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewLengthFamilySelector.ts index 89e525ad6a..f03aba1f5d 100644 --- a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewLengthFamilySelector.ts +++ b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewLengthFamilySelector.ts @@ -1,10 +1,13 @@ -import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { selector } from 'recoil'; export const prefetchViewLengthSelector = selector({ key: 'prefetchViewLengthSelector', get: ({ get }) => { - const views = get(prefetchViewsState); + const coreViews = get(coreViewsState); + + const views = coreViews.map(convertCoreViewToView); return views?.length ?? 0; }, }); diff --git a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector.ts b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector.ts index 0412dd8a2a..835ecfdc83 100644 --- a/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector.ts +++ b/packages/twenty-front/src/modules/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector.ts @@ -1,5 +1,6 @@ -import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; import { type View } from '@/views/types/View'; +import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { selectorFamily } from 'recoil'; export const prefetchViewsFromObjectMetadataItemFamilySelector = selectorFamily< @@ -10,9 +11,14 @@ export const prefetchViewsFromObjectMetadataItemFamilySelector = selectorFamily< get: ({ objectMetadataItemId }) => ({ get }) => { - const views = get(prefetchViewsState); - return views - .filter((view) => view.objectMetadataId === objectMetadataItemId) - .sort((a, b) => a.position - b.position); + const coreViews = get(coreViewsState); + + const views = coreViews.map(convertCoreViewToView); + + const filteredViews = views.filter( + (view) => view.objectMetadataId === objectMetadataItemId, + ); + + return filteredViews.sort((a, b) => a.position - b.position); }, }); diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index 36af700939..e504c6357e 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -19,6 +19,8 @@ import { getDateFormatFromWorkspaceDateFormat } from '@/localization/utils/getDa import { getTimeFormatFromWorkspaceTimeFormat } from '@/localization/utils/getTimeFormatFromWorkspaceTimeFormat'; import { AppPath } from '@/types/AppPath'; import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { enUS } from 'date-fns/locale'; import { useEffect } from 'react'; @@ -32,6 +34,7 @@ import { } from '~/generated-metadata/graphql'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isMatchingLocation } from '~/utils/isMatchingLocation'; export const UserProviderEffect = () => { @@ -63,6 +66,20 @@ export const UserProviderEffect = () => { [], ); + const setCoreViews = useRecoilCallback( + ({ set, snapshot }) => + (coreViews: CoreViewWithRelations[]) => { + const existingCoreViews = snapshot + .getLoadable(coreViewsState) + .getValue(); + + if (!isDeeplyEqual(existingCoreViews, coreViews)) { + set(coreViewsState, coreViews); + } + }, + [], + ); + const setCurrentWorkspaceMember = useSetRecoilState( currentWorkspaceMemberState, ); @@ -110,6 +127,10 @@ export const UserProviderEffect = () => { }); } + if (isDefined(queryData.currentUser?.currentWorkspace?.views)) { + setCoreViews(queryData.currentUser.currentWorkspace.views); + } + const { workspaceMember, workspaceMembers, @@ -181,7 +202,8 @@ export const UserProviderEffect = () => { setDateTimeFormat, setCurrentWorkspaceMembersWithDeleted, updateLocaleCatalog, + setCoreViews, ]); - return <>; + return null; }; diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index a98b916948..6696de00ed 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -5,12 +5,7 @@ import { import { OBJECT_PERMISSION_FRAGMENT } from '@/settings/roles/graphql/fragments/objectPermissionFragment'; import { ROLE_FRAGMENT } from '@/settings/roles/graphql/fragments/roleFragment'; import { WORKSPACE_URLS_FRAGMENT } from '@/users/graphql/fragments/workspaceUrlsFragment'; -import { VIEW_FIELD_FRAGMENT } from '@/views/graphql/fragments/viewFieldFragment'; -import { VIEW_FILTER_FRAGMENT } from '@/views/graphql/fragments/viewFilterFragment'; -import { VIEW_FILTER_GROUP_FRAGMENT } from '@/views/graphql/fragments/viewFilterGroupFragment'; import { VIEW_FRAGMENT } from '@/views/graphql/fragments/viewFragment'; -import { VIEW_GROUP_FRAGMENT } from '@/views/graphql/fragments/viewGroupFragment'; -import { VIEW_SORT_FRAGMENT } from '@/views/graphql/fragments/viewSortFragment'; import { DELETED_WORKSPACE_MEMBER_QUERY_FRAGMENT } from '@/workspace-member/graphql/fragments/deletedWorkspaceMemberQueryFragment'; import { WORKSPACE_MEMBER_QUERY_FRAGMENT } from '@/workspace-member/graphql/fragments/workspaceMemberQueryFragment'; import { gql } from '@apollo/client'; @@ -104,21 +99,6 @@ export const USER_QUERY_FRAGMENT = gql` isTwoFactorAuthenticationEnforced views { ...ViewFragment - viewFields { - ...ViewFieldFragment - } - viewFilters { - ...ViewFilterFragment - } - viewFilterGroups { - ...ViewFilterGroupFragment - } - viewSorts { - ...ViewSortFragment - } - viewGroups { - ...ViewGroupFragment - } } } availableWorkspaces { @@ -133,11 +113,6 @@ export const USER_QUERY_FRAGMENT = gql` ${WORKSPACE_URLS_FRAGMENT} ${ROLE_FRAGMENT} ${VIEW_FRAGMENT} - ${VIEW_FIELD_FRAGMENT} - ${VIEW_FILTER_FRAGMENT} - ${VIEW_FILTER_GROUP_FRAGMENT} - ${VIEW_SORT_FRAGMENT} - ${VIEW_GROUP_FRAGMENT} ${AVAILABLE_WORKSPACES_FOR_AUTH_FRAGMENT} ${AVAILABLE_WORKSPACE_FOR_AUTH_FRAGMENT} `; diff --git a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx index 385c025a5a..856c117df5 100644 --- a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx @@ -13,14 +13,11 @@ import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { ViewType } from '@/views/types/ViewType'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; -import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; -import { type View } from '@/views/types/View'; +import { coreViewsState } from '@/views/states/coreViewState'; import { within } from '@storybook/test'; import { useSetRecoilState } from 'recoil'; import { @@ -32,6 +29,10 @@ import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { + mockedCoreViewsData, + mockedViewsData, +} from '~/testing/mock-data/views'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; const meta: Meta = { @@ -50,36 +51,20 @@ const meta: Meta = { ); const setPrefetchViews = useSetRecoilState(prefetchViewsState); + const setCoreViews = useSetRecoilState(coreViewsState); - const mockView: View = { - id: 'view-1', - name: 'Test View', - objectMetadataId: companyObjectMetadataItem.id, - viewFilters: [], - viewFilterGroups: [], - type: ViewType.Table, - key: null, - isCompact: false, - openRecordIn: ViewOpenRecordInType.SIDE_PANEL, - viewFields: [], - viewGroups: [], - viewSorts: [], - kanbanFieldMetadataId: '', - kanbanAggregateOperation: AggregateOperations.COUNT, - icon: '', - kanbanAggregateOperationFieldMetadataId: '', - position: 0, - __typename: 'View', - }; + const mockView = mockedViewsData[0]; + const mockCoreView = mockedCoreViewsData[0]; setPrefetchViews([mockView]); + setCoreViews([mockCoreView]); const setCurrentViewId = useSetRecoilComponentState( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - setCurrentViewId('view-1'); + setCurrentViewId(mockView.id); const columns = companyObjectMetadataItem.fields.map( (fieldMetadataItem, index) => diff --git a/packages/twenty-front/src/modules/views/graphql/fragments/viewFragment.ts b/packages/twenty-front/src/modules/views/graphql/fragments/viewFragment.ts index 9e82d22fcb..377dee88aa 100644 --- a/packages/twenty-front/src/modules/views/graphql/fragments/viewFragment.ts +++ b/packages/twenty-front/src/modules/views/graphql/fragments/viewFragment.ts @@ -1,6 +1,17 @@ +import { VIEW_FIELD_FRAGMENT } from '@/views/graphql/fragments/viewFieldFragment'; +import { VIEW_FILTER_FRAGMENT } from '@/views/graphql/fragments/viewFilterFragment'; +import { VIEW_FILTER_GROUP_FRAGMENT } from '@/views/graphql/fragments/viewFilterGroupFragment'; +import { VIEW_GROUP_FRAGMENT } from '@/views/graphql/fragments/viewGroupFragment'; +import { VIEW_SORT_FRAGMENT } from '@/views/graphql/fragments/viewSortFragment'; import { gql } from '@apollo/client'; export const VIEW_FRAGMENT = gql` + ${VIEW_FIELD_FRAGMENT} + ${VIEW_FILTER_FRAGMENT} + ${VIEW_FILTER_GROUP_FRAGMENT} + ${VIEW_SORT_FRAGMENT} + ${VIEW_GROUP_FRAGMENT} + fragment ViewFragment on CoreView { id name @@ -16,5 +27,20 @@ export const VIEW_FRAGMENT = gql` createdAt updatedAt anyFieldFilterValue + viewFields { + ...ViewFieldFragment + } + viewFilters { + ...ViewFilterFragment + } + viewFilterGroups { + ...ViewFilterGroupFragment + } + viewSorts { + ...ViewSortFragment + } + viewGroups { + ...ViewGroupFragment + } } `; diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx index b3003279fd..e72c1d4053 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx @@ -3,19 +3,23 @@ import { renderHook } from '@testing-library/react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups } from '@/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type View } from '@/views/types/View'; import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; -import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { ViewType } from '@/views/types/ViewType'; import { mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator } from '@/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator'; import { act } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { type CoreViewFilterGroup } from '~/generated/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; +import { + mockedCoreViewsData, + mockedViewsData, +} from '~/testing/mock-data/views'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; const mockObjectMetadataItemNameSingular = 'company'; @@ -40,27 +44,29 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { positionInViewFilterGroup: 0, }; - const mockView: View = { - id: 'view-1', - name: 'Test View', - objectMetadataId: mockObjectMetadataItem.id, - viewFilters: [], - viewFilterGroups: [mockViewFilterGroup], - type: ViewType.Table, - key: null, - isCompact: false, - openRecordIn: ViewOpenRecordInType.SIDE_PANEL, - viewFields: [], - viewGroups: [], - viewSorts: [], - kanbanFieldMetadataId: '', - kanbanAggregateOperation: AggregateOperations.COUNT, - icon: '', - kanbanAggregateOperationFieldMetadataId: '', - position: 0, - __typename: 'View', + const allCompaniesView = mockedViewsData[0]; + const allCompaniesCoreView = mockedCoreViewsData[0]; + + const mockCoreViewFilterGroup: Omit = { + __typename: 'CoreViewFilterGroup', + id: 'filter-group-1', + viewId: allCompaniesCoreView.id, + logicalOperator: ViewFilterGroupLogicalOperator.AND, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + positionInViewFilterGroup: 0, }; + const mockView = { + ...allCompaniesView, + viewFilterGroups: [mockViewFilterGroup], + } satisfies View; + + const mockCoreView = { + ...allCompaniesCoreView, + viewFilterGroups: [mockCoreViewFilterGroup], + } satisfies CoreViewWithRelations; + it('should apply view filter groups from current view', () => { const { result } = renderHook( () => { @@ -85,6 +91,7 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { mockObjectMetadataItemNameSingular, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set(prefetchViewsState, [mockView]); + snapshot.set(coreViewsState, [mockCoreView]); }, }), }, @@ -142,6 +149,7 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { ); snapshot.set(prefetchViewsState, []); + snapshot.set(coreViewsState, []); }, }), }, @@ -186,6 +194,9 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { snapshot.set(prefetchViewsState, [ { ...mockView, viewFilterGroups: [] }, ]); + snapshot.set(coreViewsState, [ + { ...mockCoreView, viewFilterGroups: [] }, + ]); }, }), }, diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx index c2485929ea..b3233a2582 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx @@ -4,17 +4,24 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/ import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type View } from '@/views/types/View'; import { type ViewFilter } from '@/views/types/ViewFilter'; -import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { ViewType } from '@/views/types/ViewType'; import { act } from 'react'; import { ViewFilterOperand } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { + type CoreViewFilter, + ViewFilterOperand as CoreViewFilterOperand, +} from '~/generated/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; +import { + mockedCoreViewsData, + mockedViewsData, +} from '~/testing/mock-data/views'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters'; @@ -31,6 +38,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { ); } + const allCompaniesView = mockedViewsData[0]; + const allCompaniesCoreView = mockedCoreViewsData[0]; + const mockFieldMetadataItem = mockObjectMetadataItem.fields[0]; const mockViewFilter: ViewFilter = { @@ -39,31 +49,46 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { fieldMetadataId: mockFieldMetadataItem.id, operand: ViewFilterOperand.Contains, value: 'test', - displayValue: mockFieldMetadataItem.label, + displayValue: 'test', viewFilterGroupId: 'group-1', positionInViewFilterGroup: 0, }; - const mockView: View = { - id: 'view-1', - name: 'Test View', - objectMetadataId: mockObjectMetadataItem.id, - viewFilters: [mockViewFilter], - type: ViewType.Table, - key: null, - isCompact: false, - openRecordIn: ViewOpenRecordInType.SIDE_PANEL, - viewFields: [], - viewGroups: [], - viewSorts: [], - kanbanFieldMetadataId: '', - kanbanAggregateOperation: AggregateOperations.COUNT, - icon: '', - kanbanAggregateOperationFieldMetadataId: '', - position: 0, - __typename: 'View', + const mockCoreViewFilter: Omit = { + __typename: 'CoreViewFilter', + id: 'filter-1', + fieldMetadataId: mockFieldMetadataItem.id, + operand: CoreViewFilterOperand.CONTAINS, + value: 'test', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + viewId: allCompaniesCoreView.id, + positionInViewFilterGroup: 0, + viewFilterGroupId: 'group-1', }; + const mockView = { + ...allCompaniesView, + viewFilters: [mockViewFilter], + } satisfies View; + + const mockCoreView = { + ...allCompaniesCoreView, + viewFilters: [mockCoreViewFilter], + } satisfies CoreViewWithRelations; + + const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, + contextStoreCurrentViewId: mockView.id, + onInitializeRecoilSnapshot: (snapshot) => { + snapshot.set(prefetchViewsState, [mockView]); + snapshot.set(coreViewsState, [mockCoreView]); + }, + }); + it('should apply filters from current view', () => { const { result } = renderHook( () => { @@ -80,16 +105,7 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { }; }, { - wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ - apolloMocks: [], - componentInstanceId: 'instanceId', - contextStoreCurrentObjectMetadataNameSingular: - mockObjectMetadataItemNameSingular, - contextStoreCurrentViewId: mockView.id, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set(prefetchViewsState, [mockView]); - }, - }), + wrapper, }, ); @@ -108,6 +124,7 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { positionInRecordFilterGroup: mockViewFilter.positionInViewFilterGroup, label: mockFieldMetadataItem.label, type: getFilterTypeFromFieldType(mockFieldMetadataItem.type), + subFieldName: null, } satisfies RecordFilter, ]); }); @@ -141,6 +158,7 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { mockView.id, ); snapshot.set(prefetchViewsState, []); + snapshot.set(coreViewsState, []); }, }), }, @@ -184,6 +202,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { snapshot.set(prefetchViewsState, [ { ...mockView, viewFilters: [] }, ]); + snapshot.set(coreViewsState, [ + { ...mockCoreView, viewFilters: [] }, + ]); }, }), }, diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx index 1f8998c58e..59da351df7 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx @@ -10,10 +10,16 @@ import { type ViewSort } from '@/views/types/ViewSort'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; +import { coreViewsState } from '@/views/states/coreViewState'; +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type View } from '@/views/types/View'; import { isDefined } from 'twenty-shared/utils'; +import { ViewSortDirection, type CoreViewSort } from '~/generated/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; -import { mockedViewsData } from '~/testing/mock-data/views'; +import { + mockedCoreViewsData, + mockedViewsData, +} from '~/testing/mock-data/views'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; import { useApplyCurrentViewSortsToCurrentRecordSorts } from '../useApplyCurrentViewSortsToCurrentRecordSorts'; @@ -46,12 +52,28 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { }; const allCompaniesView = mockedViewsData[0]; + const allCompaniesCoreView = mockedCoreViewsData[0]; + + const mockCoreViewSort: Omit = { + __typename: 'CoreViewSort', + id: 'sort-1', + fieldMetadataId: mockFieldMetadataItem.id, + direction: ViewSortDirection.ASC, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + viewId: allCompaniesCoreView.id, + }; const mockView = { ...allCompaniesView, viewSorts: [mockViewSort], } satisfies View; + const mockCoreView = { + ...allCompaniesCoreView, + viewSorts: [mockCoreViewSort], + } satisfies CoreViewWithRelations; + it('should apply sorts from current view', () => { const { result } = renderHook( () => { @@ -76,6 +98,7 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { contextStoreCurrentViewId: mockView.id, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set(prefetchViewsState, [mockView]); + snapshot.set(coreViewsState, [mockCoreView]); }, }), }, diff --git a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts index e963d381ad..713f9776d0 100644 --- a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts @@ -16,6 +16,7 @@ import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePers import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords'; import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords'; import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords'; +import { coreViewsState } from '@/views/states/coreViewState'; import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState'; import { type GraphQLView } from '@/views/types/GraphQLView'; import { type View } from '@/views/types/View'; @@ -32,7 +33,12 @@ import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; -import { FeatureFlagKey, useCreateCoreViewMutation } from '~/generated/graphql'; +import { + FeatureFlagKey, + useCreateCoreViewMutation, + useFindManyCoreViewsLazyQuery, +} from '~/generated/graphql'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { @@ -64,6 +70,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const [findManyCoreViewsLazy] = useFindManyCoreViewsLazyQuery(); + const { findManyRecordsLazy } = useLazyFindManyRecords({ objectNameSingular: CoreObjectNameSingular.View, fetchPolicy: 'network-only', @@ -249,7 +257,28 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { await createViewSortRecords(viewSortsToCreate, { id: newViewId }); } - await findManyRecordsLazy(); + if (isCoreViewEnabled) { + const result = await findManyCoreViewsLazy({ + variables: { + objectMetadataId: objectMetadataItem.id, + }, + fetchPolicy: 'network-only', + }); + + const existingCoreViews = snapshot + .getLoadable(coreViewsState) + .getValue(); + + if ( + isDefined(result.data?.getCoreViews) && + !isDeeplyEqual(existingCoreViews, result.data.getCoreViews) + ) { + set(coreViewsState, result.data.getCoreViews); + } + } else { + await findManyRecordsLazy(); + } + set(isPersistingViewFieldsState, false); return newViewId; }, @@ -269,6 +298,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { currentRecordFilterGroups, isCoreViewEnabled, createCoreViewMutation, + findManyCoreViewsLazy, + objectMetadataItem.id, ], ); diff --git a/packages/twenty-front/src/modules/views/hooks/useMapViewFiltersToFilters.ts b/packages/twenty-front/src/modules/views/hooks/useMapViewFiltersToFilters.ts index 6a2e7a30e2..836b9594ed 100644 --- a/packages/twenty-front/src/modules/views/hooks/useMapViewFiltersToFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useMapViewFiltersToFilters.ts @@ -1,4 +1,5 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { type CoreViewFilter } from '~/generated/graphql'; import { type ViewFilter } from '../types/ViewFilter'; import { getFilterableFieldsWithVectorSearch } from '../utils/getFilterableFieldsWithVectorSearch'; import { mapViewFiltersToFilters } from '../utils/mapViewFiltersToFilters'; @@ -6,7 +7,9 @@ import { mapViewFiltersToFilters } from '../utils/mapViewFiltersToFilters'; export const useMapViewFiltersToFilters = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const mapViewFiltersToRecordFilters = (viewFilters: ViewFilter[]) => { + const mapViewFiltersToRecordFilters = ( + viewFilters: ViewFilter[] | CoreViewFilter[], + ) => { const filterableFieldMetadataItems = getFilterableFieldsWithVectorSearch(objectMetadataItem); return mapViewFiltersToFilters(viewFilters, filterableFieldMetadataItems); diff --git a/packages/twenty-front/src/modules/views/states/coreViewState.ts b/packages/twenty-front/src/modules/views/states/coreViewState.ts new file mode 100644 index 0000000000..980612e1b3 --- /dev/null +++ b/packages/twenty-front/src/modules/views/states/coreViewState.ts @@ -0,0 +1,7 @@ +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; +import { createState } from 'twenty-ui/utilities'; + +export const coreViewsState = createState({ + key: 'coreViewsState', + defaultValue: [], +}); diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts index cd318fb092..7de909ca63 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -4,11 +4,15 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { isSystemSearchVectorField } from '@/object-record/utils/isSystemSearchVectorField'; +import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; +import { convertViewFilterOperandFromCore } from '@/views/utils/convertViewFilterOperandFromCore'; +import { type ViewFilterOperand } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { type CoreViewFilter } from '~/generated/graphql'; import { type ViewFilter } from '../types/ViewFilter'; export const mapViewFiltersToFilters = ( - viewFilters: ViewFilter[], + viewFilters: ViewFilter[] | CoreViewFilter[], availableFieldMetadataItems: FieldMetadataItem[], ): RecordFilter[] => { return viewFilters @@ -31,17 +35,25 @@ export const mapViewFiltersToFilters = ( ? 'Search' : availableFieldMetadataItem.label; + const operand = + viewFilter.__typename === 'CoreViewFilter' + ? convertViewFilterOperandFromCore(viewFilter.operand) + : (viewFilter.operand as ViewFilterOperand); + return { id: viewFilter.id, fieldMetadataId: viewFilter.fieldMetadataId, value: viewFilter.value, - displayValue: viewFilter.displayValue, - operand: viewFilter.operand, + displayValue: + 'displayValue' in viewFilter + ? viewFilter.displayValue + : viewFilter.value, + operand, recordFilterGroupId: viewFilter.viewFilterGroupId, positionInRecordFilterGroup: viewFilter.positionInViewFilterGroup, label, type: filterType, - subFieldName: viewFilter.subFieldName, + subFieldName: viewFilter.subFieldName as CompositeFieldSubFieldName, } satisfies RecordFilter; }) .filter(isDefined); diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts index 060ad4ce8a..56591dfb31 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts @@ -11,7 +11,7 @@ import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPic import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState'; import { viewPickerTypeComponentState } from '@/views/view-picker/states/viewPickerTypeComponentState'; import { useRecoilCallback } from 'recoil'; -import { v4 } from 'uuid'; +import { isDefined } from 'twenty-shared/utils'; export const useCreateViewFromCurrentState = () => { const { closeAndResetViewPicker } = useCloseAndResetViewPicker(); @@ -73,14 +73,11 @@ export const useCreateViewFromCurrentState = () => { const shouldCopyFiltersAndSortsAndAggregate = viewPickerMode === 'create-from-current'; - const id = v4(); - set(viewPickerIsPersistingCallbackState, true); set(viewPickerIsDirtyCallbackState, false); - await createViewFromCurrentView( + const createdViewId = await createViewFromCurrentView( { - id, name, icon: iconKey, type, @@ -89,8 +86,10 @@ export const useCreateViewFromCurrentState = () => { shouldCopyFiltersAndSortsAndAggregate, ); - closeAndResetViewPicker(); - changeView(id); + if (isDefined(createdViewId)) { + closeAndResetViewPicker(); + changeView(createdViewId); + } }, [ closeAndResetViewPicker, diff --git a/packages/twenty-front/src/testing/mock-data/views.ts b/packages/twenty-front/src/testing/mock-data/views.ts index 9a9d3fddba..d0730a8574 100644 --- a/packages/twenty-front/src/testing/mock-data/views.ts +++ b/packages/twenty-front/src/testing/mock-data/views.ts @@ -1,8 +1,14 @@ import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; +import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type View } from '@/views/types/View'; import { ViewKey } from '@/views/types/ViewKey'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { ViewType } from '@/views/types/ViewType'; +import { + ViewKey as CoreViewKey, + ViewOpenRecordIn as CoreViewOpenRecordIn, + ViewType as CoreViewType, +} from '~/generated-metadata/graphql'; import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow'; const companyObjectMetadata = getMockObjectMetadataItemOrThrow('company'); @@ -94,3 +100,82 @@ export const mockedViewsData: View[] = [ __typename: 'View', }, ]; + +export const mockedCoreViewsData: CoreViewWithRelations[] = [ + { + id: '37a8a866-eb17-4e76-9382-03143a2f6a80', + name: 'All companies', + objectMetadataId: companyObjectMetadata.id, + type: CoreViewType.TABLE, + icon: 'IconSkyline', + key: CoreViewKey.INDEX, + kanbanAggregateOperation: AggregateOperations.COUNT, + kanbanAggregateOperationFieldMetadataId: '', + position: 0, + isCompact: false, + openRecordIn: CoreViewOpenRecordIn.SIDE_PANEL, + viewFilterGroups: [], + viewGroups: [], + viewFields: [], + viewFilters: [], + viewSorts: [], + __typename: 'CoreView', + }, + { + id: '6095799e-b48f-4e00-b071-10818083593a', + name: 'All people', + objectMetadataId: personObjectMetadata.id, + type: CoreViewType.TABLE, + icon: 'IconPerson', + key: CoreViewKey.INDEX, + kanbanAggregateOperation: AggregateOperations.COUNT, + kanbanAggregateOperationFieldMetadataId: '', + position: 0, + isCompact: false, + openRecordIn: CoreViewOpenRecordIn.SIDE_PANEL, + viewFilterGroups: [], + viewGroups: [], + viewFields: [], + viewFilters: [], + viewSorts: [], + __typename: 'CoreView', + }, + { + id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308', + name: 'All opportunities', + objectMetadataId: opportunityObjectMetadata.id, + type: CoreViewType.KANBAN, + icon: 'IconOpportunity', + key: CoreViewKey.INDEX, + kanbanAggregateOperation: AggregateOperations.COUNT, + kanbanAggregateOperationFieldMetadataId: '', + position: 0, + isCompact: false, + openRecordIn: CoreViewOpenRecordIn.SIDE_PANEL, + viewFilterGroups: [], + viewGroups: [], + viewFields: [], + viewFilters: [], + viewSorts: [], + __typename: 'CoreView', + }, + { + id: '5c307222-1dd5-4ff3-ab06-8d990e9b3c74', + name: 'All companies (v2)', + objectMetadataId: companyObjectMetadata.id, + type: CoreViewType.TABLE, + icon: 'IconSkyline', + key: null, + kanbanAggregateOperation: AggregateOperations.COUNT, + kanbanAggregateOperationFieldMetadataId: '', + position: 0, + isCompact: false, + openRecordIn: CoreViewOpenRecordIn.SIDE_PANEL, + viewFilterGroups: [], + viewGroups: [], + viewFields: [], + viewFilters: [], + viewSorts: [], + __typename: 'CoreView', + }, +]; diff --git a/packages/twenty-ui/package.json b/packages/twenty-ui/package.json index 3867bba9ee..9a0cad138d 100644 --- a/packages/twenty-ui/package.json +++ b/packages/twenty-ui/package.json @@ -48,6 +48,7 @@ "dist", "assets", "accessibility", + "assets", "components", "display", "feedback",