Files
twenty/packages/twenty-server/src/modules/dashboard/chart-data/utils/fill-select-gaps.util.ts
T
Raphaël Bosi d0bc8b9ffe [DASHBOARDS] Move all the graph computing logic to the backend (#17189)
- Create resolvers for each type of charts which needs data
transformation after the group by operation: Bar Chart, Line Chart and
Pie Chart
- Move all the utils to the backend and refactored some into services

This allows all the computation to be done in the backend, improving
performances in the frontend.
2026-01-19 17:25:45 +00:00

99 lines
2.5 KiB
TypeScript

import { isDefined } from 'twenty-shared/utils';
import { type FieldMetadataOption } from 'src/modules/dashboard/chart-data/types/field-metadata-option.type';
import { type GroupByRawResult } from 'src/modules/dashboard/chart-data/types/group-by-raw-result.type';
type FillSelectGapsParams = {
data: GroupByRawResult[];
selectOptions: FieldMetadataOption[] | null | undefined;
};
export const fillSelectGaps = ({
data,
selectOptions,
}: FillSelectGapsParams): GroupByRawResult[] => {
if (
!isDefined(selectOptions) ||
selectOptions.length === 0 ||
data.length === 0
) {
return data;
}
const existingGroupsMap = new Map<string, GroupByRawResult>();
for (const item of data) {
const dimensionValue = item.groupByDimensionValues?.[0];
if (isDefined(dimensionValue)) {
existingGroupsMap.set(String(dimensionValue), item);
}
}
const filledData: GroupByRawResult[] = selectOptions.map((option) => {
const existingGroup = existingGroupsMap.get(option.value);
if (isDefined(existingGroup)) {
return existingGroup;
}
return {
groupByDimensionValues: [option.value],
aggregateValue: 0,
};
});
return filledData;
};
type FillSelectGapsTwoDimensionalParams = {
data: GroupByRawResult[];
selectOptions: FieldMetadataOption[] | null | undefined;
};
export const fillSelectGapsTwoDimensional = ({
data,
selectOptions,
}: FillSelectGapsTwoDimensionalParams): GroupByRawResult[] => {
if (
!isDefined(selectOptions) ||
selectOptions.length === 0 ||
data.length === 0
) {
return data;
}
const existingGroupsMap = new Map<string, GroupByRawResult>();
const uniqueSecondDimensionValues = new Set<unknown>();
for (const item of data) {
const primaryValue = item.groupByDimensionValues?.[0];
const secondaryValue = item.groupByDimensionValues?.[1] ?? null;
if (isDefined(primaryValue)) {
const key = `${String(primaryValue)}_${String(secondaryValue)}`;
existingGroupsMap.set(key, item);
uniqueSecondDimensionValues.add(secondaryValue);
}
}
const filledData: GroupByRawResult[] = selectOptions.flatMap((option) =>
Array.from(uniqueSecondDimensionValues).map((secondaryValue) => {
const key = `${option.value}_${String(secondaryValue)}`;
const existingGroup = existingGroupsMap.get(key);
if (isDefined(existingGroup)) {
return existingGroup;
}
return {
groupByDimensionValues: [option.value, secondaryValue],
aggregateValue: 0,
};
}),
);
return filledData;
};