ydb-embedded-ui 2.2.1 → 2.3.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.
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
  ],