ydb-embedded-ui 1.11.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  ],