Skip to content

Commit 5486fe6

Browse files
cedriczieljoey-grafanahugohaggmark
authored
feat(breakdown): reserve green for success, use blue for neutral rate (#814)
* feat(breakdown): reserve green for success, use blue for neutral rate The breakdown/RED panels colored the neutral 'rate' metric (total span throughput across all statuses) green. Green connotes success/health, so applying it to total traffic — which includes errored spans — is misleading. Recolor the neutral rate/throughput series to blue and reserve green for an explicit success signal. Errors stay red, duration stays blue. Affects the RED panel, mini RED panel, attribute breakdown panels, the time-seeker series, and the breakdown legend. * fix(colors): duration panels semi-dark-blue, neutral baseline blue in comparison Address review feedback: - Duration breakdown tiles no longer fall back to the palette default (green); they now use a fixed semi-dark-blue, keeping duration in the neutral family while staying distinguishable from rate (blue) - Seeker duration color updated to semi-dark-blue to match - Comparison baseline recolored from semi-dark-green to the shared BaselineColor for all metrics, so baseline vs selection coding is consistent across rate/errors/duration and green stays reserved for success * Fix single layout colors --------- Co-authored-by: Joey <joey.tawadrous@grafana.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
1 parent 5d1221f commit 5486fe6

8 files changed

Lines changed: 39 additions & 19 deletions

File tree

src/components/Explore/TracesByService/Tabs/Breakdown/AttributesBreakdownScene.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export class AttributesBreakdownScene extends SceneObjectBase<AttributesBreakdow
177177
metric === 'duration'
178178
? []
179179
: [
180-
{ label: t('attributes-breakdown-scene.rate-label', 'Rate'), color: 'green' },
180+
{ label: t('attributes-breakdown-scene.rate-label', 'Rate'), color: 'blue' },
181181
{ label: t('attributes-breakdown-scene.error-label', 'Error'), color: 'red' },
182182
]
183183
}

