Skip to content

Commit 7d9163a

Browse files
authored
feat(VDisk): improve severity calculation (#3769)
1 parent 166db8e commit 7d9163a

12 files changed

Lines changed: 245 additions & 34 deletions

File tree

src/components/VDiskPopup/VDiskPopup.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {createVDiskDeveloperUILink, useHasDeveloperUi} from '../../utils/develop
1515
import {getStateSeverity} from '../../utils/disks/calculateVDiskSeverity';
1616
import {
1717
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY,
18-
NOT_AVAILABLE_SEVERITY,
1918
NUMERIC_SEVERITY_TO_LABEL_VIEW,
2019
VDISK_LABEL_CONFIG,
2120
} from '../../utils/disks/constants';
@@ -393,7 +392,7 @@ const prepareHeaderLabels = (data: PreparedVDisk): YDBDefinitionListHeaderLabel[
393392
});
394393
}
395394

396-
const severity = VDiskState ? getStateSeverity(VDiskState) : NOT_AVAILABLE_SEVERITY;
395+
const severity = getStateSeverity(VDiskState);
397396

398397
const {theme: stateTheme, icon: stateIcon} = NUMERIC_SEVERITY_TO_LABEL_VIEW[severity];
399398

src/components/capacityMetricsColumns/columns.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import DataTable from '@gravity-ui/react-data-table';
2+
import type {LabelProps} from '@gravity-ui/uikit';
23
import {Label} from '@gravity-ui/uikit';
34
import {isNil} from 'lodash';
45

