From 963f2de8643f693cf28d0413d5c4fabcbeeb3001 Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Tue, 17 Feb 2026 16:26:28 +0100 Subject: [PATCH] Translate page layout tab title (#17975) > [!NOTE] > The improvement will only fully work once all tabs get translated. ## When using the front-end mocks https://github.com/user-attachments/assets/cf7dc0fb-9438-4e18-841e-47558ff71474 ## When loading page layout information from database https://github.com/user-attachments/assets/d2c9d98b-97e2-4629-aa6c-53f3f3713733 ## When editing dashboard https://github.com/user-attachments/assets/c6ae3a7a-f05f-48ea-8b33-8f689e3f71f7 Closes https://github.com/twentyhq/twenty/issues/17950#issuecomment-3902782952 --- .../src/generated-metadata/graphql.ts | 13 ++- .../fragments/pageLayoutTabFragment.ts | 1 + .../components/PageLayoutTabList.tsx | 14 ++- .../__stories__/PageLayoutTabList.stories.tsx | 4 + .../DefaultCompanyRecordPageLayout.ts | 7 ++ .../constants/DefaultNoteRecordPageLayout.ts | 4 + .../DefaultOpportunityRecordPageLayout.ts | 7 ++ .../DefaultPersonRecordPageLayout.ts | 7 ++ .../constants/DefaultRecordPageLayout.ts | 5 + .../constants/DefaultTaskRecordPageLayout.ts | 4 + .../constants/DefaultWorkflowPageLayout.ts | 1 + .../constants/DefaultWorkflowRunPageLayout.ts | 2 + .../DefaultWorkflowVersionPageLayout.ts | 2 + .../StandardPageLayoutTabTitleTranslations.ts | 22 ++++ .../updatePageLayoutWithTabsAndWidgets.ts | 1 + .../useCreatePageLayoutGraphWidget.test.tsx | 4 +- .../__tests__/useCreatePageLayoutTab.test.tsx | 3 +- .../usePageLayoutDraftState.test.tsx | 5 +- .../usePageLayoutWithRelationWidgets.test.tsx | 1 + .../hooks/useCreatePageLayoutTab.ts | 9 +- .../hooks/useIsCurrentObjectCustom.ts | 25 ++++ .../utils/__tests__/addWidgetToTab.test.ts | 2 + .../convertPageLayoutToTabLayouts.test.ts | 2 + ...ageLayoutTabListInitialActiveTabId.test.ts | 1 + .../__tests__/getTabsByDisplayMode.test.ts | 1 + .../getTabsWithVisibleWidgets.test.ts | 1 + .../__tests__/removeWidgetFromTab.test.ts | 6 +- .../__stories__/WidgetRenderer.stories.tsx | 4 + .../__stories__/FieldWidget.stories.tsx | 4 +- .../standard-page-layout-tab-titles.ts | 17 +++ .../dtos/page-layout-tab.dto.ts | 3 + .../resolvers/page-layout-tab.resolver.ts | 33 +++++- ...resolve-page-layout-tab-title.util.spec.ts | 110 ++++++++++++++++++ .../resolve-page-layout-tab-title.util.ts | 27 +++++ 34 files changed, 332 insertions(+), 20 deletions(-) create mode 100644 packages/twenty-front/src/modules/page-layout/constants/StandardPageLayoutTabTitleTranslations.ts create mode 100644 packages/twenty-front/src/modules/page-layout/hooks/useIsCurrentObjectCustom.ts create mode 100644 packages/twenty-server/src/engine/metadata-modules/page-layout-tab/constants/standard-page-layout-tab-titles.ts create mode 100644 packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/__tests__/resolve-page-layout-tab-title.util.spec.ts create mode 100644 packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index a989d0a24a..7e6f558754 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -3427,6 +3427,7 @@ export type PageLayout = { export type PageLayoutTab = { __typename?: 'PageLayoutTab'; + applicationId: Scalars['UUID']; createdAt: Scalars['DateTime']; deletedAt?: Maybe; icon?: Maybe; @@ -5695,9 +5696,9 @@ export type FindManyCommandMenuItemsQueryVariables = Exact<{ [key: string]: neve export type FindManyCommandMenuItemsQuery = { __typename?: 'Query', commandMenuItems: Array<{ __typename?: 'CommandMenuItem', id: string, workflowVersionId?: string | null, frontComponentId?: string | null, label: string, icon?: string | null, isPinned: boolean, availabilityType: CommandMenuItemAvailabilityType, availabilityObjectMetadataId?: string | null, frontComponent?: { __typename?: 'FrontComponent', id: string, name: string } | null }> }; -export type PageLayoutFragmentFragment = { __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null }; +export type PageLayoutFragmentFragment = { __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, applicationId: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null }; -export type PageLayoutTabFragmentFragment = { __typename?: 'PageLayoutTab', id: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }; +export type PageLayoutTabFragmentFragment = { __typename?: 'PageLayoutTab', id: string, applicationId: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }; export type DuplicateDashboardMutationVariables = Exact<{ id: Scalars['UUID']; @@ -5711,7 +5712,7 @@ export type FindOnePageLayoutQueryVariables = Exact<{ }>; -export type FindOnePageLayoutQuery = { __typename?: 'Query', getPageLayout?: { __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } | null }; +export type FindOnePageLayoutQuery = { __typename?: 'Query', getPageLayout?: { __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, applicationId: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } | null }; export type CreateFileMutationVariables = Exact<{ file: Scalars['Upload']; @@ -5916,12 +5917,12 @@ export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ }>; -export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: string, name: string, type: PageLayoutType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, title: string, position: number, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } }; +export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: string, name: string, type: PageLayoutType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, applicationId: string, title: string, position: number, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null } }; export type FindAllRecordPageLayoutsQueryVariables = Exact<{ [key: string]: never; }>; -export type FindAllRecordPageLayoutsQuery = { __typename?: 'Query', getPageLayouts: Array<{ __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null }> }; +export type FindAllRecordPageLayoutsQuery = { __typename?: 'Query', getPageLayouts: Array<{ __typename?: 'PageLayout', id: string, name: string, objectMetadataId?: string | null, type: PageLayoutType, defaultTabToFocusOnMobileAndSidePanelId?: string | null, createdAt: string, updatedAt: string, tabs?: Array<{ __typename?: 'PageLayoutTab', id: string, applicationId: string, title: string, icon?: string | null, position: number, layoutMode?: PageLayoutTabLayoutMode | null, pageLayoutId: string, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: string, title: string, type: WidgetType, objectMetadataId?: string | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: string, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, position?: { __typename?: 'PageLayoutWidgetCanvasPosition', layoutMode: PageLayoutTabLayoutMode } | { __typename?: 'PageLayoutWidgetGridPosition', layoutMode: PageLayoutTabLayoutMode, row: number, column: number, rowSpan: number, columnSpan: number } | { __typename?: 'PageLayoutWidgetVerticalListPosition', layoutMode: PageLayoutTabLayoutMode, index: number } | null, configuration: { __typename?: 'AggregateChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, prefix?: string | null, suffix?: string | null, timezone?: string | null, firstDayOfTheWeek?: number | null, ratioAggregateConfig?: { __typename?: 'RatioAggregateConfig', fieldMetadataId: string, optionValue: string } | null } | { __typename?: 'BarChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null, layout: BarChartLayout, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'CalendarConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'EmailsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldRichTextConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FieldsConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FilesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'FrontComponentConfiguration', configurationType: WidgetConfigurationType, frontComponentId: string } | { __typename?: 'GaugeChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', configurationType: WidgetConfigurationType, url?: string | null } | { __typename?: 'LineChartConfiguration', configurationType: WidgetConfigurationType, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: string, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, primaryAxisManualSortOrder?: Array | null, secondaryAxisGroupByFieldMetadataId?: string | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisManualSortOrder?: Array | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, isStacked?: boolean | null, isCumulative?: boolean | null, splitMultiValueFields?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'NotesConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'PieChartConfiguration', configurationType: WidgetConfigurationType, groupByFieldMetadataId: string, aggregateFieldMetadataId: string, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, manualSortOrder?: Array | null, displayDataLabel?: boolean | null, showCenterMetric?: boolean | null, displayLegend?: boolean | null, hideEmptyCategory?: boolean | null, splitMultiValueFields?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'StandaloneRichTextConfiguration', configurationType: WidgetConfigurationType, body: { __typename?: 'RichTextV2Body', blocknote?: string | null, markdown?: string | null } } | { __typename?: 'TasksConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'TimelineConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'ViewConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowRunConfiguration', configurationType: WidgetConfigurationType } | { __typename?: 'WorkflowVersionConfiguration', configurationType: WidgetConfigurationType } }> | null }> | null }> }; export type BarChartDataQueryVariables = Exact<{ input: BarChartDataInput; @@ -7208,6 +7209,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` export const PageLayoutTabFragmentFragmentDoc = gql` fragment PageLayoutTabFragment on PageLayoutTab { id + applicationId title icon position @@ -11406,6 +11408,7 @@ export const UpdatePageLayoutWithTabsAndWidgetsDocument = gql` deletedAt tabs { id + applicationId title position pageLayoutId diff --git a/packages/twenty-front/src/modules/dashboards/graphql/fragments/pageLayoutTabFragment.ts b/packages/twenty-front/src/modules/dashboards/graphql/fragments/pageLayoutTabFragment.ts index 5f2d809ce0..62712f7432 100644 --- a/packages/twenty-front/src/modules/dashboards/graphql/fragments/pageLayoutTabFragment.ts +++ b/packages/twenty-front/src/modules/dashboards/graphql/fragments/pageLayoutTabFragment.ts @@ -5,6 +5,7 @@ export const PAGE_LAYOUT_TAB_FRAGMENT = gql` ${PAGE_LAYOUT_WIDGET_FRAGMENT} fragment PageLayoutTabFragment on PageLayoutTab { id + applicationId title icon position diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx index 977e636a43..a6fc8a6532 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx @@ -7,6 +7,7 @@ import { type OnDragUpdateResponder, type ResponderProvided, } from '@hello-pangea/dnd'; +import { useLingui } from '@lingui/react/macro'; import { useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { IconPlus, useIcons } from 'twenty-ui/display'; @@ -32,6 +33,8 @@ import { PAGE_LAYOUT_TAB_LIST_DROPPABLE_IDS } from '@/page-layout/components/Pag import { PageLayoutTabListReorderableOverflowDropdown } from '@/page-layout/components/PageLayoutTabListReorderableOverflowDropdown'; import { PageLayoutTabListStaticOverflowDropdown } from '@/page-layout/components/PageLayoutTabListStaticOverflowDropdown'; import { PageLayoutTabListVisibleTabs } from '@/page-layout/components/PageLayoutTabListVisibleTabs'; +import { STANDARD_PAGE_LAYOUT_TAB_TITLE_TRANSLATIONS } from '@/page-layout/constants/StandardPageLayoutTabTitleTranslations'; +import { useIsCurrentObjectCustom } from '@/page-layout/hooks/useIsCurrentObjectCustom'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { pageLayoutTabListCurrentDragDroppableIdComponentState } from '@/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState'; @@ -94,10 +97,19 @@ export const PageLayoutTabList = ({ pageLayoutType, }: PageLayoutTabListProps) => { const { getIcon } = useIcons(); + const { t } = useLingui(); + const { isCustom } = useIsCurrentObjectCustom(); + + const shouldTranslateTabTitles = !isCustom; const tabsWithIcons: SingleTabProps[] = tabs.map((tab) => ({ id: tab.id, - title: tab.title, + // TODO: drop once the configuration of all record page layouts has been migrated to the backend. + title: + shouldTranslateTabTitles && + STANDARD_PAGE_LAYOUT_TAB_TITLE_TRANSLATIONS[tab.title] + ? t(STANDARD_PAGE_LAYOUT_TAB_TITLE_TRANSLATIONS[tab.title]) + : tab.title, Icon: tab.icon ? getIcon(tab.icon) : undefined, })); diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx index 2369727144..899f78ea8c 100644 --- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx @@ -22,6 +22,7 @@ const StyledContainer = styled.div` const createInitialTabs = (): PageLayoutTab[] => [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'overview', title: 'Overview', position: 0, @@ -34,6 +35,7 @@ const createInitialTabs = (): PageLayoutTab[] => [ }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'revenue', title: 'Revenue', position: 1, @@ -45,6 +47,7 @@ const createInitialTabs = (): PageLayoutTab[] => [ }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'forecasts', title: 'Forecasts', position: 2, @@ -73,6 +76,7 @@ const PageLayoutTabListPlayground = ({ ...prev, { __typename: 'PageLayoutTab', + applicationId: '', id: `new-tab-${nextIndex}`, title: `New Tab ${nextIndex}`, position: nextIndex, diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultCompanyRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultCompanyRecordPageLayout.ts index ffbc66ecaf..4791360476 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultCompanyRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultCompanyRecordPageLayout.ts @@ -19,6 +19,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-fields', title: 'Home', icon: 'IconHome', @@ -56,6 +57,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -93,6 +95,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-tasks', title: 'Tasks', icon: 'IconCheckbox', @@ -130,6 +133,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-notes', title: 'Notes', icon: 'IconNotes', @@ -167,6 +171,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-files', title: 'Files', icon: 'IconPaperclip', @@ -204,6 +209,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-emails', title: 'Emails', icon: 'IconMail', @@ -241,6 +247,7 @@ export const DEFAULT_COMPANY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'company-tab-calendar', title: 'Calendar', icon: 'IconCalendarEvent', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultNoteRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultNoteRecordPageLayout.ts index 61e053a4d9..fc49726a88 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultNoteRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultNoteRecordPageLayout.ts @@ -18,6 +18,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'note-tab-fields', title: 'Home', icon: 'IconHome', @@ -88,6 +89,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'note-tab-note', title: 'Note', icon: 'IconNotes', @@ -132,6 +134,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'note-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -169,6 +172,7 @@ export const DEFAULT_NOTE_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'note-tab-files', title: 'Files', icon: 'IconPaperclip', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultOpportunityRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultOpportunityRecordPageLayout.ts index e38835c783..3437dfffb1 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultOpportunityRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultOpportunityRecordPageLayout.ts @@ -19,6 +19,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-fields', title: 'Home', icon: 'IconHome', @@ -56,6 +57,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -93,6 +95,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-tasks', title: 'Tasks', icon: 'IconCheckbox', @@ -130,6 +133,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-notes', title: 'Notes', icon: 'IconNotes', @@ -167,6 +171,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-files', title: 'Files', icon: 'IconPaperclip', @@ -204,6 +209,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-emails', title: 'Emails', icon: 'IconMail', @@ -241,6 +247,7 @@ export const DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'opportunity-tab-calendar', title: 'Calendar', icon: 'IconCalendarEvent', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultPersonRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultPersonRecordPageLayout.ts index 5c54d33c9a..defdfa7812 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultPersonRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultPersonRecordPageLayout.ts @@ -18,6 +18,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-fields', title: 'Home', icon: 'IconHome', @@ -55,6 +56,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -92,6 +94,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-tasks', title: 'Tasks', icon: 'IconCheckbox', @@ -129,6 +132,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-notes', title: 'Notes', icon: 'IconNotes', @@ -166,6 +170,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-files', title: 'Files', icon: 'IconPaperclip', @@ -203,6 +208,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-emails', title: 'Emails', icon: 'IconMail', @@ -240,6 +246,7 @@ export const DEFAULT_PERSON_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'person-tab-calendar', title: 'Calendar', icon: 'IconCalendarEvent', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultRecordPageLayout.ts index 15ac70d081..a9f84e73ad 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultRecordPageLayout.ts @@ -18,6 +18,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'default-tab-fields', title: 'Home', icon: 'IconHome', @@ -55,6 +56,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'default-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -92,6 +94,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'default-tab-tasks', title: 'Tasks', icon: 'IconCheckbox', @@ -129,6 +132,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'default-tab-notes', title: 'Notes', icon: 'IconNotes', @@ -166,6 +170,7 @@ export const DEFAULT_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'default-tab-files', title: 'Files', icon: 'IconPaperclip', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultTaskRecordPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultTaskRecordPageLayout.ts index fbeb3a95b9..1426ad61d4 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultTaskRecordPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultTaskRecordPageLayout.ts @@ -18,6 +18,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'task-tab-fields', title: 'Home', icon: 'IconHome', @@ -85,6 +86,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'task-tab-note', title: 'Note', icon: 'IconNotes', @@ -129,6 +131,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'task-tab-timeline', title: 'Timeline', icon: 'IconTimelineEvent', @@ -166,6 +169,7 @@ export const DEFAULT_TASK_RECORD_PAGE_LAYOUT: PageLayout = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'task-tab-files', title: 'Files', icon: 'IconPaperclip', diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowPageLayout.ts index 6214e7f6c4..219aadd800 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowPageLayout.ts @@ -23,6 +23,7 @@ export const DEFAULT_WORKFLOW_PAGE_LAYOUT: PageLayout = { // Flow tab (position 100) { __typename: 'PageLayoutTab', + applicationId: '', id: 'workflow-tab-flow', title: 'Flow', position: 100, diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowRunPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowRunPageLayout.ts index a2a185e8b3..78b33ec78f 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowRunPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowRunPageLayout.ts @@ -24,6 +24,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = { // Fields tab (position 100) { __typename: 'PageLayoutTab', + applicationId: '', id: 'workflow-run-tab-fields', title: 'Home', position: 100, @@ -62,6 +63,7 @@ export const DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT: PageLayout = { // Flow tab (position 200) { __typename: 'PageLayoutTab', + applicationId: '', id: 'workflow-run-tab-flow', title: 'Flow', position: 200, diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowVersionPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowVersionPageLayout.ts index f9b3b2caf4..38dea76f35 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowVersionPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultWorkflowVersionPageLayout.ts @@ -24,6 +24,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = { // Fields tab (position 100) { __typename: 'PageLayoutTab', + applicationId: '', id: 'workflow-version-tab-fields', title: 'Home', icon: 'IconHome', @@ -62,6 +63,7 @@ export const DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT: PageLayout = { // Flow tab (position 200) { __typename: 'PageLayoutTab', + applicationId: '', id: 'workflow-version-tab-flow', title: 'Flow', icon: 'IconSettings', diff --git a/packages/twenty-front/src/modules/page-layout/constants/StandardPageLayoutTabTitleTranslations.ts b/packages/twenty-front/src/modules/page-layout/constants/StandardPageLayoutTabTitleTranslations.ts new file mode 100644 index 0000000000..0bd87c6dd2 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/constants/StandardPageLayoutTabTitleTranslations.ts @@ -0,0 +1,22 @@ +import { msg, type MacroMessageDescriptor } from '@lingui/core/macro'; + +// Translation map for standard page layout tab titles. +// When the backend hasn't translated the tab title (e.g. when using +// frontend fallback layouts), this map is used to translate known +// standard tab titles at the rendering point. +// Custom/user-created tab titles that are not in this map will be +// displayed as-is. +export const STANDARD_PAGE_LAYOUT_TAB_TITLE_TRANSLATIONS: Record< + string, + MacroMessageDescriptor +> = { + Home: msg`Home`, + Timeline: msg`Timeline`, + Tasks: msg`Tasks`, + Notes: msg`Notes`, + Files: msg`Files`, + Emails: msg`Emails`, + Calendar: msg`Calendar`, + Note: msg`Note`, + Flow: msg`Flow`, +}; diff --git a/packages/twenty-front/src/modules/page-layout/graphql/mutations/updatePageLayoutWithTabsAndWidgets.ts b/packages/twenty-front/src/modules/page-layout/graphql/mutations/updatePageLayoutWithTabsAndWidgets.ts index 71b82fac5c..fe0df680a8 100644 --- a/packages/twenty-front/src/modules/page-layout/graphql/mutations/updatePageLayoutWithTabsAndWidgets.ts +++ b/packages/twenty-front/src/modules/page-layout/graphql/mutations/updatePageLayoutWithTabsAndWidgets.ts @@ -18,6 +18,7 @@ export const UPDATE_PAGE_LAYOUT_WITH_TABS_AND_WIDGETS = gql` deletedAt tabs { id + applicationId title position pageLayoutId diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx index f1211f5e9d..c3fbb3b36d 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx @@ -9,9 +9,9 @@ import { act, renderHook } from '@testing-library/react'; import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { - WidgetType, PageLayoutType, WidgetConfigurationType, + WidgetType, } from '~/generated-metadata/graphql'; import { PAGE_LAYOUT_TEST_INSTANCE_ID, @@ -73,6 +73,7 @@ describe('useCreatePageLayoutGraphWidget', () => { tabs: [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: '', @@ -152,6 +153,7 @@ describe('useCreatePageLayoutGraphWidget', () => { tabs: [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: '', diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx index a83ec557a9..ca4ad4a7d9 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx @@ -1,3 +1,4 @@ +import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; @@ -6,7 +7,6 @@ import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state import { act, renderHook } from '@testing-library/react'; import { useSetRecoilState } from 'recoil'; import { PageLayoutType } from '~/generated-metadata/graphql'; -import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab'; import { PAGE_LAYOUT_TEST_INSTANCE_ID, PageLayoutTestWrapper, @@ -228,6 +228,7 @@ describe('useCreatePageLayoutTab', () => { tabs: [ { id: 'existing-tab', + applicationId: '', title: 'Existing Tab', position: 0, pageLayoutId: 'test-layout', diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutDraftState.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutDraftState.test.tsx index d6a6fee810..e8dee6b1de 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutDraftState.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutDraftState.test.tsx @@ -1,12 +1,12 @@ import { usePageLayoutDraftState } from '@/page-layout/hooks/usePageLayoutDraftState'; import { act, renderHook } from '@testing-library/react'; import { - GraphOrderBy, - WidgetType, AggregateOperations, BarChartLayout, + GraphOrderBy, PageLayoutType, WidgetConfigurationType, + WidgetType, } from '~/generated-metadata/graphql'; import { PAGE_LAYOUT_TEST_INSTANCE_ID, @@ -88,6 +88,7 @@ describe('usePageLayoutDraftState', () => { tabs: [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: '', diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx index 8b15f21420..1690b5858f 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx @@ -32,6 +32,7 @@ describe('usePageLayoutWithRelationWidgets', () => { tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'tab-1', title: 'Fields', icon: 'IconList', diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts index 17b1ab822b..fd9babe43a 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts @@ -1,4 +1,8 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; +import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; +import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; +import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; +import { getEmptyTabLayout } from '@/page-layout/utils/getEmptyTabLayout'; import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; @@ -6,10 +10,6 @@ import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component- import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useRecoilCallback } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; -import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; -import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; -import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; -import { getEmptyTabLayout } from '@/page-layout/utils/getEmptyTabLayout'; export const useCreatePageLayoutTab = (pageLayoutIdFromProps?: string) => { const pageLayoutId = useAvailableComponentInstanceIdOrThrow( @@ -48,6 +48,7 @@ export const useCreatePageLayoutTab = (pageLayoutIdFromProps?: string) => { : -1; const newTab: PageLayoutTab = { id: newTabId, + applicationId: '', title: title || `Tab ${tabsLength + 1}`, position: maxPosition + 1, pageLayoutId: pageLayoutId, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useIsCurrentObjectCustom.ts b/packages/twenty-front/src/modules/page-layout/hooks/useIsCurrentObjectCustom.ts new file mode 100644 index 0000000000..01f74ea161 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/hooks/useIsCurrentObjectCustom.ts @@ -0,0 +1,25 @@ +import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; +import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; +import { useRecoilValue } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +export const useIsCurrentObjectCustom = () => { + const { targetRecordIdentifier } = useLayoutRenderingContext(); + + const objectMetadataItem = useRecoilValue( + objectMetadataItemFamilySelector({ + objectName: targetRecordIdentifier?.targetObjectNameSingular ?? '', + objectNameType: 'singular', + }), + ); + + if (!isDefined(targetRecordIdentifier)) { + return { isCustom: true }; + } + + if (!isDefined(objectMetadataItem)) { + return { isCustom: true }; + } + + return { isCustom: objectMetadataItem.isCustom }; +}; diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/addWidgetToTab.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/addWidgetToTab.test.ts index adfb92981e..ed31017c95 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/addWidgetToTab.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/addWidgetToTab.test.ts @@ -30,6 +30,7 @@ describe('addWidgetToTab', () => { const mockTabs: PageLayoutTab[] = [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: 'layout-1', @@ -40,6 +41,7 @@ describe('addWidgetToTab', () => { }, { id: 'tab-2', + applicationId: '', title: 'Tab 2', position: 1, pageLayoutId: 'layout-1', diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutToTabLayouts.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutToTabLayouts.test.ts index fa3efd0bda..76904761b6 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutToTabLayouts.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutToTabLayouts.test.ts @@ -19,6 +19,7 @@ describe('convertPageLayoutToTabLayouts', () => { tabs: [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: 'page-layout-1', @@ -97,6 +98,7 @@ describe('convertPageLayoutToTabLayouts', () => { tabs: [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: 'page-layout-1', diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getPageLayoutTabListInitialActiveTabId.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getPageLayoutTabListInitialActiveTabId.test.ts index a61494ced5..2b478ef292 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getPageLayoutTabListInitialActiveTabId.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getPageLayoutTabListInitialActiveTabId.test.ts @@ -4,6 +4,7 @@ import { getPageLayoutTabListInitialActiveTabId } from '@/page-layout/utils/getP describe('getPageLayoutTabListInitialActiveTabId', () => { const createMockTab = (id: string): PageLayoutTab => ({ id, + applicationId: '', pageLayoutId: 'page-layout-1', title: `Tab ${id}`, position: 0, diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsByDisplayMode.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsByDisplayMode.test.ts index 50d242972c..242e686636 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsByDisplayMode.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsByDisplayMode.test.ts @@ -9,6 +9,7 @@ import { describe('getTabsByDisplayMode', () => { const createMockTab = (id: string): PageLayoutTab => ({ id, + applicationId: '', pageLayoutId: 'page-layout-1', title: `Tab ${id}`, position: 0, diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsWithVisibleWidgets.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsWithVisibleWidgets.test.ts index a3a2908aa5..b43eac6f20 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsWithVisibleWidgets.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabsWithVisibleWidgets.test.ts @@ -36,6 +36,7 @@ describe('getTabsWithVisibleWidgets', () => { widgets: PageLayoutTab['widgets'], ): PageLayoutTab => ({ __typename: 'PageLayoutTab', + applicationId: '', id, pageLayoutId: 'page-layout-1', title: `Tab ${id}`, diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/removeWidgetFromTab.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/removeWidgetFromTab.test.ts index be70a5d79f..c13f0cc51e 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/removeWidgetFromTab.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/removeWidgetFromTab.test.ts @@ -1,16 +1,17 @@ +import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; +import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab'; import { AggregateOperations, GraphOrderBy, WidgetConfigurationType, WidgetType, } from '~/generated-metadata/graphql'; -import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; -import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab'; describe('removeWidgetFromTab', () => { const mockTabs: PageLayoutTab[] = [ { id: 'tab-1', + applicationId: '', title: 'Tab 1', position: 0, pageLayoutId: 'layout-1', @@ -60,6 +61,7 @@ describe('removeWidgetFromTab', () => { }, { id: 'tab-2', + applicationId: '', title: 'Tab 2', position: 1, pageLayoutId: 'layout-1', diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx index 41ff028b7b..924d71328f 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx @@ -145,6 +145,7 @@ const createPageLayoutWithWidget = ( tabs: [ { __typename: 'PageLayoutTab', + applicationId: '', id: TAB_ID_OVERVIEW, title: 'Overview', position: 0, @@ -1699,6 +1700,7 @@ export const Catalog: CatalogStory = { ? [ { __typename: 'PageLayoutTab', + applicationId: '', id: 'pinned-tab', title: 'Pinned Tab', position: 0, @@ -1710,6 +1712,7 @@ export const Catalog: CatalogStory = { }, { __typename: 'PageLayoutTab', + applicationId: '', id: 'other-tab', title: 'Other Tab', position: 1, @@ -1723,6 +1726,7 @@ export const Catalog: CatalogStory = { : [ { __typename: 'PageLayoutTab', + applicationId: '', id: TAB_ID_OVERVIEW, title: 'Overview', position: 0, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx index c8709499c5..b1f8770e20 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx @@ -22,6 +22,7 @@ import { } from '@/page-layout/hooks/__tests__/PageLayoutTestWrapper'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; +import { type PageLayout } from '@/page-layout/types/PageLayout'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { FieldWidget } from '@/page-layout/widgets/field/components/FieldWidget'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; @@ -291,7 +292,7 @@ const TAB_ID_OVERVIEW = 'tab-overview'; const createPageLayoutWithWidget = ( widget: PageLayoutWidget, objectMetadataId: string, -) => ({ +): PageLayout => ({ id: PAGE_LAYOUT_TEST_INSTANCE_ID, name: 'Mock Page Layout', type: PageLayoutType.RECORD_PAGE, @@ -299,6 +300,7 @@ const createPageLayoutWithWidget = ( tabs: [ { __typename: 'PageLayoutTab' as const, + applicationId: '', id: TAB_ID_OVERVIEW, title: 'Overview', position: 0, diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/constants/standard-page-layout-tab-titles.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/constants/standard-page-layout-tab-titles.ts new file mode 100644 index 0000000000..b6943caedb --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/constants/standard-page-layout-tab-titles.ts @@ -0,0 +1,17 @@ +import { t } from '@lingui/core/macro'; + +// This file exists solely for Lingui string extraction. +// The strings defined here correspond to standard page layout tab titles +// so they appear in the .po catalogs and can be translated at resolve time +// via generateMessageId hash lookups. +export const getStandardPageLayoutTabTitles = () => [ + t`Home`, + t`Timeline`, + t`Tasks`, + t`Notes`, + t`Files`, + t`Emails`, + t`Calendar`, + t`Note`, + t`Flow`, +]; diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto.ts index af8ffd6ff2..1ce7573176 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto.ts @@ -15,6 +15,9 @@ export class PageLayoutTabDTO { @IDField(() => UUIDScalarType) id: string; + @Field(() => UUIDScalarType, { nullable: false }) + applicationId: string; + @Field({ nullable: false }) title: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/resolvers/page-layout-tab.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/resolvers/page-layout-tab.resolver.ts index 0c00263baa..c7381058cc 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/resolvers/page-layout-tab.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/resolvers/page-layout-tab.resolver.ts @@ -4,14 +4,23 @@ import { UseInterceptors, UsePipes, } from '@nestjs/common'; -import { Args, Mutation, Query } from '@nestjs/graphql'; +import { + Args, + Context, + Mutation, + Parent, + Query, + ResolveField, +} from '@nestjs/graphql'; import { PermissionFlagType } from 'twenty-shared/constants'; +import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator'; import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe'; +import { I18nService } from 'src/engine/core-modules/i18n/i18n.service'; +import { type I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type'; import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; -import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator'; import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; @@ -19,6 +28,7 @@ import { CreatePageLayoutTabInput } from 'src/engine/metadata-modules/page-layou import { UpdatePageLayoutTabInput } from 'src/engine/metadata-modules/page-layout-tab/dtos/inputs/update-page-layout-tab.input'; import { PageLayoutTabDTO } from 'src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto'; import { PageLayoutTabService } from 'src/engine/metadata-modules/page-layout-tab/services/page-layout-tab.service'; +import { resolvePageLayoutTabTitle } from 'src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util'; import { PageLayoutGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/page-layout/utils/page-layout-graphql-api-exception.filter'; import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor'; @@ -28,7 +38,24 @@ import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/wor @UseGuards(WorkspaceAuthGuard) @UsePipes(ResolverValidationPipe) export class PageLayoutTabResolver { - constructor(private readonly pageLayoutTabService: PageLayoutTabService) {} + constructor( + private readonly pageLayoutTabService: PageLayoutTabService, + private readonly i18nService: I18nService, + ) {} + + @ResolveField(() => String) + async title( + @Parent() tab: PageLayoutTabDTO, + @Context() context: I18nContext, + ): Promise { + const i18n = this.i18nService.getI18nInstance(context.req.locale); + + return resolvePageLayoutTabTitle({ + title: tab.title, + applicationId: tab.applicationId, + i18nInstance: i18n, + }); + } @Query(() => [PageLayoutTabDTO]) @UseGuards(NoPermissionGuard) diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/__tests__/resolve-page-layout-tab-title.util.spec.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/__tests__/resolve-page-layout-tab-title.util.spec.ts new file mode 100644 index 0000000000..7406a3f4d9 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/__tests__/resolve-page-layout-tab-title.util.spec.ts @@ -0,0 +1,110 @@ +import { type I18n } from '@lingui/core'; + +import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId'; +import { resolvePageLayoutTabTitle } from 'src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; + +jest.mock('src/engine/core-modules/i18n/utils/generateMessageId'); + +const mockGenerateMessageId = generateMessageId as jest.MockedFunction< + typeof generateMessageId +>; + +describe('resolvePageLayoutTabTitle', () => { + let mockI18n: jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + mockI18n = { + _: jest.fn(), + } as unknown as jest.Mocked; + }); + + it('should return translated title when catalog has a match', () => { + mockGenerateMessageId.mockReturnValue('abc123'); + mockI18n._.mockReturnValue('Accueil'); + + const result = resolvePageLayoutTabTitle({ + title: 'Home', + applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier, + i18nInstance: mockI18n, + }); + + expect(mockGenerateMessageId).toHaveBeenCalledWith('Home'); + expect(mockI18n._).toHaveBeenCalledWith('abc123'); + expect(result).toBe('Accueil'); + }); + + it('should return original title when catalog returns the hash (no translation found)', () => { + mockGenerateMessageId.mockReturnValue('xyz789'); + mockI18n._.mockReturnValue('xyz789'); + + const result = resolvePageLayoutTabTitle({ + title: 'My Custom Tab', + applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier, + i18nInstance: mockI18n, + }); + + expect(mockGenerateMessageId).toHaveBeenCalledWith('My Custom Tab'); + expect(mockI18n._).toHaveBeenCalledWith('xyz789'); + expect(result).toBe('My Custom Tab'); + }); + + it('should return original title for empty string', () => { + mockGenerateMessageId.mockReturnValue('empty-hash'); + mockI18n._.mockReturnValue('empty-hash'); + + const result = resolvePageLayoutTabTitle({ + title: '', + applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier, + i18nInstance: mockI18n, + }); + + expect(result).toBe(''); + }); + + it('should translate standard tab titles', () => { + const standardTabs = [ + { source: 'Home', translated: 'Accueil' }, + { source: 'Timeline', translated: 'Chronologie' }, + { source: 'Tasks', translated: 'Tâches' }, + { source: 'Notes', translated: 'Notes' }, + { source: 'Files', translated: 'Fichiers' }, + { source: 'Emails', translated: 'E-mails' }, + { source: 'Calendar', translated: 'Calendrier' }, + { source: 'Note', translated: 'Note' }, + { source: 'Flow', translated: 'Flux' }, + ]; + + standardTabs.forEach(({ source, translated }) => { + jest.clearAllMocks(); + mockGenerateMessageId.mockReturnValue(`hash-${source}`); + mockI18n._.mockReturnValue(translated); + + const result = resolvePageLayoutTabTitle({ + title: source, + applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier, + i18nInstance: mockI18n, + }); + + expect(result).toBe(translated); + }); + }); + + it('should not translate title when applicationId is not from standard app', () => { + mockGenerateMessageId.mockReturnValue('abc123'); + mockI18n._.mockReturnValue('Accueil'); + + const customAppId = '11111111-1111-1111-1111-111111111111'; + + const result = resolvePageLayoutTabTitle({ + title: 'Home', + applicationId: customAppId, + i18nInstance: mockI18n, + }); + + expect(mockGenerateMessageId).not.toHaveBeenCalled(); + expect(mockI18n._).not.toHaveBeenCalled(); + expect(result).toBe('Home'); + }); +}); diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util.ts new file mode 100644 index 0000000000..61f2ed2d2f --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util.ts @@ -0,0 +1,27 @@ +import { type I18n } from '@lingui/core'; + +import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; + +export const resolvePageLayoutTabTitle = ({ + title, + applicationId, + i18nInstance, +}: { + title: string; + applicationId: string; + i18nInstance: I18n; +}): string => { + if (applicationId !== TWENTY_STANDARD_APPLICATION.universalIdentifier) { + return title; + } + + const messageId = generateMessageId(title); + const translatedMessage = i18nInstance._(messageId); + + if (translatedMessage === messageId) { + return title; + } + + return translatedMessage; +};