From 60e69f92d93ebd3b0f0eb27f2edcf398cabf5414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Wed, 26 Nov 2025 17:23:52 +0100 Subject: [PATCH] [DASHBOARDS] Add pie chart empty state (#16100) When no data is available, we display a gray circle instead of nothing. https://github.com/user-attachments/assets/54db403b-739c-43fb-b422-8dcdfb6281fb --- .../components/GraphWidgetPieChart.tsx | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx index 2c4ee3caa8..099a51165b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx @@ -16,6 +16,7 @@ import { type ComputedDatum, type PieTooltipProps, } from '@nivo/pie'; +import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; type GraphWidgetPieChartProps = { @@ -26,6 +27,10 @@ type GraphWidgetPieChartProps = { showDataLabels?: boolean; } & GraphValueFormatOptions; +const emptyStateData: PieChartDataItem[] = [ + { id: 'empty', label: '', value: 1 }, +]; + const StyledContainer = styled.div` align-items: center; display: flex; @@ -35,7 +40,7 @@ const StyledContainer = styled.div` width: 100%; `; -const StyledPieChartWrapper = styled.div` +const StyledPieChartWrapper = styled.div<{ preventHover: boolean }>` width: 100%; height: 100%; @@ -43,7 +48,8 @@ const StyledPieChartWrapper = styled.div` transition: filter 0.15s ease-in-out; &:hover { - filter: brightness(${PIE_CHART_HOVER_BRIGHTNESS}); + filter: ${({ preventHover }) => + preventHover ? 'none' : `brightness(${PIE_CHART_HOVER_BRIGHTNESS})`}; } } `; @@ -102,26 +108,38 @@ export const GraphWidgetPieChart = ({ ); }; + const hasNoData = useMemo( + () => data.length === 0 || data.every((item) => item.value === 0), + [data], + ); + + const chartData = hasNoData ? emptyStateData : data; + const chartColors = hasNoData + ? [theme.background.tertiary] + : enrichedData.map((item) => item.colorScheme.solid); + return ( - + item.colorScheme.solid)} + padAngle={hasNoData ? 0 : 1} + colors={chartColors} borderWidth={0} - enableArcLinkLabels={showDataLabels} + enableArcLinkLabels={showDataLabels && !hasNoData} enableArcLabels={false} - tooltip={renderTooltip} - onClick={handleSliceClick} - onMouseEnter={(datum) => setHoveredSliceId(datum.id)} - onMouseLeave={() => setHoveredSliceId(null)} + tooltip={hasNoData ? () => null : renderTooltip} + onClick={hasNoData ? undefined : handleSliceClick} + onMouseEnter={ + hasNoData ? undefined : (datum) => setHoveredSliceId(datum.id) + } + onMouseLeave={hasNoData ? undefined : () => setHoveredSliceId(null)} layers={['arcs', 'arcLinkLabels']} arcLinkLabel={(datum: ComputedDatum) => { const tooltipData = createTooltipData(datum); @@ -138,7 +156,7 @@ export const GraphWidgetPieChart = ({ ({ id: item.id, label: item.label || item.id,