From 94b8e34362ce7a8cb1d5ede456f0a6399af383e4 Mon Sep 17 00:00:00 2001 From: Etienne <45695613+etiennejouan@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:30:37 +0200 Subject: [PATCH] Object view widget - Introduce new TABLE_WIDGET view type (#19545) closes https://discord.com/channels/1130383047699738754/1491549365263667230/1491804729397743666 --- .../src/metadata/generated/schema.graphql | 1 + .../src/metadata/generated/schema.ts | 5 +- .../src/generated-metadata/graphql.ts | 11 +++- .../hooks/useLoadStaleMetadataEntities.ts | 58 ++++++++++++------- .../isViewDisplayableInNavigationMenu.ts | 1 + .../useSetViewTypeFromLayoutOptionsMenu.ts | 3 +- .../useCreateViewForRecordTableWidget.ts | 2 +- .../graphql/queries/findTableWidgetViews.ts | 11 ++++ ...ewsFromObjectMetadataItemFamilySelector.ts | 3 +- .../twenty-front/src/testing/graphqlMocks.ts | 7 +++ ...775752190522-add-table-widget-view-type.ts | 34 +++++++++++ .../instance-commands.constant.ts | 2 + packages/twenty-shared/src/types/ViewType.ts | 1 + 13 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 packages/twenty-front/src/modules/views/graphql/queries/findTableWidgetViews.ts create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775752190522-add-table-widget-view-type.ts diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index e6ff56414a..3f4564e3f4 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -735,6 +735,7 @@ enum ViewType { KANBAN CALENDAR FIELDS_WIDGET + TABLE_WIDGET } enum ViewKey { diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 309a2fe605..7592df05a8 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -534,7 +534,7 @@ export interface View { __typename: 'View' } -export type ViewType = 'TABLE' | 'KANBAN' | 'CALENDAR' | 'FIELDS_WIDGET' +export type ViewType = 'TABLE' | 'KANBAN' | 'CALENDAR' | 'FIELDS_WIDGET' | 'TABLE_WIDGET' export type ViewKey = 'INDEX' @@ -9267,7 +9267,8 @@ export const enumViewType = { TABLE: 'TABLE' as const, KANBAN: 'KANBAN' as const, CALENDAR: 'CALENDAR' as const, - FIELDS_WIDGET: 'FIELDS_WIDGET' as const + FIELDS_WIDGET: 'FIELDS_WIDGET' as const, + TABLE_WIDGET: 'TABLE_WIDGET' as const } export const enumViewKey = { diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 69f9a5558c..94eb7569fb 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -6217,7 +6217,8 @@ export enum ViewType { CALENDAR = 'CALENDAR', FIELDS_WIDGET = 'FIELDS_WIDGET', KANBAN = 'KANBAN', - TABLE = 'TABLE' + TABLE = 'TABLE', + TABLE_WIDGET = 'TABLE_WIDGET' } export enum ViewVisibility { @@ -8490,6 +8491,13 @@ export type FindOneViewSortQueryVariables = Exact<{ export type FindOneViewSortQuery = { __typename?: 'Query', getViewSort?: { __typename?: 'ViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, deletedAt?: string | null, updatedAt: string } | null }; +export type FindTableWidgetViewsQueryVariables = Exact<{ + viewTypes?: InputMaybe | ViewType>; +}>; + + +export type FindTableWidgetViewsQuery = { __typename?: 'Query', getViews: Array<{ __typename?: 'View', 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, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'ViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, viewFieldGroupId?: string | null, isActive: boolean, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFieldGroups: Array<{ __typename?: 'ViewFieldGroup', id: string, name: string, position: number, isVisible: boolean, viewId: string, isActive: boolean, createdAt: string, updatedAt: string, deletedAt?: string | null, viewFields: Array<{ __typename?: 'ViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, viewFieldGroupId?: string | null, isActive: boolean, createdAt: string, updatedAt: string, deletedAt?: string | null }> }>, viewFilters: Array<{ __typename?: 'ViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'ViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'ViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string, createdAt: string, deletedAt?: string | null, updatedAt: string }>, viewGroups: Array<{ __typename?: 'ViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> }; + export type DeleteWorkspaceInvitationMutationVariables = Exact<{ appTokenId: Scalars['String']; }>; @@ -8889,6 +8897,7 @@ export const FindOneViewFilterDocument = {"kind":"Document","definitions":[{"kin export const FindOneViewFilterGroupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneViewFilterGroup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getViewFilterGroup"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFilterGroupFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFilterGroupFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewFilterGroup"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"parentViewFilterGroupId"}},{"kind":"Field","name":{"kind":"Name","value":"logicalOperator"}},{"kind":"Field","name":{"kind":"Name","value":"positionInViewFilterGroup"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}}]}}]} as unknown as DocumentNode; export const FindOneViewGroupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneViewGroup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getViewGroup"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewGroupFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewGroupFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewGroup"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isVisible"}},{"kind":"Field","name":{"kind":"Name","value":"fieldValue"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}}]} as unknown as DocumentNode; export const FindOneViewSortDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneViewSort"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getViewSort"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewSortFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewSortFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewSort"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; +export const FindTableWidgetViewsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindTableWidgetViews"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"viewTypes"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ViewType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getViews"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"viewTypes"},"value":{"kind":"Variable","name":{"kind":"Name","value":"viewTypes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFieldFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewField"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"isVisible"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"aggregateOperation"}},{"kind":"Field","name":{"kind":"Name","value":"viewFieldGroupId"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFieldGroupFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewFieldGroup"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"isVisible"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}},{"kind":"Field","name":{"kind":"Name","value":"viewFields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFieldFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFilterFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewFilter"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"operand"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"viewFilterGroupId"}},{"kind":"Field","name":{"kind":"Name","value":"positionInViewFilterGroup"}},{"kind":"Field","name":{"kind":"Name","value":"subFieldName"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFilterGroupFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewFilterGroup"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"parentViewFilterGroupId"}},{"kind":"Field","name":{"kind":"Name","value":"logicalOperator"}},{"kind":"Field","name":{"kind":"Name","value":"positionInViewFilterGroup"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewSortFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewSort"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewGroupFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ViewGroup"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isVisible"}},{"kind":"Field","name":{"kind":"Name","value":"fieldValue"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"View"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"objectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"isCompact"}},{"kind":"Field","name":{"kind":"Name","value":"openRecordIn"}},{"kind":"Field","name":{"kind":"Name","value":"kanbanAggregateOperation"}},{"kind":"Field","name":{"kind":"Name","value":"kanbanAggregateOperationFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"mainGroupByFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"shouldHideEmptyGroups"}},{"kind":"Field","name":{"kind":"Name","value":"anyFieldFilterValue"}},{"kind":"Field","name":{"kind":"Name","value":"calendarFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"calendarLayout"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"createdByUserWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"viewFields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFieldFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewFieldGroups"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFieldGroupFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewFilters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFilterFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewFilterGroups"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewFilterGroupFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewSorts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewSortFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewGroups"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewGroupFragment"}}]}}]}}]} as unknown as DocumentNode; export const DeleteWorkspaceInvitationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteWorkspaceInvitation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appTokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteWorkspaceInvitation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appTokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appTokenId"}}}]}]}}]} as unknown as DocumentNode; export const ResendWorkspaceInvitationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResendWorkspaceInvitation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appTokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resendWorkspaceInvitation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appTokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appTokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"errors"}},{"kind":"Field","name":{"kind":"Name","value":"result"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceInvitation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roleId"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const SendInvitationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendInvitations"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"emails"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"roleId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sendInvitations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"emails"},"value":{"kind":"Variable","name":{"kind":"Name","value":"emails"}}},{"kind":"Argument","name":{"kind":"Name","value":"roleId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"roleId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"errors"}},{"kind":"Field","name":{"kind":"Name","value":"result"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceInvitation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roleId"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/metadata-store/hooks/useLoadStaleMetadataEntities.ts b/packages/twenty-front/src/modules/metadata-store/hooks/useLoadStaleMetadataEntities.ts index 0d1c15b66a..ca7c4765d5 100644 --- a/packages/twenty-front/src/modules/metadata-store/hooks/useLoadStaleMetadataEntities.ts +++ b/packages/twenty-front/src/modules/metadata-store/hooks/useLoadStaleMetadataEntities.ts @@ -13,6 +13,7 @@ import { FindManyCommandMenuItemsDocument, FindAllRecordPageLayoutsDocument, FindFieldsWidgetViewsDocument, + FindTableWidgetViewsDocument, FindManyFrontComponentsDocument, FindManyLogicFunctionsDocument, FindManyNavigationMenuItemsDocument, @@ -44,6 +45,7 @@ const PAGE_LAYOUTS_GROUP_KEYS: MetadataEntityKey[] = [ const INDEX_VIEW_TYPES = [ViewType.TABLE, ViewType.KANBAN, ViewType.CALENDAR]; const FIELDS_WIDGET_VIEW_TYPES = [ViewType.FIELDS_WIDGET]; +const TABLE_WIDGET_VIEW_TYPES = [ViewType.TABLE_WIDGET]; const hasOverlap = ( staleKeys: MetadataEntityKey[], @@ -93,30 +95,42 @@ export const useLoadStaleMetadataEntities = () => { variables: { viewTypes: FIELDS_WIDGET_VIEW_TYPES }, fetchPolicy: 'network-only', }), - ]).then(([indexViewsResult, fieldsWidgetViewsResult]) => { - const allViews = [ - ...(indexViewsResult.data?.getViews ?? []), - ...(fieldsWidgetViewsResult.data?.getViews ?? []), - ]; + client.query({ + query: FindTableWidgetViewsDocument, + variables: { viewTypes: TABLE_WIDGET_VIEW_TYPES }, + fetchPolicy: 'network-only', + }), + ]).then( + ([ + indexViewsResult, + fieldsWidgetViewsResult, + tableWidgetViewsResult, + ]) => { + const allViews = [ + ...(indexViewsResult.data?.getViews ?? []), + ...(fieldsWidgetViewsResult.data?.getViews ?? []), + ...(tableWidgetViewsResult.data?.getViews ?? []), + ]; - const { - flatViews, - flatViewFields, - flatViewFilters, - flatViewSorts, - flatViewGroups, - flatViewFilterGroups, - flatViewFieldGroups, - } = splitViewWithRelated(allViews); + const { + flatViews, + flatViewFields, + flatViewFilters, + flatViewSorts, + flatViewGroups, + flatViewFilterGroups, + flatViewFieldGroups, + } = splitViewWithRelated(allViews); - replaceDraft('views', flatViews); - replaceDraft('viewFields', flatViewFields); - replaceDraft('viewFilters', flatViewFilters); - replaceDraft('viewSorts', flatViewSorts); - replaceDraft('viewGroups', flatViewGroups); - replaceDraft('viewFilterGroups', flatViewFilterGroups); - replaceDraft('viewFieldGroups', flatViewFieldGroups); - }), + replaceDraft('views', flatViews); + replaceDraft('viewFields', flatViewFields); + replaceDraft('viewFilters', flatViewFilters); + replaceDraft('viewSorts', flatViewSorts); + replaceDraft('viewGroups', flatViewGroups); + replaceDraft('viewFilterGroups', flatViewFilterGroups); + replaceDraft('viewFieldGroups', flatViewFieldGroups); + }, + ), ); } diff --git a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/utils/isViewDisplayableInNavigationMenu.ts b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/utils/isViewDisplayableInNavigationMenu.ts index 92653e1a32..7dbbe028fc 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/utils/isViewDisplayableInNavigationMenu.ts +++ b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/utils/isViewDisplayableInNavigationMenu.ts @@ -4,4 +4,5 @@ import { ViewVisibility } from '~/generated-metadata/graphql'; export const isViewDisplayableInNavigationMenu = (view: View): boolean => view.type !== ViewType.FIELDS_WIDGET && + view.type !== ViewType.TABLE_WIDGET && view.visibility === ViewVisibility.WORKSPACE; diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts index 8ba55c0b7e..6c4b329047 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts @@ -4,13 +4,13 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; +import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { viewsSelector } from '@/views/states/selectors/viewsSelector'; import { type GraphQLView } from '@/views/types/GraphQLView'; import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType'; import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar'; import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy'; -import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useStore } from 'jotai'; import { useCallback } from 'react'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; @@ -112,6 +112,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => { updateCurrentViewParams.mainGroupByFieldMetadataId = null; return await updateCurrentView(updateCurrentViewParams); } + case ViewType.TABLE_WIDGET: case ViewType.FIELDS_WIDGET: { return; } diff --git a/packages/twenty-front/src/modules/page-layout/widgets/record-table/hooks/useCreateViewForRecordTableWidget.ts b/packages/twenty-front/src/modules/page-layout/widgets/record-table/hooks/useCreateViewForRecordTableWidget.ts index ea090a53b8..8f977cb5c4 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/record-table/hooks/useCreateViewForRecordTableWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/record-table/hooks/useCreateViewForRecordTableWidget.ts @@ -33,7 +33,7 @@ export const useCreateViewForRecordTableWidget = (pageLayoutId: string) => { name: `${objectMetadataItem.labelPlural} Table`, icon: objectMetadataItem.icon ?? 'IconTable', objectMetadataId: objectMetadataItem.id, - type: ViewType.TABLE, + type: ViewType.TABLE_WIDGET, }, }, objectMetadataItem.id, diff --git a/packages/twenty-front/src/modules/views/graphql/queries/findTableWidgetViews.ts b/packages/twenty-front/src/modules/views/graphql/queries/findTableWidgetViews.ts new file mode 100644 index 0000000000..2b781ec33a --- /dev/null +++ b/packages/twenty-front/src/modules/views/graphql/queries/findTableWidgetViews.ts @@ -0,0 +1,11 @@ +import { VIEW_FRAGMENT } from '@/views/graphql/fragments/viewFragment'; +import { gql } from '@apollo/client'; + +export const FIND_TABLE_WIDGET_VIEWS = gql` + ${VIEW_FRAGMENT} + query FindTableWidgetViews($viewTypes: [ViewType!]) { + getViews(viewTypes: $viewTypes) { + ...ViewFragment + } + } +`; diff --git a/packages/twenty-front/src/modules/views/states/selectors/viewsFromObjectMetadataItemFamilySelector.ts b/packages/twenty-front/src/modules/views/states/selectors/viewsFromObjectMetadataItemFamilySelector.ts index f7cd487fb5..160db26f62 100644 --- a/packages/twenty-front/src/modules/views/states/selectors/viewsFromObjectMetadataItemFamilySelector.ts +++ b/packages/twenty-front/src/modules/views/states/selectors/viewsFromObjectMetadataItemFamilySelector.ts @@ -14,7 +14,8 @@ export const viewsFromObjectMetadataItemFamilySelector = .filter( (view) => view.objectMetadataId === objectMetadataItemId && - view.type !== ViewType.FIELDS_WIDGET, + view.type !== ViewType.FIELDS_WIDGET && + view.type !== ViewType.TABLE_WIDGET, ) .sort((a, b) => a.position - b.position); }, diff --git a/packages/twenty-front/src/testing/graphqlMocks.ts b/packages/twenty-front/src/testing/graphqlMocks.ts index bdb3bc3bb0..9d83de6a95 100644 --- a/packages/twenty-front/src/testing/graphqlMocks.ts +++ b/packages/twenty-front/src/testing/graphqlMocks.ts @@ -195,6 +195,13 @@ export const graphqlMocks = { }, }); }), + metadataGraphql.query('FindTableWidgetViews', () => { + return HttpResponse.json({ + data: { + getViews: mockedViews.filter((view) => view.type === 'TABLE_WIDGET'), + }, + }); + }), metadataGraphql.query('FindAllRecordPageLayouts', () => { return HttpResponse.json({ data: { getPageLayouts: [] }, diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775752190522-add-table-widget-view-type.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775752190522-add-table-widget-view-type.ts new file mode 100644 index 0000000000..af187598bc --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775752190522-add-table-widget-view-type.ts @@ -0,0 +1,34 @@ +import { type QueryRunner } from 'typeorm'; + +import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; +import { type FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; + +@RegisteredInstanceCommand('1.22.0', 1775752190522) +export class AddTableWidgetViewTypeFastInstanceCommand + implements FastInstanceCommand +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TYPE "core"."view_type_enum" ADD VALUE IF NOT EXISTS 'TABLE_WIDGET' AFTER 'FIELDS_WIDGET'`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "CREATE TYPE \"core\".\"view_type_enum_old\" AS ENUM('TABLE', 'KANBAN', 'CALENDAR', 'FIELDS_WIDGET')", + ); + await queryRunner.query( + 'ALTER TABLE "core"."view" ALTER COLUMN "type" DROP DEFAULT', + ); + await queryRunner.query( + 'ALTER TABLE "core"."view" ALTER COLUMN "type" TYPE "core"."view_type_enum_old" USING "type"::"text"::"core"."view_type_enum_old"', + ); + await queryRunner.query( + 'ALTER TABLE "core"."view" ALTER COLUMN "type" SET DEFAULT \'TABLE\'', + ); + await queryRunner.query('DROP TYPE "core"."view_type_enum"'); + await queryRunner.query( + 'ALTER TYPE "core"."view_type_enum_old" RENAME TO "view_type_enum"', + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts index 0664772428..4490ec7844 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts @@ -5,6 +5,7 @@ import { MigrateMessagingCalendarToCoreFastInstanceCommand } from 'src/database/ import { AddEmailThreadWidgetTypeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-instance-command-fast-1775200000000-add-email-thread-widget-type'; import { AddStandalonePageFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-23/1-23-instance-command-fast-1775752781995-add-standalone-page'; import { AddPermissionFlagRoleIdIndexFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775749486425-add-permission-flag-role-id-index'; +import { AddTableWidgetViewTypeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775752190522-add-table-widget-view-type'; import { AddWorkspaceIdToIndirectEntitiesFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775758621017-add-workspace-id-to-indirect-entities'; import { AddWorkspaceIdIndexesAndFksFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775761294897-add-workspace-id-indexes-and-fks-to-indirect-entities'; import { DropObjectMetadataDataSourceFkFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-22/1-22-instance-command-fast-1775804361516-drop-object-metadata-data-source-fk'; @@ -17,6 +18,7 @@ export const INSTANCE_COMMANDS = [ AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand, MigrateMessagingCalendarToCoreFastInstanceCommand, AddEmailThreadWidgetTypeFastInstanceCommand, + AddTableWidgetViewTypeFastInstanceCommand, AddStandalonePageFastInstanceCommand, AddPermissionFlagRoleIdIndexFastInstanceCommand, AddWorkspaceIdToIndirectEntitiesFastInstanceCommand, diff --git a/packages/twenty-shared/src/types/ViewType.ts b/packages/twenty-shared/src/types/ViewType.ts index 0227f67729..e96d7e98c6 100644 --- a/packages/twenty-shared/src/types/ViewType.ts +++ b/packages/twenty-shared/src/types/ViewType.ts @@ -3,4 +3,5 @@ export enum ViewType { KANBAN = 'KANBAN', CALENDAR = 'CALENDAR', FIELDS_WIDGET = 'FIELDS_WIDGET', + TABLE_WIDGET = 'TABLE_WIDGET', }