src/components/Explore/TracesByService/Tabs/Comparison/AttributesComparisonScene.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,7 @@ export class AttributesComparisonScene extends SceneObjectBase<AttributesCompari
228228
tags={[
229229
{
230230
label: t('attributes-comparison-scene.baseline-label', 'Baseline'),
231-
color:
232-
traceExploration.getMetricFunction() === 'duration'
233-
? BaselineColor
234-
: getTheme().visualization.getColorByName('semi-dark-green'),
231+
color: BaselineColor,
235232
},
236233
{
237234
label: t('attributes-comparison-scene.selection-label', 'Selection'),

src/components/Explore/layouts/allComparison.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ export function getPanelConfig(metric: MetricFunction) {
8585
.matchFieldsWithName('Baseline')
8686
.overrideColor({
8787
mode: 'fixed',
88-
fixedColor: metric === 'duration' ? BaselineColor : 'semi-dark-green',
88+
// Baseline is a reference population, not a health signal; use the neutral
89+
// baseline blue for every metric and reserve green for success.
90+
fixedColor: BaselineColor,
8991
})
9092
.overrideUnit('percentunit');
9193
overrides

src/components/Explore/layouts/attributeBreakdown.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ export function buildNormalLayout(
7171
children: [
7272
new SceneFlexItem({
7373
minHeight: 300,
74-
body: (metric === 'duration' ? linesPanelConfig().setUnit('s') : linesPanelConfig()).build(),
74+
body: (metric === 'duration'
75+
? linesPanelConfig('semi-dark-blue').setUnit('s')
76+
: linesPanelConfig(metric === 'errors' ? 'semi-dark-red' : 'blue')
77+
).build(),
7578
}),
7679
],
7780
}),
@@ -145,7 +148,9 @@ export function getLayoutChild(
145148
},
146149
];
147150

148-
const panel = (metric === 'duration' ? linesPanelConfig().setUnit('s') : barsPanelConfig(metric))
151+
// Duration uses semi-dark-blue to stay in the neutral (non-status) family while
152+
// remaining distinguishable from the rate panels (blue).
153+
const panel = (metric === 'duration' ? linesPanelConfig('semi-dark-blue').setUnit('s') : barsPanelConfig(metric))
149154
.setTitle(getTitle(frame, variable.getValueText()))
150155
.setMenu(
151156
new PanelMenu({

src/components/Explore/panels/barsPanel.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ export const barsPanelConfig = (metric: MetricFunction, axisWidth?: number) => {
1717
.setOverrides((overrides) => {
1818
overrides.matchFieldsWithNameByRegex('.*').overrideColor({
1919
mode: 'fixed',
20-
fixedColor: isErrorsMetric ? 'semi-dark-red' : 'green',
20+
// Rate is neutral throughput (all spans); use a neutral blue and reserve
21+
// green for an explicit success signal.
22+
fixedColor: isErrorsMetric ? 'semi-dark-red' : 'blue',
2123
});
2224
})
2325
.setOption('tooltip', { mode: TooltipDisplayMode.Multi });
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
import { PanelBuilders } from '@grafana/scenes';
22
import { TooltipDisplayMode } from '@grafana/ui';
33

4-
export const linesPanelConfig = () => {
5-
return PanelBuilders.timeseries()
4+
export const linesPanelConfig = (fixedColor?: string) => {
5+
const builder = PanelBuilders.timeseries()
66
.setOption('annotations', { multiLane: true })
77
.setOption('legend', { showLegend: false })
88
.setOption('tooltip', { mode: TooltipDisplayMode.Multi })
99
.setCustomFieldConfig('fillOpacity', 15);
10+
11+
if (fixedColor) {
12+
builder.setOverrides((overrides) => {
13+
overrides.matchFieldsWithNameByRegex('.*').overrideColor({
14+
mode: 'fixed',
15+
fixedColor,
16+
});
17+
});
18+
}
19+
20+
return builder;
1021
};

src/components/Explore/seeker/TimeSeekerContext.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,20 @@ describe('TimeSeekerContext', () => {
112112
},
113113
} as any;
114114

115-
it('returns blue for duration metric', () => {
116-
expect(getMetricColor(mockTheme, 'duration')).toBe('color-blue');
115+
it('returns semi-dark-blue for duration metric', () => {
116+
expect(getMetricColor(mockTheme, 'duration')).toBe('color-semi-dark-blue');
117117
});
118118

119119
it('returns semi-dark-red for errors metric', () => {
120120
expect(getMetricColor(mockTheme, 'errors')).toBe('color-semi-dark-red');
121121
});
122122

123-
it('returns green for rate metric', () => {
124-
expect(getMetricColor(mockTheme, 'rate')).toBe('color-green');
123+
it('returns blue for rate metric', () => {
124+
expect(getMetricColor(mockTheme, 'rate')).toBe('color-blue');
125125
});
126126

127-
it('returns green for undefined metric', () => {
128-
expect(getMetricColor(mockTheme, undefined)).toBe('color-green');
127+
it('returns blue for undefined metric', () => {
128+
expect(getMetricColor(mockTheme, undefined)).toBe('color-blue');
129129
});
130130
});
131131

src/components/Explore/seeker/getMetricColor.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { MetricFunction } from 'utils/shared';
33

44
export function getMetricColor(theme: GrafanaTheme2, metric?: MetricFunction): string {
55
if (metric === 'duration') {
6-
return theme.visualization.getColorByName('blue');
6+
// Semi-dark-blue keeps duration in the neutral family but visually distinct from rate (blue).
7+
return theme.visualization.getColorByName('semi-dark-blue');
78
} else if (metric === 'errors') {
89
return theme.visualization.getColorByName('semi-dark-red');
910
}
10-
return theme.visualization.getColorByName('green');
11+
// Rate is neutral throughput (all spans, regardless of status), so use a neutral
12+
// color. Green is reserved for an explicit success signal.
13+
return theme.visualization.getColorByName('blue');
1114
}

0 commit comments

Comments
 (0)