ydb-embedded-ui 2.2.1 → 2.4.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 +37 -0
- package/dist/assets/icons/shield.svg +3 -0
- package/dist/components/Errors/403/AccessDenied.tsx +19 -0
- package/dist/components/Errors/403/index.ts +1 -0
- package/dist/components/Errors/i18n/en.json +4 -0
- package/dist/components/Errors/i18n/index.ts +11 -0
- package/dist/components/Errors/i18n/ru.json +4 -0
- package/dist/components/NodesViewer/NodesViewer.js +1 -1
- package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
- package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
- package/dist/components/Search/index.ts +1 -0
- package/dist/containers/App/App.scss +5 -1
- package/dist/containers/Nodes/Nodes.js +6 -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 +39 -50
- 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/TabletsFilters/TabletsFilters.js +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +29 -11
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
- package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
- package/dist/containers/Tenant/Preview/Preview.scss +6 -0
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- 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 +14 -16
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/store/reducers/describe.ts +71 -0
- package/dist/store/reducers/healthcheckInfo.ts +123 -0
- package/dist/store/reducers/olapStats.js +13 -0
- package/dist/store/reducers/schema.js +43 -1
- package/dist/store/reducers/storage.js +27 -17
- package/dist/store/reducers/tenant.js +3 -1
- package/dist/store/utils.ts +21 -13
- package/dist/styles/mixins.scss +1 -1
- package/dist/types/api/consumers.ts +3 -0
- package/dist/types/api/healthcheck.ts +1 -1
- package/dist/types/api/storage.ts +35 -10
- package/dist/types/store/healthcheck.ts +5 -1
- package/dist/types/store/storage.ts +1 -0
- package/dist/utils/hooks/useAutofetcher.ts +9 -3
- package/package.json +1 -1
- package/dist/containers/Storage/StorageFilter/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
- package/dist/store/reducers/describe.js +0 -45
- package/dist/store/reducers/healthcheckInfo.js +0 -45
|
@@ -4,8 +4,7 @@ import cn from 'bem-cn-lite';
|
|
|
4
4
|
import {useLocation} from 'react-router';
|
|
5
5
|
import qs from 'qs';
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import {Illustration} from '../../components/Illustration';
|
|
7
|
+
import {AccessDenied} from '../../components/Errors/403';
|
|
9
8
|
|
|
10
9
|
import {setHeader} from '../../store/reducers/header';
|
|
11
10
|
import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
|
|
@@ -16,7 +15,7 @@ import SplitPane from '../../components/SplitPane';
|
|
|
16
15
|
//@ts-ignore
|
|
17
16
|
import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
|
|
18
17
|
//@ts-ignore
|
|
19
|
-
import {disableAutorefresh, getSchema} from '../../store/reducers/schema';
|
|
18
|
+
import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
|
|
20
19
|
//@ts-ignore
|
|
21
20
|
import {getSchemaAcl} from '../../store/reducers/schemaAcl';
|
|
22
21
|
import {
|
|
@@ -57,6 +56,13 @@ function Tenant(props: TenantProps) {
|
|
|
57
56
|
(state: any) => state.schema,
|
|
58
57
|
);
|
|
59
58
|
|
|
59
|
+
const {PathType: preloadedPathType, PathSubType: preloadedPathSubType} = useSelector(
|
|
60
|
+
(state: any) => state.schema.data[currentSchemaPath]?.PathDescription?.Self || {},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const {PathType: currentPathType, PathSubType: currentPathSubType} =
|
|
64
|
+
(currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
|
|
65
|
+
|
|
60
66
|
const {data: {status: tenantStatus = 200} = {}} = useSelector((state: any) => state.tenant);
|
|
61
67
|
const {error: {status: schemaStatus = 200} = {}} = useSelector((state: any) => state.schema);
|
|
62
68
|
|
|
@@ -73,6 +79,7 @@ function Tenant(props: TenantProps) {
|
|
|
73
79
|
|
|
74
80
|
useEffect(() => {
|
|
75
81
|
const schemaPath = currentSchemaPath || tenantName;
|
|
82
|
+
dispatch(resetLoadingState());
|
|
76
83
|
dispatch(getSchema({path: tenantName}));
|
|
77
84
|
dispatch(getSchema({path: schemaPath}));
|
|
78
85
|
dispatch(getSchemaAcl({path: schemaPath}));
|
|
@@ -105,11 +112,6 @@ function Tenant(props: TenantProps) {
|
|
|
105
112
|
};
|
|
106
113
|
}, [tenantName, dispatch]);
|
|
107
114
|
|
|
108
|
-
const {
|
|
109
|
-
PathType: currentPathType,
|
|
110
|
-
PathSubType: currentPathSubType,
|
|
111
|
-
} = (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
|
|
112
|
-
|
|
113
115
|
const onCollapseSummaryHandler = () => {
|
|
114
116
|
dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerCollapse);
|
|
115
117
|
};
|
|
@@ -126,11 +128,7 @@ function Tenant(props: TenantProps) {
|
|
|
126
128
|
return (
|
|
127
129
|
<div className={b()}>
|
|
128
130
|
{showBlockingError ? (
|
|
129
|
-
<
|
|
130
|
-
image={<Illustration name="403" />}
|
|
131
|
-
title="Access denied"
|
|
132
|
-
description="You don’t have the necessary roles to view this page."
|
|
133
|
-
/>
|
|
131
|
+
<AccessDenied />
|
|
134
132
|
) : (
|
|
135
133
|
<>
|
|
136
134
|
<ObjectGeneralTabs />
|
|
@@ -144,15 +142,15 @@ function Tenant(props: TenantProps) {
|
|
|
144
142
|
onSplitStartDragAdditional={onSplitStartDragAdditional}
|
|
145
143
|
>
|
|
146
144
|
<ObjectSummary
|
|
147
|
-
type={currentPathType}
|
|
148
|
-
subType={currentPathSubType}
|
|
145
|
+
type={preloadedPathType || currentPathType}
|
|
146
|
+
subType={preloadedPathSubType || currentPathSubType}
|
|
149
147
|
onCollapseSummary={onCollapseSummaryHandler}
|
|
150
148
|
onExpandSummary={onExpandSummaryHandler}
|
|
151
149
|
isCollapsed={summaryVisibilityState.collapsed}
|
|
152
150
|
additionalTenantInfo={props.additionalTenantInfo}
|
|
153
151
|
/>
|
|
154
152
|
<ObjectGeneral
|
|
155
|
-
type={currentPathType}
|
|
153
|
+
type={preloadedPathType || currentPathType}
|
|
156
154
|
additionalTenantInfo={props.additionalTenantInfo}
|
|
157
155
|
additionalNodesInfo={props.additionalNodesInfo}
|
|
158
156
|
/>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {createSelector} from 'reselect';
|
|
2
|
+
|
|
3
|
+
import '../../services/api';
|
|
4
|
+
import {TEvDescribeSchemeResult} from '../../types/api/schema';
|
|
5
|
+
import {IConsumer} from '../../types/api/consumers';
|
|
6
|
+
import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
|
|
7
|
+
|
|
8
|
+
const FETCH_DESCRIBE = createRequestActionTypes('describe', 'FETCH_DESCRIBE');
|
|
9
|
+
|
|
10
|
+
const describe = (
|
|
11
|
+
state = {loading: false, wasLoaded: false, data: {}},
|
|
12
|
+
action: ApiRequestAction<typeof FETCH_DESCRIBE, TEvDescribeSchemeResult, unknown>,
|
|
13
|
+
) => {
|
|
14
|
+
switch (action.type) {
|
|
15
|
+
case FETCH_DESCRIBE.REQUEST: {
|
|
16
|
+
return {
|
|
17
|
+
...state,
|
|
18
|
+
loading: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
case FETCH_DESCRIBE.SUCCESS: {
|
|
22
|
+
let newData;
|
|
23
|
+
|
|
24
|
+
if (action.data.Path) {
|
|
25
|
+
newData = JSON.parse(JSON.stringify(state.data));
|
|
26
|
+
newData[action.data.Path] = action.data;
|
|
27
|
+
} else {
|
|
28
|
+
newData = state.data;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
data: newData,
|
|
34
|
+
currentDescribe: action.data,
|
|
35
|
+
loading: false,
|
|
36
|
+
wasLoaded: true,
|
|
37
|
+
error: undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
case FETCH_DESCRIBE.FAILURE: {
|
|
41
|
+
return {
|
|
42
|
+
...state,
|
|
43
|
+
error: action.error,
|
|
44
|
+
loading: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
default:
|
|
48
|
+
return state;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Consumers selectors
|
|
53
|
+
const selectConsumersNames = (state: any, path: string): string[] | undefined =>
|
|
54
|
+
state.describe.data[path]?.PathDescription?.PersQueueGroup?.PQTabletConfig?.ReadRules;
|
|
55
|
+
|
|
56
|
+
export const selectConsumers = createSelector(selectConsumersNames, (names = []): IConsumer[] => {
|
|
57
|
+
const consumers = names.map((name) => {
|
|
58
|
+
return {name};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return consumers;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export function getDescribe({path}: {path: string}) {
|
|
65
|
+
return createApiRequest({
|
|
66
|
+
request: window.api.getDescribe({path}),
|
|
67
|
+
actions: FETCH_DESCRIBE,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default describe;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import _flow from 'lodash/fp/flow';
|
|
2
|
+
import _sortBy from 'lodash/fp/sortBy';
|
|
3
|
+
import _uniqBy from 'lodash/fp/uniqBy';
|
|
4
|
+
import _omit from 'lodash/omit';
|
|
5
|
+
import {createSelector} from 'reselect';
|
|
6
|
+
|
|
7
|
+
import {IIssuesTree} from '../../types/store/healthcheck';
|
|
8
|
+
import {HealthCheckAPIResponse, IssueLog, StatusFlag} from '../../types/api/healthcheck';
|
|
9
|
+
|
|
10
|
+
import '../../services/api';
|
|
11
|
+
import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
|
|
12
|
+
|
|
13
|
+
const FETCH_HEALTHCHECK = createRequestActionTypes('cluster', 'FETCH_HEALTHCHECK');
|
|
14
|
+
|
|
15
|
+
const initialState = {loading: false, wasLoaded: false};
|
|
16
|
+
|
|
17
|
+
const healthcheckInfo = function (
|
|
18
|
+
state = initialState,
|
|
19
|
+
action: ApiRequestAction<typeof FETCH_HEALTHCHECK, HealthCheckAPIResponse, unknown>,
|
|
20
|
+
) {
|
|
21
|
+
switch (action.type) {
|
|
22
|
+
case FETCH_HEALTHCHECK.REQUEST: {
|
|
23
|
+
return {
|
|
24
|
+
...state,
|
|
25
|
+
loading: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
case FETCH_HEALTHCHECK.SUCCESS: {
|
|
29
|
+
const {data} = action;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
data,
|
|
34
|
+
wasLoaded: true,
|
|
35
|
+
loading: false,
|
|
36
|
+
error: undefined,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
case FETCH_HEALTHCHECK.FAILURE: {
|
|
40
|
+
return {
|
|
41
|
+
...state,
|
|
42
|
+
error: action.error,
|
|
43
|
+
loading: false,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
default:
|
|
47
|
+
return state;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const mapStatusToPriority: Partial<Record<StatusFlag, number>> = {
|
|
52
|
+
RED: 0,
|
|
53
|
+
ORANGE: 1,
|
|
54
|
+
YELLOW: 2,
|
|
55
|
+
BLUE: 3,
|
|
56
|
+
GREEN: 4,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const getReasonsForIssue = ({issue, data}: {issue: IssueLog; data: IssueLog[]}) => {
|
|
60
|
+
return data.filter((item) => issue.reason && issue.reason.indexOf(item.id) !== -1);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const getRoots = (data: IssueLog[]) => {
|
|
64
|
+
let roots = data.filter((item) => {
|
|
65
|
+
return !data.find((issue) => issue.reason && issue.reason.indexOf(item.id) !== -1);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
roots = _flow([
|
|
69
|
+
_uniqBy((item: IssueLog) => item.id),
|
|
70
|
+
_sortBy(({status}: {status: StatusFlag}) => mapStatusToPriority[status]),
|
|
71
|
+
])(roots);
|
|
72
|
+
|
|
73
|
+
return roots;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const getInvertedConsequencesTree = ({
|
|
77
|
+
data,
|
|
78
|
+
roots,
|
|
79
|
+
}: {
|
|
80
|
+
data: IssueLog[];
|
|
81
|
+
roots?: IssueLog[];
|
|
82
|
+
}): IIssuesTree[] => {
|
|
83
|
+
return roots
|
|
84
|
+
? roots.map((issue) => {
|
|
85
|
+
const reasonsItems = getInvertedConsequencesTree({
|
|
86
|
+
roots: getReasonsForIssue({issue, data}),
|
|
87
|
+
data,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
...issue,
|
|
92
|
+
reasonsItems,
|
|
93
|
+
};
|
|
94
|
+
})
|
|
95
|
+
: [];
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const getIssuesLog = (state: any): IssueLog[] | undefined => state.healthcheckInfo.data?.issue_log;
|
|
99
|
+
|
|
100
|
+
export const selectIssuesTreesRoots = createSelector(getIssuesLog, (issues = []) =>
|
|
101
|
+
getRoots(issues),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export const selectIssuesTrees = createSelector(
|
|
105
|
+
[getIssuesLog, selectIssuesTreesRoots],
|
|
106
|
+
(data = [], roots = []) => {
|
|
107
|
+
return getInvertedConsequencesTree({data, roots});
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
export const selectIssuesTreeById = createSelector(
|
|
112
|
+
[selectIssuesTrees, (_: any, id: string | undefined) => id],
|
|
113
|
+
(issuesTrees = [], id) => issuesTrees.find((issuesTree: IIssuesTree) => issuesTree.id === id),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
export function getHealthcheckInfo(database: string) {
|
|
117
|
+
return createApiRequest({
|
|
118
|
+
request: window.api.getHealthcheckInfo(database),
|
|
119
|
+
actions: FETCH_HEALTHCHECK,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default healthcheckInfo;
|
|
@@ -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,
|
|
@@ -16,7 +18,7 @@ export const initialState = {
|
|
|
16
18
|
showPreview: false,
|
|
17
19
|
};
|
|
18
20
|
|
|
19
|
-
const schema =
|
|
21
|
+
const schema = (state = initialState, action) => {
|
|
20
22
|
switch (action.type) {
|
|
21
23
|
case FETCH_SCHEMA.REQUEST: {
|
|
22
24
|
return {
|
|
@@ -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',
|
|
@@ -38,7 +39,7 @@ const initialState = {
|
|
|
38
39
|
type: StorageTypes.groups,
|
|
39
40
|
};
|
|
40
41
|
|
|
41
|
-
const storage =
|
|
42
|
+
const storage = (state = initialState, action) => {
|
|
42
43
|
switch (action.type) {
|
|
43
44
|
case FETCH_STORAGE.REQUEST: {
|
|
44
45
|
return {
|
|
@@ -56,10 +57,15 @@ const storage = function z(state = initialState, action) {
|
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
case FETCH_STORAGE.FAILURE: {
|
|
60
|
+
if (action.error?.isCancelled) {
|
|
61
|
+
return state;
|
|
62
|
+
}
|
|
63
|
+
|
|
59
64
|
return {
|
|
60
65
|
...state,
|
|
61
66
|
error: action.error,
|
|
62
67
|
loading: false,
|
|
68
|
+
wasLoaded: true,
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
71
|
case SET_INITIAL: {
|
|
@@ -229,6 +235,12 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
|
|
|
229
235
|
},
|
|
230
236
|
0,
|
|
231
237
|
);
|
|
238
|
+
const mediaType = group.VDisks?.reduce((type, vdisk) => {
|
|
239
|
+
const currentType = getPDiskType(vdisk.PDisk || {});
|
|
240
|
+
return currentType && (currentType === type || type === '')
|
|
241
|
+
? currentType
|
|
242
|
+
: '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/store/utils.ts
CHANGED
|
@@ -7,7 +7,10 @@ import {SET_UNAUTHENTICATED} from './reducers/authentication';
|
|
|
7
7
|
|
|
8
8
|
export const nop = (result: any) => result;
|
|
9
9
|
|
|
10
|
-
export function createRequestActionTypes<Prefix extends string, Type extends string>(
|
|
10
|
+
export function createRequestActionTypes<Prefix extends string, Type extends string>(
|
|
11
|
+
prefix: Prefix,
|
|
12
|
+
type: Type,
|
|
13
|
+
) {
|
|
11
14
|
return {
|
|
12
15
|
REQUEST: `${prefix}/${type}_REQUEST`,
|
|
13
16
|
SUCCESS: `${prefix}/${type}_SUCCESS`,
|
|
@@ -15,19 +18,24 @@ export function createRequestActionTypes<Prefix extends string, Type extends str
|
|
|
15
18
|
} as const;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
const isAxiosResponse = (response: any): response is AxiosResponse =>
|
|
21
|
+
const isAxiosResponse = (response: any): response is AxiosResponse =>
|
|
22
|
+
response && 'status' in response;
|
|
19
23
|
|
|
20
24
|
type CreateApiRequestParams<Actions, Response, HandledResponse> = {
|
|
21
25
|
actions: Actions;
|
|
22
26
|
request: Promise<Response>;
|
|
23
|
-
dataHandler
|
|
27
|
+
dataHandler?: (data: Response, getState?: () => any) => HandledResponse;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
export function createApiRequest<
|
|
27
31
|
Actions extends ReturnType<typeof createRequestActionTypes>,
|
|
28
32
|
Response,
|
|
29
33
|
HandledResponse,
|
|
30
|
-
>({
|
|
34
|
+
>({
|
|
35
|
+
actions,
|
|
36
|
+
request,
|
|
37
|
+
dataHandler = nop,
|
|
38
|
+
}: CreateApiRequestParams<Actions, Response, HandledResponse>) {
|
|
31
39
|
const doRequest = async function (dispatch: Dispatch, getState: () => any) {
|
|
32
40
|
dispatch({
|
|
33
41
|
type: actions.REQUEST,
|
|
@@ -73,16 +81,16 @@ export function createApiRequest<
|
|
|
73
81
|
export type ApiRequestAction<
|
|
74
82
|
Actions extends ReturnType<typeof createRequestActionTypes>,
|
|
75
83
|
SuccessResponse = unknown,
|
|
76
|
-
ErrorResponse = unknown
|
|
84
|
+
ErrorResponse = unknown,
|
|
77
85
|
> =
|
|
78
86
|
| {
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
type: Actions['REQUEST'];
|
|
88
|
+
}
|
|
81
89
|
| {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
type: Actions['SUCCESS'];
|
|
91
|
+
data: SuccessResponse;
|
|
92
|
+
}
|
|
85
93
|
| {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
type: Actions['FAILURE'];
|
|
95
|
+
error: ErrorResponse;
|
|
96
|
+
};
|
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;
|