This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 1c187f19d fix(metrics): keep mixed and pure series colors distinct
(#4570)
1c187f19d is described below
commit 1c187f19d1b5ffa1e87c47d5eae78ca3685747dc
Author: 烤化の初雪 <[email protected]>
AuthorDate: Sat Sep 26 18:46:49 2026 +0800
fix(metrics): keep mixed and pure series colors distinct (#4570)
The slot arithmetic for split mixed-series lines could hand the same
palette entry to a series's histogram line and the next pure series,
leaving two indistinguishable polylines and legend swatches. Reassign
duplicate strokes to the first free palette color in order.
---
web/src/components/MetricsExplorer.tsx | 13 ++++++++-
.../components/__tests__/MetricsExplorer.test.tsx | 34 ++++++++++++++++++++++
2 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/web/src/components/MetricsExplorer.tsx
b/web/src/components/MetricsExplorer.tsx
index b4c37865a..67027d8a2 100644
--- a/web/src/components/MetricsExplorer.tsx
+++ b/web/src/components/MetricsExplorer.tsx
@@ -148,7 +148,18 @@ const MetricChart = ({
});
})
.filter((series) => series.samples.length > 0);
-
+ // The slot arithmetic above can hand the same palette entry to a split
mixed series and
+ // the next pure series, which would make two polylines (and their legend
swatches)
+ // indistinguishable. Reassign duplicates to the first free palette color in
order.
+ const takenColors = new Set<string>();
+ for (const series of allSeries) {
+ if (!takenColors.has(series.color)) {
+ takenColors.add(series.color);
+ continue;
+ }
+ series.color = SERIES_COLORS.find((color) => !takenColors.has(color)) ??
series.color;
+ takenColors.add(series.color);
+ }
if (allSeries.length === 0) {
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={noSamples}
/>;
}
diff --git a/web/src/components/__tests__/MetricsExplorer.test.tsx
b/web/src/components/__tests__/MetricsExplorer.test.tsx
index c353f9c57..53b01fa7f 100644
--- a/web/src/components/__tests__/MetricsExplorer.test.tsx
+++ b/web/src/components/__tests__/MetricsExplorer.test.tsx
@@ -701,6 +701,40 @@ describe('MetricsExplorer', () => {
expect(screen.getByText(/broker-a.*\(直方图\)/)).toBeInTheDocument();
});
+ it('gives a mixed series and the following pure series distinct colors',
async () => {
+ vi.mocked(queryMetrics).mockResolvedValue({
+ ...metricData,
+ series: [
+ {
+ ...metricData.series[0],
+ histograms: [
+ { timestamp: 1_800_000_001, histogram: { count: '99', sum: '999',
buckets: [] } },
+ ],
+ },
+ {
+ labels: { cluster: 'prod', node_id: 'broker-b' },
+ values: [
+ { timestamp: 1_799_996_400, value: '30' },
+ { timestamp: 1_800_000_000, value: '31' },
+ ],
+ histograms: [],
+ },
+ ],
+ });
+
+ renderWithProviders(<MetricsExplorer />);
+
+ expect(await screen.findByText('42 messages/s')).toBeInTheDocument();
+ // The mixed broker-a line is split into a scalar and a histogram trend;
the broker-b
+ // line follows. Every drawn polyline must keep its own stroke so legend
swatches
+ // stay matchable.
+ const strokes = Array.from(
+ screen.getByRole('img', { name: 'Message In TPS time series'
}).querySelectorAll('polyline'),
+ ).map((line) => line.getAttribute('stroke'));
+ expect(strokes.length).toBe(3);
+ expect(new Set(strokes).size).toBe(strokes.length);
+ });
+
it('queries the selected data source through the datasource endpoint', async
() => {
const user = userEvent.setup();
vi.mocked(listDataSources).mockResolvedValue([