ydb-embedded-ui 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/assets/icons/shield.svg +3 -0
  3. package/dist/components/NodesViewer/NodesViewer.js +1 -1
  4. package/dist/containers/App/App.scss +5 -1
  5. package/dist/containers/Nodes/Nodes.js +1 -1
  6. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
  7. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
  8. package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
  9. package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
  10. package/dist/containers/Storage/Storage.js +29 -48
  11. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
  12. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
  13. package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
  14. package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
  15. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
  16. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
  17. package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
  18. package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
  19. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
  20. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +25 -11
  21. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
  22. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
  23. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
  24. package/dist/containers/Tenant/Tenant.tsx +12 -9
  25. package/dist/containers/Tenants/Tenants.js +1 -1
  26. package/dist/store/reducers/olapStats.js +13 -0
  27. package/dist/store/reducers/schema.js +42 -0
  28. package/dist/store/reducers/storage.js +26 -16
  29. package/dist/store/reducers/tenant.js +3 -1
  30. package/dist/styles/mixins.scss +1 -1
  31. package/dist/types/api/storage.ts +35 -10
  32. package/dist/types/store/storage.ts +1 -0
  33. package/dist/utils/hooks/useAutofetcher.ts +9 -3
  34. package/package.json +1 -1
@@ -5,6 +5,13 @@
5
5
 
6
6
  height: 100%;
7
7
 
8
+ &__loader {
9
+ display: flex;
10
+ flex-grow: 1;
11
+ justify-content: center;
12
+ align-items: center;
13
+ }
14
+
8
15
  &__header-wrapper {
9
16
  padding: 13px 20px 16px;
10
17
 
@@ -5,7 +5,7 @@ import {Link} from 'react-router-dom';
5
5
  import {useDispatch, useSelector} from 'react-redux';
6
6
  import {useLocation} from 'react-router';
7
7
 
8
- import {Switch, Tabs} from '@gravity-ui/uikit';
8
+ import {Loader, Switch, Tabs} from '@gravity-ui/uikit';
9
9
 
10
10
  //@ts-ignore
11
11
  import TopQueries from './TopQueries/TopQueries';
@@ -53,9 +53,9 @@ function Diagnostics(props: DiagnosticsProps) {
53
53
  currentSchema: currentItem = {},
54
54
  autorefresh,
55
55
  } = useSelector((state: any) => state.schema);
56
- const {
57
- diagnosticsTab = GeneralPagesIds.overview,
58
- } = useSelector((state: any) => state.tenant);
56
+ const {diagnosticsTab = GeneralPagesIds.overview, wasLoaded} = useSelector(
57
+ (state: any) => state.tenant,
58
+ );
59
59
 
60
60
  const location = useLocation();
61
61
 
@@ -79,14 +79,17 @@ function Diagnostics(props: DiagnosticsProps) {
79
79
  dispatch(setDiagnosticsTab(tab));
80
80
  };
81
81
  const activeTab = useMemo(() => {
82
- if (pages.find((el) => el.id === diagnosticsTab)) {
83
- return diagnosticsTab;
84
- } else {
85
- const newPage = pages[0].id;
86
- forwardToDiagnosticTab(newPage);
87
- return newPage;
82
+ if (wasLoaded) {
83
+ if (pages.find((el) => el.id === diagnosticsTab)) {
84
+ return diagnosticsTab;
85
+ } else {
86
+ const newPage = pages[0].id;
87
+ forwardToDiagnosticTab(newPage);
88
+ return newPage;
89
+ }
88
90
  }
89
- }, [pages, diagnosticsTab]);
91
+ return undefined;
92
+ }, [pages, diagnosticsTab, wasLoaded]);
90
93
 
