ydb-embedded-ui 1.10.2 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/components/IndexInfoViewer/IndexInfoViewer.tsx +2 -2
  3. package/dist/components/InfoViewer/InfoViewer.scss +32 -7
  4. package/dist/components/InfoViewer/InfoViewer.tsx +43 -0
  5. package/dist/components/InfoViewer/index.ts +1 -0
  6. package/dist/components/InfoViewer/utils.ts +6 -4
  7. package/dist/components/Stack/Stack.scss +55 -0
  8. package/dist/components/Stack/Stack.tsx +35 -0
  9. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +2 -0
  10. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +5 -0
  11. package/dist/containers/Storage/Pdisk/Pdisk.scss +2 -19
  12. package/dist/containers/Storage/Pdisk/Pdisk.tsx +30 -33
  13. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +40 -0
  14. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +25 -3
  15. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +39 -9
  16. package/dist/containers/Storage/Vdisk/Vdisk.js +63 -64
  17. package/dist/containers/Storage/Vdisk/Vdisk.scss +9 -28
  18. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +163 -0
  19. package/dist/containers/Storage/utils/index.ts +5 -0
  20. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +3 -3
  21. package/dist/setupTests.js +8 -0
  22. package/dist/types/api/schema.ts +6 -14
  23. package/dist/types/api/storage.ts +118 -0
  24. package/dist/types/index.ts +1 -0
  25. package/dist/utils/index.js +22 -2
  26. package/package.json +28 -5
  27. package/dist/components/InfoViewer/InfoViewer.js +0 -47
  28. package/dist/index.test.js +0 -5
@@ -1,13 +1,13 @@
1
1
  import React, {useEffect, useState, useRef, useMemo} from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cn from 'bem-cn-lite';
4
- import _ from 'lodash';
5
- import {Popup} from '@yandex-cloud/uikit';
4
+ import {Label, Popup} from '@yandex-cloud/uikit';
6
5
 
7
6
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
8
7
  import routes, {createHref} from '../../../routes';
9
8
  import {stringifyVdiskId, getPDiskId} from '../../../utils';
10
9
  import {getPDiskType} from '../../../utils/pdisk';
10
+ import {InfoViewer} from '../../../components/InfoViewer';
11
11
  import DiskStateProgressBar, {
12
12
  diskProgressColors,
13
13
  } from '../DiskStateProgressBar/DiskStateProgressBar';
@@ -26,6 +26,9 @@ const propTypes = {
26
26
  FrontQueues: PropTypes.string,
27
27
  Replicated: PropTypes.bool,
28
28
  PoolName: PropTypes.string,
29
+ VDiskId: PropTypes.object,
30
+ DonorMode: PropTypes.bool,
31
+ nodes: PropTypes.object,
29
32
  };
30
33
 
