ydb-embedded-ui 1.11.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.1...v1.12.0) (2022-08-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * **Storage:** show usage column ([73aed5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/73aed5f9ed60b6d2bd77fd315ae514ee7443c489))
9
+ * **Storage:** vividly show degraded disks count ([7315a9c](https://github.com/ydb-platform/ydb-embedded-ui/commit/7315a9cfd98002a7fab85d721712aa82c6dbb552))
10
+
3
11
  ## [1.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.0...v1.11.1) (2022-08-26)
4
12
 
5
13
 
@@ -42,6 +42,12 @@
42
42
  vertical-align: top;
43
43
  text-overflow: ellipsis;
44
44
  }
45
+ &__usage-label {
46
+ &_overload {
47
+ color: var(--yc-color-text-light-primary);
48
+ background-color: var(--yc-color-base-danger-heavy);
49
+ }
50
+ }
45
51
  &__group-id {
46
52
  font-weight: 500;
47
53
  }
@@ -1,7 +1,7 @@
1
1
  import _ from 'lodash';
2
2
  import cn from 'bem-cn-lite';
3
3
  import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
4
- import {Popover, PopoverBehavior} from '@yandex-cloud/uikit';
4
+ import {Label, Popover, PopoverBehavior} from '@yandex-cloud/uikit';
5
5
 
6
6
  import {Stack} from '../../../components/Stack/Stack';
7
7
  //@ts-ignore
@@ -16,7 +16,7 @@ import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
16
16
  import {stringifyVdiskId} from '../../../utils';
17
17
 
18
18
  import Vdisk from '../Vdisk/Vdisk';
19
- import {isFullDonorData} from '../utils';
19
+ import {isFullDonorData, getDegradedSeverity, getUsageSeverity, getUsage} from '../utils';
20
20
 
21
21
  import './StorageGroups.scss';
22
22
 
@@ -49,11 +49,11 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
49
49
  Used: 'Used',
50
50
  Limit: 'Limit',
51
51
  UsedSpaceFlag: 'Space',
52
- UsedPercents: 'Used percents',
52
+ UsedPercents: 'Usage',
53
53
  Read: 'Read',
54
54
  Write: 'Write',
55
55
  VDisks: 'VDisks',
56
- Missing: 'Missing',
56
+ Missing: 'Degraded',
57
57
  };
58
58
 
59
59
  const b = cn('global-storage-groups');
@@ -62,8 +62,8 @@ function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder
62
62
  switch (visibleEntities) {
63
63
  case VisibleEntities.All: {
64
64
  return {
65
- columnId: TableColumnsIds.GroupID,
66
- order: DataTable.ASCENDING,
65
+ columnId: TableColumnsIds.Missing,
66
+ order: DataTable.DESCENDING,
67
67
  };
68
68
  }
69
69
  case VisibleEntities.Missing: {
@@ -110,6 +110,34 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
110
110
  },
111
111
  align: DataTable.LEFT,
112
112
  },
113
+ {
114
+ name: TableColumnsIds.Missing,
115
+ header: tableColumnsNames[TableColumnsIds.Missing],
116
+ width: 100,
117
+ render: ({value, row}) => value ? (
118
+ <Label theme={getDegradedSeverity(row)}>Degraded: {value}</Label>
119
+ ) : '-',
120
+ align: DataTable.LEFT,
121
+ defaultOrder: DataTable.DESCENDING,
122
+ },
123
+ {
124
+ name: TableColumnsIds.UsedPercents,
125
+ header: tableColumnsNames[TableColumnsIds.UsedPercents],
126
+ width: 100,
127
+ render: ({row}) => {
128
+ const usage = getUsage(row, 5);
129
+ return (
130
+ <Label
131
+ theme={getUsageSeverity(usage)}
132
+ className={b('usage-label', {overload: usage >= 100})}
133
+ >
134
+ ≥ {usage}%
135
+ </Label>
136
+ );
137
+ },
138
+ sortAccessor: getUsage,
139
+ align: DataTable.LEFT,
140
+ },
113
141
  {
114
142
  name: TableColumnsIds.GroupID,
115
143
  header: tableColumnsNames[TableColumnsIds.GroupID],
@@ -137,18 +165,6 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
137
165
  },
138
166
  align: DataTable.RIGHT,
139
167
  },
140
- // {
141
- // name: tableColumnsIds.UsedPercents,
142
- // header: tableColumnsNames[tableColumnsIds.UsedPercents],
143
- // width: '100px',
144
- // render: ({row}) => {
145
- // return (
146
- // Math.round((row[tableColumnsIds.Used] * 100) / row[tableColumnsIds.Limit]) +
147
- // '%'
148
- // );
149
- // },
150
- // align: DataTable.RIGHT,
151
- // },
152
168
  {
153
169
  name: TableColumnsIds.UsedSpaceFlag,
154
170
  header: tableColumnsNames[TableColumnsIds.UsedSpaceFlag],
@@ -186,13 +202,6 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
186
202
  },
187
203
  align: DataTable.RIGHT,
188
204
  },
