fix incorrect date formatting being applied to non-date fields in graph widgets (#16254)

before - 


https://github.com/user-attachments/assets/d8d7dee3-ce09-4a04-8054-41bb302c69f4




after - 



https://github.com/user-attachments/assets/2d563c51-6700-4b71-8997-de5e87f1df68
This commit is contained in:
nitin
2025-12-02 19:56:41 +05:30
committed by GitHub
parent eecc7aaed3
commit 0158c6fb3c
9 changed files with 170 additions and 25 deletions
@@ -1,4 +1,5 @@
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { type BarChartLayout } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartLayout';
import { type BarChartSeries } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartSeries';
import { getBarChartQueryLimit } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getBarChartQueryLimit';
@@ -40,6 +41,7 @@ export const useGraphBarChartWidgetData = ({
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataItemId,
});
const { objectMetadataItems } = useObjectMetadataItems();
const limit = getBarChartQueryLimit(configuration);
@@ -59,10 +61,17 @@ export const useGraphBarChartWidgetData = ({
transformGroupByDataToBarChartData({
groupByData,
objectMetadataItem,
objectMetadataItems: objectMetadataItems ?? [],
configuration,
aggregateOperation,
}),
[groupByData, objectMetadataItem, configuration, aggregateOperation],
[
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
],
);
return {
@@ -44,6 +44,7 @@ describe('transformGroupByDataToBarChartData', () => {
id: 'group-by-field',
name: 'company',
type: FieldMetadataType.RELATION,
relation: { targetObjectMetadata: { nameSingular: 'company' } },
};
const aggregateField = {
@@ -56,9 +57,15 @@ describe('transformGroupByDataToBarChartData', () => {
id: 'obj-1',
nameSingular: 'company',
namePlural: 'companies',
fields: [groupByField, aggregateField],
fields: [
groupByField,
aggregateField,
{ id: 'createdAt', name: 'createdAt', type: FieldMetadataType.DATE },
],
} as any;
const objectMetadataItems = [objectMetadataItem];
const configuration = {
__typename: 'BarChartConfiguration',
aggregateFieldMetadataId: aggregateField.id,
@@ -81,6 +88,7 @@ describe('transformGroupByDataToBarChartData', () => {
const result = transformGroupByDataToBarChartData({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation: 'COUNT',
});
@@ -13,6 +13,7 @@ import { type GroupByRawResult } from '@/page-layout/widgets/graph/types/GroupBy
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { filterGroupByResults } from '@/page-layout/widgets/graph/utils/filterGroupByResults';
import { getFieldKey } from '@/page-layout/widgets/graph/utils/getFieldKey';
import { isNestedFieldDateType } from '@/page-layout/widgets/graph/utils/isNestedFieldDateType';
import { type BarDatum } from '@nivo/bar';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { GraphType } from '~/generated-metadata/graphql';
@@ -24,6 +25,7 @@ import {
type TransformGroupByDataToBarChartDataParams = {
groupByData: Record<string, GroupByRawResult[]> | null | undefined;
objectMetadataItem: ObjectMetadataItem;
objectMetadataItems: ObjectMetadataItem[];
configuration: BarChartConfiguration;
aggregateOperation: string;
};
@@ -59,6 +61,7 @@ const EMPTY_BAR_CHART_RESULT: TransformGroupByDataToBarChartDataResult = {
export const transformGroupByDataToBarChartData = ({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
}: TransformGroupByDataToBarChartDataParams): TransformGroupByDataToBarChartDataResult => {
@@ -97,6 +100,8 @@ export const transformGroupByDataToBarChartData = ({
const primaryAxisSubFieldName =
configuration.primaryAxisGroupBySubFieldName ?? undefined;
const secondaryAxisSubFieldName =
configuration.secondaryAxisGroupBySubFieldName ?? undefined;
const indexByKey = getFieldKey({
field: groupByFieldX,
@@ -154,9 +159,44 @@ export const transformGroupByDataToBarChartData = ({
const showLegend = configuration.displayLegend ?? true;
const isDateField = isFieldMetadataDateKind(groupByFieldX.type);
const isNestedDateField =
!isDateField && isDefined(configuration.primaryAxisDateGranularity);
const shouldApplyDateGapFill = isDateField || isNestedDateField;
const isNestedDateField = isNestedFieldDateType(
groupByFieldX,
primaryAxisSubFieldName,
objectMetadataItems,
);
const primaryAxisDateGranularity =
isDateField || isNestedDateField
? (configuration.primaryAxisDateGranularity ??
GRAPH_DEFAULT_DATE_GRANULARITY)
: undefined;
const isSecondaryDateField = isDefined(groupByFieldY)
? isFieldMetadataDateKind(groupByFieldY.type)
: false;
const isSecondaryNestedDateField =
isDefined(groupByFieldY) &&
isNestedFieldDateType(
groupByFieldY,
secondaryAxisSubFieldName ?? undefined,
objectMetadataItems,
);
const secondaryAxisDateGranularity =
isSecondaryDateField || isSecondaryNestedDateField
? (configuration.secondaryAxisGroupByDateGranularity ??
GRAPH_DEFAULT_DATE_GRANULARITY)
: undefined;
const sanitizedConfiguration: BarChartConfiguration = {
...configuration,
primaryAxisDateGranularity: primaryAxisDateGranularity ?? undefined,
secondaryAxisGroupByDateGranularity:
secondaryAxisDateGranularity ?? undefined,
};
const shouldApplyDateGapFill = isDefined(primaryAxisDateGranularity);
const omitNullValues = configuration.omitNullValues ?? false;
@@ -166,8 +206,7 @@ export const transformGroupByDataToBarChartData = ({
data: filteredResults,
keys: [aggregateField.name],
dateGranularity:
configuration.primaryAxisDateGranularity ??
GRAPH_DEFAULT_DATE_GRANULARITY,
primaryAxisDateGranularity ?? GRAPH_DEFAULT_DATE_GRANULARITY,
hasSecondDimension: isDefined(groupByFieldY),
})
: { data: filteredResults, wasTruncated: false };
@@ -181,7 +220,7 @@ export const transformGroupByDataToBarChartData = ({
groupByFieldX,
groupByFieldY,
aggregateField,
configuration,
configuration: sanitizedConfiguration,
aggregateOperation,
objectMetadataItem,
primaryAxisSubFieldName,
@@ -190,7 +229,7 @@ export const transformGroupByDataToBarChartData = ({
rawResults: filteredResultsWithDateGaps,
groupByFieldX,
aggregateField,
configuration,
configuration: sanitizedConfiguration,
aggregateOperation,
objectMetadataItem,
primaryAxisSubFieldName,
@@ -1,4 +1,5 @@
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { type LineChartSeries } from '@/page-layout/widgets/graph/graphWidgetLineChart/types/LineChartSeries';
import { getLineChartQueryLimit } from '@/page-layout/widgets/graph/graphWidgetLineChart/utils/getLineChartQueryLimit';
import { useGraphWidgetGroupByQuery } from '@/page-layout/widgets/graph/hooks/useGraphWidgetGroupByQuery';
@@ -34,6 +35,7 @@ export const useGraphLineChartWidgetData = ({
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataItemId,
});
const { objectMetadataItems } = useObjectMetadataItems();
const limit = getLineChartQueryLimit(configuration);
@@ -53,10 +55,17 @@ export const useGraphLineChartWidgetData = ({
transformGroupByDataToLineChartData({
groupByData,
objectMetadataItem,
objectMetadataItems: objectMetadataItems ?? [],
configuration,
aggregateOperation,
}),
[groupByData, objectMetadataItem, configuration, aggregateOperation],
[
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
],
);
return {
@@ -1,4 +1,5 @@
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { EXTRA_ITEM_TO_DETECT_TOO_MANY_GROUPS } from '@/page-layout/widgets/graph/constants/ExtraItemToDetectTooManyGroups.constant';
import { PIE_CHART_MAXIMUM_NUMBER_OF_SLICES } from '@/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMaximumNumberOfSlices.constant';
@@ -33,6 +34,7 @@ export const useGraphPieChartWidgetData = ({
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataItemId,
});
const { objectMetadataItems } = useObjectMetadataItems();
const {
data: groupByData,
@@ -51,10 +53,17 @@ export const useGraphPieChartWidgetData = ({
transformGroupByDataToPieChartData({
groupByData,
objectMetadataItem,
objectMetadataItems: objectMetadataItems ?? [],
configuration,
aggregateOperation,
}),
[groupByData, objectMetadataItem, configuration, aggregateOperation],
[
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
],
);
return {
@@ -41,6 +41,7 @@ describe('transformGroupByDataToPieChartData', () => {
namePlural: 'companies',
fields: [groupByField, aggregateField],
} as any;
const objectMetadataItems = [objectMetadataItem];
const configuration = {
__typename: 'PieChartConfiguration',
@@ -72,6 +73,7 @@ describe('transformGroupByDataToPieChartData', () => {
const result = transformGroupByDataToPieChartData({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation: 'COUNT',
});
@@ -106,6 +108,7 @@ describe('transformGroupByDataToPieChartData', () => {
namePlural: 'companies',
fields: [groupByField, aggregateField],
} as any;
const objectMetadataItems = [objectMetadataItem];
const configuration = {
__typename: 'PieChartConfiguration',
@@ -137,6 +140,7 @@ describe('transformGroupByDataToPieChartData', () => {
const result = transformGroupByDataToPieChartData({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation: 'COUNT',
});
@@ -11,12 +11,15 @@ import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDim
import { buildFormattedToRawLookup } from '@/page-layout/widgets/graph/utils/buildFormattedToRawLookup';
import { computeAggregateValueFromGroupByResult } from '@/page-layout/widgets/graph/utils/computeAggregateValueFromGroupByResult';
import { formatPrimaryDimensionValues } from '@/page-layout/widgets/graph/utils/formatPrimaryDimensionValues';
import { isDefined } from 'twenty-shared/utils';
import { isNestedFieldDateType } from '@/page-layout/widgets/graph/utils/isNestedFieldDateType';
import { type ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { type PieChartConfiguration } from '~/generated/graphql';
type TransformGroupByDataToPieChartDataParams = {
groupByData: Record<string, GroupByRawResult[]> | null | undefined;
objectMetadataItem: ObjectMetadataItem;
objectMetadataItems: ObjectMetadataItem[];
configuration: PieChartConfiguration;
aggregateOperation: string;
};
@@ -38,6 +41,7 @@ const EMPTY_PIE_CHART_RESULT: TransformGroupByDataToPieChartDataResult = {
export const transformGroupByDataToPieChartData = ({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
}: TransformGroupByDataToPieChartDataParams): TransformGroupByDataToPieChartDataResult => {
@@ -66,6 +70,18 @@ export const transformGroupByDataToPieChartData = ({
return EMPTY_PIE_CHART_RESULT;
}
const isDateField = isFieldMetadataDateKind(groupByField.type);
const isNestedDateField = isNestedFieldDateType(
groupByField,
configuration.groupBySubFieldName ?? undefined,
objectMetadataItems,
);
const dateGranularity: ObjectRecordGroupByDateGranularity | undefined =
isDateField || isNestedDateField
? (configuration.dateGranularity ?? undefined)
: undefined;
// TODO: Add a limit to the query instead of slicing here (issue: twentyhq/core-team-issues#1600)
const limitedResults = rawResults.slice(
0,
@@ -75,7 +91,7 @@ export const transformGroupByDataToPieChartData = ({
const formattedValues = formatPrimaryDimensionValues({
groupByRawResults: limitedResults,
primaryAxisGroupByField: groupByField,
primaryAxisDateGranularity: configuration.dateGranularity ?? undefined,
primaryAxisDateGranularity: dateGranularity,
primaryAxisGroupBySubFieldName:
configuration.groupBySubFieldName ?? undefined,
});
@@ -41,13 +41,16 @@ const normalizeMultiSelectValue = (value: unknown): unknown[] => {
export const formatDimensionValue = ({
value,
fieldMetadata,
dateGranularity = GRAPH_DEFAULT_DATE_GRANULARITY as ObjectRecordGroupByDateGranularity,
dateGranularity,
subFieldName,
}: FormatDimensionValueParams): string => {
if (!isDefined(value)) {
return t`Not Set`;
}
const effectiveDateGranularity = (dateGranularity ??
GRAPH_DEFAULT_DATE_GRANULARITY) as ObjectRecordGroupByDateGranularity;
switch (fieldMetadata.type) {
case FieldMetadataType.SELECT: {
const selectedOption = fieldMetadata.options?.find(
@@ -75,21 +78,31 @@ export const formatDimensionValue = ({
case FieldMetadataType.DATE:
case FieldMetadataType.DATE_TIME: {
const parsedDate = new Date(String(value));
if (isNaN(parsedDate.getTime())) {
return String(value);
}
if (
dateGranularity ===
effectiveDateGranularity ===
ObjectRecordGroupByDateGranularity.DAY_OF_THE_WEEK ||
dateGranularity ===
effectiveDateGranularity ===
ObjectRecordGroupByDateGranularity.MONTH_OF_THE_YEAR ||
dateGranularity ===
effectiveDateGranularity ===
ObjectRecordGroupByDateGranularity.QUARTER_OF_THE_YEAR
) {
return String(value);
}
return formatDateByGranularity(new Date(String(value)), dateGranularity);
return formatDateByGranularity(parsedDate, effectiveDateGranularity);
}
case FieldMetadataType.RELATION: {
if (isDefined(dateGranularity)) {
const parsedDate = new Date(String(value));
if (isNaN(parsedDate.getTime())) {
return String(value);
}
if (
dateGranularity ===
ObjectRecordGroupByDateGranularity.DAY_OF_THE_WEEK ||
@@ -100,10 +113,7 @@ export const formatDimensionValue = ({
) {
return String(value);
}
return formatDateByGranularity(
new Date(String(value)),
dateGranularity,
);
return formatDateByGranularity(parsedDate, dateGranularity);
}
return String(value);
}
@@ -9,7 +9,8 @@ import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDim
import { filterGroupByResults } from '@/page-layout/widgets/graph/utils/filterGroupByResults';
import { transformOneDimensionalGroupByToLineChartData } from '@/page-layout/widgets/graph/utils/transformOneDimensionalGroupByToLineChartData';
import { transformTwoDimensionalGroupByToLineChartData } from '@/page-layout/widgets/graph/utils/transformTwoDimensionalGroupByToLineChartData';
import { isDefined } from 'twenty-shared/utils';
import { isNestedFieldDateType } from '@/page-layout/widgets/graph/utils/isNestedFieldDateType';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import {
AxisNameDisplay,
type LineChartConfiguration,
@@ -18,6 +19,7 @@ import {
type TransformGroupByDataToLineChartDataParams = {
groupByData: Record<string, GroupByRawResult[]> | null | undefined;
objectMetadataItem: ObjectMetadataItem;
objectMetadataItems: ObjectMetadataItem[];
configuration: LineChartConfiguration;
aggregateOperation: string;
};
@@ -45,6 +47,7 @@ const EMPTY_LINE_CHART_RESULT: TransformGroupByDataToLineChartDataResult = {
export const transformGroupByDataToLineChartData = ({
groupByData,
objectMetadataItem,
objectMetadataItems,
configuration,
aggregateOperation,
}: TransformGroupByDataToLineChartDataParams): TransformGroupByDataToLineChartDataResult => {
@@ -77,6 +80,8 @@ export const transformGroupByDataToLineChartData = ({
const primaryAxisSubFieldName =
configuration.primaryAxisGroupBySubFieldName ?? undefined;
const secondaryAxisSubFieldName =
configuration.secondaryAxisGroupBySubFieldName ?? undefined;
const queryResultGqlFieldName =
getGroupByQueryResultGqlFieldName(objectMetadataItem);
@@ -121,13 +126,49 @@ export const transformGroupByDataToLineChartData = ({
const showDataLabels = configuration.displayDataLabel ?? false;
const showLegend = configuration.displayLegend ?? true;
const isDateField = isFieldMetadataDateKind(groupByFieldX.type);
const isNestedDateField = isNestedFieldDateType(
groupByFieldX,
primaryAxisSubFieldName,
objectMetadataItems,
);
const primaryAxisDateGranularity =
isDateField || isNestedDateField
? configuration.primaryAxisDateGranularity
: undefined;
const isSecondaryDateField = isDefined(groupByFieldY)
? isFieldMetadataDateKind(groupByFieldY.type)
: false;
const isSecondaryNestedDateField =
isDefined(groupByFieldY) &&
isNestedFieldDateType(
groupByFieldY,
secondaryAxisSubFieldName,
objectMetadataItems,
);
const secondaryAxisDateGranularity =
isSecondaryDateField || isSecondaryNestedDateField
? configuration.secondaryAxisGroupByDateGranularity
: undefined;
const sanitizedConfiguration: LineChartConfiguration = {
...configuration,
primaryAxisDateGranularity: primaryAxisDateGranularity ?? undefined,
secondaryAxisGroupByDateGranularity:
secondaryAxisDateGranularity ?? undefined,
};
const baseResult = isDefined(groupByFieldY)
? transformTwoDimensionalGroupByToLineChartData({
rawResults: filteredResults,
groupByFieldX,
groupByFieldY,
aggregateField,
configuration,
configuration: sanitizedConfiguration,
aggregateOperation,
objectMetadataItem,
primaryAxisSubFieldName,
@@ -136,7 +177,7 @@ export const transformGroupByDataToLineChartData = ({
rawResults: filteredResults,
groupByFieldX,
aggregateField,
configuration,
configuration: sanitizedConfiguration,
aggregateOperation,
objectMetadataItem,
primaryAxisSubFieldName,