nitin
2025-10-31 13:54:13 +01:00
committed by GitHub
parent 3d21ffb4d1
commit 809791a4a8
3 changed files with 201 additions and 1 deletions
@@ -0,0 +1,144 @@
import { GraphOrderBy } from '~/generated/graphql';
import { sortBarChartDataBySecondaryDimensionSum } from '../sortBarChartDataBySecondaryDimensionSum';
describe('sortBarChartDataBySecondaryDimensionSum', () => {
const mockData = [
{ city: 'Paris', Open: 5, Closed: 10 },
{ city: 'London', Open: 20, Closed: 2 },
{ city: 'Berlin', Open: 8, Closed: 7 },
];
const keys = ['Open', 'Closed'];
describe('VALUE_DESC sorting', () => {
it('should sort by totals in descending order', () => {
const result = sortBarChartDataBySecondaryDimensionSum({
data: mockData,
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual([
{ city: 'London', Open: 20, Closed: 2 },
{ city: 'Paris', Open: 5, Closed: 10 },
{ city: 'Berlin', Open: 8, Closed: 7 },
]);
});
});
describe('VALUE_ASC sorting', () => {
it('should sort by totals in ascending order', () => {
const result = sortBarChartDataBySecondaryDimensionSum({
data: mockData,
keys,
orderBy: GraphOrderBy.VALUE_ASC,
});
expect(result).toEqual([
{ city: 'Paris', Open: 5, Closed: 10 },
{ city: 'Berlin', Open: 8, Closed: 7 },
{ city: 'London', Open: 20, Closed: 2 },
]);
});
});
describe('FIELD_ASC/FIELD_DESC (non-value sorting)', () => {
it('should not sort when orderBy is FIELD_ASC', () => {
const result = sortBarChartDataBySecondaryDimensionSum({
data: mockData,
keys,
orderBy: GraphOrderBy.FIELD_ASC,
});
expect(result).toEqual(mockData);
});
it('should not sort when orderBy is FIELD_DESC', () => {
const result = sortBarChartDataBySecondaryDimensionSum({
data: mockData,
keys,
orderBy: GraphOrderBy.FIELD_DESC,
});
expect(result).toEqual(mockData);
});
});
describe('edge cases', () => {
it('should handle data with missing keys in some items', () => {
const dataWithMissing = [
{ city: 'Paris', Open: 5 } as any,
{ city: 'London', Open: 20, Closed: 2 },
];
const result = sortBarChartDataBySecondaryDimensionSum({
data: dataWithMissing,
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual([
{ city: 'London', Open: 20, Closed: 2 },
{ city: 'Paris', Open: 5 },
]);
});
it('should handle data with zero values', () => {
const dataWithZeros = [
{ city: 'Paris', Open: 0, Closed: 10 },
{ city: 'London', Open: 20, Closed: 0 },
];
const result = sortBarChartDataBySecondaryDimensionSum({
data: dataWithZeros,
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual([
{ city: 'London', Open: 20, Closed: 0 },
{ city: 'Paris', Open: 0, Closed: 10 },
]);
});
it('should handle empty data array', () => {
const result = sortBarChartDataBySecondaryDimensionSum({
data: [],
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual([]);
});
it('should handle single item', () => {
const singleItem = [{ city: 'Paris', Open: 5, Closed: 10 }];
const result = sortBarChartDataBySecondaryDimensionSum({
data: singleItem,
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual(singleItem);
});
});
describe('stability with equal totals', () => {
it('should maintain original order for items with equal totals', () => {
const dataWithEqualTotals = [
{ city: 'Paris', Open: 10, Closed: 5 },
{ city: 'Berlin', Open: 7, Closed: 8 },
{ city: 'Madrid', Open: 9, Closed: 6 },
];
const result = sortBarChartDataBySecondaryDimensionSum({
data: dataWithEqualTotals,
keys,
orderBy: GraphOrderBy.VALUE_DESC,
});
expect(result).toEqual(dataWithEqualTotals);
});
});
});
@@ -0,0 +1,46 @@
import { type BarChartDataItem } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartDataItem';
import { isDefined } from 'twenty-shared/utils';
import { GraphOrderBy } from '~/generated/graphql';
type SortBarChartDataBySecondaryDimensionSumParams = {
data: BarChartDataItem[];
keys: string[];
orderBy: GraphOrderBy;
};
export const sortBarChartDataBySecondaryDimensionSum = ({
data,
keys,
orderBy,
}: SortBarChartDataBySecondaryDimensionSumParams): BarChartDataItem[] => {
if (
orderBy !== GraphOrderBy.VALUE_ASC &&
orderBy !== GraphOrderBy.VALUE_DESC
) {
return data;
}
const dataWithSecondaryDimensionSums = data.map((barChartDataItem) => {
const secondaryDimensionSum = keys.reduce((sumAccumulator, segmentKey) => {
const segmentValue = barChartDataItem[segmentKey];
if (isDefined(segmentValue) && typeof segmentValue === 'number') {
return sumAccumulator + segmentValue;
}
return sumAccumulator;
}, 0);
return { barChartDataItem, secondaryDimensionSum };
});
dataWithSecondaryDimensionSums.sort((a, b) => {
if (orderBy === GraphOrderBy.VALUE_ASC) {
return a.secondaryDimensionSum - b.secondaryDimensionSum;
} else {
return b.secondaryDimensionSum - a.secondaryDimensionSum;
}
});
return dataWithSecondaryDimensionSums.map(
({ barChartDataItem }) => barChartDataItem,
);
};
@@ -10,6 +10,7 @@ import { computeAggregateValueFromGroupByResult } from '@/page-layout/widgets/gr
import { formatDimensionValue } from '@/page-layout/widgets/graph/utils/formatDimensionValue';
import { getFieldKey } from '@/page-layout/widgets/graph/utils/getFieldKey';
import { getSortedKeys } from '@/page-layout/widgets/graph/utils/getSortedKeys';
import { sortBarChartDataBySecondaryDimensionSum } from '@/page-layout/widgets/graph/utils/sortBarChartDataBySecondaryDimensionSum';
import { isDefined } from 'twenty-shared/utils';
import {
BarChartGroupMode,
@@ -132,8 +133,17 @@ export const transformTwoDimensionalGroupByToBarChartData = ({
color: configuration.color as GraphColor,
}));
const unsortedData = Array.from(dataMap.values());
const data = isDefined(configuration.primaryAxisOrderBy)
? sortBarChartDataBySecondaryDimensionSum({
data: unsortedData,
keys,
orderBy: configuration.primaryAxisOrderBy,
})
: unsortedData;
return {
data: Array.from(dataMap.values()),
data,
indexBy: indexByKey,
keys,
series,