189
- {
190
- name: TableColumnsIds.Missing,
191
- header: tableColumnsNames[TableColumnsIds.Missing],
192
- width: 100,
193
- align: DataTable.CENTER,
194
- defaultOrder: DataTable.DESCENDING,
195
- },
196
205
  {
197
206
  name: TableColumnsIds.VDisks,
198
207
  className: b('vdisks-column'),
@@ -1,6 +1,50 @@
1
1
  import type {TVDiskStateInfo, TVSlotId} from '../../../types/api/storage';
2
+ import type {IStoragePoolGroup} from '../../../types/store/storage';
2
3
 
3
4
  export * from './constants';
4
5
 
5
6
  export const isFullDonorData = (donor: TVDiskStateInfo | TVSlotId): donor is TVDiskStateInfo =>
6
7
  'VDiskId' in donor;
8
+
9
+ const generateEvaluator = (warn: number, crit: number) =>
10
+ (value: number) => {
11
+ if (0 <= value && value < warn) {
12
+ return 'success';
13
+ }
14
+
15
+ if (warn <= value && value < crit) {
16
+ return 'warning';
17
+ }
18
+
19
+ if (crit <= value) {
20
+ return 'danger';
21
+ }
22
+
23
+ return undefined;
24
+ };
25
+
26
+ const defaultDegradationEvaluator = generateEvaluator(1, 2);
27
+
28
+ const degradationEvaluators = {
29
+ 'block-4-2': generateEvaluator(1, 2),
30
+ 'mirror-3-dc': generateEvaluator(1, 3),
31
+ };
32
+
33
+ const canEvaluateErasureSpecies = (value?: string): value is keyof typeof degradationEvaluators =>
34
+ value !== undefined && value in degradationEvaluators;
35
+
36
+ export const getDegradedSeverity = (group: IStoragePoolGroup) => {
37
+ const evaluate = canEvaluateErasureSpecies(group.ErasureSpecies) ?
38
+ degradationEvaluators[group.ErasureSpecies] :
39
+ defaultDegradationEvaluator;
40
+
41
+ return evaluate(group.Missing);
42
+ };
43
+
44
+ export const getUsageSeverity = generateEvaluator(80, 85);
45
+
46
+ export const getUsage = (data: IStoragePoolGroup, step = 1) => {
47
+ const usage = Math.round((data.Used * 100) / data.Limit);
48
+
49
+ return Math.floor(usage / step) * step;
50
+ };
@@ -4,6 +4,15 @@ interface Window {
4
4
  params: {path: string},
5
5
  axiosOptions?: {concurrentId?: string},
6
6
  ) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
7
+ getStorageInfo: (
8
+ params: {
9
+ tenant: string,
10
+ filter: string,
11
+ nodeId: string,
12
+ type: 'Groups' | 'Nodes',
13
+ },
14
+ axiosOptions?: {concurrentId?: string},
15
+ ) => Promise<import('../types/api/storage').TStorageInfo>;
7
16
  [method: string]: Function;
8
17
  };
9
18
  }
@@ -170,3 +170,49 @@ export interface TVDiskStateInfo {
170
170
  */
171
171
  WriteThroughput?: string;
172
172
  }
173
+
174
+ export interface TBSGroupStateInfo {
175
+ /** uint32 */
176
+ GroupID?: string;
177
+ ErasureSpecies?: string;
178
+ VDisks?: TVDiskStateInfo[];
179
+ /** uint64 */
180
+ ChangeTime?: string;
181
+ /** uint32 */
182
+ NodeId?: string; // filled during merge
183
+ /** uint32 */
184
+ GroupGeneration?: string;
185
+ Overall?: EFlag;
186
+ Latency?: EFlag;
187
+ /** uint32 */
188
+ Count?: string; // filled during group count
189
+ StoragePoolName?: string; // from BS_CONTROLLER
190
+ }
191
+
192
+ export interface TStoragePoolInfo {
193
+ Overall?: EFlag;
194
+ Name?: string;
195
+ Kind?: string;
196
+ Groups?: TBSGroupStateInfo[];
197
+ /** uint64 */
198
+ AcquiredUnits?: string;
199
+ AcquiredIOPS?: number;
200
+ /** uint64 */
201
+ AcquiredThroughput?: string;
202
+ /** uint64 */
203
+ AcquiredSize?: string;
204
+ MaximumIOPS?: number;
205
+ /** uint64 */
206
+ MaximumThroughput?: string;
207
+ /** uint64 */
208
+ MaximumSize?: string;
209
+ }
210
+
211
+ export interface TStorageInfo {
212
+ Overall?: EFlag;
213
+ StoragePools?: TStoragePoolInfo[];
214
+ /** uint64 */
215
+ TotalGroups?: string;
216
+ /** uint64 */
217
+ FoundGroups?: string;
218
+ }
@@ -0,0 +1,11 @@
1
+ import type {TBSGroupStateInfo} from '../api/storage';
2
+
3
+ export interface IStoragePoolGroup extends TBSGroupStateInfo {
4
+ Read: number;
5
+ Write: number;
6
+ PoolName?: string;
7
+ Used: number;
8
+ Limit: number;
9
+ Missing: number;
10
+ UsedSpaceFlag: number;
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],