From f301f07e43b51313b26ad2e1f2b3f8322d45a986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:48:42 +0200 Subject: [PATCH] Convert number chart to aggregate chart allowing date aggregates (#15294) - Convert number chart to aggregate chart - Allow date aggregates on all charts - Only allow `EARLIEST` and `LATEST` on Aggregate chart and Gauge chart - Various design fixes https://github.com/user-attachments/assets/b5a2239d-7b11-48b5-93e6-98ceffae5cab --- .../src/generated-metadata/graphql.ts | 28 ++++++------ .../twenty-front/src/generated/graphql.ts | 34 +++++++-------- .../page-layout/components/ChartSettings.tsx | 43 ++++++++++++++++--- .../components/ChartTypeSelectionSection.tsx | 2 +- ...egateOperationSelectionDropdownContent.tsx | 22 ++++++++-- ...onForAggregateOperationDropdownContent.tsx | 10 +---- ...tSettings.ts => AggregateChartSettings.ts} | 2 +- .../constants/GraphTypeInformation.ts | 16 +++---- .../constants/GraphTypeToConfigTypename.ts | 2 +- .../settings/DataDisplayAggregateSetting.ts | 4 +- .../hooks/useChartSettingsValues.ts | 11 +++-- .../page-layout/types/ChartConfiguration.ts | 4 +- .../types/ChartWidgetConfiguration.ts | 4 +- .../PageLayoutRenderer.stories.tsx | 4 +- .../page-layout/constants/WidgetSizes.ts | 2 +- .../fragments/pageLayoutWidgetFragment.ts | 2 +- .../useCreatePageLayoutGraphWidget.test.tsx | 6 +-- .../utils/__tests__/addWidgetToTab.test.ts | 2 +- .../__tests__/convertLayoutsToWidgets.test.ts | 2 +- .../convertPageLayoutToTabLayouts.test.ts | 2 +- .../extractFieldMetadataIdsFromWidget.test.ts | 6 +-- .../__tests__/removeWidgetFromTab.test.ts | 2 +- .../utils/createDefaultGraphWidget.ts | 6 +-- .../extractFieldMetadataIdsFromWidget.ts | 2 +- .../page-layout/utils/getDefaultWidgetData.ts | 2 +- .../page-layout/utils/getWidgetTitle.ts | 2 +- .../__stories__/WidgetRenderer.stories.tsx | 12 +++--- .../widgets/graph/components/GraphWidget.tsx | 6 +-- ... => GraphWidgetAggregateChart.stories.tsx} | 10 ++--- .../components/GraphWidgetAggregateChart.tsx} | 9 ++-- .../GraphWidgetAggregateChartRenderer.tsx} | 14 +++--- .../utils/formatNumberChartTrend.ts | 0 .../hooks/useGraphWidgetAggregateQuery.ts | 20 +++++---- .../graph/hooks/useGraphWidgetQueryCommon.ts | 4 +- ...reChartConfigurationFieldsValidForQuery.ts | 2 +- ...s => aggregate-chart-configuration.dto.ts} | 6 +-- .../dtos/widget-configuration.interface.ts | 10 ++--- .../page-layout/enums/graph-type.enum.ts | 2 +- ...and-transform-widget-configuration.util.ts | 6 +-- .../get-page-layout-widget-data-seeds.util.ts | 16 +++---- .../page-layout-gql-fields.constants.ts | 2 +- ...idget-configuration-test-data.constants.ts | 12 +++--- .../display/icon/components/TablerIcons.ts | 1 + packages/twenty-ui/src/display/index.ts | 1 + .../navigation/menu/components/MenuPicker.tsx | 1 - 45 files changed, 205 insertions(+), 151 deletions(-) rename packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/{NumberChartSettings.ts => AggregateChartSettings.ts} (90%) rename packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/{GraphWidgetNumberChart.stories.tsx => GraphWidgetAggregateChart.stories.tsx} (73%) rename packages/twenty-front/src/modules/page-layout/widgets/graph/{graphWidgetNumberChart/components/GraphWidgetNumberChart.tsx => graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx} (88%) rename packages/twenty-front/src/modules/page-layout/widgets/graph/{graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer.tsx => graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer.tsx} (62%) rename packages/twenty-front/src/modules/page-layout/widgets/graph/{graphWidgetNumberChart => graphWidgetAggregateChart}/utils/formatNumberChartTrend.ts (100%) rename packages/twenty-server/src/engine/core-modules/page-layout/dtos/{number-chart-configuration.dto.ts => aggregate-chart-configuration.dto.ts} (92%) diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 2461198cb3..bf7849817f 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -126,6 +126,18 @@ export type AgentIdInput = { id: Scalars['UUID']; }; +export type AggregateChartConfiguration = { + __typename?: 'AggregateChartConfiguration'; + aggregateFieldMetadataId: Scalars['UUID']; + aggregateOperation: AggregateOperations; + description?: Maybe; + displayDataLabel?: Maybe; + filter?: Maybe; + format?: Maybe; + graphType: GraphType; + label?: Maybe; +}; + export enum AggregateOperations { AVG = 'AVG', COUNT = 'COUNT', @@ -1453,10 +1465,10 @@ export enum GraphOrderBy { /** Type of graph widget */ export enum GraphType { + AGGREGATE = 'AGGREGATE', GAUGE = 'GAUGE', HORIZONTAL_BAR = 'HORIZONTAL_BAR', LINE = 'LINE', - NUMBER = 'NUMBER', PIE = 'PIE', VERTICAL_BAR = 'VERTICAL_BAR' } @@ -2789,18 +2801,6 @@ export type NativeModelCapabilities = { webSearch?: Maybe; }; -export type NumberChartConfiguration = { - __typename?: 'NumberChartConfiguration'; - aggregateFieldMetadataId: Scalars['UUID']; - aggregateOperation: AggregateOperations; - description?: Maybe; - displayDataLabel?: Maybe; - filter?: Maybe; - format?: Maybe; - graphType: GraphType; - label?: Maybe; -}; - export type Object = { __typename?: 'Object'; applicationId?: Maybe; @@ -4540,7 +4540,7 @@ export type Webhook = { workspaceId: Scalars['UUID']; }; -export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration; +export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration; export enum WidgetType { CALENDAR = 'CALENDAR', diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 180c094ce6..e4c895b8be 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -126,6 +126,18 @@ export type AgentIdInput = { id: Scalars['UUID']; }; +export type AggregateChartConfiguration = { + __typename?: 'AggregateChartConfiguration'; + aggregateFieldMetadataId: Scalars['UUID']; + aggregateOperation: AggregateOperations; + description?: Maybe; + displayDataLabel?: Maybe; + filter?: Maybe; + format?: Maybe; + graphType: GraphType; + label?: Maybe; +}; + export enum AggregateOperations { AVG = 'AVG', COUNT = 'COUNT', @@ -1410,10 +1422,10 @@ export enum GraphOrderBy { /** Type of graph widget */ export enum GraphType { + AGGREGATE = 'AGGREGATE', GAUGE = 'GAUGE', HORIZONTAL_BAR = 'HORIZONTAL_BAR', LINE = 'LINE', - NUMBER = 'NUMBER', PIE = 'PIE', VERTICAL_BAR = 'VERTICAL_BAR' } @@ -2700,18 +2712,6 @@ export type NativeModelCapabilities = { webSearch?: Maybe; }; -export type NumberChartConfiguration = { - __typename?: 'NumberChartConfiguration'; - aggregateFieldMetadataId: Scalars['UUID']; - aggregateOperation: AggregateOperations; - description?: Maybe; - displayDataLabel?: Maybe; - filter?: Maybe; - format?: Maybe; - graphType: GraphType; - label?: Maybe; -}; - export type Object = { __typename?: 'Object'; applicationId?: Maybe; @@ -4368,7 +4368,7 @@ export type Webhook = { workspaceId: Scalars['UUID']; }; -export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration; +export type WidgetConfiguration = AggregateChartConfiguration | BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | PieChartConfiguration; export enum WidgetType { CALENDAR = 'CALENDAR', @@ -4627,7 +4627,7 @@ export type SearchQueryVariables = Exact<{ export type SearchQuery = { __typename?: 'Query', search: { __typename?: 'SearchResultConnection', edges: Array<{ __typename?: 'SearchResultEdge', cursor: string, node: { __typename?: 'SearchRecord', recordId: any, objectNameSingular: string, label: string, imageUrl?: string | null, tsRankCD: number, tsRank: number } }>, pageInfo: { __typename?: 'SearchResultPageInfo', hasNextPage: boolean, endCursor?: string | null } } }; -export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'NumberChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null }; +export type PageLayoutWidgetFragmentFragment = { __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null }; export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ id: Scalars['String']; @@ -4635,7 +4635,7 @@ export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ }>; -export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'NumberChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null }> | null }> | null } }; +export type UpdatePageLayoutWithTabsAndWidgetsMutation = { __typename?: 'Mutation', updatePageLayoutWithTabsAndWidgets: { __typename?: 'PageLayout', id: any, name: string, type: PageLayoutType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, tabs?: Array<{ __typename?: 'PageLayoutTab', id: any, title: string, position: number, pageLayoutId: any, createdAt: string, updatedAt: string, widgets?: Array<{ __typename?: 'PageLayoutWidget', id: any, title: string, type: WidgetType, objectMetadataId?: any | null, createdAt: string, updatedAt: string, deletedAt?: string | null, pageLayoutTabId: any, gridPosition: { __typename?: 'GridPosition', column: number, columnSpan: number, row: number, rowSpan: number }, configuration?: { __typename?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, description?: string | null, filter?: any | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null, groupMode?: BarChartGroupMode | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'IframeConfiguration', url: string } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisOrderBy?: GraphOrderBy | null, omitNullValues?: boolean | null, axisNameDisplay?: AxisNameDisplay | null, displayDataLabel?: boolean | null, rangeMin?: number | null, rangeMax?: number | null, color?: string | null, description?: string | null, filter?: any | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null } | null }> | null }> | null } }; export type OnDbEventSubscriptionVariables = Exact<{ input: OnDbEventInput; @@ -4983,7 +4983,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` description filter } - ... on NumberChartConfiguration { + ... on AggregateChartConfiguration { graphType aggregateFieldMetadataId aggregateOperation diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx index 930649b427..917371933b 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx @@ -16,6 +16,7 @@ import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds'; import { isChartSettingDisabled } from '@/command-menu/pages/page-layout/utils/isChartSettingDisabled'; import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { GRAPH_MAXIMUM_NUMBER_OF_GROUPS } from '@/page-layout/widgets/graph/constants/GraphMaximumNumberOfGroups.constant'; import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; @@ -23,9 +24,14 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; +import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils'; import { SidePanelInformationBanner } from 'twenty-ui/display'; -import { GraphType, type PageLayoutWidget } from '~/generated/graphql'; +import { + AggregateOperations, + GraphType, + type PageLayoutWidget, +} from '~/generated/graphql'; const StyledSidePanelInformationBanner = styled(SidePanelInformationBanner)` margin-top: ${({ theme }) => theme.spacing(2)}; @@ -41,6 +47,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => { const { setSelectedItemId } = useSelectableList( COMMAND_MENU_LIST_SELECTABLE_LIST_ID, ); + const { objectMetadataItems } = useObjectMetadataItems(); if (widget.configuration?.__typename === 'IframeConfiguration') { throw new Error(t`IframeConfiguration is not supported`); @@ -69,11 +76,37 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => { useRecoilComponentState(hasWidgetTooManyGroupsComponentState); const handleGraphTypeChange = (graphType: GraphType) => { + const configToUpdate: Record = { + __typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType], + graphType, + }; + + if (graphType !== GraphType.AGGREGATE && graphType !== GraphType.GAUGE) { + const currentAggregateFieldMetadataId = + configuration.aggregateFieldMetadataId; + + const objectMetadataItem = objectMetadataItems.find( + (item) => item.id === widget.objectMetadataId, + ); + + if (isDefined(objectMetadataItem)) { + const aggregateField = objectMetadataItem.fields.find( + (field) => field.id === currentAggregateFieldMetadataId, + ); + + if ( + isDefined(aggregateField) && + isFieldMetadataDateKind(aggregateField.type) && + (configuration.aggregateOperation === AggregateOperations.MIN || + configuration.aggregateOperation === AggregateOperations.MAX) + ) { + configToUpdate.aggregateOperation = AggregateOperations.COUNT; + } + } + } + updateCurrentWidgetConfig({ - configToUpdate: { - __typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType], - graphType, - }, + configToUpdate, }); updateCommandMenuPageInfo({ diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx index e74241e8bd..9571465963 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx @@ -8,7 +8,7 @@ import { MenuPicker } from 'twenty-ui/navigation'; const graphTypeOptions = [ GraphType.VERTICAL_BAR, GraphType.HORIZONTAL_BAR, - GraphType.NUMBER, + GraphType.AGGREGATE, GraphType.PIE, GraphType.LINE, GraphType.GAUGE, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartAggregateOperationSelectionDropdownContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartAggregateOperationSelectionDropdownContent.tsx index 9f21c13bd2..9f2cbd96b4 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartAggregateOperationSelectionDropdownContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartAggregateOperationSelectionDropdownContent.tsx @@ -3,6 +3,7 @@ import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/h import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel'; +import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations'; import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType'; import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; @@ -22,7 +23,7 @@ import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronLeft } from 'twenty-ui/display'; import { MenuItemSelect } from 'twenty-ui/navigation'; -import { type AggregateOperations } from '~/generated/graphql'; +import { GraphType, type AggregateOperations } from '~/generated/graphql'; import { filterBySearchQuery } from '~/utils/filterBySearchQuery'; export const ChartAggregateOperationSelectionDropdownContent = ({ @@ -40,7 +41,8 @@ export const ChartAggregateOperationSelectionDropdownContent = ({ if ( widgetInEditMode?.configuration?.__typename !== 'BarChartConfiguration' && widgetInEditMode?.configuration?.__typename !== 'LineChartConfiguration' && - widgetInEditMode?.configuration?.__typename !== 'NumberChartConfiguration' + widgetInEditMode?.configuration?.__typename !== + 'AggregateChartConfiguration' ) { throw new Error('Invalid configuration type'); } @@ -71,7 +73,21 @@ export const ChartAggregateOperationSelectionDropdownContent = ({ }) : []; - const aggregateOperationsWithLabels = availableAggregateOperations.map( + const isAggregateOrGaugeChart = + widgetInEditMode.configuration.graphType === GraphType.AGGREGATE || + widgetInEditMode.configuration.graphType === GraphType.GAUGE; + + const filteredAggregateOperations = availableAggregateOperations.filter( + (operation) => { + return ( + isAggregateOrGaugeChart || + (operation !== DateAggregateOperations.EARLIEST && + operation !== DateAggregateOperations.LATEST) + ); + }, + ); + + const aggregateOperationsWithLabels = filteredAggregateOperations.map( (operation) => ({ operation, label: getAggregateOperationLabel(operation), diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent.tsx index ce1d7a6e9f..320cc7230a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartFieldSelectionForAggregateOperationDropdownContent.tsx @@ -14,7 +14,6 @@ import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/com import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; -import { isFieldMetadataDateKind } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; import { MenuItemSelect } from 'twenty-ui/navigation'; import { filterBySearchQuery } from '~/utils/filterBySearchQuery'; @@ -32,7 +31,7 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => { if ( configuration?.__typename !== 'BarChartConfiguration' && configuration?.__typename !== 'LineChartConfiguration' && - configuration?.__typename !== 'NumberChartConfiguration' + configuration?.__typename !== 'AggregateChartConfiguration' ) { throw new Error('Invalid configuration type'); } @@ -61,12 +60,7 @@ export const ChartFieldSelectionForAggregateOperationDropdownContent = () => { searchQuery, getSearchableValues: (item) => [item.label, item.name], // TODO: remove the relation filter once group by is supported for relation fields - }).filter( - (field) => - !isFieldRelation(field) && - !field.isSystem && - !isFieldMetadataDateKind(field.type), - ); + }).filter((field) => !isFieldRelation(field) && !field.isSystem); const { getIcon } = useIcons(); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/NumberChartSettings.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/AggregateChartSettings.ts similarity index 90% rename from packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/NumberChartSettings.ts rename to packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/AggregateChartSettings.ts index b849f2f3da..c104fb317b 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/NumberChartSettings.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/AggregateChartSettings.ts @@ -3,7 +3,7 @@ import { DATA_DISPLAY_AGGREGATE_SETTING } from '@/command-menu/pages/page-layout import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting'; import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; -export const NUMBER_CHART_SETTINGS: ChartSettingsGroup[] = [ +export const AGGREGATE_CHART_SETTINGS: ChartSettingsGroup[] = [ { heading: 'Data', items: [ diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeInformation.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeInformation.ts index f24610a967..b3a7e3b883 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeInformation.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeInformation.ts @@ -1,19 +1,19 @@ +import { AGGREGATE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/AggregateChartSettings'; import { GAUGE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/GaugeChartSettings'; import { LINE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/LineChartSettings'; -import { NUMBER_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/NumberChartSettings'; import { PIE_CHART_SETTINGS } from '@/command-menu/pages/page-layout/constants/PieChartSettings'; import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; import { getBarChartSettings } from '@/command-menu/pages/page-layout/utils/getBarChartSettings'; import { type MessageDescriptor } from '@lingui/core'; import { msg } from '@lingui/core/macro'; import { - Icon123, IconChartBar, IconChartBarHorizontal, IconChartLine, IconChartPie, type IconComponent, IconGauge, + IconSum, } from 'twenty-ui/display'; import { GraphType } from '~/generated-metadata/graphql'; @@ -26,12 +26,12 @@ export const GRAPH_TYPE_INFORMATION: Record< } > = { [GraphType.VERTICAL_BAR]: { - label: msg`Vertical Bar`, + label: msg`Vertical`, icon: IconChartBar, settings: getBarChartSettings(GraphType.VERTICAL_BAR), }, [GraphType.HORIZONTAL_BAR]: { - label: msg`Horizontal Bar`, + label: msg`Horizontal`, icon: IconChartBarHorizontal, settings: getBarChartSettings(GraphType.HORIZONTAL_BAR), }, @@ -45,10 +45,10 @@ export const GRAPH_TYPE_INFORMATION: Record< icon: IconChartLine, settings: LINE_CHART_SETTINGS, }, - [GraphType.NUMBER]: { - label: msg`Number`, - icon: Icon123, - settings: NUMBER_CHART_SETTINGS, + [GraphType.AGGREGATE]: { + label: msg`Aggregate`, + icon: IconSum, + settings: AGGREGATE_CHART_SETTINGS, }, [GraphType.GAUGE]: { label: msg`Gauge`, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename.ts index 4c4955fa8b..245fbfd8ed 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename.ts @@ -5,6 +5,6 @@ export const GRAPH_TYPE_TO_CONFIG_TYPENAME = { [GraphType.HORIZONTAL_BAR]: 'BarChartConfiguration', [GraphType.LINE]: 'LineChartConfiguration', [GraphType.PIE]: 'PieChartConfiguration', - [GraphType.NUMBER]: 'NumberChartConfiguration', + [GraphType.AGGREGATE]: 'AggregateChartConfiguration', [GraphType.GAUGE]: 'GaugeChartConfiguration', } as const; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/DataDisplayAggregateSetting.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/DataDisplayAggregateSetting.ts index df2bb24996..4f297132d3 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/DataDisplayAggregateSetting.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/DataDisplayAggregateSetting.ts @@ -2,11 +2,11 @@ import { ChartFieldSelectionForAggregateOperationDropdownContent } from '@/comma import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels'; import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds'; import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; -import { Icon123 } from 'twenty-ui/display'; +import { IconSum } from 'twenty-ui/display'; export const DATA_DISPLAY_AGGREGATE_SETTING: ChartSettingsItem = { isBoolean: false, - Icon: Icon123, + Icon: IconSum, label: CHART_CONFIGURATION_SETTING_LABELS.DATA_ON_DISPLAY_AGGREGATE, id: CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_AGGREGATE, dependsOn: [CHART_CONFIGURATION_SETTING_IDS.SOURCE], diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useChartSettingsValues.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useChartSettingsValues.ts index 493c9e3532..e7923769b9 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useChartSettingsValues.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useChartSettingsValues.ts @@ -6,6 +6,7 @@ import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout import { getFieldLabelWithSubField } from '@/command-menu/pages/page-layout/utils/getFieldLabelWithSubField'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel'; +import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; import { useRecoilValue } from 'recoil'; import { type CompositeFieldSubFieldName } from 'twenty-shared/types'; import { capitalize, isDefined } from 'twenty-shared/utils'; @@ -83,7 +84,11 @@ export const useChartSettingsValues = ({ fieldMetadataItem.id === configuration.aggregateFieldMetadataId, ); - const yAxisAggregateOperation = configuration.aggregateOperation; + const aggregateOperation = + convertAggregateOperationToExtendedAggregateOperation( + configuration.aggregateOperation, + aggregateField?.type, + ); const xAxisOrderByLabel = isDefined(xAxisOrderBy) && isDefined(groupByFieldXId) @@ -131,11 +136,11 @@ export const useChartSettingsValues = ({ case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_Y: case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_AGGREGATE: { const hasAggregateLabel = isDefined(aggregateField?.label); - const hasAggregateOperation = isDefined(yAxisAggregateOperation); + const hasAggregateOperation = isDefined(aggregateOperation); return `${aggregateField?.label ?? ''}${ hasAggregateLabel && hasAggregateOperation - ? ` (${getAggregateOperationLabel(yAxisAggregateOperation)})` + ? ` (${getAggregateOperationLabel(aggregateOperation)})` : '' }`; } diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfiguration.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfiguration.ts index c4336634fb..107a0c1c38 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfiguration.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfiguration.ts @@ -1,8 +1,8 @@ import { + type AggregateChartConfiguration, type BarChartConfiguration, type GaugeChartConfiguration, type LineChartConfiguration, - type NumberChartConfiguration, type PieChartConfiguration, } from '~/generated/graphql'; @@ -10,5 +10,5 @@ export type ChartConfiguration = | BarChartConfiguration | LineChartConfiguration | PieChartConfiguration - | NumberChartConfiguration + | AggregateChartConfiguration | GaugeChartConfiguration; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartWidgetConfiguration.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartWidgetConfiguration.ts index 6828497b7e..bb430eb9cf 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartWidgetConfiguration.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartWidgetConfiguration.ts @@ -1,8 +1,8 @@ import { + type AggregateChartConfiguration, type BarChartConfiguration, type GaugeChartConfiguration, type LineChartConfiguration, - type NumberChartConfiguration, type PieChartConfiguration, } from '~/generated/graphql'; @@ -10,5 +10,5 @@ export type ChartWidgetConfiguration = | BarChartConfiguration | GaugeChartConfiguration | LineChartConfiguration - | NumberChartConfiguration + | AggregateChartConfiguration | PieChartConfiguration; diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx index aae3ff7f1d..1ac258a465 100644 --- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx @@ -88,8 +88,8 @@ const mixedGraphsPageLayoutMocks = { columnSpan: 3, }, configuration: { - __typename: 'NumberChartConfiguration', - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration', + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: idField.id, }, diff --git a/packages/twenty-front/src/modules/page-layout/constants/WidgetSizes.ts b/packages/twenty-front/src/modules/page-layout/constants/WidgetSizes.ts index aa1e1bfdc0..a357282e42 100644 --- a/packages/twenty-front/src/modules/page-layout/constants/WidgetSizes.ts +++ b/packages/twenty-front/src/modules/page-layout/constants/WidgetSizes.ts @@ -6,7 +6,7 @@ type WidgetSizeConfig = { }; export const WIDGET_SIZES: Record = { - [GraphType.NUMBER]: { + [GraphType.AGGREGATE]: { default: { w: 3, h: 2 }, minimum: { w: 2, h: 2 }, }, diff --git a/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts b/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts index 59e9ae8483..76d435239c 100644 --- a/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts +++ b/packages/twenty-front/src/modules/page-layout/graphql/fragments/pageLayoutWidgetFragment.ts @@ -67,7 +67,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql` description filter } - ... on NumberChartConfiguration { + ... on AggregateChartConfiguration { graphType aggregateFieldMetadataId aggregateOperation 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 b64ba4c08a..d20ade3ae9 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 @@ -1,6 +1,7 @@ import { useCreatePageLayoutGraphWidget } from '@/page-layout/hooks/useCreatePageLayoutGraphWidget'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; +import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; @@ -13,7 +14,6 @@ import { PAGE_LAYOUT_TEST_INSTANCE_ID, PageLayoutTestWrapper, } from './PageLayoutTestWrapper'; -import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection'; jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid'), @@ -160,7 +160,7 @@ describe('useCreatePageLayoutGraphWidget', () => { }); const graphTypes = [ - GraphType.NUMBER, + GraphType.AGGREGATE, GraphType.GAUGE, GraphType.PIE, GraphType.VERTICAL_BAR, @@ -169,7 +169,7 @@ describe('useCreatePageLayoutGraphWidget', () => { const mockFieldSelections: Partial< Record > = { - [GraphType.NUMBER]: { + [GraphType.AGGREGATE]: { objectMetadataId: 'test-object-id', aggregateFieldMetadataId: 'test-aggregate-field-id', }, 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 ddd09a4c37..6a8a65f80a 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 @@ -14,7 +14,7 @@ describe('addWidgetToTab', () => { title: 'Test Widget', type: WidgetType.GRAPH, configuration: { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: 'id', displayDataLabel: false, diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertLayoutsToWidgets.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertLayoutsToWidgets.test.ts index 1b7ab3f63d..e39bdb8543 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertLayoutsToWidgets.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertLayoutsToWidgets.test.ts @@ -22,7 +22,7 @@ describe('convertLayoutsToWidgets', () => { columnSpan: 2, }, configuration: { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: 'id', displayDataLabel: false, 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 907ecfc2c5..c66b304a75 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 @@ -29,7 +29,7 @@ describe('convertPageLayoutToTabLayouts', () => { title: 'Widget 1', type: WidgetType.GRAPH, configuration: { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: 'id', displayDataLabel: false, diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/extractFieldMetadataIdsFromWidget.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/extractFieldMetadataIdsFromWidget.test.ts index 4868acda40..74fb78067c 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/extractFieldMetadataIdsFromWidget.test.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/extractFieldMetadataIdsFromWidget.test.ts @@ -135,11 +135,11 @@ describe('extractFieldMetadataIdsFromWidget', () => { expect(result).toContain('field-2'); }); - it('should extract field IDs from NumberChartConfiguration', () => { + it('should extract field IDs from AggregateChartConfiguration', () => { const widget = createMockWidget({ configuration: { - __typename: 'NumberChartConfiguration' as const, - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration' as const, + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: 'field-1', aggregateOperation: AggregateOperations.AVG, displayDataLabel: false, 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 8b75386970..44af87f4e8 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 @@ -22,7 +22,7 @@ describe('removeWidgetFromTab', () => { title: 'Widget 1', type: WidgetType.GRAPH, configuration: { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: 'id', displayDataLabel: false, diff --git a/packages/twenty-front/src/modules/page-layout/utils/createDefaultGraphWidget.ts b/packages/twenty-front/src/modules/page-layout/utils/createDefaultGraphWidget.ts index dd19c6a72d..06941e6845 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/createDefaultGraphWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/createDefaultGraphWidget.ts @@ -18,13 +18,13 @@ const createDefaultGraphConfiguration = ( fieldSelection?: GraphWidgetFieldSelection, ): WidgetConfiguration | null => { switch (graphType) { - case GraphType.NUMBER: + case GraphType.AGGREGATE: if (!isDefined(fieldSelection?.aggregateFieldMetadataId)) { return null; } return { - __typename: 'NumberChartConfiguration', - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration', + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: fieldSelection.aggregateFieldMetadataId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, diff --git a/packages/twenty-front/src/modules/page-layout/utils/extractFieldMetadataIdsFromWidget.ts b/packages/twenty-front/src/modules/page-layout/utils/extractFieldMetadataIdsFromWidget.ts index bc0288a5b0..2f2de974ad 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/extractFieldMetadataIdsFromWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/extractFieldMetadataIdsFromWidget.ts @@ -34,7 +34,7 @@ export const extractFieldMetadataIdsFromWidget = ( config.groupByFieldMetadataId, ].filter(isDefined); - case 'NumberChartConfiguration': + case 'AggregateChartConfiguration': return [config.aggregateFieldMetadataId].filter(isDefined); case 'GaugeChartConfiguration': diff --git a/packages/twenty-front/src/modules/page-layout/utils/getDefaultWidgetData.ts b/packages/twenty-front/src/modules/page-layout/utils/getDefaultWidgetData.ts index 9c2c78a1e1..6bc4f37fbf 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/getDefaultWidgetData.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/getDefaultWidgetData.ts @@ -2,7 +2,7 @@ import { GraphType } from '~/generated-metadata/graphql'; export const getDefaultWidgetData = (graphType: GraphType) => { switch (graphType) { - case GraphType.NUMBER: + case GraphType.AGGREGATE: return { value: '1,234', trendPercentage: 15.2, diff --git a/packages/twenty-front/src/modules/page-layout/utils/getWidgetTitle.ts b/packages/twenty-front/src/modules/page-layout/utils/getWidgetTitle.ts index ca684d1b49..0b63edc61e 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/getWidgetTitle.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/getWidgetTitle.ts @@ -2,7 +2,7 @@ import { GraphType } from '~/generated/graphql'; export const getWidgetTitle = (graphType: GraphType, index: number): string => { const baseNames: Record = { - [GraphType.NUMBER]: 'Number', + [GraphType.AGGREGATE]: 'Number', [GraphType.GAUGE]: 'Gauge', [GraphType.PIE]: 'Pie Chart', [GraphType.VERTICAL_BAR]: 'Vertical Bar Chart', 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 83b0392df3..fa3647f54b 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 @@ -169,8 +169,8 @@ export const WithNumberChart: Story = { columnSpan: 3, }, configuration: { - __typename: 'NumberChartConfiguration', - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration', + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: idField.id, displayDataLabel: true, @@ -277,8 +277,8 @@ export const SmallWidget: Story = { columnSpan: 2, }, configuration: { - __typename: 'NumberChartConfiguration', - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration', + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: idField.id, displayDataLabel: true, @@ -409,8 +409,8 @@ export const WideWidget: Story = { columnSpan: 8, }, configuration: { - __typename: 'NumberChartConfiguration', - graphType: GraphType.NUMBER, + __typename: 'AggregateChartConfiguration', + graphType: GraphType.AGGREGATE, aggregateOperation: AggregateOperations.COUNT, aggregateFieldMetadataId: idField.id, displayDataLabel: true, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx index 6ff1c44921..c1421162bc 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidget.tsx @@ -2,8 +2,8 @@ import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMeta import { getDefaultWidgetData } from '@/page-layout/utils/getDefaultWidgetData'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; +import { GraphWidgetAggregateChartRenderer } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer'; import { GraphWidgetBarChartRenderer } from '@/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer'; -import { GraphWidgetNumberChartRenderer } from '@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer'; import { areChartConfigurationFieldsValidForQuery } from '@/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery'; import { lazy, Suspense } from 'react'; import { GraphType, type PageLayoutWidget } from '~/generated/graphql'; @@ -63,8 +63,8 @@ export const GraphWidget = ({ } switch (graphType) { - case GraphType.NUMBER: - return ; + case GraphType.AGGREGATE: + return ; case GraphType.GAUGE: return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetNumberChart.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetAggregateChart.stories.tsx similarity index 73% rename from packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetNumberChart.stories.tsx rename to packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetAggregateChart.stories.tsx index 451c5a11af..a0a07114f1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetNumberChart.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/__stories__/GraphWidgetAggregateChart.stories.tsx @@ -1,16 +1,16 @@ import { type Meta, type StoryObj } from '@storybook/react'; +import { GraphWidgetAggregateChart } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart'; import { ComponentDecorator } from 'twenty-ui/testing'; -import { GraphWidgetNumberChart } from '@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart'; -const meta: Meta = { - title: 'Modules/PageLayout/Widgets/GraphWidgetNumberChart', - component: GraphWidgetNumberChart, +const meta: Meta = { + title: 'Modules/PageLayout/Widgets/GraphWidgetAggregateChart', + component: GraphWidgetAggregateChart, decorators: [ComponentDecorator], }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Default: Story = { args: { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx similarity index 88% rename from packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart.tsx rename to packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx index 96b0e5cbb0..d7a7e47643 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx @@ -1,4 +1,4 @@ -import { formatNumberChartTrend } from '@/page-layout/widgets/graph/graphWidgetNumberChart/utils/formatNumberChartTrend'; +import { formatNumberChartTrend } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/utils/formatNumberChartTrend'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -9,7 +9,7 @@ import { IconTrendingUp, } from 'twenty-ui/display'; -type GraphWidgetNumberChartProps = { +type GraphWidgetAggregateChartProps = { value: string | number; trendPercentage?: number; }; @@ -36,13 +36,14 @@ const StyledTrendIconContainer = styled.div` `; const StyledH1Title = styled(H1Title)` + font-size: ${({ theme }) => theme.font.size.xxl}; margin: 0; `; -export const GraphWidgetNumberChart = ({ +export const GraphWidgetAggregateChart = ({ value, trendPercentage, -}: GraphWidgetNumberChartProps) => { +}: GraphWidgetAggregateChartProps) => { const theme = useTheme(); const formattedPercentage = isDefined(trendPercentage) diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer.tsx similarity index 62% rename from packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer.tsx rename to packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer.tsx index fd83142cb1..ea734fd97e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChartRenderer.tsx @@ -2,26 +2,26 @@ import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/Char import { useGraphWidgetAggregateQuery } from '@/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery'; import { lazy, Suspense } from 'react'; import { - type NumberChartConfiguration, + type AggregateChartConfiguration, type PageLayoutWidget, } from '~/generated/graphql'; -const GraphWidgetNumberChart = lazy(() => +const GraphWidgetAggregateChart = lazy(() => import( - '@/page-layout/widgets/graph/graphWidgetNumberChart/components/GraphWidgetNumberChart' + '@/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart' ).then((module) => ({ - default: module.GraphWidgetNumberChart, + default: module.GraphWidgetAggregateChart, })), ); -export const GraphWidgetNumberChartRenderer = ({ +export const GraphWidgetAggregateChartRenderer = ({ widget, }: { widget: PageLayoutWidget; }) => { const { value, loading } = useGraphWidgetAggregateQuery({ objectMetadataItemId: widget.objectMetadataId, - configuration: widget.configuration as NumberChartConfiguration, + configuration: widget.configuration as AggregateChartConfiguration, }); if (loading) { @@ -30,7 +30,7 @@ export const GraphWidgetNumberChartRenderer = ({ return ( }> - + ); }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/utils/formatNumberChartTrend.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/utils/formatNumberChartTrend.ts similarity index 100% rename from packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetNumberChart/utils/formatNumberChartTrend.ts rename to packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/utils/formatNumberChartTrend.ts diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts index 1f32eb7343..abf0200eda 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts @@ -1,11 +1,11 @@ import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords'; import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel'; -import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; +import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; import { useGraphWidgetQueryCommon } from '@/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon'; import { UserContext } from '@/users/contexts/UserContext'; import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; -import { type NumberChartConfiguration } from '~/generated/graphql'; +import { type AggregateChartConfiguration } from '~/generated/graphql'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; export const useGraphWidgetAggregateQuery = ({ @@ -13,7 +13,7 @@ export const useGraphWidgetAggregateQuery = ({ configuration, }: { objectMetadataItemId: string; - configuration: NumberChartConfiguration; + configuration: AggregateChartConfiguration; }) => { const { objectMetadataItem, gqlOperationFilter, aggregateField } = useGraphWidgetQueryCommon({ @@ -21,14 +21,18 @@ export const useGraphWidgetAggregateQuery = ({ configuration, }); - // TODO: Move this enum to shared - const aggregateOperation = - configuration.aggregateOperation as unknown as ExtendedAggregateOperations; + const aggregateOperation = configuration.aggregateOperation; + + const extendedAggregateOperation = + convertAggregateOperationToExtendedAggregateOperation( + aggregateOperation, + aggregateField.type, + ); const { data, loading, error } = useAggregateRecords({ objectNameSingular: objectMetadataItem.nameSingular, recordGqlFieldsAggregate: { - [aggregateField.name]: [aggregateOperation], + [aggregateField.name]: [extendedAggregateOperation], }, filter: gqlOperationFilter, }); @@ -40,7 +44,7 @@ export const useGraphWidgetAggregateQuery = ({ data, objectMetadataItem, fieldMetadataId: configuration.aggregateFieldMetadataId, - aggregateOperation, + aggregateOperation: extendedAggregateOperation, dateFormat, timeFormat, timeZone, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon.ts index fb67b54cd4..c1f85fc5c3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon.ts @@ -4,8 +4,8 @@ import { isDefined, } from 'twenty-shared/utils'; import { + type AggregateChartConfiguration, type BarChartConfiguration, - type NumberChartConfiguration, } from '~/generated/graphql'; export const useGraphWidgetQueryCommon = ({ @@ -13,7 +13,7 @@ export const useGraphWidgetQueryCommon = ({ configuration, }: { objectMetadataItemId: string; - configuration: BarChartConfiguration | NumberChartConfiguration; + configuration: BarChartConfiguration | AggregateChartConfiguration; }) => { const { objectMetadataItem } = useObjectMetadataItemById({ objectId: objectMetadataItemId, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery.ts index 8a37939db3..bb92036398 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/areChartConfigurationFieldsValidForQuery.ts @@ -53,7 +53,7 @@ export const areChartConfigurationFieldsValidForQuery = ( fieldExists(configuration.groupByFieldMetadataId, objectMetadataItem) ); - case 'NumberChartConfiguration': + case 'AggregateChartConfiguration': case 'GaugeChartConfiguration': return fieldExists( configuration.aggregateFieldMetadataId, diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto.ts b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto.ts similarity index 92% rename from packages/twenty-server/src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto.ts rename to packages/twenty-server/src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto.ts index 77f2cb2fd8..08f21e9a5c 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto.ts @@ -17,12 +17,12 @@ import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum'; -@ObjectType('NumberChartConfiguration') -export class NumberChartConfigurationDTO { +@ObjectType('AggregateChartConfiguration') +export class AggregateChartConfigurationDTO { @Field(() => GraphType) @IsEnum(GraphType) @IsNotEmpty() - graphType: GraphType.NUMBER; + graphType: GraphType.AGGREGATE; @Field(() => UUIDScalarType) @IsUUID() diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/widget-configuration.interface.ts b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/widget-configuration.interface.ts index 7aef50003f..2f2b1c0ad1 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/widget-configuration.interface.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/widget-configuration.interface.ts @@ -1,10 +1,10 @@ import { createUnionType } from '@nestjs/graphql'; +import { AggregateChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto'; import { BarChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto'; import { GaugeChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/gauge-chart-configuration.dto'; import { IframeConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/iframe-configuration.dto'; import { LineChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto'; -import { NumberChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto'; import { PieChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto'; import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum'; import { WidgetConfigurationType } from 'src/engine/core-modules/page-layout/enums/widget-configuration-type.enum'; @@ -15,7 +15,7 @@ export const WidgetConfiguration = createUnionType({ BarChartConfigurationDTO, LineChartConfigurationDTO, PieChartConfigurationDTO, - NumberChartConfigurationDTO, + AggregateChartConfigurationDTO, GaugeChartConfigurationDTO, IframeConfigurationDTO, ], @@ -37,8 +37,8 @@ export const WidgetConfiguration = createUnionType({ return LineChartConfigurationDTO; case GraphType.PIE: return PieChartConfigurationDTO; - case GraphType.NUMBER: - return NumberChartConfigurationDTO; + case GraphType.AGGREGATE: + return AggregateChartConfigurationDTO; case GraphType.GAUGE: return GaugeChartConfigurationDTO; default: @@ -62,6 +62,6 @@ export type WidgetConfigurationInterface = | BarChartConfigurationDTO | LineChartConfigurationDTO | PieChartConfigurationDTO - | NumberChartConfigurationDTO + | AggregateChartConfigurationDTO | GaugeChartConfigurationDTO | IframeConfigurationDTO; diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/enums/graph-type.enum.ts b/packages/twenty-server/src/engine/core-modules/page-layout/enums/graph-type.enum.ts index 394d5fcfee..af1307da7f 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/enums/graph-type.enum.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/enums/graph-type.enum.ts @@ -1,7 +1,7 @@ import { registerEnumType } from '@nestjs/graphql'; export enum GraphType { - NUMBER = 'NUMBER', + AGGREGATE = 'AGGREGATE', GAUGE = 'GAUGE', PIE = 'PIE', VERTICAL_BAR = 'VERTICAL_BAR', diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/utils/validate-and-transform-widget-configuration.util.ts b/packages/twenty-server/src/engine/core-modules/page-layout/utils/validate-and-transform-widget-configuration.util.ts index c72461ee23..b555af5537 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/utils/validate-and-transform-widget-configuration.util.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/utils/validate-and-transform-widget-configuration.util.ts @@ -1,11 +1,11 @@ import { plainToInstance } from 'class-transformer'; import { validateSync, type ValidationError } from 'class-validator'; +import { AggregateChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/aggregate-chart-configuration.dto'; import { BarChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto'; import { GaugeChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/gauge-chart-configuration.dto'; import { IframeConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/iframe-configuration.dto'; import { LineChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto'; -import { NumberChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/number-chart-configuration.dto'; import { PieChartConfigurationDTO } from 'src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto'; import { type WidgetConfigurationInterface } from 'src/engine/core-modules/page-layout/dtos/widget-configuration.interface'; import { GraphType } from 'src/engine/core-modules/page-layout/enums/graph-type.enum'; @@ -79,9 +79,9 @@ const validateGraphConfiguration = ( return instance; } - case GraphType.NUMBER: { + case GraphType.AGGREGATE: { const instance = plainToInstance( - NumberChartConfigurationDTO, + AggregateChartConfigurationDTO, configuration, ); diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts index e92d5369ba..9c6ebdcad2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts @@ -94,7 +94,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, configuration: isDefined(opportunityAmountFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: opportunityAmountFieldId, aggregateOperation: AggregateOperations.SUM, displayDataLabel: true, @@ -116,7 +116,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 3, rowSpan: 4, columnSpan: 4 }, configuration: isDefined(rocketIdFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: rocketIdFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, @@ -222,7 +222,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 5, rowSpan: 5, columnSpan: 7 }, configuration: isDefined(opportunityIdFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: opportunityIdFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, @@ -246,7 +246,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 0, rowSpan: 2, columnSpan: 3 }, configuration: isDefined(companyIdFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: companyIdFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, @@ -326,7 +326,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 0, rowSpan: 4, columnSpan: 4 }, configuration: isDefined(companyArrFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: companyArrFieldId, aggregateOperation: AggregateOperations.SUM, displayDataLabel: true, @@ -395,7 +395,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 2, column: 0, rowSpan: 4, columnSpan: 3 }, configuration: isDefined(companyLinkedinLinkFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: companyLinkedinLinkFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, @@ -441,7 +441,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 0, rowSpan: 5, columnSpan: 6 }, configuration: isDefined(personIdFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: personIdFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, @@ -513,7 +513,7 @@ export const getPageLayoutWidgetDataSeeds = ( gridPosition: { row: 0, column: 6, rowSpan: 6, columnSpan: 6 }, configuration: isDefined(taskIdFieldId) ? { - graphType: 'NUMBER', + graphType: 'AGGREGATE', aggregateFieldMetadataId: taskIdFieldId, aggregateOperation: AggregateOperations.COUNT, displayDataLabel: true, diff --git a/packages/twenty-server/test/integration/constants/page-layout-gql-fields.constants.ts b/packages/twenty-server/test/integration/constants/page-layout-gql-fields.constants.ts index 1aafe25de0..c29bd0f045 100644 --- a/packages/twenty-server/test/integration/constants/page-layout-gql-fields.constants.ts +++ b/packages/twenty-server/test/integration/constants/page-layout-gql-fields.constants.ts @@ -71,7 +71,7 @@ export const PAGE_LAYOUT_WIDGET_CONFIGURATION_FIELDS = ` color description } - ... on NumberChartConfiguration { + ... on AggregateChartConfiguration { graphType aggregateFieldMetadataId aggregateOperation diff --git a/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts b/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts index 78062659c2..50ac3eb18b 100644 --- a/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts +++ b/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts @@ -17,7 +17,7 @@ export const TEST_IFRAME_CONFIG_ALTERNATIVE = { }; export const TEST_NUMBER_CHART_CONFIG = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1, aggregateOperation: AggregateOperations.COUNT, label: 'Total Records', @@ -27,7 +27,7 @@ export const TEST_NUMBER_CHART_CONFIG = { }; export const TEST_NUMBER_CHART_CONFIG_MINIMAL = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1, aggregateOperation: AggregateOperations.SUM, displayDataLabel: false, @@ -174,17 +174,17 @@ export const INVALID_IFRAME_CONFIG_EMPTY_URL = { }; export const INVALID_NUMBER_CHART_CONFIG_MISSING_FIELDS = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, }; export const INVALID_NUMBER_CHART_CONFIG_BAD_UUID = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: 'not-a-uuid', aggregateOperation: AggregateOperations.COUNT, }; export const INVALID_NUMBER_CHART_CONFIG_INVALID_OPERATION = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, aggregateFieldMetadataId: TEST_FIELD_METADATA_ID_1, aggregateOperation: 'INVALID_OP' as any, }; @@ -218,7 +218,7 @@ export const INVALID_HORIZONTAL_BAR_CHART_CONFIG_BAD_ORDER_BY = { }; export const CONFIG_TYPE_MISMATCH_IFRAME_WITH_GRAPH = { - graphType: GraphType.NUMBER, + graphType: GraphType.AGGREGATE, url: 'https://example.com', }; diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index 21fe743217..628a48c3b0 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -326,6 +326,7 @@ export { IconStatusChange, IconStepInto, IconStrikethrough, + IconSum, IconSun, IconSunMoon, IconSwitchHorizontal, diff --git a/packages/twenty-ui/src/display/index.ts b/packages/twenty-ui/src/display/index.ts index 1d2339a8a5..f9dd04087a 100644 --- a/packages/twenty-ui/src/display/index.ts +++ b/packages/twenty-ui/src/display/index.ts @@ -391,6 +391,7 @@ export { IconStatusChange, IconStepInto, IconStrikethrough, + IconSum, IconSun, IconSunMoon, IconSwitchHorizontal, diff --git a/packages/twenty-ui/src/navigation/menu/components/MenuPicker.tsx b/packages/twenty-ui/src/navigation/menu/components/MenuPicker.tsx index 28b72c684f..e88fd2c167 100644 --- a/packages/twenty-ui/src/navigation/menu/components/MenuPicker.tsx +++ b/packages/twenty-ui/src/navigation/menu/components/MenuPicker.tsx @@ -75,7 +75,6 @@ const StyledLabel = styled.div<{ font-family: ${({ theme }) => theme.font.family}; font-size: ${({ theme }) => theme.font.size.xs}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; - line-height: 1; max-width: 100%; overflow: hidden; text-align: center;