Fix chart sorting (#16996)

I introduced a bug in the chart sorting in this PR:
https://github.com/twentyhq/twenty/pull/16794
This PR fixes this.

The sorting on the first axis is already done by the group by for
FIELD_ASC and FIELD_DESC. It is sorted also for the second axis but in
each group.
For instance, if I create a graph that displays the amount of sales on
each day of the week grouped by vendor
I can have for:
Monday: Vendor B, Vendor C
Tuesday: Vendor A, Vendor B
Wednesday: Vendor A, Vendor C
...
Inside each day the order of the vendor is correct, but by looking at
only one day, I can't know the order of all the vendors.
That is why we always need to sort the second axis.
This commit is contained in:
Raphaël Bosi
2026-01-08 13:46:56 +01:00
committed by GitHub
parent 8630efc3d7
commit c207214f0b
13 changed files with 210 additions and 81 deletions
@@ -4,9 +4,11 @@ import { sortBarChartDataBySecondaryDimensionSum } from '@/page-layout/widgets/g
import { type GraphColor } from '@/page-layout/widgets/graph/types/GraphColor';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { sortSecondaryAxisData } from '@/page-layout/widgets/graph/utils/sortSecondaryAxisData';
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually';
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded';
import { type BarDatum } from '@nivo/bar';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FieldMetadataType } from '~/generated-metadata/graphql';
import { type BarChartConfiguration, GraphOrderBy } from '~/generated/graphql';
type SortTwoDimensionalBarChartDataConfiguration = {
@@ -18,6 +20,8 @@ type SortTwoDimensionalBarChartDataConfiguration = {
primaryAxisSelectFieldOptions?: FieldMetadataItemOption[] | null;
secondaryAxisFormattedToRawLookup?: Map<string, RawDimensionValue>;
secondaryAxisSelectFieldOptions?: FieldMetadataItemOption[] | null;
secondaryAxisFieldType?: FieldMetadataType;
secondaryAxisSubFieldName?: CompositeFieldSubFieldName;
};
type SortTwoDimensionalBarChartDataResult = {
@@ -41,6 +45,8 @@ export const sortTwoDimensionalBarChartData = ({
primaryAxisSelectFieldOptions,
secondaryAxisFormattedToRawLookup,
secondaryAxisSelectFieldOptions,
secondaryAxisFieldType,
secondaryAxisSubFieldName,
}: SortTwoDimensionalBarChartDataConfiguration): SortTwoDimensionalBarChartDataResult => {
const sortedKeys = sortSecondaryAxisData({
items: keys,
@@ -49,6 +55,8 @@ export const sortTwoDimensionalBarChartData = ({
formattedToRawLookup: secondaryAxisFormattedToRawLookup,
selectFieldOptions: secondaryAxisSelectFieldOptions,
getFormattedValue: (item) => item,
fieldType: secondaryAxisFieldType,
subFieldName: secondaryAxisSubFieldName,
});
const sortedSeries: BarChartSeries[] = sortedKeys.map((key) => ({
@@ -70,14 +78,15 @@ export const sortTwoDimensionalBarChartData = ({
orderBy: primaryAxisOrderBy,
});
} else {
sortedData = sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually({
data,
orderBy: primaryAxisOrderBy,
manualSortOrder: primaryAxisManualSortOrder,
formattedToRawLookup: primaryAxisFormattedToRawLookup,
getFormattedValue: (datum) => datum[indexByKey] as string,
selectFieldOptions: primaryAxisSelectFieldOptions,
});
sortedData =
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded({
data,
orderBy: primaryAxisOrderBy,
manualSortOrder: primaryAxisManualSortOrder,
formattedToRawLookup: primaryAxisFormattedToRawLookup,
getFormattedValue: (datum) => datum[indexByKey] as string,
selectFieldOptions: primaryAxisSelectFieldOptions,
});
}
}
@@ -9,7 +9,7 @@ import { type GroupByRawResult } from '@/page-layout/widgets/graph/types/GroupBy
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { getFieldKey } from '@/page-layout/widgets/graph/utils/getFieldKey';
import { processOneDimensionalGroupByResults } from '@/page-layout/widgets/graph/utils/processOneDimensionalGroupByResults';
import { sortChartData } from '@/page-layout/widgets/graph/utils/sortChartData';
import { sortChartDataIfNeeded } from '@/page-layout/widgets/graph/utils/sortChartDataIfNeeded';
import { type BarDatum } from '@nivo/bar';
import {
type FirstDayOfTheWeek,
@@ -79,7 +79,7 @@ export const transformOneDimensionalGroupByToBarChartData = ({
}),
);
const sortedData = sortChartData({
const sortedData = sortChartDataIfNeeded({
data: unsortedData,
orderBy: configuration.primaryAxisOrderBy,
manualSortOrder: configuration.primaryAxisManualSortOrder,
@@ -10,6 +10,7 @@ import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDim
import { getFieldKey } from '@/page-layout/widgets/graph/utils/getFieldKey';
import { processTwoDimensionalGroupByResults } from '@/page-layout/widgets/graph/utils/processTwoDimensionalGroupByResults';
import { type BarDatum } from '@nivo/bar';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { type FirstDayOfTheWeek } from 'twenty-shared/utils';
import { type BarChartConfiguration } from '~/generated/graphql';
@@ -81,6 +82,11 @@ export const transformTwoDimensionalGroupByToBarChartData = ({
primaryAxisSelectFieldOptions: groupByFieldX.options,
secondaryAxisFormattedToRawLookup: yFormattedToRawLookup,
secondaryAxisSelectFieldOptions: groupByFieldY.options,
secondaryAxisFieldType: groupByFieldY.type,
secondaryAxisSubFieldName:
(configuration.secondaryAxisGroupBySubFieldName ?? undefined) as
| CompositeFieldSubFieldName
| undefined,
});
const { limitedData, limitedKeys, limitedSeries, hasTooManyGroups } =
@@ -4,8 +4,10 @@ import { type LineChartSeries } from '@/page-layout/widgets/graph/graphWidgetLin
import { sortLineChartDataBySecondaryDimensionSum } from '@/page-layout/widgets/graph/graphWidgetLineChart/utils/sortLineChartDataBySecondaryDimensionSum';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { sortSecondaryAxisData } from '@/page-layout/widgets/graph/utils/sortSecondaryAxisData';
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually';
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FieldMetadataType } from '~/generated-metadata/graphql';
import { type LineChartConfiguration, GraphOrderBy } from '~/generated/graphql';
type SortTwoDimensionalLineChartDataConfiguration = {
@@ -15,6 +17,8 @@ type SortTwoDimensionalLineChartDataConfiguration = {
primaryAxisSelectFieldOptions?: FieldMetadataItemOption[] | null;
secondaryAxisFormattedToRawLookup?: Map<string, RawDimensionValue>;
secondaryAxisSelectFieldOptions?: FieldMetadataItemOption[] | null;
secondaryAxisFieldType?: FieldMetadataType;
secondaryAxisSubFieldName?: CompositeFieldSubFieldName;
};
type SortTwoDimensionalLineChartDataResult = {
@@ -33,6 +37,8 @@ export const sortTwoDimensionalLineChartData = ({
primaryAxisSelectFieldOptions,
secondaryAxisFormattedToRawLookup,
secondaryAxisSelectFieldOptions,
secondaryAxisFieldType,
secondaryAxisSubFieldName,
}: SortTwoDimensionalLineChartDataConfiguration): SortTwoDimensionalLineChartDataResult => {
let sortedSeries = series;
@@ -48,7 +54,7 @@ export const sortTwoDimensionalLineChartData = ({
} else {
sortedSeries = series.map((seriesItem) => {
const sortedDataPoints =
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually({
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded({
data: seriesItem.data,
orderBy: primaryAxisOrderBy,
manualSortOrder: primaryAxisManualSortOrder,
@@ -73,6 +79,8 @@ export const sortTwoDimensionalLineChartData = ({
formattedToRawLookup: secondaryAxisFormattedToRawLookup,
selectFieldOptions: secondaryAxisSelectFieldOptions,
getFormattedValue: (item) => item.id,
fieldType: secondaryAxisFieldType,
subFieldName: secondaryAxisSubFieldName,
});
return {
@@ -9,7 +9,7 @@ import { type GraphColor } from '@/page-layout/widgets/graph/types/GraphColor';
import { type GroupByRawResult } from '@/page-layout/widgets/graph/types/GroupByRawResult';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { processOneDimensionalGroupByResults } from '@/page-layout/widgets/graph/utils/processOneDimensionalGroupByResults';
import { sortChartData } from '@/page-layout/widgets/graph/utils/sortChartData';
import { sortChartDataIfNeeded } from '@/page-layout/widgets/graph/utils/sortChartDataIfNeeded';
import {
isFieldMetadataSelectKind,
type FirstDayOfTheWeek,
@@ -65,7 +65,7 @@ export const transformOneDimensionalGroupByToLineChartData = ({
}),
);
const sortedData = sortChartData({
const sortedData = sortChartDataIfNeeded({
data: unsortedData,
orderBy: configuration.primaryAxisOrderBy,
manualSortOrder: configuration.primaryAxisManualSortOrder,
@@ -10,6 +10,7 @@ import { type GraphColor } from '@/page-layout/widgets/graph/types/GraphColor';
import { type GroupByRawResult } from '@/page-layout/widgets/graph/types/GroupByRawResult';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { processTwoDimensionalGroupByResults } from '@/page-layout/widgets/graph/utils/processTwoDimensionalGroupByResults';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { type FirstDayOfTheWeek } from 'twenty-shared/utils';
import { type LineChartConfiguration } from '~/generated/graphql';
@@ -70,6 +71,11 @@ export const transformTwoDimensionalGroupByToLineChartData = ({
primaryAxisSelectFieldOptions: groupByFieldX.options,
secondaryAxisFormattedToRawLookup: yFormattedToRawLookup,
secondaryAxisSelectFieldOptions: groupByFieldY.options,
secondaryAxisFieldType: groupByFieldY.type,
secondaryAxisSubFieldName:
(configuration.secondaryAxisGroupBySubFieldName ?? undefined) as
| CompositeFieldSubFieldName
| undefined,
});
const { limitedSeries, hasTooManyGroups } = limitTwoDimensionalLineChartData({
@@ -8,7 +8,7 @@ import { type GraphColor } from '@/page-layout/widgets/graph/types/GraphColor';
import { type GroupByRawResult } from '@/page-layout/widgets/graph/types/GroupByRawResult';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { processOneDimensionalGroupByResults } from '@/page-layout/widgets/graph/utils/processOneDimensionalGroupByResults';
import { sortChartData } from '@/page-layout/widgets/graph/utils/sortChartData';
import { sortChartDataIfNeeded } from '@/page-layout/widgets/graph/utils/sortChartDataIfNeeded';
import { type FirstDayOfTheWeek } from 'twenty-shared/types';
import { isDefined, isFieldMetadataSelectKind } from 'twenty-shared/utils';
import { type PieChartConfiguration } from '~/generated/graphql';
@@ -106,7 +106,7 @@ export const transformGroupByDataToPieChartData = ({
rawValue: isDefined(rawXValue) ? String(rawXValue) : null,
}));
const sortedDataWithRawValues = sortChartData({
const sortedDataWithRawValues = sortChartDataIfNeeded({
data: unsortedDataWithRawValues,
orderBy: configuration.orderBy ?? undefined,
manualSortOrder: configuration.manualSortOrder ?? undefined,
@@ -1,9 +1,9 @@
import { type FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { sortChartData } from '@/page-layout/widgets/graph/utils/sortChartData';
import { sortChartDataIfNeeded } from '@/page-layout/widgets/graph/utils/sortChartDataIfNeeded';
import { GraphOrderBy } from '~/generated/graphql';
describe('sortChartData', () => {
describe('sortChartDataIfNeeded', () => {
type TestDataPoint = { label: string; value: number };
const testData: TestDataPoint[] = [
@@ -12,6 +12,18 @@ describe('sortChartData', () => {
{ label: 'Gamma', value: 20 },
];
const fieldAscTestData: TestDataPoint[] = [
{ label: 'Alpha', value: 10 },
{ label: 'Beta', value: 30 },
{ label: 'Gamma', value: 20 },
];
const fieldDescTestData: TestDataPoint[] = [
{ label: 'Gamma', value: 20 },
{ label: 'Beta', value: 30 },
{ label: 'Alpha', value: 10 },
];
const formattedToRawLookup = new Map<string, RawDimensionValue>([
['Alpha', 'ALPHA'],
['Beta', 'BETA'],
@@ -23,7 +35,7 @@ describe('sortChartData', () => {
describe('null or undefined orderBy', () => {
it('should return data unchanged when orderBy is null', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: null,
formattedToRawLookup,
@@ -35,7 +47,7 @@ describe('sortChartData', () => {
});
it('should return data unchanged when orderBy is undefined', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: undefined,
formattedToRawLookup,
@@ -48,9 +60,9 @@ describe('sortChartData', () => {
});
describe('FIELD_ASC sorting', () => {
it('should sort by field value ascending', () => {
const result = sortChartData({
data: testData,
it('should return data unchanged by field value ascending, since it is already sorted by the backend', () => {
const result = sortChartDataIfNeeded({
data: fieldAscTestData,
orderBy: GraphOrderBy.FIELD_ASC,
formattedToRawLookup,
getFieldValue,
@@ -66,9 +78,9 @@ describe('sortChartData', () => {
});
describe('FIELD_DESC sorting', () => {
it('should sort by field value descending', () => {
const result = sortChartData({
data: testData,
it('should return data unchanged by field value descending, since it is already sorted by the backend', () => {
const result = sortChartDataIfNeeded({
data: fieldDescTestData,
orderBy: GraphOrderBy.FIELD_DESC,
formattedToRawLookup,
getFieldValue,
@@ -85,7 +97,7 @@ describe('sortChartData', () => {
describe('VALUE_ASC sorting', () => {
it('should sort by numeric value ascending', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.VALUE_ASC,
formattedToRawLookup,
@@ -99,7 +111,7 @@ describe('sortChartData', () => {
describe('VALUE_DESC sorting', () => {
it('should sort by numeric value descending', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.VALUE_DESC,
formattedToRawLookup,
@@ -115,7 +127,7 @@ describe('sortChartData', () => {
it('should sort by manual order', () => {
const manualSortOrder = ['GAMMA', 'ALPHA', 'BETA'];
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.MANUAL,
manualSortOrder,
@@ -132,7 +144,7 @@ describe('sortChartData', () => {
});
it('should return data unchanged when manual order is undefined', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.MANUAL,
manualSortOrder: undefined,
@@ -145,7 +157,7 @@ describe('sortChartData', () => {
});
it('should return data unchanged when manual order is null', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.MANUAL,
manualSortOrder: null,
@@ -166,7 +178,7 @@ describe('sortChartData', () => {
];
it('should sort by select option position ascending', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.FIELD_POSITION_ASC,
formattedToRawLookup,
@@ -184,7 +196,7 @@ describe('sortChartData', () => {
it('should throw error when select options are not provided', () => {
expect(() =>
sortChartData({
sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.FIELD_POSITION_ASC,
formattedToRawLookup,
@@ -196,7 +208,7 @@ describe('sortChartData', () => {
it('should throw error when select options are empty', () => {
expect(() =>
sortChartData({
sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.FIELD_POSITION_ASC,
formattedToRawLookup,
@@ -216,7 +228,7 @@ describe('sortChartData', () => {
];
it('should sort by select option position descending', () => {
const result = sortChartData({
const result = sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.FIELD_POSITION_DESC,
formattedToRawLookup,
@@ -237,7 +249,7 @@ describe('sortChartData', () => {
it('should not mutate the original data array', () => {
const originalData = [...testData];
sortChartData({
sortChartDataIfNeeded({
data: testData,
orderBy: GraphOrderBy.FIELD_ASC,
formattedToRawLookup,
@@ -1,4 +1,4 @@
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually';
import { sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded } from '@/page-layout/widgets/graph/utils/sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded';
import { GraphOrderBy } from '~/generated/graphql';
type TestItem = { label: string };
@@ -8,44 +8,55 @@ const testData: TestItem[] = [
{ label: 'Alpha' },
{ label: 'Gamma' },
];
const fieldAscTestData: TestItem[] = [
{ label: 'Alpha' },
{ label: 'Beta' },
{ label: 'Gamma' },
];
const formattedToRawLookup = new Map([
['Alpha', 'ALPHA'],
['Beta', 'BETA'],
['Gamma', 'GAMMA'],
]);
const getFormattedValue = (item: TestItem) => item.label;
describe('sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually', () => {
it('should sort by FIELD_ASC', () => {
const result = sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually({
data: testData,
orderBy: GraphOrderBy.FIELD_ASC,
formattedToRawLookup,
getFormattedValue,
});
describe('sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded', () => {
it('should return data unchanged by FIELD_ASC, since it is already sorted by the backend', () => {
const result =
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded({
data: fieldAscTestData,
orderBy: GraphOrderBy.FIELD_ASC,
formattedToRawLookup,
getFormattedValue,
});
expect(result.map((i) => i.label)).toEqual(['Alpha', 'Beta', 'Gamma']);
});
it('should sort by MANUAL order', () => {
const result = sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually({
data: testData,
orderBy: GraphOrderBy.MANUAL,
manualSortOrder: ['GAMMA', 'ALPHA', 'BETA'],
formattedToRawLookup,
getFormattedValue,
});
const result =
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded({
data: testData,
orderBy: GraphOrderBy.MANUAL,
manualSortOrder: ['GAMMA', 'ALPHA', 'BETA'],
formattedToRawLookup,
getFormattedValue,
});
expect(result.map((i) => i.label)).toEqual(['Gamma', 'Alpha', 'Beta']);
});
it('should return data unchanged when orderBy is undefined', () => {
const result = sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually({
data: testData,
orderBy: undefined,
formattedToRawLookup,
getFormattedValue,
});
const result =
sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded({
data: testData,
orderBy: undefined,
formattedToRawLookup,
getFormattedValue,
});
expect(result).toEqual(testData);
});
@@ -0,0 +1,72 @@
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { Temporal } from 'temporal-polyfill';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import {
isDefined,
isFieldMetadataDateKind,
isFieldMetadataNumericKind,
} from 'twenty-shared/utils';
import { FieldMetadataType } from '~/generated-metadata/graphql';
const parseDate = (
rawValue: RawDimensionValue | undefined,
fieldType?: FieldMetadataType,
): Temporal.PlainDate | null => {
if (!isDefined(rawValue)) return null;
const stringValue = String(rawValue);
return fieldType === FieldMetadataType.DATE
? Temporal.PlainDate.from(stringValue)
: Temporal.Instant.from(stringValue)
.toZonedDateTimeISO('UTC')
.toPlainDate();
};
type CompareDimensionValuesParams = {
rawValueA: RawDimensionValue | undefined;
rawValueB: RawDimensionValue | undefined;
formattedValueA: string;
formattedValueB: string;
direction: 'ASC' | 'DESC';
fieldType?: FieldMetadataType;
subFieldName?: CompositeFieldSubFieldName;
};
export const compareDimensionValues = ({
rawValueA,
rawValueB,
formattedValueA,
formattedValueB,
direction,
fieldType,
subFieldName,
}: CompareDimensionValuesParams): number => {
const applyDirection = (comparison: number) =>
direction === 'ASC' ? comparison : -comparison;
if (isDefined(fieldType)) {
if (isFieldMetadataDateKind(fieldType)) {
const dateA = parseDate(rawValueA, fieldType);
const dateB = parseDate(rawValueB, fieldType);
if (isDefined(dateA) && isDefined(dateB)) {
return applyDirection(Temporal.PlainDate.compare(dateA, dateB));
}
}
if (fieldType === FieldMetadataType.CURRENCY) {
if (subFieldName === 'amountMicros') {
if (isDefined(rawValueA) && isDefined(rawValueB)) {
return applyDirection(Number(rawValueA) - Number(rawValueB));
}
}
return applyDirection(formattedValueA.localeCompare(formattedValueB));
}
if (isFieldMetadataNumericKind(fieldType)) {
if (isDefined(rawValueA) && isDefined(rawValueB)) {
return applyDirection(Number(rawValueA) - Number(rawValueB));
}
}
}
return applyDirection(formattedValueA.localeCompare(formattedValueB));
};
@@ -15,7 +15,7 @@ type SortChartDataParams<T> = {
selectFieldOptions?: FieldMetadataItemOption[] | null;
};
export const sortChartData = <T>({
export const sortChartDataIfNeeded = <T>({
data,
orderBy,
manualSortOrder,
@@ -50,13 +50,8 @@ export const sortChartData = <T>({
case GraphOrderBy.VALUE_DESC:
return data.toSorted((a, b) => getNumericValue(b) - getNumericValue(a));
case GraphOrderBy.FIELD_ASC:
return data.toSorted((a, b) =>
getFieldValue(a).localeCompare(getFieldValue(b)),
);
case GraphOrderBy.FIELD_DESC:
return data.toSorted((a, b) =>
getFieldValue(b).localeCompare(getFieldValue(a)),
);
return data;
case GraphOrderBy.FIELD_POSITION_ASC:
if (!isDefined(selectFieldOptions) || selectFieldOptions.length === 0) {
throw new Error('Select field options are required');
@@ -1,8 +1,11 @@
import { type FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
import { type RawDimensionValue } from '@/page-layout/widgets/graph/types/RawDimensionValue';
import { compareDimensionValues } from '@/page-layout/widgets/graph/utils/compareDimensionValues';
import { sortByManualOrder } from '@/page-layout/widgets/graph/utils/sortByManualOrder';
import { sortBySelectOptionPosition } from '@/page-layout/widgets/graph/utils/sortBySelectOptionPosition';
import { type CompositeFieldSubFieldName } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FieldMetadataType } from '~/generated-metadata/graphql';
import { GraphOrderBy } from '~/generated/graphql';
type SortSecondaryAxisDataParams<T> = {
@@ -12,6 +15,8 @@ type SortSecondaryAxisDataParams<T> = {
formattedToRawLookup?: Map<string, RawDimensionValue>;
selectFieldOptions?: FieldMetadataItemOption[] | null;
getFormattedValue: (item: T) => string;
fieldType?: FieldMetadataType;
subFieldName?: CompositeFieldSubFieldName;
};
export const sortSecondaryAxisData = <T>({
@@ -21,17 +26,26 @@ export const sortSecondaryAxisData = <T>({
formattedToRawLookup,
selectFieldOptions,
getFormattedValue,
fieldType,
subFieldName,
}: SortSecondaryAxisDataParams<T>): T[] => {
switch (orderBy) {
case GraphOrderBy.FIELD_ASC:
return items.toSorted((a, b) =>
getFormattedValue(a).localeCompare(getFormattedValue(b)),
);
case GraphOrderBy.FIELD_DESC:
return items.toSorted((a, b) =>
getFormattedValue(b).localeCompare(getFormattedValue(a)),
);
return items.toSorted((a, b) => {
const formattedValueA = getFormattedValue(a);
const formattedValueB = getFormattedValue(b);
return compareDimensionValues({
rawValueA: formattedToRawLookup?.get(formattedValueA),
rawValueB: formattedToRawLookup?.get(formattedValueB),
formattedValueA,
formattedValueB,
direction: orderBy === GraphOrderBy.FIELD_ASC ? 'ASC' : 'DESC',
fieldType,
subFieldName,
});
});
case GraphOrderBy.FIELD_POSITION_ASC:
case GraphOrderBy.FIELD_POSITION_DESC: {
@@ -19,7 +19,9 @@ type SortTwoDimensionalChartPrimaryAxisDataParams<T> = {
selectFieldOptions?: FieldMetadataItemOption[] | null;
};
export const sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually = <T>({
export const sortTwoDimensionalChartPrimaryAxisDataByFieldOrManuallyIfNeeded = <
T,
>({
data,
orderBy,
manualSortOrder,
@@ -50,14 +52,8 @@ export const sortTwoDimensionalChartPrimaryAxisDataByFieldOrManually = <T>({
}
case GraphOrderBy.FIELD_ASC:
return data.toSorted((a, b) =>
getFormattedValue(a).localeCompare(getFormattedValue(b)),
);
case GraphOrderBy.FIELD_DESC:
return data.toSorted((a, b) =>
getFormattedValue(b).localeCompare(getFormattedValue(a)),
);
return data;
case GraphOrderBy.FIELD_POSITION_ASC:
case GraphOrderBy.FIELD_POSITION_DESC: {