91
94
  const onAutorefreshToggle = (value: boolean) => {
92
95
  if (value) {
@@ -185,6 +188,17 @@ function Diagnostics(props: DiagnosticsProps) {
185
188
  );
186
189
  };
187
190
 
191
+ // Loader prevents incorrect loading of tabs
192
+ // After tabs are initially loaded it is no longer needed
193
+ // Thus there is no also "loading" check as in other parts of the project
194
+ if (!wasLoaded) {
195
+ return (
196
+ <div className={b('loader')}>
197
+ <Loader size="l" />
198
+ </div>
199
+ );
200
+ }
201
+
188
202
  return (
189
203
  <div className={b()}>
190
204
  {renderTabs()}
@@ -15,9 +15,12 @@ import {
15
15
  import {EPathType} from '../../../../types/api/schema';
16
16
  import {isColumnEntityType, isTableType} from '../../utils/schema';
17
17
  //@ts-ignore
18
- import {getSchema} from '../../../../store/reducers/schema';
18
+ import {getSchema, resetLoadingState} from '../../../../store/reducers/schema';
19
19
  //@ts-ignore
20
- import {getOlapStats} from '../../../../store/reducers/olapStats';
20
+ import {
21
+ getOlapStats,
22
+ resetLoadingState as resetOlapLoadingState,
23
+ } from '../../../../store/reducers/olapStats';
21
24
  import {useAutofetcher} from '../../../../utils/hooks';
22
25
 
23
26
  import './Overview.scss';
@@ -64,24 +67,36 @@ function Overview(props: OverviewProps) {
64
67
 
65
68
  const {
66
69
  currentSchema: currentItem = {},
67
- loading,
70
+ loading: schemaLoading,
68
71
  wasLoaded,
69
72
  autorefresh,
70
73
  currentSchemaPath,
71
74
  } = useSelector((state: any) => state.schema);
72
75
 
73
- const {
74
- data: { result: olapStats } = { result: undefined },
75
- } = useSelector((state: any) => state.olapStats);
76
+ const {data: {result: olapStats} = {result: undefined}, loading: olapStatsLoading} =
77
+ useSelector((state: any) => state.olapStats);
78
+
79
+ const loading = schemaLoading || olapStatsLoading;
76
80
 
77
- useAutofetcher(() => {
78
- const schemaPath = currentSchemaPath || tenantName;
79
- dispatch(getSchema({path: schemaPath}));
81
+ useAutofetcher(
82
+ (isBackground) => {
83
+ if (!isBackground) {
84
+ dispatch(resetLoadingState());
85
+ }
80
86
 
81
- if (isTableType(type) && isColumnEntityType(type)) {
82
- dispatch(getOlapStats({path: schemaPath}));
83
- }
84
- }, [currentSchemaPath, dispatch, tenantName, type], autorefresh);
87
+ const schemaPath = currentSchemaPath || tenantName;
88
+ dispatch(getSchema({path: schemaPath}));
89
+
90
+ if (isTableType(type) && isColumnEntityType(type)) {
91
+ if (!isBackground) {
92
+ dispatch(resetOlapLoadingState());
93
+ }
94
+ dispatch(getOlapStats({path: schemaPath}));
95
+ }
96
+ },
97
+ [currentSchemaPath, dispatch, tenantName, type],
98
+ autorefresh,
99
+ );
85
100
 
86
101
  const tableSchema =
87
102
  currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
@@ -116,17 +131,17 @@ function Overview(props: OverviewProps) {
116
131
  [EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
117
132
  };
118
133
 
119
- return (type && pathTypeToComponent[type]?.()) || (
120
- <SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
134
+ return (
135
+ (type && pathTypeToComponent[type]?.()) || (
136
+ <SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
137
+ )
121
138
  );
122
- }
139
+ };
123
140
 
124
141
  return loading && !wasLoaded ? (
125
142
  renderLoader()
126
143
  ) : (
127
- <div className={props.className}>
128
- {renderContent()}
129
- </div>
144
+ <div className={props.className}>{renderContent()}</div>
130
145
  );
131
146
  }
132
147
 
@@ -83,7 +83,7 @@ function SaveQuery({savedQueries, onSaveQuery, saveButtonDisabled}) {
83
83
  <TextInput
84
84
  id="queryName"
85
85
  placeholder="Enter query name"
86
- text={queryName}
86
+ value={queryName}
87
87
  onUpdate={onQueryNameChange}
88
88
  hasClear
89
89
  autoFocus
@@ -3,7 +3,7 @@ import {useDispatch} from 'react-redux';
3
3
 
4
4
  import {NavigationTree} from 'ydb-ui-components';
5
5
 
6
- import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
6
+ import {setCurrentSchemaPath, getSchema, preloadSchema} from '../../../../store/reducers/schema';
7
7
  import {getDescribe} from '../../../../store/reducers/describe';
8
8
  import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
9
9
  import type {EPathType} from '../../../../types/api/schema';
@@ -19,28 +19,35 @@ interface SchemaTreeProps {
19
19
  }
20
20
 
21
21
  export function SchemaTree(props: SchemaTreeProps) {
22
- const {
23
- rootPath,
24
- rootName,
25
- rootType,
26
- currentPath,
27
- } = props;
22
+ const {rootPath, rootName, rootType, currentPath} = props;
28
23
 
29
24
  const dispatch = useDispatch();
30
25
 
31
- const fetchPath = (path: string) => window.api.getSchema(
32
- {path},
33
- {concurrentId: `NavigationTree.getSchema|${path}`},
34
- )
35
- .then(({PathDescription: {Children = []} = {}}) => {
36
- return Children.map(({Name = '', PathType, PathSubType}) => ({
37
- name: Name,
38
- type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
39
- // FIXME: should only be explicitly set to true for tables with indexes
40
- // at the moment of writing there is no property to determine this, fix later
41
- expandable: true,
42
- }));
43
- });
26
+ const fetchPath = (path: string) =>
27
+ window.api
28
+ .getSchema({path}, {concurrentId: `NavigationTree.getSchema|${path}`})
29
+ .then((data) => {
30
+ const {PathDescription: {Children = []} = {}} = data;
31
+
32
+ dispatch(preloadSchema(path, data));
33
+
34
+ return Children.map((childData) => {
35
+ const {Name = '', PathType, PathSubType} = childData;
36
+
37
+ // not full data, but it contains PathType, which ensures seamless switch between nodes
38
+ dispatch(
39
+ preloadSchema(`${path}/${Name}`, {PathDescription: {Self: childData}}),
40
+ );
41
+
42
+ return {
43
+ name: Name,
44
+ type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
45
+ // FIXME: should only be explicitly set to true for tables with indexes
46
+ // at the moment of writing there is no property to determine this, fix later
47
+ expandable: true,
48
+ };
49
+ });
50
+ });
44
51
 
45
52
  const handleActivePathUpdate = (activePath: string) => {
46
53
  dispatch(setCurrentSchemaPath(activePath));
@@ -16,7 +16,7 @@ import SplitPane from '../../components/SplitPane';
16
16
  //@ts-ignore
17
17
  import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
18
18
  //@ts-ignore
19
- import {disableAutorefresh, getSchema} from '../../store/reducers/schema';
19
+ import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
20
20
  //@ts-ignore
21
21
  import {getSchemaAcl} from '../../store/reducers/schemaAcl';
22
22
  import {
@@ -57,6 +57,13 @@ function Tenant(props: TenantProps) {
57
57
  (state: any) => state.schema,
58
58
  );
59
59
 
60
+ const {PathType: preloadedPathType, PathSubType: preloadedPathSubType} = useSelector(
61
+ (state: any) => state.schema.data[currentSchemaPath]?.PathDescription?.Self || {},
62
+ );
63
+
64
+ const {PathType: currentPathType, PathSubType: currentPathSubType} =
65
+ (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
66
+
60
67
  const {data: {status: tenantStatus = 200} = {}} = useSelector((state: any) => state.tenant);
61
68
  const {error: {status: schemaStatus = 200} = {}} = useSelector((state: any) => state.schema);
62
69
 
@@ -73,6 +80,7 @@ function Tenant(props: TenantProps) {
73
80
 
74
81
  useEffect(() => {
75
82
  const schemaPath = currentSchemaPath || tenantName;
83
+ dispatch(resetLoadingState());
76
84
  dispatch(getSchema({path: tenantName}));
77
85
  dispatch(getSchema({path: schemaPath}));
78
86
  dispatch(getSchemaAcl({path: schemaPath}));
@@ -105,11 +113,6 @@ function Tenant(props: TenantProps) {
105
113
  };
106
114
  }, [tenantName, dispatch]);
107
115
 
108
- const {
109
- PathType: currentPathType,
110
- PathSubType: currentPathSubType,
111
- } = (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
112
-
113
116
  const onCollapseSummaryHandler = () => {
114
117
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerCollapse);
115
118
  };
@@ -144,15 +147,15 @@ function Tenant(props: TenantProps) {
144
147
  onSplitStartDragAdditional={onSplitStartDragAdditional}
145
148
  >
146
149
  <ObjectSummary
147
- type={currentPathType}
148
- subType={currentPathSubType}
150
+ type={preloadedPathType || currentPathType}
151
+ subType={preloadedPathSubType || currentPathSubType}
149
152
  onCollapseSummary={onCollapseSummaryHandler}
150
153
  onExpandSummary={onExpandSummaryHandler}
151
154
  isCollapsed={summaryVisibilityState.collapsed}
152
155
  additionalTenantInfo={props.additionalTenantInfo}
153
156
  />
154
157
  <ObjectGeneral
155
- type={currentPathType}
158
+ type={preloadedPathType || currentPathType}
156
159
  additionalTenantInfo={props.additionalTenantInfo}
157
160
  additionalNodesInfo={props.additionalNodesInfo}
158
161
  />
@@ -95,7 +95,7 @@ class Tenants extends React.Component {
95
95
  <TextInput
96
96
  className={b('search')}
97
97
  placeholder="Database name"
98
- text={searchQuery}
98
+ value={searchQuery}
99
99
  onUpdate={handleSearchQuery}
100
100
  hasClear
101
101
  autoFocus
@@ -6,6 +6,7 @@ import {createRequestActionTypes, createApiRequest} from '../utils';
6
6
 
7
7
  const FETCH_OLAP_STATS = createRequestActionTypes('query', 'SEND_OLAP_STATS_QUERY');
8
8
  const SET_OLAP_STATS_OPTIONS = createRequestActionTypes('query', 'SET_OLAP_STATS_OPTIONS');
9
+ const RESET_LOADING_STATE = 'olapStats/RESET_LOADING_STATE';
9
10
 
10
11
  const initialState = {
11
12
  loading: false,
@@ -48,6 +49,12 @@ const olapStats = (state = initialState, action) => {
48
49
  ...state,
49
50
  ...action.data,
50
51
  };
52
+ case RESET_LOADING_STATE: {
53
+ return {
54
+ ...state,
55
+ wasLoaded: initialState.wasLoaded,
56
+ };
57
+ }
51
58
  default:
52
59
  return state;
53
60
  }
@@ -73,4 +80,10 @@ export function setOlapStatsOptions(options) {
73
80
  };
74
81
  }
75
82
 
83
+ export function resetLoadingState() {
84
+ return {
85
+ type: RESET_LOADING_STATE,
86
+ };
87
+ }
88
+
76
89
  export default olapStats;
@@ -2,10 +2,12 @@ import {createRequestActionTypes, createApiRequest} from '../utils';
2
2
  import '../../services/api';
3
3
 
4
4
  const FETCH_SCHEMA = createRequestActionTypes('schema', 'FETCH_SCHEMA');
5
+ const PRELOAD_SCHEMA = 'schema/PRELOAD_SCHEMA';
5
6
  const SET_SCHEMA = 'schema/SET_SCHEMA';
6
7
  const SET_SHOW_PREVIEW = 'schema/SET_SHOW_PREVIEW';
7
8
  const ENABLE_AUTOREFRESH = 'schema/ENABLE_AUTOREFRESH';
8
9
  const DISABLE_AUTOREFRESH = 'schema/DISABLE_AUTOREFRESH';
10
+ const RESET_LOADING_STATE = 'schema/RESET_LOADING_STATE';
9
11
 
10
12
  export const initialState = {
11
13
  loading: true,
@@ -42,16 +44,34 @@ const schema = function z(state = initialState, action) {
42
44
  };
43
45
  }
44
46
  case FETCH_SCHEMA.FAILURE: {
47
+ if (action.error.isCancelled) {
48
+ return state;
49
+ }
50
+
45
51
  return {
46
52
  ...state,
47
53
  error: action.error,
48
54
  loading: false,
49
55
  };
50
56
  }
57
+ case PRELOAD_SCHEMA: {
58
+ if (state.data[action.path]) {
59
+ return state;
60
+ }
61
+
62
+ return {
63
+ ...state,
64
+ data: {
65
+ ...state.data,
66
+ [action.path]: action.data,
67
+ },
68
+ };
69
+ }
51
70
  case SET_SCHEMA: {
52
71
  return {
53
72
  ...state,
54
73
  currentSchemaPath: action.data,
74
+ wasLoaded: false,
55
75
  };
56
76
  }
57
77
  case ENABLE_AUTOREFRESH: {
@@ -72,6 +92,12 @@ const schema = function z(state = initialState, action) {
72
92
  showPreview: action.data,
73
93
  };
74
94
  }
95
+ case RESET_LOADING_STATE: {
96
+ return {
97
+ ...state,
98
+ wasLoaded: initialState.wasLoaded,
99
+ };
100
+ }
75
101
  default:
76
102
  return state;
77
103
  }
@@ -106,4 +132,20 @@ export function setShowPreview(value) {
106
132
  data: value,
107
133
  };
108
134
  }
135
+
136
+ // only stores the passed data if the path doesn't exist yet
137
+ export function preloadSchema(path, data) {
138
+ return {
139
+ type: PRELOAD_SCHEMA,
140
+ path,
141
+ data,
142
+ };
143
+ }
144
+
145
+ export function resetLoadingState() {
146
+ return {
147
+ type: RESET_LOADING_STATE,
148
+ };
149
+ }
150
+
109
151
  export default schema;
@@ -4,6 +4,7 @@ import _ from 'lodash';
4
4
  import {createSelector} from 'reselect';
5
5
  import {calcUptime} from '../../utils';
6
6
  import {getUsage} from '../../utils/storage';
7
+ import {getPDiskType} from '../../utils/pdisk';
7
8
 
8
9
  export const VisibleEntities = {
9
10
  All: 'All',
@@ -56,10 +57,17 @@ const storage = function z(state = initialState, action) {
56
57
  };
57
58
  }
58
59
  case FETCH_STORAGE.FAILURE: {
60
+ if (action.error.isCancelled) {
61
+ return {
62
+ ...state,
63
+ };
64
+ }
65
+
59
66
  return {
60
67
  ...state,
61
68
  error: action.error,
62
69
  loading: false,
70
+ wasLoaded: true,
63
71
  };
64
72
  }
65
73
  case SET_INITIAL: {
@@ -229,6 +237,10 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
229
237
  },
230
238
  0,
231
239
  );
240
+ const mediaType = group.VDisks?.reduce((type, vdisk) => {
241
+ const currentType = getPDiskType(vdisk.PDisk || {});
242
+ return currentType && (currentType === type || type === '') ? currentType : 'Mixed';
243
+ }, '');
232
244
  return [
233
245
  ...acc,
234
246
  {
@@ -240,6 +252,7 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
240
252
  Limit: limitSizeBytes,
241
253
  Missing: missing,
242
254
  UsedSpaceFlag,
255
+ Type: mediaType || null,
243
256
  },
244
257
  ];
245
258
  },
@@ -334,25 +347,22 @@ export const getFilteredEntities = createSelector(
334
347
  },
335
348
  );
336
349
 
337
- export const getUsageFilterOptions = createSelector(
338
- getVisibleEntitiesList,
339
- (entities) => {
340
- const items = {};
350
+ export const getUsageFilterOptions = createSelector(getVisibleEntitiesList, (entities) => {
351
+ const items = {};
341
352
 
342
- entities.forEach((entity) => {
343
- const usage = getUsage(entity, 5);
353
+ entities.forEach((entity) => {
354
+ const usage = getUsage(entity, 5);
344
355
 
345
- if (!Object.hasOwn(items, usage)) {
346
- items[usage] = 0;
347
- }
356
+ if (!Object.hasOwn(items, usage)) {
357
+ items[usage] = 0;
358
+ }
348
359
 
349
- items[usage] += 1;
350
- });
360
+ items[usage] += 1;
361
+ });
351
362
 
352
- return Object.entries(items)
353
- .map(([threshold, count]) => ({threshold, count}))
354
- .sort((a, b) => b.threshold - a.threshold);
355
- },
356
- );
363
+ return Object.entries(items)
364
+ .map(([threshold, count]) => ({threshold, count}))
365
+ .sort((a, b) => b.threshold - a.threshold);
366
+ });
357
367
 
358
368
  export default storage;
@@ -6,7 +6,7 @@ const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
6
6
  const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
7
7
  const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
8
8
 
9
- const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
9
+ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, action) => {
10
10
  switch (action.type) {
11
11
  case FETCH_TENANT.REQUEST: {
12
12
  return {
@@ -23,6 +23,7 @@ const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
23
23
  tenant,
24
24
  tenantNodes,
25
25
  loading: false,
26
+ wasLoaded: true,
26
27
  error: undefined,
27
28
  };
28
29
  }
@@ -32,6 +33,7 @@ const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
32
33
  ...state,
33
34
  data: action.error,
34
35
  loading: false,
36
+ wasLoaded: true,
35
37
  };
36
38
  }
37
39
 
@@ -150,7 +150,7 @@
150
150
  background-color: var(--yc-color-base-background);
151
151
  }
152
152
  .data-table__row:hover .data-table__td:nth-child(#{$nth}) {
153
- background-color: var(--yc-color-base-float-hover) !important;
153
+ background-color: var(--ydb-data-table-color-hover) !important;
154
154
  }
155
155
  }
156
156
 
@@ -172,28 +172,53 @@ export interface TVDiskStateInfo {
172
172
  }
173
173
 
174
174
  export interface TBSGroupStateInfo {
175
- /** uint32 */
176
- GroupID?: string;
175
+ GroupID?: number;
177
176
  ErasureSpecies?: string;
178
177
  VDisks?: TVDiskStateInfo[];
179
178
  /** uint64 */
180
179
  ChangeTime?: string;
181
- /** uint32 */
182
- NodeId?: string; // filled during merge
183
- /** uint32 */
184
- GroupGeneration?: string;
180
+ NodeId?: number;
181
+ GroupGeneration?: number;
185
182
  Overall?: EFlag;
186
183
  Latency?: EFlag;
187
- /** uint32 */
188
- Count?: string; // filled during group count
189
- StoragePoolName?: string; // from BS_CONTROLLER
184
+ Count?: number;
185
+ StoragePoolName?: string;
186
+ /** uint64 */
187
+ AllocatedSize?: string;
188
+ /** uint64 */
189
+ AvailableSize?: string;
190
+ /** uint64 */
191
+ ReadThroughput?: string;
192
+ /** uint64 */
193
+ WriteThroughput?: string;
194
+ Encryption?: boolean;
195
+ }
196
+
197
+ interface THiveStorageGroupStats {
198
+ GroupID?: number;
199
+ /** uint64 */
200
+ AcquiredUnits?: string;
201
+ AcquiredIOPS?: number;
202
+ /** uint64 */
203
+ AcquiredThroughput?: string;
204
+ /** uint64 */
205
+ AcquiredSize?: string;
206
+ MaximumIOPS?: number;
207
+ /** uint64 */
208
+ MaximumThroughput?: string;
209
+ /** uint64 */
210
+ MaximumSize?: string;
211
+ /** uint64 */
212
+ AllocatedSize?: string;
213
+ /** uint64 */
214
+ AvailableSize?: string;
190
215
  }
191
216
 
192
217
  export interface TStoragePoolInfo {
193
218
  Overall?: EFlag;
194
219
  Name?: string;
195
220
  Kind?: string;
196
- Groups?: TBSGroupStateInfo[];
221
+ Groups?: (TBSGroupStateInfo & THiveStorageGroupStats)[];
197
222
  /** uint64 */
198
223
  AcquiredUnits?: string;
199
224
  AcquiredIOPS?: number;
@@ -8,4 +8,5 @@ export interface IStoragePoolGroup extends TBSGroupStateInfo {
8
8
  Limit: number;
9
9
  Missing: number;
10
10
  UsedSpaceFlag: number;
11
+ Type: string | null;
11
12
  }
@@ -2,7 +2,11 @@ import {DependencyList, useEffect, useRef} from 'react';
2
2
 
3
3
  import {AutoFetcher} from '../autofetcher';
4
4
 
5
- export const useAutofetcher = (fetchData: VoidFunction, deps: DependencyList, enabled = true) => {
5
+ export const useAutofetcher = (
6
+ fetchData: (isBackground: boolean) => void,
7
+ deps: DependencyList,
8
+ enabled = true,
9
+ ) => {
6
10
  const ref = useRef<AutoFetcher | null>(null);
7
11
 
8
12
  if (ref.current === null) {
@@ -12,14 +16,16 @@ export const useAutofetcher = (fetchData: VoidFunction, deps: DependencyList, en
12
16
  const autofetcher = ref.current;
13
17
 
14
18
  // initial fetch
15
- useEffect(fetchData, deps); // eslint-disable-line react-hooks/exhaustive-deps
19
+ useEffect(() => {
20
+ fetchData(false);
21
+ }, deps); // eslint-disable-line react-hooks/exhaustive-deps
16
22
 
17
23
  useEffect(() => {
18
24
  autofetcher.stop();
19
25
 
20
26
  if (enabled) {
21
27
  autofetcher.start();
22
- autofetcher.fetch(fetchData);
28
+ autofetcher.fetch(() => fetchData(true));
23
29
  }
24
30
 
25
31
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],