6+
import {isCapacityAlert} from '../../types/api/enums';
57
import {getCapacityAlertTheme} from '../../utils/capacityAlerts';
68
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
79
import {formatPercent} from '../../utils/dataFormatters/dataFormatters';
@@ -32,7 +34,9 @@ export function getVDiskSlotUsageColumn<
3234
header: CAPACITY_METRICS_COLUMN_TITLES.MaxVDiskSlotUsage,
3335
width: 180,
3436
render: ({row}) => {
35-
const theme = getCapacityAlertTheme(row.CapacityAlert);
37+
const theme: LabelProps['theme'] = isCapacityAlert(row.CapacityAlert)
38+
? getCapacityAlertTheme(row.CapacityAlert)
39+
: 'normal';
3640

3741
return isNumeric(row.MaxVDiskSlotUsage) ? (
3842
<Label theme={theme}>

src/store/reducers/storage/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export interface PreparedStorageNode
4242

4343
MaxPDiskUsage?: number;
4444
MaxVDiskSlotUsage?: number;
45-
CapacityAlert?: ECapacityAlert;
45+
CapacityAlert?: ECapacityAlert | string;
4646
}
4747

4848
export interface PreparedStorageGroupFilters {
@@ -106,7 +106,7 @@ export interface PreparedStorageGroup {
106106
MaxVDiskSlotUsage?: number;
107107
MaxVDiskRawUsage?: number;
108108
MaxNormalizedOccupancy?: number;
109-
CapacityAlert?: ECapacityAlert;
109+
CapacityAlert?: ECapacityAlert | string;
110110
}
111111

112112
export type TableGroup = {

src/types/api/enums.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,12 @@ export enum ECapacityAlert {
2222
RED = 'RED',
2323
BLACK = 'BLACK',
2424
}
25+
26+
const capacityAlertValues = new Set<string>(Object.values(ECapacityAlert));
27+
28+
export function isCapacityAlert(value?: string): value is ECapacityAlert {
29+
if (!value) {
30+
return false;
31+
}
32+
return capacityAlertValues.has(value);
33+
}

src/types/api/nodes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export interface TNodeInfo {
7575
// Capacity metrics experiment
7676
MaxPDiskUsage?: number;
7777
MaxVDiskSlotUsage?: number;
78-
CapacityAlert?: ECapacityAlert;
78+
CapacityAlert?: ECapacityAlert | string;
7979
}
8080

8181
export interface TNodesGroup {

src/types/api/storage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ export interface TGroupsStorageGroupInfo {
201201
MaxVDiskSlotUsage?: number;
202202
MaxVDiskRawUsage?: number;
203203
MaxNormalizedOccupancy?: number;
204-
CapacityAlert?: ECapacityAlert;
204+
CapacityAlert?: ECapacityAlert | string;
205205
}
206206

207207
/**

src/types/api/vdisk.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {EFlag} from './enums';
1+
import type {ECapacityAlert, EFlag} from './enums';
22
import type {TPDiskStateInfo} from './pdisk';
33
/**
44
* Node whiteboard VDisk data
@@ -82,6 +82,7 @@ export interface TVDiskStateInfo {
8282
* Write bytes per second to PDisk for TEvVPut blobs and replication bytes only
8383
*/
8484
WriteThroughput?: string;
85+
CapacityAlert?: ECapacityAlert | string;
8586
}
8687

8788
export interface TVSlotId {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {ECapacityAlert} from '../../types/api/enums';
2+
import {getCapacityAlertSeverity, getCapacityAlertTheme} from '../capacityAlerts';
3+
import {DISK_COLOR_STATE_TO_NUMERIC_SEVERITY} from '../disks/constants';
4+
5+
describe('getCapacityAlertSeverity', () => {
6+
test('Should return Green severity for GREEN and CYAN alerts', () => {
7+
expect(getCapacityAlertSeverity(ECapacityAlert.GREEN)).toEqual(
8+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green,
9+
);
10+
expect(getCapacityAlertSeverity(ECapacityAlert.CYAN)).toEqual(
11+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green,
12+
);
13+
});
14+
15+
test('Should return Yellow severity for LIGHT_YELLOW alert', () => {
16+
expect(getCapacityAlertSeverity(ECapacityAlert.LIGHTYELLOW)).toEqual(
17+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow,
18+
);
19+
});
20+
21+
test('Should return Red severity for YELLOW through BLACK alerts', () => {
22+
const dangerAlerts: ECapacityAlert[] = [
23+
ECapacityAlert.YELLOW,
24+
ECapacityAlert.LIGHTORANGE,
25+
ECapacityAlert.PREORANGE,
26+
ECapacityAlert.ORANGE,
27+
ECapacityAlert.RED,
28+
ECapacityAlert.BLACK,
29+
];
30+
for (const alert of dangerAlerts) {
31+
expect(getCapacityAlertSeverity(alert)).toEqual(
32+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red,
33+
);
34+
}
35+
});
36+
37+
test('Should return Grey severity for undefined or unknown alerts', () => {
38+
expect(getCapacityAlertSeverity(undefined)).toEqual(
39+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey,
40+
);
41+
expect(getCapacityAlertSeverity('UNKNOWN' as ECapacityAlert)).toEqual(
42+
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey,
43+
);
44+
});
45+
});
46+
47+
describe('getCapacityAlertTheme', () => {
48+
test('Should return success theme for GREEN and CYAN alerts', () => {
49+
expect(getCapacityAlertTheme(ECapacityAlert.GREEN)).toEqual('success');
50+
expect(getCapacityAlertTheme(ECapacityAlert.CYAN)).toEqual('success');
51+
});
52+
53+
test('Should return warning theme for LIGHT_YELLOW alert', () => {
54+
expect(getCapacityAlertTheme(ECapacityAlert.LIGHTYELLOW)).toEqual('warning');
55+
});
56+
57+
test('Should return danger theme for YELLOW through BLACK alerts', () => {
58+
const dangerAlerts: ECapacityAlert[] = [
59+
ECapacityAlert.YELLOW,
60+
ECapacityAlert.LIGHTORANGE,
61+
ECapacityAlert.PREORANGE,
62+
ECapacityAlert.ORANGE,
63+
ECapacityAlert.RED,
64+
ECapacityAlert.BLACK,
65+
];
66+
for (const alert of dangerAlerts) {
67+
expect(getCapacityAlertTheme(alert)).toEqual('danger');
68+
}
69+
});
70+
71+
test('Should return normal theme for undefined or unknown alerts', () => {
72+
expect(getCapacityAlertTheme(undefined)).toEqual('normal');
73+
expect(getCapacityAlertTheme('UNKNOWN' as ECapacityAlert)).toEqual('normal');
74+
});
75+
});

src/utils/capacityAlerts.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,41 @@
11
import type {LabelProps} from '@gravity-ui/uikit';
22

3-
export function getCapacityAlertTheme(capacityAlert?: string): LabelProps['theme'] {
3+
import type {ECapacityAlert} from '../types/api/enums';
4+
5+
import {DISK_COLOR_STATE_TO_NUMERIC_SEVERITY} from './disks/constants';
6+
7+
type NumericSeverity =
8+
(typeof DISK_COLOR_STATE_TO_NUMERIC_SEVERITY)[keyof typeof DISK_COLOR_STATE_TO_NUMERIC_SEVERITY];
9+
10+
const SEVERITY_TO_THEME: Record<NumericSeverity, LabelProps['theme']> = {
11+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey]: 'normal',
12+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green]: 'success',
13+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Blue]: 'info',
14+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow]: 'warning',
15+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Orange]: 'danger',
16+
[DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red]: 'danger',
17+
};
18+
19+
export function getCapacityAlertSeverity(capacityAlert?: ECapacityAlert): NumericSeverity {
420
switch (capacityAlert) {
521
case 'GREEN':
622
case 'CYAN':
7-
return 'success';
23+
return DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green;
824
case 'LIGHT_YELLOW':
9-
return 'warning';
25+
return DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow;
1026
case 'YELLOW':
1127
case 'LIGHT_ORANGE':
1228
case 'PRE_ORANGE':
1329
case 'ORANGE':
1430
case 'RED':
1531
case 'BLACK':
16-
return 'danger';
32+
return DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red;
1733
default:
18-
return 'normal';
34+
return DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey;
1935
}
2036
}
37+
38+
export function getCapacityAlertTheme(capacityAlert?: ECapacityAlert): LabelProps['theme'] {
39+
const severity = getCapacityAlertSeverity(capacityAlert);
40+
return SEVERITY_TO_THEME[severity];
41+
}