31
34
  const stateSeverity = {
@@ -53,7 +56,7 @@ function Vdisk(props) {
53
56
 
54
57
  // determine disk status severity
55
58
  useEffect(() => {
56
- const {DiskSpace, VDiskState, FrontQueues, Replicated} = props;
59
+ const {DiskSpace, VDiskState, FrontQueues, Replicated, DonorMode} = props;
57
60
 
58
61
  // if the disk is not available, this determines its status severity regardless of other features
59
62
  if (!VDiskState) {
@@ -66,7 +69,10 @@ function Vdisk(props) {
66
69
  const FrontQueuesSeverity = Math.min(colorSeverity.Orange, getColorSeverity(FrontQueues));
67
70
 
68
71
  let newSeverity = Math.max(DiskSpaceSeverity, VDiskSpaceSeverity, FrontQueuesSeverity);
69
- if (!Replicated && newSeverity === colorSeverity.Green) {
72
+
73
+ // donors are always in the not replicated state since they are leftovers
74
+ // painting them blue is useless
75
+ if (!Replicated && !DonorMode && newSeverity === colorSeverity.Green) {
70
76
  newSeverity = colorSeverity.Blue;
71
77
  }
72
78
 
@@ -95,62 +101,62 @@ function Vdisk(props) {
95
101
  ReadThroughput,
96
102
  WriteThroughput,
97
103
  } = props;
98
- const vdiskData = [{property: 'VDisk', value: stringifyVdiskId(VDiskId)}];
99
- vdiskData.push({property: 'State', value: VDiskState ?? 'not available'});
100
- PoolName && vdiskData.push({property: 'StoragePool', value: PoolName});
104
+ const vdiskData = [{label: 'VDisk', value: stringifyVdiskId(VDiskId)}];
105
+ vdiskData.push({label: 'State', value: VDiskState ?? 'not available'});
106
+ PoolName && vdiskData.push({label: 'StoragePool', value: PoolName});
101
107
 
102
108
  SatisfactionRank &&
103
109
  SatisfactionRank.FreshRank?.Flag !== diskProgressColors[colorSeverity.Green] &&
104
110
  vdiskData.push({
105
- property: 'Fresh',
111
+ label: 'Fresh',
106
112
  value: SatisfactionRank.FreshRank.Flag,
107
113
  });
108
114
 
109
115
  SatisfactionRank &&
110
116
  SatisfactionRank.LevelRank?.Flag !== diskProgressColors[colorSeverity.Green] &&
111
117
  vdiskData.push({
112
- property: 'Level',
118
+ label: 'Level',
113
119
  value: SatisfactionRank.LevelRank.Flag,
114
120
  });
115
121
 
116
122
  SatisfactionRank &&
117
123
  SatisfactionRank.FreshRank?.RankPercent &&
118
124
  vdiskData.push({
119
- property: 'Fresh',
125
+ label: 'Fresh',
120
126
  value: SatisfactionRank.FreshRank.RankPercent,
121
127
  });
122
128
 
123
129
  SatisfactionRank &&
124
130
  SatisfactionRank.LevelRank?.RankPercent &&
125
131
  vdiskData.push({
126
- property: 'Level',
132
+ label: 'Level',
127
133
  value: SatisfactionRank.LevelRank.RankPercent,
128
134
  });
129
135
 
130
136
  DiskSpace &&
131
137
  DiskSpace !== diskProgressColors[colorSeverity.Green] &&
132
- vdiskData.push({property: 'Space', value: DiskSpace});
138
+ vdiskData.push({label: 'Space', value: DiskSpace});
133
139
 
134
140
  FrontQueues &&
135
141
  FrontQueues !== diskProgressColors[colorSeverity.Green] &&
136
- vdiskData.push({property: 'FrontQueues', value: FrontQueues});
142
+ vdiskData.push({label: 'FrontQueues', value: FrontQueues});
137
143
 
138
- !Replicated && vdiskData.push({property: 'Replicated', value: 'NO'});
144
+ !Replicated && vdiskData.push({label: 'Replicated', value: 'NO'});
139
145
 
140
- UnsyncedVDisks && vdiskData.push({property: 'UnsyncVDisks', value: UnsyncedVDisks});
146
+ UnsyncedVDisks && vdiskData.push({label: 'UnsyncVDisks', value: UnsyncedVDisks});
141
147
 
142
148
  Boolean(Number(AllocatedSize)) &&
143
149
  vdiskData.push({
144
- property: 'Allocated',
150
+ label: 'Allocated',
145
151
  value: bytesToGB(AllocatedSize),
146
152
  });
147
153
 
148
154
  Boolean(Number(ReadThroughput)) &&
149
- vdiskData.push({property: 'Read', value: bytesToSpeed(ReadThroughput)});
155
+ vdiskData.push({label: 'Read', value: bytesToSpeed(ReadThroughput)});
150
156
 
151
157
  Boolean(Number(WriteThroughput)) &&
152
158
  vdiskData.push({
153
- property: 'Write',
159
+ label: 'Write',
154
160
  value: bytesToSpeed(WriteThroughput),
155
161
  });
156
162
 
@@ -165,61 +171,54 @@ function Vdisk(props) {
165
171
  diskProgressColors[colorSeverity.Yellow],
166
172
  ];
167
173
  if (PDisk && nodes) {
168
- const pdiskData = [{property: 'PDisk', value: getPDiskId(PDisk)}];
174
+ const pdiskData = [{label: 'PDisk', value: getPDiskId(PDisk)}];
169
175
  pdiskData.push({
170
- property: 'State',
176
+ label: 'State',
171
177
  value: PDisk.State || 'not available',
172
178
  });
173
- pdiskData.push({property: 'Type', value: getPDiskType(PDisk) || 'unknown'});
174
- PDisk.NodeId && pdiskData.push({property: 'Node Id', value: PDisk.NodeId});
179
+ pdiskData.push({label: 'Type', value: getPDiskType(PDisk) || 'unknown'});
180
+ PDisk.NodeId && pdiskData.push({label: 'Node Id', value: PDisk.NodeId});
175
181
  PDisk.NodeId &&
176
182
  nodes[PDisk.NodeId] &&
177
- pdiskData.push({property: 'Host', value: nodes[PDisk.NodeId]});
178
- PDisk.Path && pdiskData.push({property: 'Path', value: PDisk.Path});
183
+ pdiskData.push({label: 'Host', value: nodes[PDisk.NodeId]});
184
+ PDisk.Path && pdiskData.push({label: 'Path', value: PDisk.Path});
179
185
  pdiskData.push({
180
- property: 'Available',
186
+ label: 'Available',
181
187
  value: `${bytesToGB(PDisk.AvailableSize)} of ${bytesToGB(PDisk.TotalSize)}`,
182
188
  });
183
189
  errorColors.includes(PDisk.Realtime) &&
184
- pdiskData.push({property: 'Realtime', value: PDisk.Realtime});
190
+ pdiskData.push({label: 'Realtime', value: PDisk.Realtime});
185
191
  errorColors.includes(PDisk.Device) &&
186
- pdiskData.push({property: 'Device', value: PDisk.Device});
192
+ pdiskData.push({label: 'Device', value: PDisk.Device});
187
193
  return pdiskData;
188
194
  }
189
195
  return null;
190
196
  };
191
197
  /* eslint-enable */
192
198
 
193
- const renderPopup = () => {
194
- const vdiskData = prepareVdiskData();
195
- const pdiskData = preparePdiskData();
196
- return (
197
- <Popup
198
- className={b('popup-wrapper')}
199
- anchorRef={anchor}
200
- open={isPopupVisible}
201
- placement={['top', 'bottom']}
202
- hasArrow
203
- >
204
- <div className={b('popup-content')}>
205
- <div className={b('popup-section-name')}>VDisk</div>
206
- {_.map(vdiskData, (row) => (
207
- <React.Fragment key={row.property}>
208
- <div className={b('property')}>{row.property}</div>
209
- <div className={b('value')}>{row.value}</div>
210
- </React.Fragment>
211
- ))}
212
- <div className={b('popup-section-name')}>PDisk</div>
213
- {_.map(pdiskData, (row) => (
214
- <React.Fragment key={row.property}>
215
- <div className={b('property')}>{row.property}</div>
216
- <div className={b('value')}>{row.value}</div>
217
- </React.Fragment>
218
- ))}
219
- </div>
220
- </Popup>
221
- );
222
- };
199
+ const renderPopup = () => (
200
+ <Popup
201
+ className={b('popup-wrapper')}
202
+ anchorRef={anchor}
203
+ open={isPopupVisible}
204
+ placement={['top', 'bottom']}
205
+ // bigger offset for easier switching to neighbour nodes
206
+ // matches the default offset for popup with arrow out of a sense of beauty
207
+ offset={[0, 12]}
208
+ >
209
+ {props.DonorMode && <Label className={b('donor-label')}>Donor</Label>}
210
+ <InfoViewer
211
+ title="VDisk"
212
+ info={prepareVdiskData()}
213
+ size="s"
214
+ />
215
+ <InfoViewer
216
+ title="PDisk"
217
+ info={preparePdiskData()}
218
+ size="s"
219
+ />
220
+ </Popup>
221
+ );
223
222
 
224
223
  const vdiskAllocatedPercent = useMemo(() => {
225
224
  const {AvailableSize, AllocatedSize, PDisk} = props;
@@ -243,13 +242,13 @@ function Vdisk(props) {
243
242
  href={
244
243
  props.NodeId
245
244
  ? createHref(
246
- routes.node,
247
- {id: props.NodeId, activeTab: STRUCTURE},
248
- {
249
- pdiskId: props.PDisk?.PDiskId,
250
- vdiskId: stringifyVdiskId(props.VDiskId),
251
- },
252
- )
245
+ routes.node,
246
+ {id: props.NodeId, activeTab: STRUCTURE},
247
+ {
248
+ pdiskId: props.PDisk?.PDiskId,
249
+ vdiskId: stringifyVdiskId(props.VDiskId),
250
+ },
251
+ )
253
252
  : undefined
254
253
  }
255
254
  />
@@ -1,35 +1,16 @@
1
1
  .vdisk-storage {
2
- display: flex;
3
- flex-grow: 1;
4
- align-items: center;
5
-
6
- max-width: 200px;
7
- margin-right: 10px;
8
-
9
- cursor: pointer;
10
-
11
- &:last-child {
12
- margin-right: 0px;
13
- }
14
2
  &__popup-wrapper {
15
- padding: 5px 10px;
16
- }
17
- &__popup-content {
18
- display: grid;
19
- justify-items: stretch;
20
- column-gap: 5px;
21
- }
22
- &__popup-section-name {
23
- grid-column: 1 / 3;
3
+ padding: 12px;
24
4
 
25
- margin: 5px 0;
5
+ .info-viewer + .info-viewer {
6
+ margin-top: 8px;
7
+ padding-top: 8px;
26
8
 
27
- font-weight: 500;
28
- text-align: center;
29
-
30
- border-bottom: 1px solid var(--yc-color-line-generic);
9
+ border-top: 1px solid var(--yc-color-line-generic);
10
+ }
31
11
  }
32
- &__property {
33
- text-align: right;
12
+
13
+ &__donor-label {
14
+ margin-bottom: 8px;
34
15
  }
35
16
  }
@@ -0,0 +1,163 @@
1
+ import {render} from '@testing-library/react'
2
+
3
+ import VDisk from '../Vdisk'
4
+
5
+ describe('VDisk state', () => {
6
+ it('Should determine severity based on the highest value among VDiskState, DiskSpace and FrontQueues', () => {
7
+ const {getAllByRole} = render(
8
+ <>
9
+ <VDisk
10
+ VDiskId={{Domain: 1}}
11
+ VDiskState="OK" // severity 1, green
12
+ DiskSpace="Yellow" // severity 3, yellow
13
+ FrontQueues="Green" // severity 1, green
14
+ />
15
+ <VDisk
16
+ VDiskId={{Domain: 2}}
17
+ VDiskState="PDiskError" // severity 5, red
18
+ DiskSpace="Yellow" // severity 3, yellow
19
+ FrontQueues="Green" // severity 1, green
20
+ />
21
+ <VDisk
22
+ VDiskId={{Domain: 3}}
23
+ VDiskState="OK" // severity 1, green
24
+ DiskSpace="Yellow" // severity 3, yellow
25
+ FrontQueues="Orange" // severity 4, orange
26
+ />
27
+ </>
28
+ );
29
+
30
+ const [disk1, disk2, disk3] = getAllByRole('meter');
31
+
32
+ expect(disk1.className).toMatch(/_yellow\b/i);
33
+ expect(disk2.className).toMatch(/_red\b/i);
34
+ expect(disk3.className).toMatch(/_orange\b/i);
35
+ });
36
+
37
+ it('Should not pick the highest severity based on FrontQueues value', () => {
38
+ const {getAllByRole} = render(
39
+ <>
40
+ <VDisk
41
+ VDiskId={{Domain: 1}}
42
+ VDiskState="OK" // severity 1, green
43
+ DiskSpace="Green" // severity 1, green
44
+ FrontQueues="Red" // severity 5, red
45
+ />
46
+ <VDisk
47
+ VDiskId={{Domain: 2}}
48
+ VDiskState="OK" // severity 1, green
49
+ DiskSpace="Red" // severity 5, red
50
+ FrontQueues="Red" // severity 5, red
51
+ />
52
+ </>
53
+ );
54
+
55
+ const [disk1, disk2] = getAllByRole('meter');
56
+
57
+ expect(disk1.className).not.toMatch(/_red\b/i);
58
+ expect(disk2.className).toMatch(/_red\b/i);
59
+ });
60
+
61
+ it('Should display as unavailable when no VDiskState is provided', () => {
62
+ const {getAllByRole} = render(
63
+ <>
64
+ <VDisk VDiskId={{Domain: 1}} />
65
+ <VDisk VDiskId={{Domain: 2}} VDiskState="OK" />
66
+ <VDisk VDiskId={{Domain: 3}} DiskSpace="Green" />
67
+ <VDisk VDiskId={{Domain: 4}} FrontQueues="Green" />
68
+ <VDisk VDiskId={{Domain: 5}} VDiskState="OK" DiskSpace="Green" />
69
+ <VDisk VDiskId={{Domain: 6}} VDiskState="OK" FrontQueues="Green" />
70
+ <VDisk VDiskId={{Domain: 7}} DiskSpace="Green" FrontQueues="Green" />
71
+ <VDisk VDiskId={{Domain: 8}} VDiskState="OK" DiskSpace="Green" FrontQueues="Green" />
72
+ </>
73
+ );
74
+
75
+ const [disk1, disk2, disk3, disk4, disk5, disk6, disk7, disk8] = getAllByRole('meter');
76
+
77
+ // unavailable disks display with the highest severity
78
+ expect(disk1.className).toMatch(/_red\b/i);
79
+ expect(disk2.className).not.toMatch(/_red\b/i);
80
+ expect(disk3.className).toMatch(/_red\b/i);
81
+ expect(disk4.className).toMatch(/_red\b/i);
82
+ expect(disk5.className).not.toMatch(/_red\b/i);
83
+ expect(disk6.className).not.toMatch(/_red\b/i);
84
+ expect(disk7.className).toMatch(/_red\b/i);
85
+ expect(disk8.className).not.toMatch(/_red\b/i);
86
+ });
87
+
88
+ it('Should display replicating VDisks in OK state with a distinct color', () => {
89
+ const {getAllByRole} = render(
90
+ <>
91
+ <VDisk
92
+ VDiskId={{Domain: 1}}
93
+ VDiskState="OK" // severity 1, green
94
+ Replicated={false}
95
+ />
96
+ <VDisk
97
+ VDiskId={{Domain: 2}}
98
+ VDiskState="OK" // severity 1, green
99
+ Replicated={true}
100
+ />
101
+ </>
102
+ );
103
+
104
+ const [disk1, disk2] = getAllByRole('meter');
105
+
106
+ expect(disk1.className).toMatch(/_blue\b/i);
107
+ expect(disk2.className).not.toMatch(/_blue\b/i);
108
+ });
109
+
110
+ it('Should display replicating VDisks in a not-OK state with a regular color', () => {
111
+ const {getAllByRole} = render(
112
+ <>
113
+ <VDisk
114
+ VDiskId={{Domain: 1}}
115
+ VDiskState="Initial" // severity 3, yellow
116
+ Replicated={false}
117
+ />
118
+ <VDisk
119
+ VDiskId={{Domain: 2}}
120
+ VDiskState="PDiskError" // severity 5, red
121
+ Replicated={false}
122
+ />
123
+ </>
124
+ );
125
+
126
+ const [disk1, disk2] = getAllByRole('meter');
127
+
128
+ expect(disk1.className).toMatch(/_yellow\b/i);
129
+ expect(disk2.className).toMatch(/_red\b/i);
130
+ });
131
+
132
+ it('Should always display donor VDisks with a regular color', () => {
133
+ const {getAllByRole} = render(
134
+ <>
135
+ <VDisk
136
+ VDiskId={{Domain: 1}}
137
+ VDiskState="OK" // severity 1, green
138
+ Replicated={false} // donors are always in the not replicated state since they are leftovers
139
+ DonorMode
140
+ />
141
+ <VDisk
142
+ VDiskId={{Domain: 2}}
143
+ VDiskState="Initial" // severity 3, yellow
144
+ Replicated={false}
145
+ DonorMode
146
+ />
147
+ <VDisk
148
+ VDiskId={{Domain: 3}}
149
+ VDiskState="PDiskError" // severity 5, red
150
+ Replicated={false}
151
+ DonorMode
152
+ />
153
+ </>
154
+ );
155
+
156
+ const [disk1, disk2, disk3] = getAllByRole('meter');
157
+
158
+ expect(disk1.className).not.toMatch(/_blue\b/i);
159
+ expect(disk1.className).toMatch(/_green\b/i);
160
+ expect(disk2.className).toMatch(/_yellow\b/i);
161
+ expect(disk3.className).toMatch(/_red\b/i);
162
+ });
163
+ });
@@ -1 +1,6 @@
1
+ import type {TVDiskStateInfo, TVSlotId} from '../../../types/api/storage';
2
+
1
3
  export * from './constants';
4
+
5
+ export const isFullDonorData = (donor: TVDiskStateInfo | TVSlotId): donor is TVDiskStateInfo =>
6
+ 'VDiskId' in donor;
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import cn from 'bem-cn-lite';
4
4
  import './SchemaInfoViewer.scss';
5
5
 
6
- import {formatCPU, formatBytes, formatNumber, formatBps} from '../../../../utils';
6
+ import {formatCPU, formatBytes, formatNumber, formatBps, formatDateTime} from '../../../../utils';
7
7
 
8
8
  import {InfoViewer, createInfoFormatter} from '../../../../components/InfoViewer';
9
9
 
@@ -38,8 +38,8 @@ const formatTableStatsItem = createInfoFormatter({
38
38
  values: {
39
39
  DataSize: formatBytes,
40
40
  IndexSize: formatBytes,
41
- LastAccessTime: (value) => value > 0 ? new Date(Number(value)).toUTCString() : 'N/A',
42
- LastUpdateTime: (value) => value > 0 ? new Date(Number(value)).toUTCString() : 'N/A',
41
+ LastAccessTime: formatDateTime,
42
+ LastUpdateTime: formatDateTime,
43
43
  },
44
44
  defaultValueFormatter: formatNumber,
45
45
  });
@@ -3,3 +3,11 @@
3
3
  // expect(element).toHaveTextContent(/react/i)
4
4
  // learn more: https://github.com/testing-library/jest-dom
5
5
  import '@testing-library/jest-dom';
6
+
7
+ import {configure as configureUiKit} from '@yandex-cloud/uikit';
8
+ import {configure as configureYdbUiComponents} from 'ydb-ui-components';
9
+ import {i18n, Lang} from '../src/utils/i18n';
10
+
11
+ i18n.setLang(Lang.En);
12
+ configureYdbUiComponents({lang: Lang.En});
13
+ configureUiKit({lang: Lang.En});
@@ -91,27 +91,19 @@ export interface TTableDescription {
91
91
  export interface TPartitionConfig {
92
92
  /** uint64 */
93
93
  FollowerCount?: string;
94
- /**
95
- * uint32
96
- * @deprecated use FollowerGroups
97
- */
98
- CrossDataCenterFollowerCount?: string;
94
+ /** @deprecated use FollowerGroups */
95
+ CrossDataCenterFollowerCount?: number;
99
96
  /** 0 or 1 items */
100
97
  FollowerGroups?: TFollowerGroup[];
101
98
  }
102
99
 
103
100
  export interface TFollowerGroup {
104
- /** uint32 */
105
- FollowerCount?: string;
101
+ FollowerCount?: number;
106
102
  AllowLeaderPromotion?: boolean;
107
103
  AllowClientRead?: boolean;
108
- /** uint32[] */
109
- AllowedNodeIDs?: string[];
110
- /**
111
- * uint32[]
112
- * @deprecated use AllowedDataCenters
113
- */
114
- AllowedDataCenterNumIDs?: string[];
104
+ AllowedNodeIDs?: number[];
105
+ /** @deprecated use AllowedDataCenters */
106
+ AllowedDataCenterNumIDs?: number[];
115
107
  RequireAllDataCenters?: boolean;
116
108
  LocalNodeOnly?: boolean;
117
109
  RequireDifferentNodes?: boolean;
@@ -52,3 +52,121 @@ export interface TPDiskStateInfo {
52
52
  Overall?: EFlag;
53
53
  SerialNumber?: string;
54
54
  }
55
+
56
+ export enum EVDiskState {
57
+ Initial = 'Initial',
58
+ LocalRecoveryError = 'LocalRecoveryError',
59
+ SyncGuidRecovery = 'SyncGuidRecovery',
60
+ SyncGuidRecoveryError = 'SyncGuidRecoveryError',
61
+ OK = 'OK',
62
+ PDiskError = 'PDiskError',
63
+ }
64
+
65
+ interface TRank {
66
+ /**
67
+ * Rank in percents; 0-100% is good; >100% is bad.
68
+ * Formula for rank calculation is the following:
69
+ * Rank = actual_value / max_allowed_value * 100
70
+ */
71
+ RankPercent?: number;
72
+
73
+ /**
74
+ * Flag is the Rank transformed to something simple
75
+ * to understand: Green, Yellow or Red
76
+ */
77
+ Flag?: EFlag;
78
+ }
79
+
80
+ interface TVDiskSatisfactionRank {
81
+ FreshRank?: TRank;
82
+ LevelRank?: TRank;
83
+ }
84
+
85
+ interface TVDiskID {
86
+ GroupID?: number;
87
+ GroupGeneration?: number;
88
+ Ring?: number;
89
+ Domain?: number;
90
+ VDisk?: number;
91
+ }
92
+
93
+ export interface TVSlotId {
94
+ NodeId?: number;
95
+ PDiskId?: number;
96
+ VSlotId?: number;
97
+ }
98
+
99
+ export interface TVDiskStateInfo {
100
+ VDiskId?: TVDiskID;
101
+ /** uint64 */
102
+ CreateTime?: string;
103
+ /** uint64 */
104
+ ChangeTime?: string;
105
+ PDisk?: TPDiskStateInfo;
106
+ VDiskSlotId?: number;
107
+ /** uint64 */
108
+ Guid?: string;
109
+ /** uint64 */
110
+ Kind?: string;
111
+ NodeId?: number;
112
+ Count?: number;
113
+
114
+ Overall?: EFlag;
115
+
116
+ /** Current state of VDisk */
117
+ VDiskState?: EVDiskState;
118
+ /** Disk space flags */
119
+ DiskSpace?: EFlag;
120
+ /** Compaction satisfaction rank */
121
+ SatisfactionRank?: TVDiskSatisfactionRank;
122
+ /** Is VDisk replicated? (i.e. contains all blobs it must have) */
123
+ Replicated?: boolean;
124
+ /** Does this VDisk has any yet unreplicated phantom-like blobs? */
125
+ UnreplicatedPhantoms?: boolean;
126
+ /** The same for the non-phantom-like blobs. */
127
+ UnreplicatedNonPhantoms?: boolean;
128
+ /**
129
+ * uint64
130
+ * How many unsynced VDisks from current BlobStorage group we see
131
+ */
132
+ UnsyncedVDisks?: string;
133
+ /**
134
+ * uint64
135
+ * How much this VDisk have allocated on corresponding PDisk
136
+ */
137
+ AllocatedSize?: string;
138
+ /**
139
+ * uint64
140
+ * How much space is available for VDisk corresponding to PDisk's hard space limits
141
+ */
142
+ AvailableSize?: string;
143
+ /** Does this disk has some unreadable but not yet restored blobs? */
144
+ HasUnreadableBlobs?: boolean;
145
+ /** fixed64 */
146
+ IncarnationGuid?: string;
147
+ DonorMode?: boolean;
148
+ /**
149
+ * fixed64
150
+ * VDisk actor instance guid
151
+ */
152
+ InstanceGuid?: string;
153
+ // in reality it is `Donors: TVDiskStateInfo[] | TVSlotId[]`, but this way it is more error-proof
154
+ Donors?: Array<TVDiskStateInfo | TVSlotId>;
155
+
156
+ /** VDisk (Skeleton) Front Queue Status */
157
+ FrontQueues?: EFlag;
158
+
159
+ /** VDisk storage pool label */
160
+ StoragePoolName?: string;
161
+
162
+ /**
163
+ * uint64
164
+ * Read bytes per second from PDisk for TEvVGet blobs only
165
+ */
166
+ ReadThroughput?: string;
167
+ /**
168
+ * uint64
169
+ * Write bytes per second to PDisk for TEvVPut blobs and replication bytes only
170
+ */
171
+ WriteThroughput?: string;
172
+ }
@@ -0,0 +1 @@
1
+ export type RequiredField<Src, Fields extends keyof Src> = Src & Required<Pick<Src, Fields>>;