From ee58591687a7f9e0182ddd9ff88dcf95d585280a Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Wed, 28 May 2025 23:24:44 -0600 Subject: [PATCH] fix broken --- .../charts/MetricChart/BusterMetricChart.tsx | 6 +- .../aggregateAndCreateDatasets.ts | 76 ++++++++++--------- web/src/components/ui/charts/helpers.ts | 3 +- web/src/components/ui/dropdown/Dropdown.tsx | 1 + .../components/ui/dropdown/SearchDropdown.tsx | 1 + .../ui/error/ErrorClosableContainer.tsx | 1 + .../ui/grid/_BusterDragColumnMarkers.tsx | 8 +- .../grid/_BusterSortableItemDragContainer.tsx | 1 + .../ui/grid/_BusterSortableOverlay.tsx | 6 +- .../ui/list/BusterList/interfaces.ts | 8 +- .../TanStackDataGrid/defaultFormat.ts | 4 +- 11 files changed, 69 insertions(+), 46 deletions(-) diff --git a/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx b/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx index d6fedfdde..c599aaa9b 100644 --- a/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx +++ b/web/src/components/ui/charts/MetricChart/BusterMetricChart.tsx @@ -1,4 +1,4 @@ -import { DEFAULT_COLUMN_LABEL_FORMAT } from '@/api/asset_interfaces/metric'; +import { DEFAULT_CHART_CONFIG, DEFAULT_COLUMN_LABEL_FORMAT } from '@/api/asset_interfaces/metric'; import type { ColumnLabelFormat, MetricChartProps } from '@/api/asset_interfaces/metric/charts'; import { Title } from '@/components/ui/typography'; import { useMount } from '@/hooks'; @@ -28,7 +28,7 @@ export const BusterMetricChart: React.FC = React.memo( const headerColumnLabelFormat: ColumnLabelFormat = useMemo(() => { const isDerivedTitle = typeof metricHeader === 'object' && metricHeader?.columnId; if (isDerivedTitle && columnLabelFormats[metricHeader.columnId]) { - return columnLabelFormats[metricHeader.columnId]!; + return columnLabelFormats[metricHeader.columnId] as ColumnLabelFormat; } return DEFAULT_COLUMN_LABEL_FORMAT; }, [metricHeader, columnLabelFormats]); @@ -225,7 +225,7 @@ const fallbackAggregate = ( const isNumber = columnLabelFormat.style === 'number' && columnLabelFormat.columnType === 'number'; const isValid = isNumber; - if (isValid) return aggregate; + if (isValid) return aggregate || DEFAULT_CHART_CONFIG.metricValueAggregate; return 'first'; }; diff --git a/web/src/components/ui/charts/chartHooks/useDatasetOptions/aggregateAndCreateDatasets.ts b/web/src/components/ui/charts/chartHooks/useDatasetOptions/aggregateAndCreateDatasets.ts index 633ad7389..99bb84422 100644 --- a/web/src/components/ui/charts/chartHooks/useDatasetOptions/aggregateAndCreateDatasets.ts +++ b/web/src/components/ui/charts/chartHooks/useDatasetOptions/aggregateAndCreateDatasets.ts @@ -34,12 +34,15 @@ export function aggregateAndCreateDatasets< ...tooltipKeys ]); const colFormats: Record = {}; - allKeys.forEach((k) => { + for (const k of allKeys) { colFormats[k] = columnLabelFormats[k] || {}; - }); + } // Parse numeric values with replaceMissingDataWith - function parseNumeric(raw: any, fmt: ColumnLabelFormatBase): number | null { + function parseNumeric( + raw: string | number | null | undefined | Date | boolean, + fmt: ColumnLabelFormatBase + ): number | null { const rep = fmt.replaceMissingDataWith === null ? null : (fmt.replaceMissingDataWith ?? 0); const n = Number(raw); if (raw == null || raw === '' || Number.isNaN(n)) { @@ -51,7 +54,10 @@ export function aggregateAndCreateDatasets< } // Format tooltip values, treating missing as empty or replacement - function formatTooltip(raw: any, fmt: ColumnLabelFormatBase): string | number | boolean { + function formatTooltip( + raw: string | number | null | undefined | Date | boolean, + fmt: ColumnLabelFormatBase + ): string | number | boolean { if (raw == null || raw === '') { if (fmt.replaceMissingDataWith !== undefined) { const rep = fmt.replaceMissingDataWith; @@ -60,7 +66,7 @@ export function aggregateAndCreateDatasets< return ''; } if (typeof raw === 'boolean') return raw; - if (typeof raw === 'object') return raw; + if (typeof raw === 'object') return raw.toString(); const num = Number(raw); return Number.isNaN(num) ? raw : num; } @@ -71,17 +77,17 @@ export function aggregateAndCreateDatasets< rows: T[] ): Array<{ id: string; rec: Record; rows: T[] }> { const map = new Map; rows: T[] }>(); - rows.forEach((row) => { + for (const row of rows) { const rec: Record = {}; - keys.forEach((k) => { - rec[k] = String((row as any)[k]); - }); + for (const k of keys) { + rec[k] = String((row as Record)[k]); + } const id = keys.map((k) => rec[k]).join('|'); if (!map.has(id)) { map.set(id, { rec, rows: [] }); } map.get(id)?.rows.push(row); - }); + } return Array.from(map.entries()).map(([id, g]) => ({ id, rec: g.rec, rows: g.rows })); } @@ -96,9 +102,9 @@ export function aggregateAndCreateDatasets< // If there are categories, add them if (catRec && catKeys.length > 0) { - catKeys.forEach((catKey) => { + for (const catKey of catKeys) { labels.push({ key: catKey, value: catRec[catKey] }); - }); + } } else if (yKeys.length + y2Keys.length === 1) { // If no categories and only one y-axis, use the metric key labels.push({ key: metric, value: '' }); @@ -123,8 +129,8 @@ export function aggregateAndCreateDatasets< // SCATTER: for each category group and each yKey const scatterTicksKey: KV[] = xKeys.map((key) => ({ key, value: '' })); - catGroups.forEach(({ rec: catRec, rows }) => { - yKeys.forEach((yKey) => { + for (const { rec: catRec, rows } of catGroups) { + for (const yKey of yKeys) { const fmtY = colFormats[yKey]; const axisType = 'y'; @@ -144,7 +150,7 @@ export function aggregateAndCreateDatasets< const tooltipArr = validRows.map((r) => { const pts: KV[] = []; if (tooltipKeys.length) { - tooltipKeys.forEach((k) => { + for (const k of tooltipKeys) { const tooltip: KV = { key: k, value: formatTooltip(r[k], colFormats[k] || {}) @@ -157,9 +163,9 @@ export function aggregateAndCreateDatasets< } pts.push(tooltip); - }); + } } else { - xKeys.forEach((k) => { + for (const k of xKeys) { const tooltip: KV = { key: k, value: formatTooltip(r[k], colFormats[k] || {}) @@ -172,14 +178,14 @@ export function aggregateAndCreateDatasets< } pts.push(tooltip); - }); + } pts.push({ key: yKey, value: formatTooltip(r[yKey], fmtY) }); - if (sizeArr) { + if (sizeArr && sizeKey) { pts.push({ - key: sizeKey!, - value: formatTooltip(r[sizeKey!], colFormats[sizeKey!] || {}) + key: sizeKey, + value: formatTooltip(r[sizeKey], colFormats[sizeKey] || {}) }); } } @@ -207,8 +213,8 @@ export function aggregateAndCreateDatasets< ticksForScatter, ...(sizeArr && { sizeData: sizeArr, sizeDataKey: sizeKey ?? undefined }) }); - }); - }); + } + } return { datasets, @@ -219,9 +225,9 @@ export function aggregateAndCreateDatasets< // NON-SCATTER if (catKeys.length) { // With categories - seriesMeta.forEach(({ key: metric, axisType }) => { + for (const { key: metric, axisType } of seriesMeta) { const fmt = colFormats[metric]; - catGroups.forEach(({ rec: catRec, rows: catRows }) => { + for (const { rec: catRec, rows: catRows } of catGroups) { const xSub = groupRows(xKeys, catRows); const xMap = new Map(xSub.map((g) => [g.id, g.rows])); @@ -229,11 +235,11 @@ export function aggregateAndCreateDatasets< const grp = xMap.get(g.id) || []; let sum = 0; let sawNull = false; - grp.forEach((r) => { + for (const r of grp) { const v = parseNumeric(r[metric], fmt); if (v === null) sawNull = true; else if (!Number.isNaN(v)) sum += v; - }); + } return sawNull ? null : sum; }); @@ -298,28 +304,28 @@ export function aggregateAndCreateDatasets< axisType, tooltipData: tooltipArr }); - }); - }); + } + } } else { // Without categories - seriesMeta.forEach(({ key: metric, axisType }) => { + for (const { key: metric, axisType } of seriesMeta) { const fmt = colFormats[metric]; // Create a single dataset with all x-group data const dataArr: (number | null)[] = []; // Collect all values for the dataset - xGroups.forEach(({ rec, rows: grpRows }) => { + for (const { rec, rows: grpRows } of xGroups) { let sum = 0; let sawNull = false; - grpRows.forEach((r) => { + for (const r of grpRows) { const v = parseNumeric(r[metric], fmt); if (v === null) sawNull = true; else if (!Number.isNaN(v)) sum += v; - }); + } const value = sawNull ? null : sum; dataArr.push(value); - }); + } // Generate labels according to the rules const labelArr = generateLabels(metric); @@ -362,7 +368,7 @@ export function aggregateAndCreateDatasets< axisType, tooltipData: tooltipArr }); - }); + } } // Create ticks from the x-axis values diff --git a/web/src/components/ui/charts/helpers.ts b/web/src/components/ui/charts/helpers.ts index 468bd4fb9..10a6e29db 100644 --- a/web/src/components/ui/charts/helpers.ts +++ b/web/src/components/ui/charts/helpers.ts @@ -26,5 +26,6 @@ export const doesChartHaveValidAxis = ({ isTable: boolean; }) => { if (isTable) return true; - return AxisMethodCheckRecord[selectedChartType](selectedAxis!); + if (!selectedAxis) return false; + return AxisMethodCheckRecord[selectedChartType](selectedAxis); }; diff --git a/web/src/components/ui/dropdown/Dropdown.tsx b/web/src/components/ui/dropdown/Dropdown.tsx index 066f020ef..da98e31bd 100644 --- a/web/src/components/ui/dropdown/Dropdown.tsx +++ b/web/src/components/ui/dropdown/Dropdown.tsx @@ -315,6 +315,7 @@ const DropdownItemSelector = React.memo( }: { item: DropdownItems[number]; index: number; + // biome-ignore lint/suspicious/noExplicitAny: onSelect?: (value: any) => void; // Using any here to resolve the type mismatch onSelectItem: (index: number) => void; closeOnSelect: boolean; diff --git a/web/src/components/ui/dropdown/SearchDropdown.tsx b/web/src/components/ui/dropdown/SearchDropdown.tsx index 1a62bd43d..b126a1e5b 100644 --- a/web/src/components/ui/dropdown/SearchDropdown.tsx +++ b/web/src/components/ui/dropdown/SearchDropdown.tsx @@ -56,6 +56,7 @@ export const SearchDropdown = React.memo( {items.map((item, index) => ( key={index} className="group min-h-10" onClick={() => onSelect(item)}> diff --git a/web/src/components/ui/error/ErrorClosableContainer.tsx b/web/src/components/ui/error/ErrorClosableContainer.tsx index 4a1064b74..6011551f7 100644 --- a/web/src/components/ui/error/ErrorClosableContainer.tsx +++ b/web/src/components/ui/error/ErrorClosableContainer.tsx @@ -34,6 +34,7 @@ export const ErrorClosableContainer: React.FC<{ {error}