Skip to content
Merged
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
4 changes: 3 additions & 1 deletion app/src/lib/plugin/chart-plugin-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ export interface ChartPluginConfig {
* Transforms raw rows with an explicit column mapping (optional).
* Used when the user overrides auto-detected axis columns in the UI.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- mapping shape lives in component package
// ColumnMapping shape: { xAxis?, yAxis?, groupBy? } from component package.
// Using a loose type here to avoid coupling the registry to the component package.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ColumnMapping lives in component package
transformWithMapping?: (data: unknown, mapping: any) => unknown;
/**
* Validates raw data shape. Returns an error string when data is present
Expand Down
2 changes: 0 additions & 2 deletions app/src/plugins/bar/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ function BarPluginComponent({
data,
settings: raw,
onChartClick,
colorThresholds,
stylingRules,
paramValues,
}: PluginProps) {
Expand All @@ -43,7 +42,6 @@ function BarPluginComponent({
showGridLines={settings.showGridLines}
axisLabelRotation={settings.axisLabelRotation}
referenceLines={settings.referenceLines}
colorThresholds={colorThresholds}
stylingRules={stylingRules as StylingRule[] | undefined}
paramValues={paramValues}
onClick={onClick}
Expand Down
2 changes: 0 additions & 2 deletions app/src/plugins/line/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ function LinePluginComponent({
stylingRules,
paramValues,
onChartClick,
colorThresholds,
}: PluginProps) {
const onClick = useEChartsClick(onChartClick, data);
const settings = lineSettingsSchema.parse(raw);
Expand Down Expand Up @@ -53,7 +52,6 @@ function LinePluginComponent({
connectNulls={settings.connectNulls}
endLabel={settings.endLabel}
referenceLines={settings.referenceLines}
colorThresholds={colorThresholds}
stylingRules={stylingRules as StylingRule[] | undefined}
paramValues={paramValues}
onClick={onClick}
Expand Down
2 changes: 0 additions & 2 deletions app/src/plugins/pie/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ function PiePluginComponent({
stylingRules,
paramValues,
onChartClick,
colorThresholds,
}: PluginProps) {
const onClick = useEChartsClick(onChartClick, data);
const settings = pieSettingsSchema.parse(raw);
Expand All @@ -40,7 +39,6 @@ function PiePluginComponent({
sortSlices={settings.sortSlices}
topN={settings.topN}
donutCenterText={settings.donutCenterText}
colorThresholds={colorThresholds}
stylingRules={stylingRules as StylingRule[] | undefined}
paramValues={paramValues}
onClick={onClick}
Expand Down
2 changes: 0 additions & 2 deletions app/src/plugins/single-value/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function SingleValuePluginComponent({
settings: raw,
stylingRules,
paramValues,
colorThresholds,
}: PluginProps) {
const parsed = singleValueSettingsSchema.safeParse(raw);
const settings = parsed.success
Expand All @@ -50,7 +49,6 @@ function SingleValuePluginComponent({
fontSize={settings.fontSize}
numberFormat={settings.numberFormat}
decimalPlaces={settings.decimalPlaces}
colorThresholds={colorThresholds}
stylingRules={stylingRules as StylingRule[] | undefined}
paramValues={paramValues}
/>
Expand Down
1 change: 0 additions & 1 deletion app/src/plugins/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export interface PluginProps {
query?: string;
autoFit?: boolean;
clickableColumns?: string[];
colorThresholds?: string;
}

/**
Expand Down
66 changes: 46 additions & 20 deletions component/src/charts/__tests__/single-value-chart.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ describe("SingleValueChart", () => {

it("shows up trend", () => {
render(
<SingleValueChart value={100} trend={{ direction: "up", label: "+12%" }} />,
<SingleValueChart
value={100}
trend={{ direction: "up", label: "+12%" }}
/>,
);
expect(screen.getByText(/\+12%/)).toBeInTheDocument();
});

it("shows down trend", () => {
render(
<SingleValueChart value={80} trend={{ direction: "down", label: "-5%" }} />,
<SingleValueChart
value={80}
trend={{ direction: "down", label: "-5%" }}
/>,
);
expect(screen.getByText(/-5%/)).toBeInTheDocument();
});
Expand Down Expand Up @@ -97,29 +103,49 @@ describe("SingleValueChart", () => {
});

it("format prop takes precedence over numberFormat", () => {
render(<SingleValueChart value={1000} format={(v) => `~${v}`} numberFormat="comma" />);
render(
<SingleValueChart
value={1000}
format={(v) => `~${v}`}
numberFormat="comma"
/>,
);
expect(screen.getByText("~1000")).toBeInTheDocument();
});

// --- New options: colorThresholds ---
// --- Styling rules (replaced legacy colorThresholds) ---

it("applies threshold color when value is below threshold", () => {
const thresholds = JSON.stringify([{ value: 50, color: "#ff0000" }, { value: 100, color: "#00ff00" }]);
const { container } = render(<SingleValueChart value={30} colorThresholds={thresholds} />);
it("applies styling rule color when value matches", () => {
const rules = [
{ id: "r1", operator: "<" as const, value: 50, color: "#ff0000" },
{ id: "r2", operator: ">=" as const, value: 50, color: "#00ff00" },
];
const { container } = render(
<SingleValueChart value={30} stylingRules={rules} />,
);
const valueEl = container.querySelector("[style]");
expect(valueEl).toHaveStyle({ color: "rgb(255, 0, 0)" });
});

it("applies next threshold color when value exceeds first threshold", () => {
const thresholds = JSON.stringify([{ value: 50, color: "#ff0000" }, { value: 100, color: "#00ff00" }]);
const { container } = render(<SingleValueChart value={75} colorThresholds={thresholds} />);
it("applies second styling rule when value exceeds first threshold", () => {
const rules = [
{ id: "r1", operator: "<" as const, value: 50, color: "#ff0000" },
{ id: "r2", operator: ">=" as const, value: 50, color: "#00ff00" },
];
const { container } = render(
<SingleValueChart value={75} stylingRules={rules} />,
);
const valueEl = container.querySelector("[style]");
expect(valueEl).toHaveStyle({ color: "rgb(0, 255, 0)" });
});

it("does not apply threshold color for string values", () => {
const thresholds = JSON.stringify([{ value: 50, color: "red" }]);
const { container } = render(<SingleValueChart value="N/A" colorThresholds={thresholds} />);
it("does not apply styling rule color for string values", () => {
const rules = [
{ id: "r1", operator: "<" as const, value: 50, color: "red" },
];
const { container } = render(
<SingleValueChart value="N/A" stylingRules={rules} />,
);
expect(container.querySelector("[style]")).not.toBeInTheDocument();
});

Expand All @@ -136,18 +162,18 @@ describe("SingleValueChart", () => {
});

it("combines decimalPlaces with numberFormat comma", () => {
render(<SingleValueChart value={1234567.891} decimalPlaces={1} numberFormat="comma" />);
render(
<SingleValueChart
value={1234567.891}
decimalPlaces={1}
numberFormat="comma"
/>,
);
expect(screen.getByText("1,234,567.9")).toBeInTheDocument();
});

it("ignores decimalPlaces of -1 (automatic)", () => {
render(<SingleValueChart value={3.14159} decimalPlaces={-1} />);
expect(screen.getByText("3.14159")).toBeInTheDocument();
});

it("handles invalid JSON in colorThresholds gracefully", () => {
expect(() =>
render(<SingleValueChart value={10} colorThresholds="not-json" />),
).not.toThrow();
});
});
17 changes: 3 additions & 14 deletions component/src/charts/bar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
parseReferenceLines,
buildMarkLineFromRefs,
} from "./chart-utils";
import { parseColorThresholds } from "./color-threshold";
import type { StylingRule } from "./styling-rule";

export interface BarChartProps extends Omit<BaseChartProps, "options"> {
Expand Down Expand Up @@ -42,8 +41,6 @@ export interface BarChartProps extends Omit<BaseChartProps, "options"> {
axisLabelRotation?: number;
/** JSON string of reference lines: [{ value, label?, color? }] */
referenceLines?: string;
/** @deprecated Use stylingRules instead. JSON string of thresholds for per-bar coloring */
colorThresholds?: string;
/** Rule-based styling rules */
stylingRules?: StylingRule[];
/** Resolved parameter values for parameterRef comparisons */
Expand Down Expand Up @@ -72,7 +69,6 @@ function BarChart({
yAxisLabel,
axisLabelRotation,
referenceLines: referenceLinesJson,
colorThresholds,
stylingRules,
paramValues,
...rest
Expand All @@ -92,9 +88,8 @@ function BarChart({
const isHorizontal = orientation === "horizontal";
const effectiveShowValues = compact ? false : showValues;
const effectiveBarWidth = barWidth > 0 ? barWidth : undefined;
const thresholds = stylingRules
? []
: parseColorThresholds(colorThresholds ?? "");
// Legacy colorThresholds removed — styling is now handled exclusively
// via stylingRules (migrated at the card-container level).
const refLines = parseReferenceLines(referenceLinesJson);
const markLine = buildMarkLineFromRefs(refLines);

Expand Down Expand Up @@ -141,12 +136,7 @@ function BarChart({
const numericValue =
typeof rawValue === "number" ? rawValue : Number(rawValue);
const color = Number.isFinite(numericValue)
? resolveItemColor(
numericValue,
stylingRules,
paramValues,
thresholds,
)
? resolveItemColor(numericValue, stylingRules, paramValues)
: undefined;
return color ? { value: rawValue, itemStyle: { color } } : rawValue;
}),
Expand Down Expand Up @@ -177,7 +167,6 @@ function BarChart({
yAxisLabel,
axisLabelRotation,
referenceLinesJson,
colorThresholds,
stylingRules,
paramValues,
compact,
Expand Down
8 changes: 1 addition & 7 deletions component/src/charts/chart-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { EChartsOption } from "echarts";
import type { ColorThreshold } from "./color-threshold";
import { resolveThresholdColor } from "./color-threshold";
import type { StylingRule } from "./styling-rule";
import { resolveStylingRuleColor } from "./styling-rule";
import type { PieChartDataPoint } from "./types";
Expand Down Expand Up @@ -348,15 +346,11 @@ export function buildCompactGrid(compact: boolean, showLegend: boolean) {
export function resolveItemColor(
value: number,
stylingRules: StylingRule[] | undefined,
paramValues: Record<string, unknown> | undefined,
thresholds: ColorThreshold[] = [],
paramValues?: Record<string, unknown>,
): string | undefined {
if (stylingRules?.length) {
return resolveStylingRuleColor(value, stylingRules, paramValues);
}
if (thresholds.length) {
return resolveThresholdColor(value, thresholds);
}
return undefined;
}

Expand Down
10 changes: 1 addition & 9 deletions component/src/charts/line-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
buildMarkLineFromRefs,
isTimeSeriesData,
} from "./chart-utils";
import { parseColorThresholds } from "./color-threshold";
import type { StylingRule } from "./styling-rule";

export interface LineChartProps extends Omit<BaseChartProps, "options"> {
Expand Down Expand Up @@ -44,8 +43,6 @@ export interface LineChartProps extends Omit<BaseChartProps, "options"> {
endLabel?: boolean;
/** JSON string of reference lines: [{ value, label?, color? }] */
referenceLines?: string;
/** @deprecated Use stylingRules instead. JSON string of thresholds */
colorThresholds?: string;
/** Rule-based styling rules */
stylingRules?: StylingRule[];
/** Resolved parameter values for parameterRef comparisons */
Expand Down Expand Up @@ -83,7 +80,6 @@ function LineChart({
connectNulls = false,
endLabel = false,
referenceLines: referenceLinesJson,
colorThresholds,
stylingRules,
paramValues,
rightAxisSeries,
Expand All @@ -104,9 +100,6 @@ function LineChart({
seriesKeys.length,
hideLegend,
);
const thresholds = stylingRules
? []
: parseColorThresholds(colorThresholds ?? "");
const refLines = parseReferenceLines(referenceLinesJson);
const markLine = buildMarkLineFromRefs(refLines);
const xValues = data.map((d) => d.x);
Expand Down Expand Up @@ -160,7 +153,7 @@ function LineChart({
}
const seriesColor =
lastValue !== undefined
? resolveItemColor(lastValue, stylingRules, paramValues, thresholds)
? resolveItemColor(lastValue, stylingRules, paramValues)
: undefined;
return {
name: key,
Expand Down Expand Up @@ -201,7 +194,6 @@ function LineChart({
connectNulls,
endLabel,
referenceLinesJson,
colorThresholds,
stylingRules,
paramValues,
rightAxisSeries,
Expand Down
15 changes: 1 addition & 14 deletions component/src/charts/pie-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
resolveItemColor,
groupTopN,
} from "./chart-utils";
import { parseColorThresholds } from "./color-threshold";
import type { StylingRule } from "./styling-rule";

export interface PieChartProps extends Omit<BaseChartProps, "options"> {
Expand All @@ -34,8 +33,6 @@ export interface PieChartProps extends Omit<BaseChartProps, "options"> {
topN?: number;
/** Text shown in the center of a donut chart (e.g. total value). Empty = auto-total. */
donutCenterText?: string;
/** @deprecated Use stylingRules instead. JSON string of thresholds */
colorThresholds?: string;
/** Rule-based styling rules */
stylingRules?: StylingRule[];
/** Resolved parameter values for parameterRef comparisons */
Expand All @@ -61,7 +58,6 @@ function PieChart({
sortSlices = false,
topN = 0,
donutCenterText,
colorThresholds,
stylingRules,
paramValues,
...rest
Expand All @@ -83,16 +79,8 @@ function PieChart({
: data;
const sortedData = groupTopN(sorted, topN);

const thresholds = stylingRules
? []
: parseColorThresholds(colorThresholds ?? "");
const coloredData = sortedData.map((d) => {
const color = resolveItemColor(
d.value,
stylingRules,
paramValues,
thresholds,
);
const color = resolveItemColor(d.value, stylingRules, paramValues);
return color ? { ...d, itemStyle: { color } } : d;
});

Expand Down Expand Up @@ -190,7 +178,6 @@ function PieChart({
sortSlices,
topN,
donutCenterText,
colorThresholds,
stylingRules,
paramValues,
compact,
Expand Down
Loading
Loading