Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 112 additions & 2 deletions src/pages/audit-report/components/DynamicDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,112 @@ interface RowAttributes {
icon?: IconName | "health" | "warning" | "unhealthy" | "unknown";
url?: string;
max?: number;
derivedMax?: boolean; // True if max was computed from data, not explicitly set
config?: {
id: string;
type: string;
class: string;
};
}

type GaugeMaxValue = { max: number; derivedMax: boolean };

export const hiddenColumnTypes = ["row_attributes", "grants"];

/**
* Computes the maximum 'max' value for each gauge column across all rows and tracks whether it was derived.
* Considers column-level gauge.max, row-level attributes, and falls back
* to the maximum value among all rows if no explicit max is defined.
*/
const computeGaugeMaxValues = (
columns: ViewColumnDef[],
data: Record<string, any>[]
): Map<string, GaugeMaxValue> => {
const maxValues = new Map<string, GaugeMaxValue>();

const gaugeColumns = columns.filter((col) => col.type === "gauge");

for (const col of gaugeColumns) {
// col.gauge?.max might be a CEL expression string, so only use if it's a valid number
const colMax = col.gauge?.max;
const hasValidColMax = typeof colMax === "number" && colMax > 0;
let maxValue = hasValidColMax ? colMax : 0;
let derivedMax = false;
let explicitMaxFound = hasValidColMax;

// First, try to find max from row attributes
for (const row of data) {
const rowMax = row.__rowAttributes?.[col.name]?.max;
if (rowMax === undefined) continue;

const numMax = Number(rowMax);
if (!isNaN(numMax) && numMax > 0) {
explicitMaxFound = true;
if (numMax > maxValue) {
maxValue = numMax;
}
}
}

// If no valid max found, fall back to the maximum value among all rows
if (!explicitMaxFound) {
for (const row of data) {
const value = row[col.name];
if (typeof value === "number" && value > maxValue) {
maxValue = value;
}
}
if (maxValue > 0) {
derivedMax = true;
}
}

if (maxValue > 0) {
maxValues.set(col.name, { max: maxValue, derivedMax });
}
}

return maxValues;
};

/**
* Injects computed max values into rows that are missing or have zero max for gauge columns.
* Also carries over whether the max was derived so it can be styled differently.
*/
const injectMissingGaugeMax = (
data: Record<string, any>[],
columns: ViewColumnDef[],
maxValues: Map<string, GaugeMaxValue>
): Record<string, any>[] => {
const gaugeColumns = columns.filter((col) => col.type === "gauge");

return data.map((row) => {
let modified = false;
let newAttributes = { ...row.__rowAttributes };

for (const col of gaugeColumns) {
const computedMaxEntry = maxValues.get(col.name);
if (computedMaxEntry === undefined) continue;

const existingMax = newAttributes?.[col.name]?.max;
// Inject if max is missing or is zero/falsy
if (existingMax === undefined || Number(existingMax) === 0) {
newAttributes = {
...newAttributes,
[col.name]: {
...newAttributes?.[col.name],
max: computedMaxEntry.max,
derivedMax: computedMaxEntry.derivedMax // Flag to indicate max was computed, not explicit
}
};
modified = true;
}
}

return modified ? { ...row, __rowAttributes: newAttributes } : row;
});
};

const DynamicDataTable: React.FC<DynamicDataTableProps> = ({
columns,
rows,
Expand Down Expand Up @@ -96,12 +193,20 @@ const DynamicDataTable: React.FC<DynamicDataTableProps> = ({
return rowObj;
});

// Pre-process gauge columns to compute and inject missing max values
const gaugeMaxValues = computeGaugeMaxValues(columns, adaptedData);
const processedData = injectMissingGaugeMax(
adaptedData,
columns,
gaugeMaxValues
);

return (
<MRTDataTable
enableColumnActions={false}
columns={columnDef}
isLoading={isLoading}
data={adaptedData}
data={processedData}
enableServerSideSorting
enableServerSidePagination
manualPageCount={pageCount}
Expand Down Expand Up @@ -262,6 +367,7 @@ const renderCellValue = (
RowAttributes
>;
const maxFromAttributes = rowAttributes?.[column.name]?.max;
const isDerivedMax = rowAttributes?.[column.name]?.derivedMax === true;

const gaugeConfig =
maxFromAttributes !== undefined
Expand All @@ -276,7 +382,11 @@ const renderCellValue = (
};

cellContent = (
<GaugeCell value={formattedValue} gauge={finalGaugeConfig} />
<GaugeCell
value={formattedValue}
gauge={finalGaugeConfig}
derivedMax={isDerivedMax}
/>
);
}
break;
Expand Down
24 changes: 17 additions & 7 deletions src/pages/audit-report/components/GaugeCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import { Tooltip } from "react-tooltip";
interface GaugeCellProps {
value: number | { min: number; max: number; value: number };
gauge?: GaugeConfig;
derivedMax?: boolean; // True if max was computed from data, not explicitly set
}

const GaugeCell: React.FC<GaugeCellProps> = ({ value, gauge }) => {
// Blue color for gauges with derived max (no explicit limit set)
const DERIVED_MAX_COLOR = "#3b82f6"; // Tailwind blue-500

const GaugeCell: React.FC<GaugeCellProps> = ({ value, gauge, derivedMax }) => {
const gaugeValue = typeof value === "number" ? value : value.value;
const gaugeConfig =
typeof value === "number"
Expand All @@ -17,7 +21,8 @@ const GaugeCell: React.FC<GaugeCellProps> = ({ value, gauge }) => {

const gaugeData = generateGaugeData({ value: gaugeValue }, gaugeConfig);
const percentage = gaugeData.value;
const color = gaugeData.color;
// Use blue for derived max to indicate no explicit limit was set
const color = derivedMax ? DERIVED_MAX_COLOR : gaugeData.color;

const displayValue = formatDisplayValue(
gaugeValue,
Expand All @@ -34,15 +39,20 @@ const GaugeCell: React.FC<GaugeCellProps> = ({ value, gauge }) => {

const tooltipId = `gauge-tooltip-${Math.random().toString(36).slice(2, 9)}`;

// Build tooltip text
let tooltipText: string | undefined;
if (maxDisplayValue) {
tooltipText = `${percentage.toFixed(2)}% of ${maxDisplayValue}`;
if (derivedMax) {
tooltipText += " (no limit set)";
}
}

return (
<div
className="flex w-full items-center gap-2"
data-tooltip-id={maxDisplayValue ? tooltipId : undefined}
data-tooltip-html={
maxDisplayValue
? `${percentage.toFixed(2)}% of ${maxDisplayValue}`
: undefined
}
data-tooltip-html={tooltipText}
>
{/* Progress bar */}
<div className="h-2 flex-1 overflow-hidden rounded-full bg-gray-200">
Expand Down
Loading