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
This commit is contained in:
+13
-10
@@ -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;
|
||||
|
||||
+29
-4
@@ -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 <GraphWidgetTooltip items={[tooltipData.tooltipItem]} />;
|
||||
return (
|
||||
<GraphWidgetTooltip
|
||||
items={[tooltipData.tooltipItem]}
|
||||
onGraphWidgetTooltipClick={() => handleSliceClick(datum)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -99,16 +111,29 @@ export const GraphWidgetPieChart = ({
|
||||
<StyledPieChartWrapper>
|
||||
<ResponsivePie
|
||||
data={data}
|
||||
margin={showDataLabels ? PIE_CHART_MARGINS : {}}
|
||||
innerRadius={0.8}
|
||||
padAngle={1}
|
||||
colors={enrichedData.map((item) => 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<PieChartDataItem>) => {
|
||||
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}
|
||||
/>
|
||||
</StyledPieChartWrapper>
|
||||
</GraphWidgetChartContainer>
|
||||
|
||||
+11
-5
@@ -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}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export const PIE_CHART_MARGINS = {
|
||||
top: 40,
|
||||
right: 80,
|
||||
bottom: 40,
|
||||
left: 80,
|
||||
} as const;
|
||||
+2
@@ -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,
|
||||
};
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ export const WidgetCardHeader = ({
|
||||
|
||||
return (
|
||||
<StyledWidgetCardHeader className={className}>
|
||||
<AnimatePresence>
|
||||
<AnimatePresence initial={false}>
|
||||
{!isEmpty && isInEditMode && (
|
||||
<WidgetGrip
|
||||
className="drag-handle"
|
||||
@@ -83,7 +83,7 @@ export const WidgetCardHeader = ({
|
||||
</StyledTitleContainer>
|
||||
<StyledRightContainer>
|
||||
{isDefined(forbiddenDisplay) && forbiddenDisplay}
|
||||
<AnimatePresence>
|
||||
<AnimatePresence initial={false}>
|
||||
{!isResizing &&
|
||||
!isEmpty &&
|
||||
isInEditMode &&
|
||||
|
||||
Reference in New Issue
Block a user