Files
twenty/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useChartSettingsValues.ts
T
Raphaël Bosi 1739ee0595 Add date granularity and timezone and first day of the week to graphs (#15543)
- Allow users to choose the date granularity of the x axis and the group
by of the y axis on a bar chart
- Display those options conditionally
- Store timezones in graphs: each graph has its own timezone, defaults
to the user timezone. There will be a picker in the v2 to choose the
timezone. For now the timezone is not used by the backend, but it will
be used in filters and in group by queries.
- Store first day of the week



https://github.com/user-attachments/assets/66a5d156-dd93-4ebe-8c8f-d172f93e25be
2025-11-03 15:27:47 +01:00

203 lines
8.3 KiB
TypeScript

import { useGraphGroupBySortOptionLabels } from '@/command-menu/pages/page-layout/hooks/useGraphGroupBySortOptionLabels';
import { useGraphXSortOptionLabels } from '@/command-menu/pages/page-layout/hooks/useGraphXSortOptionLabels';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { getChartAxisNameDisplayOptions } from '@/command-menu/pages/page-layout/utils/getChartAxisNameDisplayOptions';
import { getDateGranularityLabel } from '@/command-menu/pages/page-layout/utils/getDateGranularityLabel';
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';
import { type GraphOrderBy } from '~/generated-metadata/graphql';
export const useChartSettingsValues = ({
objectMetadataId,
configuration,
}: {
objectMetadataId: string;
configuration?: ChartConfiguration;
}) => {
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const objectMetadataItem = objectMetadataItems.find(
(objectMetadataItem) => objectMetadataItem.id === objectMetadataId,
);
const { getXSortOptionLabel } = useGraphXSortOptionLabels({
objectMetadataId,
});
const { getGroupBySortOptionLabel } = useGraphGroupBySortOptionLabels({
objectMetadataId,
});
if (!configuration) {
return {
getChartSettingsValues: () => undefined,
};
}
const isBarOrLineChart =
configuration.__typename === 'BarChartConfiguration' ||
configuration.__typename === 'LineChartConfiguration';
let groupByFieldXId: string | undefined;
let groupByFieldYId: string | undefined;
let groupBySubFieldNameX: CompositeFieldSubFieldName | undefined;
let groupBySubFieldNameY: CompositeFieldSubFieldName | undefined;
let xAxisOrderBy: GraphOrderBy | undefined | null;
let groupByOrderBy: GraphOrderBy | undefined | null;
if (isBarOrLineChart) {
groupByFieldXId = configuration.primaryAxisGroupByFieldMetadataId;
groupByFieldYId = configuration.secondaryAxisGroupByFieldMetadataId;
groupBySubFieldNameX = configuration.primaryAxisGroupBySubFieldName as
| CompositeFieldSubFieldName
| undefined;
groupBySubFieldNameY = configuration.secondaryAxisGroupBySubFieldName as
| CompositeFieldSubFieldName
| undefined;
xAxisOrderBy = configuration.primaryAxisOrderBy;
groupByOrderBy = configuration.secondaryAxisOrderBy;
}
const groupByFieldX = isDefined(groupByFieldXId)
? objectMetadataItem?.fields.find((field) => field.id === groupByFieldXId)
: undefined;
const groupByFieldY = isDefined(groupByFieldYId)
? objectMetadataItem?.fields.find((field) => field.id === groupByFieldYId)
: undefined;
const groupBySubFieldNameXLabel =
isDefined(groupBySubFieldNameX) && isDefined(groupByFieldX)
? getFieldLabelWithSubField({
field: groupByFieldX,
subFieldName: groupBySubFieldNameX,
})
: undefined;
const aggregateField = objectMetadataItem?.fields.find(
(fieldMetadataItem) =>
fieldMetadataItem.id === configuration.aggregateFieldMetadataId,
);
const aggregateOperation =
convertAggregateOperationToExtendedAggregateOperation(
configuration.aggregateOperation,
aggregateField?.type,
);
const xAxisOrderByLabel =
isDefined(xAxisOrderBy) && isDefined(groupByFieldXId)
? getXSortOptionLabel({
graphOrderBy: xAxisOrderBy,
groupByFieldMetadataIdX: groupByFieldXId,
groupBySubFieldNameX: groupBySubFieldNameX,
aggregateFieldMetadataId: configuration.aggregateFieldMetadataId,
aggregateOperation: configuration.aggregateOperation ?? undefined,
})
: undefined;
if (configuration.__typename === 'PieChartConfiguration') {
groupByOrderBy = configuration.orderBy;
groupByFieldYId = configuration.groupByFieldMetadataId;
groupBySubFieldNameY = configuration.groupBySubFieldName as
| CompositeFieldSubFieldName
| undefined;
}
const finalGroupByFieldYId = groupByFieldYId;
const finalGroupBySubFieldNameY = groupBySubFieldNameY;
const groupByOrderByLabel =
isDefined(groupByOrderBy) && isDefined(finalGroupByFieldYId)
? getGroupBySortOptionLabel({
graphOrderBy: groupByOrderBy,
groupByFieldMetadataId: finalGroupByFieldYId,
groupBySubFieldName: finalGroupBySubFieldNameY,
})
: undefined;
const getChartSettingsValues = (
itemId: CHART_CONFIGURATION_SETTING_IDS,
): boolean | string | undefined => {
switch (itemId) {
case CHART_CONFIGURATION_SETTING_IDS.SOURCE:
return objectMetadataItem?.labelPlural;
case CHART_CONFIGURATION_SETTING_IDS.DATA_ON_DISPLAY_X:
return groupBySubFieldNameXLabel ?? groupByFieldX?.label;
case CHART_CONFIGURATION_SETTING_IDS.COLORS:
return 'color' in configuration && isDefined(configuration.color)
? capitalize(configuration.color)
: undefined;
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(aggregateOperation);
return `${aggregateField?.label ?? ''}${
hasAggregateLabel && hasAggregateOperation
? ` (${getAggregateOperationLabel(aggregateOperation)})`
: ''
}`;
}
case CHART_CONFIGURATION_SETTING_IDS.GROUP_BY:
return groupByFieldY?.label;
case CHART_CONFIGURATION_SETTING_IDS.AXIS_NAME:
return 'axisNameDisplay' in configuration &&
isDefined(configuration.axisNameDisplay)
? getChartAxisNameDisplayOptions(configuration.axisNameDisplay)
: undefined;
case CHART_CONFIGURATION_SETTING_IDS.SORT_BY_X:
return xAxisOrderByLabel;
case CHART_CONFIGURATION_SETTING_IDS.SORT_BY_GROUP_BY_FIELD:
return groupByOrderByLabel;
case CHART_CONFIGURATION_SETTING_IDS.DATA_LABELS:
return configuration.displayDataLabel ?? undefined;
case CHART_CONFIGURATION_SETTING_IDS.STACKED_BARS:
return 'groupMode' in configuration
? configuration.groupMode !== 'GROUPED'
: true;
case CHART_CONFIGURATION_SETTING_IDS.OMIT_NULL_VALUES:
return 'omitNullValues' in configuration
? (configuration.omitNullValues ?? false)
: false;
case CHART_CONFIGURATION_SETTING_IDS.MIN_RANGE:
return 'rangeMin' in configuration
? (configuration.rangeMin?.toString() ?? '')
: '';
case CHART_CONFIGURATION_SETTING_IDS.MAX_RANGE:
return 'rangeMax' in configuration
? (configuration.rangeMax?.toString() ?? '')
: '';
case CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_X:
return 'primaryAxisDateGranularity' in configuration &&
isDefined(configuration.primaryAxisDateGranularity)
? getDateGranularityLabel(configuration.primaryAxisDateGranularity)
: undefined;
case CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_Y:
return 'secondaryAxisGroupByDateGranularity' in configuration &&
isDefined(configuration.secondaryAxisGroupByDateGranularity)
? getDateGranularityLabel(
configuration.secondaryAxisGroupByDateGranularity,
)
: undefined;
case CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY:
return 'dateGranularity' in configuration &&
isDefined(configuration.dateGranularity)
? getDateGranularityLabel(configuration.dateGranularity)
: undefined;
default:
return '';
}
};
return {
getChartSettingsValues,
};
};