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.
- package/CHANGELOG.md +20 -0
- package/dist/assets/icons/shield.svg +3 -0
- package/dist/components/NodesViewer/NodesViewer.js +1 -1
- package/dist/containers/App/App.scss +5 -1
- package/dist/containers/Nodes/Nodes.js +1 -1
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
- package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
- package/dist/containers/Storage/Storage.js +29 -48
- package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
- package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
- package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
- package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
- package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +25 -11
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
- package/dist/containers/Tenant/Tenant.tsx +12 -9
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/store/reducers/olapStats.js +13 -0
- package/dist/store/reducers/schema.js +42 -0
- package/dist/store/reducers/storage.js +26 -16
- package/dist/store/reducers/tenant.js +3 -1
- package/dist/styles/mixins.scss +1 -1
- package/dist/types/api/storage.ts +35 -10
- package/dist/types/store/storage.ts +1 -0
- package/dist/utils/hooks/useAutofetcher.ts +9 -3
- package/package.json +1 -1
@@ -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
|
-
|
58
|
-
|
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 (
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
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 {
|
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
|
-
|
75
|
-
|
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
|
-
|
79
|
-
|
81
|
+
useAutofetcher(
|
82
|
+
(isBackground) => {
|
83
|
+
if (!isBackground) {
|
84
|
+
dispatch(resetLoadingState());
|
85
|
+
}
|
80
86
|
|
81
|
-
|
82
|
-
dispatch(
|
83
|
-
|
84
|
-
|
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 (
|
120
|
-
|
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
|
|
@@ -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) =>
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
/>
|
@@ -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
|
-
|
339
|
-
(entities) => {
|
340
|
-
const items = {};
|
350
|
+
export const getUsageFilterOptions = createSelector(getVisibleEntitiesList, (entities) => {
|
351
|
+
const items = {};
|
341
352
|
|
342
|
-
|
343
|
-
|
353
|
+
entities.forEach((entity) => {
|
354
|
+
const usage = getUsage(entity, 5);
|
344
355
|
|
345
|
-
|
346
|
-
|
347
|
-
|
356
|
+
if (!Object.hasOwn(items, usage)) {
|
357
|
+
items[usage] = 0;
|
358
|
+
}
|
348
359
|
|
349
|
-
|
350
|
-
|
360
|
+
items[usage] += 1;
|
361
|
+
});
|
351
362
|
|
352
|
-
|
353
|
-
|
354
|
-
|
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
|
|
package/dist/styles/mixins.scss
CHANGED
@@ -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(--
|
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
|
-
|
176
|
-
GroupID?: string;
|
175
|
+
GroupID?: number;
|
177
176
|
ErasureSpecies?: string;
|
178
177
|
VDisks?: TVDiskStateInfo[];
|
179
178
|
/** uint64 */
|
180
179
|
ChangeTime?: string;
|
181
|
-
|
182
|
-
|
183
|
-
/** uint32 */
|
184
|
-
GroupGeneration?: string;
|
180
|
+
NodeId?: number;
|
181
|
+
GroupGeneration?: number;
|
185
182
|
Overall?: EFlag;
|
186
183
|
Latency?: EFlag;
|
187
|
-
|
188
|
-
|
189
|
-
|
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;
|
@@ -2,7 +2,11 @@ import {DependencyList, useEffect, useRef} from 'react';
|
|
2
2
|
|
3
3
|
import {AutoFetcher} from '../autofetcher';
|
4
4
|
|
5
|
-
export const useAutofetcher = (
|
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(
|
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 () => {
|