mirror of https://github.com/buster-so/buster.git
fix broken
This commit is contained in:
parent
2ba62e5abc
commit
ee58591687
|
@ -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<BusterMetricChartProps> = 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';
|
||||
};
|
||||
|
||||
|
|
|
@ -34,12 +34,15 @@ export function aggregateAndCreateDatasets<
|
|||
...tooltipKeys
|
||||
]);
|
||||
const colFormats: Record<string, ColumnLabelFormatBase> = {};
|
||||
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<string, string>; rows: T[] }> {
|
||||
const map = new Map<string, { rec: Record<string, string>; rows: T[] }>();
|
||||
rows.forEach((row) => {
|
||||
for (const row of rows) {
|
||||
const rec: Record<string, string> = {};
|
||||
keys.forEach((k) => {
|
||||
rec[k] = String((row as any)[k]);
|
||||
});
|
||||
for (const k of keys) {
|
||||
rec[k] = String((row as Record<string, string | number | null | undefined>)[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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -315,6 +315,7 @@ const DropdownItemSelector = React.memo(
|
|||
}: {
|
||||
item: DropdownItems<T>[number];
|
||||
index: number;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
onSelect?: (value: any) => void; // Using any here to resolve the type mismatch
|
||||
onSelectItem: (index: number) => void;
|
||||
closeOnSelect: boolean;
|
||||
|
|
|
@ -56,6 +56,7 @@ export const SearchDropdown = React.memo(
|
|||
{items.map((item, index) => (
|
||||
<DropdownMenuItem
|
||||
disabled={item.disabled}
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
|
||||
key={index}
|
||||
className="group min-h-10"
|
||||
onClick={() => onSelect(item)}>
|
||||
|
|
|
@ -34,6 +34,7 @@ export const ErrorClosableContainer: React.FC<{
|
|||
<span>{error}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onClose?.();
|
||||
setClosed(true);
|
||||
|
|
|
@ -25,6 +25,7 @@ export const BusterDragColumnMarkers: React.FC<{
|
|||
}}>
|
||||
{Array.from({ length: NUMBER_OF_COLUMNS + 1 }).map((_, index) => (
|
||||
<div
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
|
||||
key={index}
|
||||
className={cn(
|
||||
'bg-border',
|
||||
|
@ -48,7 +49,7 @@ export const BusterDragColumnMarkers: React.FC<{
|
|||
const geHideSnappedDot = (
|
||||
isDraggingIndex: number | null,
|
||||
index: number,
|
||||
disabled,
|
||||
disabled: boolean | undefined,
|
||||
itemsLength: number
|
||||
) => {
|
||||
if (disabled || index < 3 || index > 9) return true;
|
||||
|
@ -112,7 +113,10 @@ const hackForTesting = (
|
|||
DEFAULT: 0
|
||||
}
|
||||
};
|
||||
const offsetRecord = dragIndexRecord[isDraggingIndex as 1]!;
|
||||
const offsetRecord = dragIndexRecord[isDraggingIndex as 1];
|
||||
if (!offsetRecord) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
left: `calc(${((dotIndex + 0) / NUMBER_OF_COLUMNS) * 100}% - ${offsetRecord?.[dotIndex as 4] || offsetRecord?.DEFAULT}px)`
|
||||
|
|
|
@ -5,6 +5,7 @@ import React, { createContext, useMemo } from 'react';
|
|||
import { BusterSortableItemContent } from './_BusterSortableItemContent';
|
||||
|
||||
interface Context {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
attributes: Record<string, any>;
|
||||
listeners: DraggableSyntheticListeners;
|
||||
// ref(node: HTMLElement | null): void;
|
||||
|
|
|
@ -37,7 +37,11 @@ export const BusterSortableOverlay: React.FC<{
|
|||
const indexOfItem = r?.items.findIndex((item) => item.id === activeId);
|
||||
|
||||
if (r && indexOfItem !== undefined && indexOfItem !== -1) {
|
||||
const widthOfGrid = document.querySelector('.buster-resizeable-grid')?.clientWidth!;
|
||||
const widthOfGrid = document.querySelector('.buster-resizeable-grid')?.clientWidth;
|
||||
if (widthOfGrid === undefined) {
|
||||
// Handle the case where widthOfGrid is undefined
|
||||
return { widthOfItem: undefined, useSnapToCenter: false };
|
||||
}
|
||||
let columnsOfItem = r.columnSizes?.[indexOfItem] || 4;
|
||||
const useSnapToCenter = columnsOfItem === 12;
|
||||
if (useSnapToCenter) {
|
||||
|
|
|
@ -20,7 +20,11 @@ export interface BusterListColumn {
|
|||
width?: number;
|
||||
minWidth?: number;
|
||||
align?: 'left' | 'center' | 'right'; //TODO
|
||||
render?: (value: any, record: any) => React.JSX.Element | string | React.ReactNode;
|
||||
render?: (
|
||||
value: string | number | boolean | null | undefined,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
record: any
|
||||
) => React.JSX.Element | string | React.ReactNode;
|
||||
headerRender?: (title: string) => React.ReactNode;
|
||||
ellipsis?: boolean;
|
||||
}
|
||||
|
@ -28,7 +32,7 @@ export interface BusterListColumn {
|
|||
export type BusterListRow = BusterListRowItem;
|
||||
export interface BusterListRowItem {
|
||||
id: string;
|
||||
data: Record<string, string | React.ReactNode | any> | null;
|
||||
data: Record<string, string | React.ReactNode | number | boolean | null | undefined> | null;
|
||||
onClick?: () => void;
|
||||
link?: string;
|
||||
onSelect?: () => void;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { makeHumanReadble } from '@/lib/text';
|
||||
|
||||
export const defaultHeaderFormat = (v: any) => makeHumanReadble(v);
|
||||
export const defaultCellFormat = (v: any) => v;
|
||||
export const defaultHeaderFormat = (v: unknown) => makeHumanReadble(v);
|
||||
export const defaultCellFormat = (v: unknown) => v;
|
||||
|
|
Loading…
Reference in New Issue