fix: Orderby secondary dimension sum (#15493)
before: https://github.com/user-attachments/assets/6919c45b-1435-408f-87e3-0452dd70fbdb after: https://github.com/user-attachments/assets/efa60d28-ac04-4219-831a-92aada13fa9c
This commit is contained in:
+144
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
+46
@@ -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,
|
||||
);
|
||||
};
|
||||
+11
-1
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user