[Dashboards] add hide empty category option for pie charts (#16550)

closes
https://discord.com/channels/1130383047699738754/1445403391722520677


https://github.com/user-attachments/assets/980225a8-153e-4b49-89f7-5944227c8fdb


toggle label ie `Hide empty category` -- debatable
This commit is contained in:
nitin
2025-12-15 21:10:46 +05:30
committed by GitHub
parent 75f2c26d3f
commit fc74a06f53
10 changed files with 51 additions and 3 deletions
@@ -3187,6 +3187,7 @@ export type PieChartConfiguration = {
graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
orderBy?: Maybe<GraphOrderBy>;
showCenterMetric?: Maybe<Scalars['Boolean']>;
timezone?: Maybe<Scalars['String']>;
@@ -3108,6 +3108,7 @@ export type PieChartConfiguration = {
graphType: GraphType;
groupByFieldMetadataId: Scalars['UUID'];
groupBySubFieldName?: Maybe<Scalars['String']>;
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
orderBy?: Maybe<GraphOrderBy>;
showCenterMetric?: Maybe<Scalars['Boolean']>;
timezone?: Maybe<Scalars['String']>;
@@ -7,6 +7,7 @@ import { DATA_LABELS_SETTING } from '@/command-menu/pages/page-layout/constants/
import { DATE_GRANULARITY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/DateGranularitySetting';
import { EACH_SLICE_REPRESENTS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/EachSliceRepresentsSetting';
import { FILTER_SETTING } from '@/command-menu/pages/page-layout/constants/settings/FilterSetting';
import { HIDE_EMPTY_CATEGORY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/HideEmptyCategorySetting';
import { PRIMARY_SORT_BY_SETTING } from '@/command-menu/pages/page-layout/constants/settings/PrimarySortBySetting';
import { SHOW_LEGEND_SETTING } from '@/command-menu/pages/page-layout/constants/settings/ShowLegendSetting';
import { type ChartSettingsGroup } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
@@ -21,6 +22,7 @@ export const PIE_CHART_SETTINGS: ChartSettingsGroup[] = [
DATE_GRANULARITY_SETTING,
EACH_SLICE_REPRESENTS_SETTING,
PRIMARY_SORT_BY_SETTING,
HIDE_EMPTY_CATEGORY_SETTING,
],
},
{
@@ -18,6 +18,7 @@ export const CHART_CONFIGURATION_SETTING_LABELS = {
STACKED_BARS: msg`Stacked bars`,
STACKED_LINES: msg`Stacked lines`,
OMIT_NULL_VALUES: msg`Omit zero values`,
HIDE_EMPTY_CATEGORY: msg`Hide empty category`,
MIN_RANGE: msg`Min range`,
MAX_RANGE: msg`Max range`,
DATE_GRANULARITY_X: msg`Date granularity`,
@@ -0,0 +1,11 @@
import { CHART_CONFIGURATION_SETTING_LABELS } from '@/command-menu/pages/page-layout/constants/settings/ChartConfigurationSettingLabels';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { type ChartSettingsItem } from '@/command-menu/pages/page-layout/types/ChartSettingsGroup';
import { IconEyeOff } from 'twenty-ui/display';
export const HIDE_EMPTY_CATEGORY_SETTING: ChartSettingsItem = {
isBoolean: true,
Icon: IconEyeOff,
label: CHART_CONFIGURATION_SETTING_LABELS.HIDE_EMPTY_CATEGORY,
id: CHART_CONFIGURATION_SETTING_IDS.HIDE_EMPTY_CATEGORY,
};
@@ -255,6 +255,8 @@ export const useChartSettingsValues = ({
return isBarOrLineChart
? (configuration.omitNullValues ?? false)
: false;
case CHART_CONFIGURATION_SETTING_IDS.HIDE_EMPTY_CATEGORY:
return isPieChart ? (configuration.hideEmptyCategory ?? false) : false;
case CHART_CONFIGURATION_SETTING_IDS.MIN_RANGE:
return isBarOrLineChart
? (configuration.rangeMin?.toString() ?? '')
@@ -17,6 +17,7 @@ export enum CHART_CONFIGURATION_SETTING_IDS {
STACKED_BARS = 'STACKED_BARS',
STACKED_LINES = 'STACKED_LINES',
OMIT_NULL_VALUES = 'OMIT_NULL_VALUES',
HIDE_EMPTY_CATEGORY = 'HIDE_EMPTY_CATEGORY',
MIN_RANGE = 'MIN_RANGE',
MAX_RANGE = 'MAX_RANGE',
DATE_GRANULARITY_X = 'DATE_GRANULARITY_X',
@@ -34,6 +35,7 @@ export const CHART_CONFIGURATION_SETTING_TO_CONFIG_KEY_MAP = {
[CHART_CONFIGURATION_SETTING_IDS.STACKED_BARS]: 'groupMode',
[CHART_CONFIGURATION_SETTING_IDS.STACKED_LINES]: 'isStacked',
[CHART_CONFIGURATION_SETTING_IDS.OMIT_NULL_VALUES]: 'omitNullValues',
[CHART_CONFIGURATION_SETTING_IDS.HIDE_EMPTY_CATEGORY]: 'hideEmptyCategory',
[CHART_CONFIGURATION_SETTING_IDS.MIN_RANGE]: 'rangeMin',
[CHART_CONFIGURATION_SETTING_IDS.MAX_RANGE]: 'rangeMax',
[CHART_CONFIGURATION_SETTING_IDS.DATE_GRANULARITY_X]:
@@ -39,6 +39,22 @@ export const usePieChartCenterMetricData = ({
configuration,
});
const groupByField = objectMetadataItem.fields.find(
(field) => field.id === configuration.groupByFieldMetadataId,
);
const centerMetricFilter = useMemo(() => {
if (!configuration.hideEmptyCategory || !groupByField) {
return gqlOperationFilter;
}
const notNullFilter = { [groupByField.name]: { is: 'NOT_NULL' as const } };
return isDefined(gqlOperationFilter)
? { and: [gqlOperationFilter, notNullFilter] }
: notNullFilter;
}, [gqlOperationFilter, configuration.hideEmptyCategory, groupByField]);
const centerMetricAggregateOperation =
configuration.aggregateOperation as AggregateOperations;
@@ -58,7 +74,7 @@ export const usePieChartCenterMetricData = ({
const { data: centerMetricData } = useAggregateRecords({
objectNameSingular: objectMetadataItem.nameSingular,
recordGqlFieldsAggregate,
filter: gqlOperationFilter,
filter: centerMetricFilter,
skip,
});
@@ -82,8 +82,14 @@ export const transformGroupByDataToPieChartData = ({
? (configuration.dateGranularity ?? undefined)
: undefined;
const filteredResults = configuration.hideEmptyCategory
? rawResults.filter((result) =>
isDefined(result.groupByDimensionValues?.[0]),
)
: rawResults;
// TODO: Add a limit to the query instead of slicing here (issue: twentyhq/core-team-issues#1600)
const limitedResults = rawResults.slice(
const limitedResults = filteredResults.slice(
0,
PIE_CHART_MAXIMUM_NUMBER_OF_SLICES,
);
@@ -122,7 +128,8 @@ export const transformGroupByDataToPieChartData = ({
return {
data,
showLegend,
hasTooManyGroups: rawResults.length > PIE_CHART_MAXIMUM_NUMBER_OF_SLICES,
hasTooManyGroups:
filteredResults.length > PIE_CHART_MAXIMUM_NUMBER_OF_SLICES,
formattedToRawLookup,
};
};
@@ -81,6 +81,11 @@ export class PieChartConfigurationDTO {
@IsOptional()
displayLegend?: boolean;
@Field(() => Boolean, { nullable: true, defaultValue: false })
@IsBoolean()
@IsOptional()
hideEmptyCategory?: boolean;
@Field(() => String, { nullable: true })
@IsString()
@IsOptional()