diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 78f664ea9f2..a0fec64e4d3 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -321,6 +321,7 @@ export type BarChartConfiguration = { color?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; @@ -1671,6 +1672,7 @@ export type LineChartConfiguration = { color?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; @@ -3105,6 +3107,7 @@ export type PieChartConfiguration = { dateGranularity?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 9a23a636d9b..f89b6051ef9 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -321,6 +321,7 @@ export type BarChartConfiguration = { color?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; @@ -1647,6 +1648,7 @@ export type LineChartConfiguration = { color?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; @@ -3039,6 +3041,7 @@ export type PieChartConfiguration = { dateGranularity?: Maybe; description?: Maybe; displayDataLabel?: Maybe; + displayLegend?: Maybe; filter?: Maybe; firstDayOfTheWeek?: Maybe; graphType: GraphType; @@ -4751,7 +4754,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?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | 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, isStacked?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | null }; export type UpdatePageLayoutWithTabsAndWidgetsMutationVariables = Exact<{ id: Scalars['String']; @@ -4759,7 +4762,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?: 'AggregateChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | 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, isStacked?: boolean | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | 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, label?: string | null, displayDataLabel?: boolean | null, format?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'BarChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'GaugeChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, displayDataLabel?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'IframeConfiguration', url?: string | null } | { __typename?: 'LineChartConfiguration', graphType: GraphType, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, primaryAxisGroupByFieldMetadataId: any, primaryAxisGroupBySubFieldName?: string | null, primaryAxisDateGranularity?: ObjectRecordGroupByDateGranularity | null, primaryAxisOrderBy?: GraphOrderBy | null, secondaryAxisGroupByFieldMetadataId?: any | null, secondaryAxisGroupBySubFieldName?: string | null, secondaryAxisGroupByDateGranularity?: ObjectRecordGroupByDateGranularity | null, secondaryAxisOrderBy?: GraphOrderBy | 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, timezone?: string | null, firstDayOfTheWeek?: number | null } | { __typename?: 'PieChartConfiguration', graphType: GraphType, groupByFieldMetadataId: any, aggregateFieldMetadataId: any, aggregateOperation: AggregateOperations, groupBySubFieldName?: string | null, dateGranularity?: ObjectRecordGroupByDateGranularity | null, orderBy?: GraphOrderBy | null, displayDataLabel?: boolean | null, displayLegend?: boolean | null, color?: string | null, description?: string | null, filter?: any | null, timezone?: string | null, firstDayOfTheWeek?: number | null } | null }> | null }> | null } }; export type OnDbEventSubscriptionVariables = Exact<{ input: OnDbEventInput; @@ -5085,6 +5088,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` omitNullValues axisNameDisplay displayDataLabel + displayLegend rangeMin rangeMax color @@ -5109,6 +5113,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` omitNullValues axisNameDisplay displayDataLabel + displayLegend rangeMin rangeMax color @@ -5127,6 +5132,7 @@ export const PageLayoutWidgetFragmentFragmentDoc = gql` dateGranularity orderBy displayDataLabel + displayLegend color description filter diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/LineChartSettings.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/LineChartSettings.ts index e839d40e242..9bef09926be 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/LineChartSettings.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/LineChartSettings.ts @@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting'; import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting'; import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting'; +import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting'; import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout/constants/settings/SortByGroupByFieldSetting'; import { STACKED_LINES_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedLineSettings'; import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; @@ -48,6 +49,7 @@ export const LINE_CHART_SETTINGS: ChartSettingsGroup[] = [ AXIS_NAME_SETTING, STACKED_LINES_SETTING, DATA_LABELS_SETTING, + SHOW_LEGEND_SETTING, ], }, ]; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/PieChartSettings.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/PieChartSettings.ts index a5c20db25f7..887a562bea5 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/PieChartSettings.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/PieChartSettings.ts @@ -6,6 +6,7 @@ import { DATE_GRANULARITY_SETTING } from '@/command-menu/pages/page-layout/const import { EACH_SLICE_REPRESENTS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/EachSliceRepresentsSetting'; import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting'; import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting'; +import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting'; import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; export const PIE_CHART_SETTINGS: ChartSettingsGroup[] = [ @@ -22,6 +23,6 @@ export const PIE_CHART_SETTINGS: ChartSettingsGroup[] = [ }, { heading: 'Style', - items: [COLORS_SETTING, DATA_LABELS_SETTING], + items: [COLORS_SETTING, DATA_LABELS_SETTING, SHOW_LEGEND_SETTING], }, ]; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels.ts index 4fcff748c5a..c5dfefef273 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels.ts @@ -22,4 +22,5 @@ export const CHART_CONFIGURATION_SETTING_LABELS = { DATE_GRANULARITY_X: msg`Date granularity`, DATE_GRANULARITY_Y: msg`Date granularity`, DATE_GRANULARITY: msg`Date granularity`, + SHOW_LEGEND: msg`Legend`, }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ShowLegendSetting.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ShowLegendSetting.ts new file mode 100644 index 00000000000..b511d0fb867 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/constants/settings/ShowLegendSetting.ts @@ -0,0 +1,12 @@ +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 { IconList } from 'twenty-ui/display'; + +export const SHOW_LEGEND_SETTING: ChartSettingsItem = { + isBoolean: true, + Icon: IconList, + label: CHART_CONFIGURATION_SETTING_LABELS.SHOW_LEGEND, + id: CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND, + dependsOn: [CHART_CONFIGURATION_SETTING_IDS.GROUP_BY], +}; 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 245597d5594..9ff28d8a7b7 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 @@ -235,6 +235,8 @@ export const useChartSettingsValues = ({ return isPieChart && isDefined(configuration.dateGranularity) ? getDateGranularityLabel(configuration.dateGranularity) : undefined; + case CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND: + return isPieChart ? (configuration.displayLegend ?? true) : true; default: return ''; } diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfigurationSettingIds.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfigurationSettingIds.ts index 152fb0f071d..a0c26bb9e5e 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfigurationSettingIds.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/types/ChartConfigurationSettingIds.ts @@ -21,6 +21,7 @@ export enum CHART_CONFIGURATION_SETTING_IDS { DATE_GRANULARITY_X = 'DATE_GRANULARITY_X', DATE_GRANULARITY_Y = 'DATE_GRANULARITY_Y', DATE_GRANULARITY = 'DATE_GRANULARITY', + SHOW_LEGEND = 'SHOW_LEGEND', } export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = { @@ -35,4 +36,5 @@ export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = { [CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_Y]: 'secondaryAxisGroupByDateGranularity', [CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY]: 'dateGranularity', + [CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND]: 'displayLegend', } as const; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/__tests__/getBarChartSettings.test.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/__tests__/getBarChartSettings.test.ts index 2b18de0437f..a1d95b42a5f 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/__tests__/getBarChartSettings.test.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/__tests__/getBarChartSettings.test.ts @@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting'; import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting'; import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting'; +import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting'; import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout/constants/settings/SortByGroupByFieldSetting'; import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting'; import { IconAxisX, IconAxisY } from 'twenty-ui/display'; @@ -143,6 +144,7 @@ describe('getBarChartSettings', () => { AXIS_NAME_SETTING, STACKED_BARS_SETTING, DATA_LABELS_SETTING, + SHOW_LEGEND_SETTING, ]); }); }); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/getBarChartSettings.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/getBarChartSettings.ts index 1dd182e20cf..eaf24cd4f62 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/getBarChartSettings.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/getBarChartSettings.ts @@ -12,6 +12,7 @@ import { OMIT_NULL_VALUES_SETTING } from '@/command-menu/pages/page-layout/const import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting'; import { RANGE_MAX_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMaxSetting'; import { RANGE_MIN_SETTING } from '@/command-menu/pages/page-layout/constants/settings/RangeMinSetting'; +import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting'; import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout/constants/settings/SortByGroupByFieldSetting'; import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting'; import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup'; @@ -65,6 +66,7 @@ export const getBarChartSettings = ( AXIS_NAME_SETTING, STACKED_BARS_SETTING, DATA_LABELS_SETTING, + SHOW_LEGEND_SETTING, ], }, ]; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/shouldHideChartSetting.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/shouldHideChartSetting.ts index f216bdbff26..6a57609a8bd 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/shouldHideChartSetting.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/utils/shouldHideChartSetting.ts @@ -74,6 +74,12 @@ export const shouldHideChartSetting = ( ); } } + + if (item.id === CHART_CONFIGURATION_SETTING_IDS.SHOW_LEGEND) { + if (configuration.__typename === 'PieChartConfiguration') { + return false; + } + } } return ( 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 09fbf3a9316..ba1eeeb4241 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 @@ -31,6 +31,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql` omitNullValues axisNameDisplay displayDataLabel + displayLegend rangeMin rangeMax color @@ -55,6 +56,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql` omitNullValues axisNameDisplay displayDataLabel + displayLegend rangeMin rangeMax color @@ -73,6 +75,7 @@ export const PAGE_LAYOUT_WIDGET_FRAGMENT = gql` dateGranularity orderBy displayDataLabel + displayLegend color description filter diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx index daab99eabfb..a22a28c3910 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx @@ -1,5 +1,18 @@ -import { CHART_LEGEND_ITEM_THRESHOLD } from '@/page-layout/widgets/graph/constants/ChartLegendItemThreshold'; +import { GraphWidgetLegendDot } from '@/page-layout/widgets/graph/components/GraphWidgetLegendDot'; +import { LEGEND_ITEM_ESTIMATED_WIDTH } from '@/page-layout/widgets/graph/constants/LegendItemEstimatedWidth.constant'; +import { LEGEND_LABEL_MAX_WIDTH } from '@/page-layout/widgets/graph/constants/LegendLabelMaxWidth.constant'; +import { LEGEND_PAGINATION_CONTROLS_WIDTH } from '@/page-layout/widgets/graph/constants/LegendPaginationControlsWidth.constant'; +import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect'; +import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { AnimatePresence, motion } from 'framer-motion'; +import { useRef, useState } from 'react'; +import { + IconChevronLeft, + IconChevronRight, + OverflowingTextWithTooltip, +} from 'twenty-ui/display'; +import { LightIconButton } from 'twenty-ui/input'; export type GraphWidgetLegendItem = { id: string; @@ -12,59 +25,232 @@ type GraphWidgetLegendProps = { show?: boolean; }; -const StyledLegendContainer = styled.div` - display: flex; - flex-wrap: wrap; - gap: ${({ theme }) => theme.spacing(3)}; - justify-content: center; - padding-top: ${({ theme }) => theme.spacing(3)}; +type AnimationDirection = 'forward' | 'backward'; + +const StyledAnimationClipContainer = styled.div` + flex: 1; + min-width: 0; + overflow: hidden; + position: relative; `; -const StyledLegendItem = styled.div` +const StyledLegendMotionWrapper = styled(motion.div)` + width: 100%; +`; + +const StyledItemsWrapper = styled(motion.div)<{ centered?: boolean }>` + display: flex; + gap: ${({ theme }) => theme.spacing(3)}; + flex-wrap: nowrap; + flex: 1; + min-width: 0; + justify-content: ${({ centered }) => (centered ? 'center' : 'flex-start')}; +`; + +const StyledLegendContainer = styled.div<{ needsPagination: boolean }>` + display: flex; + flex-wrap: nowrap; + gap: ${({ theme }) => theme.spacing(3)}; + justify-content: ${({ needsPagination }) => + needsPagination ? 'flex-start' : 'center'}; + padding-top: ${({ theme }) => theme.spacing(3)}; + overflow: hidden; + width: 100%; + align-items: center; +`; + +const StyledLegendItem = styled.div<{ canShrink?: boolean }>` align-items: center; display: flex; gap: ${({ theme }) => theme.spacing(1)}; font-size: ${({ theme }) => theme.font.size.xs}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; + flex-shrink: ${({ canShrink }) => (canShrink ? 1 : 0)}; + min-width: 0; `; -const StyledLegendLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; +const StyledLegendLabel = styled.div<{ fixedWidth?: boolean }>` + color: ${({ theme }) => theme.font.color.secondary}; + ${({ fixedWidth }) => fixedWidth && `width: ${LEGEND_LABEL_MAX_WIDTH}px;`} + overflow: hidden; `; -const StyledDot = styled.div<{ color: string }>` - background: ${({ color }) => color}; - border-radius: 50%; - height: 6px; - width: 6px; +const StyledPaginationContainer = styled.div` + align-items: center; + display: flex; + flex-direction: row; flex-shrink: 0; + gap: ${({ theme }) => theme.spacing(0.5)}; `; +const StyledPaginationIndicator = styled.span` + color: ${({ theme }) => theme.font.color.light}; + font-size: ${({ theme }) => theme.font.size.xs}; +`; + +const legendEnterExitVariants = { + hidden: { + y: 10, + opacity: 0, + }, + visible: { + y: 0, + opacity: 1, + }, + exit: { + y: 10, + opacity: 0, + }, +}; + export const GraphWidgetLegend = ({ items, show = true, }: GraphWidgetLegendProps) => { - const areThereTooManyItems = items.length > CHART_LEGEND_ITEM_THRESHOLD; + const containerRef = useRef(null); - const isItASingleItem = items.length === 1; + const [currentPage, setCurrentPage] = useState(0); - const thereAreNoItems = items.length === 0; + const [containerWidth, setContainerWidth] = useState(0); - const shouldShowLegend = - show && !areThereTooManyItems && !isItASingleItem && !thereAreNoItems; + const [animationDirection, setAnimationDirection] = + useState('forward'); - if (!shouldShowLegend) { - return null; - } + const theme = useTheme(); + + const shouldShowLegend = show && items.length > 1; + + const availableWidth = containerWidth - LEGEND_PAGINATION_CONTROLS_WIDTH; + + const itemsPerPage = Math.max( + 1, + Math.floor(availableWidth / LEGEND_ITEM_ESTIMATED_WIDTH), + ); + + const needsPagination = items.length > itemsPerPage; + const totalPages = Math.ceil(items.length / itemsPerPage); + const safeCurrentPage = Math.min(currentPage, Math.max(0, totalPages - 1)); + + const startIndex = safeCurrentPage * itemsPerPage; + const visibleItems = needsPagination + ? items.slice(startIndex, startIndex + itemsPerPage) + : items; + + const handlePreviousPage = (e: React.MouseEvent) => { + e.stopPropagation(); + setAnimationDirection('backward'); + setCurrentPage((prevPage) => Math.max(0, prevPage - 1)); + }; + + const handleNextPage = (e: React.MouseEvent) => { + e.stopPropagation(); + setAnimationDirection('forward'); + setCurrentPage((prevPage) => Math.min(totalPages - 1, prevPage + 1)); + }; + + const slideOffset = availableWidth; + + const variants = { + enter: (direction: AnimationDirection) => ({ + x: direction === 'forward' ? slideOffset : -slideOffset, + }), + center: { + x: 0, + }, + exit: (direction: AnimationDirection) => ({ + x: direction === 'forward' ? -slideOffset : slideOffset, + }), + }; return ( - - {items.map((item) => ( - - - {item.label} - - ))} - + + {shouldShowLegend && ( + + + { + const newItemsPerPage = Math.max( + 1, + Math.floor( + (width - LEGEND_PAGINATION_CONTROLS_WIDTH) / + LEGEND_ITEM_ESTIMATED_WIDTH, + ), + ); + + if (newItemsPerPage !== itemsPerPage) { + setCurrentPage(0); + } + + setContainerWidth(width); + }} + /> + {needsPagination && ( + + + + {safeCurrentPage + 1}/{totalPages} + + + + )} + + + + {visibleItems.map((item) => ( + + + + + + + ))} + + + + + + )} + ); }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegendDot.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegendDot.tsx new file mode 100644 index 00000000000..591a5d394f4 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegendDot.tsx @@ -0,0 +1,17 @@ +import styled from '@emotion/styled'; + +type GraphWidgetLegendDotProps = { + color: string; +}; + +const StyledDot = styled.div<{ color: string }>` + background: ${({ color }) => color}; + border-radius: 2px; + height: 8px; + width: 8px; + flex-shrink: 0; +`; + +export const GraphWidgetLegendDot = ({ color }: GraphWidgetLegendDotProps) => { + return ; +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetTooltip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetTooltip.tsx index eaf693baf0f..9b5dff001f0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetTooltip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetTooltip.tsx @@ -1,12 +1,13 @@ import { GRAPH_TOOLTIP_MAX_WIDTH_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipMaxWidthPx'; import { GRAPH_TOOLTIP_MIN_WIDTH_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipMinWidthPx'; import { GRAPH_TOOLTIP_SCROLL_MAX_HEIGHT_PX } from '@/page-layout/widgets/graph/components/constants/GraphTooltipScrollMaxHeightPx'; +import { GraphWidgetLegendDot } from '@/page-layout/widgets/graph/components/GraphWidgetLegendDot'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; -import { IconArrowUpRight } from 'twenty-ui/display'; import { isDefined } from 'twenty-shared/utils'; +import { IconArrowUpRight } from 'twenty-ui/display'; const StyledTooltip = styled.div` background: ${({ theme }) => theme.background.primary}; @@ -43,14 +44,6 @@ const StyledTooltipRowContainer = styled.div` overflow-y: auto; `; -const StyledDot = styled.div<{ color: string }>` - background: ${({ color }) => color}; - border-radius: 50%; - height: 6px; - width: 6px; - flex-shrink: 0; -`; - const StyledTooltipLink = styled.div` align-items: center; color: ${({ theme }) => theme.font.color.light}; @@ -168,7 +161,7 @@ export const GraphWidgetTooltip = ({ shouldHighlight && highlightedKey === item.key; return ( - + {item.label} diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/ChartLegendItemThreshold.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/ChartLegendItemThreshold.ts deleted file mode 100644 index 09a9d5df8e5..00000000000 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/ChartLegendItemThreshold.ts +++ /dev/null @@ -1 +0,0 @@ -export const CHART_LEGEND_ITEM_THRESHOLD = 10; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendItemEstimatedWidth.constant.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendItemEstimatedWidth.constant.ts new file mode 100644 index 00000000000..e26f447fe23 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendItemEstimatedWidth.constant.ts @@ -0,0 +1,2 @@ +// Estimated width of a legend item in pixels (dot + gap + label + container gap) +export const LEGEND_ITEM_ESTIMATED_WIDTH = 100; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendLabelMaxWidth.constant.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendLabelMaxWidth.constant.ts new file mode 100644 index 00000000000..86680697168 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendLabelMaxWidth.constant.ts @@ -0,0 +1,2 @@ +// Max width of a legend label before truncation +export const LEGEND_LABEL_MAX_WIDTH = 80; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendPaginationControlsWidth.constant.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendPaginationControlsWidth.constant.ts new file mode 100644 index 00000000000..fb1b0e9c52d --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/constants/LegendPaginationControlsWidth.constant.ts @@ -0,0 +1,2 @@ +// Width of pagination controls (prev button + indicator + next button) +export const LEGEND_PAGINATION_CONTROLS_WIDTH = 70; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx index 3e90cb49bb3..427e13a4abd 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx @@ -1,3 +1,4 @@ +import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect'; import { useGraphBarChartWidgetData } from '@/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData'; @@ -5,7 +6,6 @@ import { type BarChartDataItem } from '@/page-layout/widgets/graph/graphWidgetBa import { getEffectiveGroupMode } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getEffectiveGroupMode'; import { buildChartDrilldownQueryParams } from '@/page-layout/widgets/graph/utils/buildChartDrilldownQueryParams'; import { generateChartAggregateFilterKey } from '@/page-layout/widgets/graph/utils/generateChartAggregateFilterKey'; -import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { type ComputedDatum } from '@nivo/bar'; @@ -40,6 +40,7 @@ export const GraphWidgetBarChartRenderer = ({ xAxisLabel, yAxisLabel, showDataLabels, + showLegend, layout, loading, hasTooManyGroups, @@ -116,6 +117,7 @@ export const GraphWidgetBarChartRenderer = ({ xAxisLabel={xAxisLabel} yAxisLabel={yAxisLabel} showValues={showDataLabels} + showLegend={showLegend} layout={layout} groupMode={groupMode} id={widget.id} diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts index 72c099bcdcf..65c24d80ea6 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts @@ -17,9 +17,9 @@ export const useBarChartTheme = () => { }, legend: { text: { - fill: theme.font.color.secondary, - fontSize: 12, - fontWeight: theme.font.weight.regular, + fill: theme.font.color.primary, + fontSize: theme.font.size.sm, + fontWeight: theme.font.weight.medium, }, }, }, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData.ts index 3a64ff8b2e5..e7d126b26d2 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useGraphBarChartWidgetData.ts @@ -22,6 +22,7 @@ type UseGraphBarChartWidgetDataResult = { xAxisLabel?: string; yAxisLabel?: string; showDataLabels: boolean; + showLegend: boolean; layout?: BarChartLayout; loading: boolean; error?: Error; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts index ed61a02bcf8..89f3797a91b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts @@ -37,6 +37,7 @@ type TransformGroupByDataToBarChartDataResult = { xAxisLabel?: string; yAxisLabel?: string; showDataLabels: boolean; + showLegend: boolean; layout?: BarChartLayout; hasTooManyGroups: boolean; formattedToRawLookup: Map; @@ -50,6 +51,7 @@ const EMPTY_BAR_CHART_RESULT: TransformGroupByDataToBarChartDataResult = { xAxisLabel: undefined, yAxisLabel: undefined, showDataLabels: false, + showLegend: true, layout: BarChartLayout.VERTICAL, hasTooManyGroups: false, formattedToRawLookup: new Map(), @@ -146,6 +148,7 @@ export const transformGroupByDataToBarChartData = ({ : undefined; const showDataLabels = configuration.displayDataLabel ?? false; + const showLegend = configuration.displayLegend ?? true; const isDateField = groupByFieldX.type === FieldMetadataType.DATE || @@ -199,6 +202,7 @@ export const transformGroupByDataToBarChartData = ({ xAxisLabel, yAxisLabel, showDataLabels, + showLegend, layout, hasTooManyGroups: baseResult.hasTooManyGroups || dateRangeWasTruncated, formattedToRawLookup: baseResult.formattedToRawLookup, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx index 0edbe5d6ad8..016cdf317c9 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx @@ -1,3 +1,4 @@ +import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { ChartSkeletonLoader } from '@/page-layout/widgets/graph/components/ChartSkeletonLoader'; import { GraphWidgetChartHasTooManyGroupsEffect } from '@/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect'; import { LINE_CHART_IS_STACKED_DEFAULT } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartIsStackedDefault'; @@ -5,7 +6,6 @@ import { useGraphLineChartWidgetData } from '@/page-layout/widgets/graph/graphWi import { type LineChartDataPoint } from '@/page-layout/widgets/graph/graphWidgetLineChart/types/LineChartDataPoint'; import { buildChartDrilldownQueryParams } from '@/page-layout/widgets/graph/utils/buildChartDrilldownQueryParams'; import { generateChartAggregateFilterKey } from '@/page-layout/widgets/graph/utils/generateChartAggregateFilterKey'; -import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { type LineSeries, type Point } from '@nivo/line'; @@ -37,6 +37,7 @@ export const GraphWidgetLineChartRenderer = ({ xAxisLabel, yAxisLabel, showDataLabels, + showLegend, hasTooManyGroups, loading, formattedToRawLookup, @@ -113,6 +114,7 @@ export const GraphWidgetLineChartRenderer = ({ xAxisLabel={xAxisLabel} yAxisLabel={yAxisLabel} enablePointLabel={showDataLabels} + showLegend={showLegend} rangeMin={configuration.rangeMin ?? undefined} rangeMax={configuration.rangeMax ?? undefined} omitNullValues={configuration.omitNullValues ?? false} diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useGraphLineChartWidgetData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useGraphLineChartWidgetData.ts index 655176cda56..b35225540d8 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useGraphLineChartWidgetData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useGraphLineChartWidgetData.ts @@ -17,6 +17,7 @@ type UseGraphLineChartWidgetDataResult = { xAxisLabel?: string; yAxisLabel?: string; showDataLabels: boolean; + showLegend: boolean; hasTooManyGroups: boolean; formattedToRawLookup: Map; loading: boolean; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts index 631f5083315..de2276afa9f 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts @@ -23,9 +23,9 @@ export const useLineChartTheme = () => { }, legend: { text: { - fill: theme.font.color.secondary, - fontSize: 12, - fontWeight: theme.font.weight.regular, + fill: theme.font.color.primary, + fontSize: theme.font.size.sm, + fontWeight: theme.font.weight.medium, }, }, }, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx index 099a51165bf..fdd9dae0dfd 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx @@ -152,6 +152,14 @@ export const GraphWidgetPieChart = ({ arcLinkLabelsStraightLength={10} arcLinkLabelsTextColor={theme.font.color.light} arcLinkLabelsColor={theme.font.color.extraLight} + theme={{ + labels: { + text: { + fontSize: theme.font.size.sm, + fontWeight: theme.font.weight.medium, + }, + }, + }} /> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx index 8de8f85e737..816ed8b6747 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx @@ -32,8 +32,9 @@ export const GraphWidgetPieChartRenderer = ({ loading, hasTooManyGroups, objectMetadataItem, - formattedToRawLookup, + showLegend, showDataLabels, + formattedToRawLookup, } = useGraphPieChartWidgetData({ objectMetadataItemId: widget.objectMetadataId, configuration: widget.configuration as PieChartConfiguration, @@ -84,6 +85,7 @@ export const GraphWidgetPieChartRenderer = ({ ; }; const EMPTY_PIE_CHART_RESULT: TransformGroupByDataToPieChartDataResult = { data: [], + showLegend: true, hasTooManyGroups: false, formattedToRawLookup: new Map(), }; @@ -99,8 +101,11 @@ export const transformGroupByDataToPieChartData = ({ }; }); + const showLegend = configuration.displayLegend ?? true; + return { data, + showLegend, hasTooManyGroups: rawResults.length > PIE_CHART_MAXIMUM_NUMBER_OF_SLICES, formattedToRawLookup, }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/transformGroupByDataToLineChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/transformGroupByDataToLineChartData.ts index 5983fc26986..177f0004ebf 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/transformGroupByDataToLineChartData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/utils/transformGroupByDataToLineChartData.ts @@ -27,6 +27,7 @@ type TransformGroupByDataToLineChartDataResult = { xAxisLabel?: string; yAxisLabel?: string; showDataLabels: boolean; + showLegend: boolean; hasTooManyGroups: boolean; formattedToRawLookup: Map; }; @@ -36,6 +37,7 @@ const EMPTY_LINE_CHART_RESULT: TransformGroupByDataToLineChartDataResult = { xAxisLabel: undefined, yAxisLabel: undefined, showDataLabels: false, + showLegend: true, hasTooManyGroups: false, formattedToRawLookup: new Map(), }; @@ -113,6 +115,7 @@ export const transformGroupByDataToLineChartData = ({ : undefined; const showDataLabels = configuration.displayDataLabel ?? false; + const showLegend = configuration.displayLegend ?? true; const baseResult = isDefined(groupByFieldY) ? transformTwoDimensionalGroupByToLineChartData({ @@ -140,6 +143,7 @@ export const transformGroupByDataToLineChartData = ({ xAxisLabel, yAxisLabel, showDataLabels, + showLegend, formattedToRawLookup: baseResult.formattedToRawLookup, }; }; diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto.ts b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto.ts index 07d03ce1214..104373e90a2 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/bar-chart-configuration.dto.ts @@ -108,6 +108,11 @@ export class BarChartConfigurationDTO { @IsOptional() displayDataLabel?: boolean; + @Field(() => Boolean, { nullable: true, defaultValue: true }) + @IsBoolean() + @IsOptional() + displayLegend?: boolean; + @Field(() => Number, { nullable: true }) @IsNumber() @IsOptional() diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto.ts b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto.ts index c3bdb8994e3..4716974cc54 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/line-chart-configuration.dto.ts @@ -109,6 +109,11 @@ export class LineChartConfigurationDTO { @IsOptional() displayDataLabel?: boolean; + @Field(() => Boolean, { nullable: true, defaultValue: true }) + @IsBoolean() + @IsOptional() + displayLegend?: boolean; + @Field(() => Number, { nullable: true }) @IsNumber() @IsOptional() diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto.ts b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto.ts index 5e3f75120e1..5145408eb7e 100644 --- a/packages/twenty-server/src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/page-layout/dtos/pie-chart-configuration.dto.ts @@ -71,6 +71,11 @@ export class PieChartConfigurationDTO { @IsOptional() displayDataLabel?: boolean; + @Field(() => Boolean, { nullable: true, defaultValue: true }) + @IsBoolean() + @IsOptional() + displayLegend?: boolean; + @Field(() => String, { nullable: true }) @IsString() @IsOptional()