src/utils/disks/__test__/calculateVDiskSeverity.test.ts

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {EFlag} from '../../../types/api/enums';
1+
import {ECapacityAlert, EFlag} from '../../../types/api/enums';
22
import {EVDiskState} from '../../../types/api/vdisk';
33
import {calculateVDiskSeverity} from '../calculateVDiskSeverity';
44
import {DISK_COLOR_STATE_TO_NUMERIC_SEVERITY} from '../constants';
@@ -18,7 +18,7 @@ describe('VDisk state', () => {
1818
const severity3 = calculateVDiskSeverity({
1919
VDiskState: EVDiskState.OK, // severity 1, green
2020
DiskSpace: EFlag.Yellow, // severity 3, yellow
21-
FrontQueues: EFlag.Orange, // severity 4, orange
21+
FrontQueues: EFlag.Orange, // severity 4, orange — but capped at yellow (3)
2222
});
2323

2424
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
@@ -30,16 +30,34 @@ describe('VDisk state', () => {
3030
const severity1 = calculateVDiskSeverity({
3131
VDiskState: EVDiskState.OK, // severity 1, green
3232
DiskSpace: EFlag.Green, // severity 1, green
33-
FrontQueues: EFlag.Red, // severity 5, red
33+
FrontQueues: EFlag.Red, // severity 5, red — but capped at yellow
34+
});
35+
36+
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
37+
});
38+
39+
test('Should display DiskSpace Orange as Red severity', () => {
40+
const severity = calculateVDiskSeverity({
41+
VDiskState: EVDiskState.OK,
42+
DiskSpace: EFlag.Orange,
43+
});
44+
45+
expect(severity).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
46+
});
47+
48+
test('Should display DiskSpace Red as Red severity', () => {
49+
const severity1 = calculateVDiskSeverity({
50+
VDiskState: EVDiskState.OK,
51+
DiskSpace: EFlag.Red,
3452
});
3553
const severity2 = calculateVDiskSeverity({
36-
VDiskState: EVDiskState.OK, // severity 1, green
37-
DiskSpace: EFlag.Red, // severity 5, red
38-
FrontQueues: EFlag.Red, // severity 5, red
54+
VDiskState: EVDiskState.OK,
55+
DiskSpace: EFlag.Red,
56+
FrontQueues: EFlag.Red,
3957
});
4058

41-
expect(severity1).not.toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
42-
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
59+
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
60+
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
4361
});
4462

4563
// prettier-ignore
@@ -127,15 +145,15 @@ describe('VDisk state', () => {
127145

128146
test('Should display replicating VDisks in a not-OK state with a regular color', () => {
129147
const severity1 = calculateVDiskSeverity({
130-
VDiskState: EVDiskState.Initial, // severity 3, yellow
148+
VDiskState: EVDiskState.Initial, // severity 5, red
131149
Replicated: false,
132150
});
133151
const severity2 = calculateVDiskSeverity({
134152
VDiskState: EVDiskState.PDiskError, // severity 5, red
135153
Replicated: false,
136154
});
137155

138-
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
156+
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
139157
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
140158
});
141159

@@ -146,7 +164,7 @@ describe('VDisk state', () => {
146164
DonorMode: true,
147165
});
148166
const severity2 = calculateVDiskSeverity({
149-
VDiskState: EVDiskState.Initial, // severity 3, yellow
167+
VDiskState: EVDiskState.Initial, // severity 5, red
150168
Replicated: false,
151169
DonorMode: true,
152170
});
@@ -157,7 +175,77 @@ describe('VDisk state', () => {
157175
});
158176

159177
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Blue);
160-
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
178+
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
161179
expect(severity3).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
162180
});
163181
});
182+
183+
describe('VDisk CapacityAlert', () => {
184+
test('Should use CapacityAlert instead of DiskSpace when CapacityAlert is present', () => {
185+
const severity = calculateVDiskSeverity({
186+
VDiskState: EVDiskState.OK,
187+
DiskSpace: EFlag.Red,
188+
FrontQueues: EFlag.Orange,
189+
CapacityAlert: ECapacityAlert.GREEN,
190+
});
191+
192+
// CapacityAlert GREEN maps to Green severity and overrides DiskSpace completely
193+
// VDiskStateSeverity is Green (1), CapacityAlert-derived severity is Green (1)
194+
// FrontQueuesSeverity is Orange (4), but capped at Yellow (3)
195+
// max(1, 3, 1, 3) = Yellow
196+
expect(severity).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
197+
});
198+
199+
test('Should return Green severity for GREEN and CYAN CapacityAlert', () => {
200+
expect(
201+
calculateVDiskSeverity({
202+
VDiskState: EVDiskState.OK,
203+
CapacityAlert: ECapacityAlert.GREEN,
204+
}),
205+
).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green);
206+
207+
expect(
208+
calculateVDiskSeverity({
209+
VDiskState: EVDiskState.OK,
210+
CapacityAlert: ECapacityAlert.CYAN,
211+
}),
212+
).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green);
213+
});
214+
215+
test('Should return Yellow severity for LIGHT_YELLOW CapacityAlert', () => {
216+
expect(
217+
calculateVDiskSeverity({
218+
VDiskState: EVDiskState.OK,
219+
CapacityAlert: ECapacityAlert.LIGHTYELLOW,
220+
}),
221+
).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
222+
});
223+
224+
test('Should return Red severity for danger-level CapacityAlert values', () => {
225+
const dangerAlerts = [
226+
ECapacityAlert.YELLOW,
227+
ECapacityAlert.LIGHTORANGE,
228+
ECapacityAlert.PREORANGE,
229+
ECapacityAlert.ORANGE,
230+
ECapacityAlert.RED,
231+
ECapacityAlert.BLACK,
232+
];
233+
234+
for (const alert of dangerAlerts) {
235+
expect(
236+
calculateVDiskSeverity({
237+
VDiskState: EVDiskState.OK,
238+
CapacityAlert: alert,
239+
}),
240+
).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
241+
}
242+
});
243+
244+
test('Should still display as unavailable when no VDiskState even with CapacityAlert', () => {
245+
const severity = calculateVDiskSeverity({
246+
CapacityAlert: ECapacityAlert.RED,
247+
});
248+
249+
expect(severity).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey);
250+
});
251+
});

0 commit comments

Comments
 (0)