ydb-embedded-ui 1.11.1 → 1.12.2

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,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.12.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.1...v1.12.2) (2022-08-29)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **Storage:** bright red usage starting from 90% ([69b7ed2](https://github.com/ydb-platform/ydb-embedded-ui/commit/69b7ed248151f518ffc5fabbdccf5ea9bbcd9405))
9
+ * **Storage:** display usage without gte sign ([39630a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/39630a2a06b574d53d0ef74c1b3e0dc96b9666a8))
10
+
11
+ ## [1.12.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.0...v1.12.1) (2022-08-26)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **Storage:** properly display usage for 0 storage ([aee67f9](https://github.com/ydb-platform/ydb-embedded-ui/commit/aee67f9314341c995e2c9468f5eedc48fa0a3d35))
17
+
18
+ ## [1.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.1...v1.12.0) (2022-08-26)
19
+
20
+
21
+ ### Features
22
+
23
+ * **Storage:** show usage column ([73aed5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/73aed5f9ed60b6d2bd77fd315ae514ee7443c489))
24
+ * **Storage:** vividly show degraded disks count ([7315a9c](https://github.com/ydb-platform/ydb-embedded-ui/commit/7315a9cfd98002a7fab85d721712aa82c6dbb552))
25
+
3
26
  ## [1.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.11.0...v1.11.1) (2022-08-26)
4
27
 
5
28
 
@@ -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,37 @@ 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
+ // without a limit the usage can be evaluated as 0,
130
+ // but the absence of a value is more clear
131
+ return row.Limit ? (
132
+ <Label
133
+ theme={getUsageSeverity(usage)}
134
+ className={b('usage-label', {overload: usage >= 90})}
135
+ >
136
+ {usage}%
137
+ </Label>
138
+ ) : '-';
139
+ },
140
+ // without a limit exclude usage from sort to display at the bottom
141
+ sortAccessor: (row) => row.Limit ? getUsage(row) : null,
142
+ align: DataTable.LEFT,
143
+ },
113
144
  {
114
145
  name: TableColumnsIds.GroupID,
115
146
  header: tableColumnsNames[TableColumnsIds.GroupID],
@@ -137,18 +168,6 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
137
168
  },
138
169
  align: DataTable.RIGHT,
139
170
  },
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
171
  {
153
172
  name: TableColumnsIds.UsedSpaceFlag,
154
173
  header: tableColumnsNames[TableColumnsIds.UsedSpaceFlag],
@@ -186,13 +205,6 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
186
205
  },
187
206
  align: DataTable.RIGHT,
188
207
  },
189
- {
190
- name: TableColumnsIds.Missing,
191
- header: tableColumnsNames[TableColumnsIds.Missing],
192
- width: 100,
193
- align: DataTable.CENTER,
194
- defaultOrder: DataTable.DESCENDING,
195
- },
196
208
  {
197
209
  name: TableColumnsIds.VDisks,
198
210
  className: b('vdisks-column'),
@@ -1,6 +1,51 @@
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
+ // if limit is 0, display 0
48
+ const usage = Math.round((data.Used * 100) / data.Limit) || 0;
49
+
50
+ return Math.floor(usage / step) * step;
51
+ };
@@ -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.2",
4
4
  "files": [
5
5
  "dist"
6
6
  ],