From c1df04548dd8742804d50efe3f8038a2423128cf Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:50:14 +0200 Subject: [PATCH] feat: add impact metrics wildcard label (#10373) --- .../components/LabelsFilter.tsx | 118 +++++++++++++----- .../impact-metrics/hooks/useChartData.ts | 1 + 2 files changed, 85 insertions(+), 34 deletions(-) diff --git a/frontend/src/component/impact-metrics/ImpactMetricsControls/components/LabelsFilter.tsx b/frontend/src/component/impact-metrics/ImpactMetricsControls/components/LabelsFilter.tsx index b65d09f22a..caa5f233a8 100644 --- a/frontend/src/component/impact-metrics/ImpactMetricsControls/components/LabelsFilter.tsx +++ b/frontend/src/component/impact-metrics/ImpactMetricsControls/components/LabelsFilter.tsx @@ -1,5 +1,13 @@ import type { FC } from 'react'; -import { Box, Autocomplete, TextField, Typography, Chip } from '@mui/material'; +import { + Box, + Autocomplete, + TextField, + Typography, + Chip, + Checkbox, + FormControlLabel, +} from '@mui/material'; import type { ImpactMetricsLabels } from 'hooks/api/getters/useImpactMetricsData/useImpactMetricsData'; export type LabelsFilterProps = { @@ -23,6 +31,16 @@ export const LabelsFilter: FC = ({ onChange(newLabels); }; + const handleAllToggle = (labelKey: string, checked: boolean) => { + const newLabels = { ...selectedLabels }; + if (checked) { + newLabels[labelKey] = ['*']; + } else { + delete newLabels[labelKey]; + } + onChange(newLabels); + }; + const clearAllLabels = () => { onChange({}); }; @@ -45,42 +63,74 @@ export const LabelsFilter: FC = ({ )} - {Object.entries(availableLabels).map(([labelKey, values]) => ( - - handleLabelChange(labelKey, newValues) - } - renderTags={(value, getTagProps) => - value.map((option, index) => { - const { key, ...chipProps } = getTagProps({ - index, - }); - return ( - { + const currentSelection = selectedLabels[labelKey] || []; + const isAllSelected = currentSelection.includes('*'); + + return ( + ({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(3), + })} + > + { + handleLabelChange(labelKey, newValues); + }} + disabled={isAllSelected} + renderTags={(value, getTagProps) => + value.map((option, index) => { + const { key, ...chipProps } = getTagProps({ + index, + }); + return ( + + ); + }) + } + renderInput={(params) => ( + - ); - }) - } - renderInput={(params) => ( - - )} - sx={{ minWidth: 300 }} - /> - ))} + + handleAllToggle( + labelKey, + e.target.checked, + ) + } + /> + } + label='All' + /> + + ); + })} ); }; diff --git a/frontend/src/component/impact-metrics/hooks/useChartData.ts b/frontend/src/component/impact-metrics/hooks/useChartData.ts index 0519908c67..786778f6ce 100644 --- a/frontend/src/component/impact-metrics/hooks/useChartData.ts +++ b/frontend/src/component/impact-metrics/hooks/useChartData.ts @@ -8,6 +8,7 @@ const getColorStartingIndex = (modulo: number, series?: string): number => { return 0; } + // https://stackoverflow.com/a/7616484/1729641 let hash = 0; for (let i = 0; i < series.length; i++) { const char = series.charCodeAt(i);