From 0d34651d5e5dcad61df0e5f6052401e80dba6ad2 Mon Sep 17 00:00:00 2001
From: nitin <142569587+ehconitin@users.noreply.github.com>
Date: Wed, 26 Nov 2025 15:02:48 +0530
Subject: [PATCH] pie chart data labels, slice gap and initial animate presence
on widget card header (#16084)
closes:
https://discord.com/channels/1130383047699738754/1442899090047373463
https://discord.com/channels/1130383047699738754/1438537119248285758
pie chart labels:
https://github.com/user-attachments/assets/d8f8e164-745f-4601-bee7-11a655ccd9b6
fixed header animations:
https://github.com/user-attachments/assets/76587a6d-53c4-4a11-a546-b4c83754870a
---
.../transformGroupByDataToBarChartData.ts | 23 +++++++------
.../components/GraphWidgetPieChart.tsx | 33 ++++++++++++++++---
.../GraphWidgetPieChartRenderer.tsx | 16 ++++++---
.../constants/PieChartMargins.ts | 6 ++++
.../hooks/useGraphPieChartWidgetData.ts | 2 ++
.../components/WidgetCardHeader.tsx | 4 +--
6 files changed, 63 insertions(+), 21 deletions(-)
create mode 100644 packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMargins.ts
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts
index 19e6dd9f47..ed61a02bcf 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts
+++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/utils/transformGroupByDataToBarChartData.ts
@@ -151,16 +151,19 @@ export const transformGroupByDataToBarChartData = ({
groupByFieldX.type === FieldMetadataType.DATE ||
groupByFieldX.type === FieldMetadataType.DATE_TIME;
- const dateGapFillResult = isDateField
- ? fillDateGapsInBarChartData({
- data: filteredResults,
- keys: [aggregateField.name],
- dateGranularity:
- configuration.primaryAxisDateGranularity ??
- GRAPH_DEFAULT_DATE_GRANULARITY,
- hasSecondDimension: isDefined(groupByFieldY),
- })
- : { data: filteredResults, wasTruncated: false };
+ const omitNullValues = configuration.omitNullValues ?? false;
+
+ const dateGapFillResult =
+ isDateField && !omitNullValues
+ ? fillDateGapsInBarChartData({
+ data: filteredResults,
+ keys: [aggregateField.name],
+ dateGranularity:
+ configuration.primaryAxisDateGranularity ??
+ GRAPH_DEFAULT_DATE_GRANULARITY,
+ hasSecondDimension: isDefined(groupByFieldY),
+ })
+ : { data: filteredResults, wasTruncated: false };
const filteredResultsWithDateGaps = dateGapFillResult.data;
const dateRangeWasTruncated = dateGapFillResult.wasTruncated;
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 80f5cfb750..2c4ee3caa8 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
@@ -2,6 +2,7 @@ import { GraphWidgetChartContainer } from '@/page-layout/widgets/graph/component
import { GraphWidgetLegend } from '@/page-layout/widgets/graph/components/GraphWidgetLegend';
import { GraphWidgetTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetTooltip';
import { PIE_CHART_HOVER_BRIGHTNESS } from '@/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartHoverBrightness';
+import { PIE_CHART_MARGINS } from '@/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMargins';
import { usePieChartData } from '@/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartData';
import { usePieChartHandlers } from '@/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartHandlers';
import { usePieChartTooltip } from '@/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartTooltip';
@@ -10,7 +11,11 @@ import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/crea
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
-import { ResponsivePie, type PieTooltipProps } from '@nivo/pie';
+import {
+ ResponsivePie,
+ type ComputedDatum,
+ type PieTooltipProps,
+} from '@nivo/pie';
import { isDefined } from 'twenty-shared/utils';
type GraphWidgetPieChartProps = {
@@ -18,6 +23,7 @@ type GraphWidgetPieChartProps = {
showLegend?: boolean;
id: string;
onSliceClick?: (datum: PieChartDataItem) => void;
+ showDataLabels?: boolean;
} & GraphValueFormatOptions;
const StyledContainer = styled.div`
@@ -52,6 +58,7 @@ export const GraphWidgetPieChart = ({
suffix,
customFormatter,
onSliceClick,
+ showDataLabels = false,
}: GraphWidgetPieChartProps) => {
const theme = useTheme();
const colorRegistry = createGraphColorRegistry(theme);
@@ -87,7 +94,12 @@ export const GraphWidgetPieChart = ({
const tooltipData = createTooltipData(datum);
if (!isDefined(tooltipData)) return null;
- return ;
+ return (
+ handleSliceClick(datum)}
+ />
+ );
};
return (
@@ -99,16 +111,29 @@ export const GraphWidgetPieChart = ({
item.colorScheme.solid)}
borderWidth={0}
- enableArcLinkLabels={false}
+ enableArcLinkLabels={showDataLabels}
enableArcLabels={false}
tooltip={renderTooltip}
onClick={handleSliceClick}
onMouseEnter={(datum) => setHoveredSliceId(datum.id)}
onMouseLeave={() => setHoveredSliceId(null)}
- layers={['arcs']}
+ layers={['arcs', 'arcLinkLabels']}
+ arcLinkLabel={(datum: ComputedDatum) => {
+ const tooltipData = createTooltipData(datum);
+ return (
+ tooltipData?.tooltipItem.formattedValue ||
+ datum.data.value.toString()
+ );
+ }}
+ arcLinkLabelsDiagonalLength={10}
+ arcLinkLabelsStraightLength={10}
+ arcLinkLabelsTextColor={theme.font.color.light}
+ arcLinkLabelsColor={theme.font.color.extraLight}
/>
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx
index f7ba00cb27..7f234d41ba 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx
@@ -26,11 +26,16 @@ export const GraphWidgetPieChartRenderer = ({
}: {
widget: PageLayoutWidget;
}) => {
- const { data, loading, hasTooManyGroups, objectMetadataItem } =
- useGraphPieChartWidgetData({
- objectMetadataItemId: widget.objectMetadataId,
- configuration: widget.configuration as PieChartConfiguration,
- });
+ const {
+ data,
+ loading,
+ hasTooManyGroups,
+ objectMetadataItem,
+ showDataLabels,
+ } = useGraphPieChartWidgetData({
+ objectMetadataItemId: widget.objectMetadataId,
+ configuration: widget.configuration as PieChartConfiguration,
+ });
const navigate = useNavigate();
@@ -66,6 +71,7 @@ export const GraphWidgetPieChartRenderer = ({
id={widget.id}
displayType="shortNumber"
onSliceClick={handleSliceClick}
+ showDataLabels={showDataLabels}
/>
);
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMargins.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMargins.ts
new file mode 100644
index 0000000000..7dd9b64b45
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartMargins.ts
@@ -0,0 +1,6 @@
+export const PIE_CHART_MARGINS = {
+ top: 40,
+ right: 80,
+ bottom: 40,
+ left: 80,
+} as const;
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/useGraphPieChartWidgetData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/useGraphPieChartWidgetData.ts
index 45e9337f7f..9df1a4e08d 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/useGraphPieChartWidgetData.ts
+++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/useGraphPieChartWidgetData.ts
@@ -18,6 +18,7 @@ type UseGraphPieChartWidgetDataResult = {
error?: Error;
hasTooManyGroups: boolean;
objectMetadataItem: ObjectMetadataItem;
+ showDataLabels: boolean;
};
// TODO: Remove this once backend returns total group count
@@ -57,6 +58,7 @@ export const useGraphPieChartWidgetData = ({
return {
...transformedData,
objectMetadataItem,
+ showDataLabels: configuration.displayDataLabel ?? false,
loading,
error,
};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx
index 59f1b7a89b..d1365bd69a 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx
@@ -70,7 +70,7 @@ export const WidgetCardHeader = ({
return (
-
+
{!isEmpty && isInEditMode && (
{isDefined(forbiddenDisplay) && forbiddenDisplay}
-
+
{!isResizing &&
!isEmpty &&
isInEditMode &&