ydb-embedded-ui 2.4.4 → 2.6.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 +42 -0
- package/dist/components/InfoViewer/InfoViewer.scss +3 -3
- package/dist/components/InfoViewer/formatters/schema.ts +2 -1
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +23 -22
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +8 -13
- package/dist/components/InfoViewer/schemaInfo/TableIndexInfo.tsx +2 -12
- package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +3 -16
- package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +8 -13
- package/dist/components/InfoViewer/utils.ts +6 -6
- package/dist/components/Loader/Loader.scss +6 -3
- package/dist/components/Loader/Loader.tsx +7 -5
- package/dist/components/Loader/index.ts +1 -0
- package/dist/components/UptimeFIlter/UptimeFilter.tsx +21 -0
- package/dist/components/UptimeFIlter/index.ts +1 -0
- package/dist/containers/Node/Node.scss +1 -0
- package/dist/containers/Node/Node.tsx +3 -8
- package/dist/containers/Node/NodeStructure/NodeStructure.scss +0 -6
- package/dist/containers/Node/NodeStructure/NodeStructure.tsx +1 -1
- package/dist/containers/Nodes/Nodes.js +22 -10
- package/dist/{components → containers}/NodesViewer/NodesViewer.js +49 -62
- package/dist/{components → containers}/NodesViewer/NodesViewer.scss +0 -0
- package/dist/containers/Storage/Pdisk/Pdisk.scss +1 -1
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +3 -9
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +1 -1
- package/dist/containers/Storage/Storage.js +46 -11
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +39 -32
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +2 -2
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +35 -17
- package/dist/containers/Storage/StorageNodes/i18n/en.json +6 -4
- package/dist/containers/Storage/StorageNodes/i18n/ru.json +6 -4
- package/dist/containers/Storage/UsageFilter/UsageFilter.scss +10 -5
- package/dist/containers/Tenant/Acl/Acl.js +1 -7
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +22 -14
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +52 -10
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +42 -15
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +0 -7
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +19 -15
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +1 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +13 -5
- package/dist/containers/Tenant/Diagnostics/Network/Network.js +17 -4
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +50 -16
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +16 -2
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +21 -13
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +1 -5
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +4 -4
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -4
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +23 -28
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
- package/dist/containers/Tenant/TenantPages.tsx +1 -1
- package/dist/containers/Tenant/utils/schema.ts +84 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +9 -20
- package/dist/services/api.d.ts +17 -11
- package/dist/store/reducers/clusterNodes.js +29 -10
- package/dist/store/reducers/describe.ts +56 -14
- package/dist/store/reducers/healthcheckInfo.ts +23 -8
- package/dist/store/reducers/network.js +22 -1
- package/dist/store/reducers/nodes.js +37 -3
- package/dist/store/reducers/schema.ts +229 -0
- package/dist/store/reducers/storage.js +59 -5
- package/dist/types/api/enums.ts +10 -0
- package/dist/types/api/nodes.ts +96 -0
- package/dist/types/api/pdisk.ts +48 -0
- package/dist/types/api/schema.ts +148 -9
- package/dist/types/api/storage.ts +3 -173
- package/dist/types/api/tablet.ts +97 -0
- package/dist/types/api/vdisk.ts +120 -0
- package/dist/types/store/describe.ts +8 -2
- package/dist/types/store/healthcheck.ts +12 -0
- package/dist/types/store/schema.ts +52 -0
- package/dist/utils/index.js +6 -2
- package/dist/utils/nodes.ts +9 -0
- package/dist/utils/pdisk.ts +1 -1
- package/dist/utils/storage.ts +1 -1
- package/package.json +1 -1
- package/dist/store/reducers/schema.js +0 -148
@@ -1,5 +1,5 @@
|
|
1
|
-
import {ReactNode, useMemo} from 'react';
|
2
|
-
import {useDispatch, useSelector} from 'react-redux';
|
1
|
+
import {ReactNode, useCallback, useMemo} from 'react';
|
2
|
+
import {shallowEqual, useDispatch, useSelector} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
5
|
import {Loader} from '@gravity-ui/uikit';
|
@@ -13,15 +13,24 @@ import {
|
|
13
13
|
} from '../../../../components/InfoViewer/schemaInfo';
|
14
14
|
|
15
15
|
import {EPathType, TColumnTableDescription} from '../../../../types/api/schema';
|
16
|
-
import {
|
16
|
+
import {
|
17
|
+
isEntityWithMergedImplementation,
|
18
|
+
isColumnEntityType,
|
19
|
+
isTableType,
|
20
|
+
} from '../../utils/schema';
|
17
21
|
//@ts-ignore
|
18
|
-
import {
|
22
|
+
import {
|
23
|
+
getSchema,
|
24
|
+
getSchemaBatched,
|
25
|
+
resetLoadingState,
|
26
|
+
selectSchemaMergedChildrenPaths,
|
27
|
+
} from '../../../../store/reducers/schema';
|
19
28
|
//@ts-ignore
|
20
29
|
import {
|
21
30
|
getOlapStats,
|
22
31
|
resetLoadingState as resetOlapLoadingState,
|
23
32
|
} from '../../../../store/reducers/olapStats';
|
24
|
-
import {useAutofetcher} from '../../../../utils/hooks';
|
33
|
+
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
25
34
|
|
26
35
|
import './Overview.scss';
|
27
36
|
|
@@ -60,9 +69,7 @@ interface OverviewProps {
|
|
60
69
|
|
61
70
|
const b = cn('kv-tenant-overview');
|
62
71
|
|
63
|
-
function Overview(
|
64
|
-
const {tenantName, type} = props;
|
65
|
-
|
72
|
+
function Overview({type, tenantName, className}: OverviewProps) {
|
66
73
|
const dispatch = useDispatch();
|
67
74
|
|
68
75
|
const {
|
@@ -78,14 +85,31 @@ function Overview(props: OverviewProps) {
|
|
78
85
|
|
79
86
|
const loading = schemaLoading || olapStatsLoading;
|
80
87
|
|
81
|
-
|
82
|
-
|
88
|
+
const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
|
89
|
+
|
90
|
+
// There is a circular dependency here. Fetch data depends on children paths
|
91
|
+
// When data in store updated on fetch request,
|
92
|
+
// new object is set there, so source children array is updated
|
93
|
+
// This updates selector, the selector returns a new array, and data is fetched again
|
94
|
+
// To prevent it, shallowEqual, which compares array content, was added
|
95
|
+
const mergedChildrenPaths = useTypedSelector(
|
96
|
+
(state) => selectSchemaMergedChildrenPaths(state, currentSchemaPath, type),
|
97
|
+
shallowEqual,
|
98
|
+
);
|
99
|
+
|
100
|
+
const fetchData = useCallback(
|
101
|
+
(isBackground: boolean) => {
|
83
102
|
if (!isBackground) {
|
84
103
|
dispatch(resetLoadingState());
|
85
104
|
}
|
86
105
|
|
87
106
|
const schemaPath = currentSchemaPath || tenantName;
|
88
|
-
|
107
|
+
|
108
|
+
if (!isEntityWithMergedImpl) {
|
109
|
+
dispatch(getSchema({path: schemaPath}));
|
110
|
+
} else if (mergedChildrenPaths) {
|
111
|
+
dispatch(getSchemaBatched([schemaPath, ...mergedChildrenPaths]));
|
112
|
+
}
|
89
113
|
|
90
114
|
if (isTableType(type) && isColumnEntityType(type)) {
|
91
115
|
if (!isBackground) {
|
@@ -94,10 +118,18 @@ function Overview(props: OverviewProps) {
|
|
94
118
|
dispatch(getOlapStats({path: schemaPath}));
|
95
119
|
}
|
96
120
|
},
|
97
|
-
[
|
98
|
-
|
121
|
+
[
|
122
|
+
tenantName,
|
123
|
+
currentSchemaPath,
|
124
|
+
type,
|
125
|
+
isEntityWithMergedImpl,
|
126
|
+
mergedChildrenPaths,
|
127
|
+
dispatch,
|
128
|
+
],
|
99
129
|
);
|
100
130
|
|
131
|
+
useAutofetcher(fetchData, [fetchData], autorefresh);
|
132
|
+
|
101
133
|
const tableSchema =
|
102
134
|
currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
|
103
135
|
|
@@ -128,7 +160,9 @@ function Overview(props: OverviewProps) {
|
|
128
160
|
[EPathType.EPathTypeExtSubDomain]: undefined,
|
129
161
|
[EPathType.EPathTypeColumnStore]: undefined,
|
130
162
|
[EPathType.EPathTypeColumnTable]: undefined,
|
131
|
-
[EPathType.EPathTypeCdcStream]: () =>
|
163
|
+
[EPathType.EPathTypeCdcStream]: () => (
|
164
|
+
<CDCStreamInfo data={schemaData} childrenPaths={mergedChildrenPaths} />
|
165
|
+
),
|
132
166
|
[EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
|
133
167
|
};
|
134
168
|
|
@@ -139,10 +173,10 @@ function Overview(props: OverviewProps) {
|
|
139
173
|
);
|
140
174
|
};
|
141
175
|
|
142
|
-
return loading && !wasLoaded ? (
|
176
|
+
return (loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths) ? (
|
143
177
|
renderLoader()
|
144
178
|
) : (
|
145
|
-
<div className={
|
179
|
+
<div className={className}>{renderContent()}</div>
|
146
180
|
);
|
147
181
|
}
|
148
182
|
|
@@ -53,6 +53,7 @@ class TenantOverview extends React.Component {
|
|
53
53
|
|
54
54
|
componentDidMount() {
|
55
55
|
const {tenantName, autorefresh, getTenantInfo} = this.props;
|
56
|
+
getTenantInfo({path: tenantName});
|
56
57
|
this.autofetcher = new AutoFetcher();
|
57
58
|
if (autorefresh) {
|
58
59
|
this.autofetcher.start();
|
@@ -62,12 +63,25 @@ class TenantOverview extends React.Component {
|
|
62
63
|
|
63
64
|
componentDidUpdate(prevProps) {
|
64
65
|
const {autorefresh, tenantName, getTenantInfo} = this.props;
|
65
|
-
|
66
|
-
|
66
|
+
|
67
|
+
const restartAutorefresh = () => {
|
67
68
|
this.autofetcher.stop();
|
68
69
|
this.autofetcher.start();
|
69
70
|
this.autofetcher.fetch(() => getTenantInfo({path: tenantName}));
|
71
|
+
};
|
72
|
+
|
73
|
+
if (prevProps.tenantName !== this.props.tenantName) {
|
74
|
+
getTenantInfo({path: tenantName});
|
75
|
+
if (autorefresh) {
|
76
|
+
restartAutorefresh();
|
77
|
+
}
|
70
78
|
}
|
79
|
+
|
80
|
+
if (autorefresh && !prevProps.autorefresh) {
|
81
|
+
getTenantInfo({path: tenantName});
|
82
|
+
restartAutorefresh();
|
83
|
+
}
|
84
|
+
|
71
85
|
if (!autorefresh && prevProps.autorefresh) {
|
72
86
|
this.autofetcher.stop();
|
73
87
|
}
|
@@ -47,17 +47,23 @@ function prepareDateSizeValue(value) {
|
|
47
47
|
}
|
48
48
|
|
49
49
|
function stringToDataTableSortOrder(value) {
|
50
|
-
return
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
return (
|
51
|
+
value &&
|
52
|
+
value.split(',').map((columnId) => ({
|
53
|
+
columnId,
|
54
|
+
order: DataTable.DESCENDING,
|
55
|
+
}))
|
56
|
+
);
|
54
57
|
}
|
55
58
|
|
56
59
|
function stringToQuerySortOrder(value) {
|
57
|
-
return
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
return (
|
61
|
+
value &&
|
62
|
+
value.split(',').map((columnId) => ({
|
63
|
+
columnId,
|
64
|
+
order: 'DESC',
|
65
|
+
}))
|
66
|
+
);
|
61
67
|
}
|
62
68
|
|
63
69
|
function dataTableToStringSortOrder(value = []) {
|
@@ -85,11 +91,13 @@ function TopShards({
|
|
85
91
|
|
86
92
|
if (autorefresh) {
|
87
93
|
autofetcher.start();
|
88
|
-
autofetcher.fetch(() =>
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
94
|
+
autofetcher.fetch(() =>
|
95
|
+
sendShardQuery({
|
96
|
+
database: path,
|
97
|
+
path: currentSchemaPath,
|
98
|
+
sortOrder: stringToQuerySortOrder(sortOrder),
|
99
|
+
}),
|
100
|
+
);
|
93
101
|
}
|
94
102
|
|
95
103
|
return () => {
|
@@ -54,11 +54,7 @@ function ObjectGeneral(props: ObjectGeneralProps) {
|
|
54
54
|
if (!tenantName) {
|
55
55
|
return null;
|
56
56
|
}
|
57
|
-
return (
|
58
|
-
<div className={b()}>
|
59
|
-
{renderTabContent()}
|
60
|
-
</div>
|
61
|
-
);
|
57
|
+
return <div className={b()}>{renderTabContent()}</div>;
|
62
58
|
};
|
63
59
|
|
64
60
|
return renderContent();
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, {
|
1
|
+
import React, {useEffect, useRef, useState} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import MonacoEditor from 'react-monaco-editor';
|
4
4
|
import {Loader, RadioButton} from '@gravity-ui/uikit';
|
@@ -58,7 +58,7 @@ function GraphRoot(props) {
|
|
58
58
|
updateComponentTheme(theme);
|
59
59
|
}, [theme]);
|
60
60
|
|
61
|
-
const render =
|
61
|
+
const render = () => {
|
62
62
|
if (version === explainVersions.v2) {
|
63
63
|
paranoid.current = getTopology('graphRoot', data, opts, shapes);
|
64
64
|
paranoid.current.render();
|
@@ -66,7 +66,7 @@ function GraphRoot(props) {
|
|
66
66
|
paranoid.current = getCompactTopology('graphRoot', data, opts);
|
67
67
|
paranoid.current.renderCompactTopology();
|
68
68
|
}
|
69
|
-
}
|
69
|
+
};
|
70
70
|
|
71
71
|
useEffect(() => {
|
72
72
|
render();
|
@@ -86,7 +86,7 @@ function GraphRoot(props) {
|
|
86
86
|
graphRoot.innerHTML = '';
|
87
87
|
|
88
88
|
render();
|
89
|
-
}, [componentTheme
|
89
|
+
}, [componentTheme]);
|
90
90
|
|
91
91
|
useEffect(() => {
|
92
92
|
paranoid.current?.updateData?.(props.data);
|
@@ -73,10 +73,7 @@ function SaveQuery({savedQueries, onSaveQuery, saveButtonDisabled}) {
|
|
73
73
|
</div>
|
74
74
|
)}
|
75
75
|
<div className={b('dialog-row')}>
|
76
|
-
<label
|
77
|
-
htmlFor="queryName"
|
78
|
-
className={b('field-title', 'required')}
|
79
|
-
>
|
76
|
+
<label htmlFor="queryName" className={b('field-title', 'required')}>
|
80
77
|
Query name
|
81
78
|
</label>
|
82
79
|
<div className={b('control-wrapper')}>
|
@@ -44,9 +44,10 @@ const formatTableStatsItem = createInfoFormatter({
|
|
44
44
|
defaultValueFormatter: formatNumber,
|
45
45
|
});
|
46
46
|
|
47
|
-
const formatTableStats = (fields) =>
|
48
|
-
.
|
49
|
-
|
47
|
+
const formatTableStats = (fields) =>
|
48
|
+
Object.entries(fields)
|
49
|
+
.map(([label, value]) => formatTableStatsItem(label, value))
|
50
|
+
.filter(({value}) => Boolean(value));
|
50
51
|
|
51
52
|
class SchemaInfoViewer extends React.Component {
|
52
53
|
static propTypes = {
|
@@ -60,17 +61,18 @@ class SchemaInfoViewer extends React.Component {
|
|
60
61
|
|
61
62
|
return (
|
62
63
|
<div className={b('item')}>
|
63
|
-
<InfoViewer
|
64
|
-
title={title}
|
65
|
-
info={itemData}
|
66
|
-
/>
|
64
|
+
<InfoViewer title={title} info={itemData} />
|
67
65
|
</div>
|
68
66
|
);
|
69
67
|
}
|
70
68
|
|
71
69
|
renderContent(data) {
|
72
70
|
const {PathDescription = {}} = data;
|
73
|
-
const {
|
71
|
+
const {
|
72
|
+
TableStats = {},
|
73
|
+
TabletMetrics = {},
|
74
|
+
Table: {PartitionConfig = {}} = {},
|
75
|
+
} = PathDescription;
|
74
76
|
const {
|
75
77
|
PartCount,
|
76
78
|
RowCount,
|
@@ -127,33 +129,30 @@ class SchemaInfoViewer extends React.Component {
|
|
127
129
|
];
|
128
130
|
|
129
131
|
const tabletMetricsInfo = Object.keys(TabletMetrics).map((key) =>
|
130
|
-
formatTabletMetricsItem(key, TabletMetrics[key])
|
132
|
+
formatTabletMetricsItem(key, TabletMetrics[key]),
|
131
133
|
);
|
132
134
|
|
133
135
|
const partitionConfigInfo = [];
|
134
136
|
|
135
137
|
if (Array.isArray(FollowerGroups) && FollowerGroups.length > 0) {
|
136
|
-
partitionConfigInfo.push(...Object.keys(FollowerGroups[0]).map((key) =>
|
137
|
-
formatFollowerGroupItem(key, FollowerGroups[0][key])
|
138
|
-
));
|
139
|
-
} else if (FollowerCount !== undefined) {
|
140
138
|
partitionConfigInfo.push(
|
141
|
-
|
139
|
+
...Object.keys(FollowerGroups[0]).map((key) =>
|
140
|
+
formatFollowerGroupItem(key, FollowerGroups[0][key]),
|
141
|
+
),
|
142
142
|
);
|
143
|
+
} else if (FollowerCount !== undefined) {
|
144
|
+
partitionConfigInfo.push(formatPartitionConfigItem('FollowerCount', FollowerCount));
|
143
145
|
} else if (CrossDataCenterFollowerCount !== undefined) {
|
144
146
|
partitionConfigInfo.push(
|
145
|
-
formatPartitionConfigItem(
|
147
|
+
formatPartitionConfigItem(
|
148
|
+
'CrossDataCenterFollowerCount',
|
149
|
+
CrossDataCenterFollowerCount,
|
150
|
+
),
|
146
151
|
);
|
147
152
|
}
|
148
153
|
|
149
|
-
if ([
|
150
|
-
|
151
|
-
partitionConfigInfo,
|
152
|
-
tableStatsInfo.flat(),
|
153
|
-
].flat().length === 0) {
|
154
|
-
return (
|
155
|
-
<div className={b('item')}>Empty</div>
|
156
|
-
);
|
154
|
+
if ([tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat().length === 0) {
|
155
|
+
return <div className={b('item')}>Empty</div>;
|
157
156
|
}
|
158
157
|
|
159
158
|
return (
|
@@ -179,11 +178,7 @@ class SchemaInfoViewer extends React.Component {
|
|
179
178
|
const {data} = this.props;
|
180
179
|
|
181
180
|
if (data) {
|
182
|
-
return (
|
183
|
-
<div className={b()}>
|
184
|
-
{this.renderContent(data)}
|
185
|
-
</div>
|
186
|
-
);
|
181
|
+
return <div className={b()}>{this.renderContent(data)}</div>;
|
187
182
|
} else {
|
188
183
|
return <div className="error">no schema data</div>;
|
189
184
|
}
|
@@ -6,7 +6,7 @@ import {NavigationTree} from 'ydb-ui-components';
|
|
6
6
|
import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema';
|
7
7
|
import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
|
8
8
|
|
9
|
-
import {mapPathTypeToNavigationTreeType} from '../../utils/schema';
|
9
|
+
import {isChildlessPathType, mapPathTypeToNavigationTreeType} from '../../utils/schema';
|
10
10
|
import {getActions} from '../../utils/schemaActions';
|
11
11
|
|
12
12
|
interface SchemaTreeProps {
|
@@ -42,7 +42,7 @@ export function SchemaTree(props: SchemaTreeProps) {
|
|
42
42
|
type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
|
43
43
|
// FIXME: should only be explicitly set to true for tables with indexes
|
44
44
|
// at the moment of writing there is no property to determine this, fix later
|
45
|
-
expandable:
|
45
|
+
expandable: !isChildlessPathType(PathType, PathSubType),
|
46
46
|
};
|
47
47
|
});
|
48
48
|
|
@@ -88,3 +88,87 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
|
|
88
88
|
};
|
89
89
|
|
90
90
|
export const isColumnEntityType = (type?: EPathType) => (type && pathTypeToIsColumn[type]) ?? false;
|
91
|
+
|
92
|
+
// ====================
|
93
|
+
|
94
|
+
const pathTypeToIsDatabase: Record<EPathType, boolean> = {
|
95
|
+
[EPathType.EPathTypeSubDomain]: true,
|
96
|
+
[EPathType.EPathTypeExtSubDomain]: true,
|
97
|
+
|
98
|
+
[EPathType.EPathTypeInvalid]: false,
|
99
|
+
[EPathType.EPathTypeDir]: false,
|
100
|
+
[EPathType.EPathTypeColumnStore]: false,
|
101
|
+
[EPathType.EPathTypeColumnTable]: false,
|
102
|
+
[EPathType.EPathTypeTable]: false,
|
103
|
+
[EPathType.EPathTypeTableIndex]: false,
|
104
|
+
[EPathType.EPathTypeCdcStream]: false,
|
105
|
+
[EPathType.EPathTypePersQueueGroup]: false,
|
106
|
+
};
|
107
|
+
|
108
|
+
export const isDatabaseEntityType = (type?: EPathType) =>
|
109
|
+
(type && pathTypeToIsDatabase[type]) ?? false;
|
110
|
+
|
111
|
+
// ====================
|
112
|
+
|
113
|
+
const pathTypeToIsCdcStream: Record<EPathType, boolean> = {
|
114
|
+
[EPathType.EPathTypeCdcStream]: true,
|
115
|
+
|
116
|
+
[EPathType.EPathTypeInvalid]: false,
|
117
|
+
[EPathType.EPathTypeColumnStore]: false,
|
118
|
+
[EPathType.EPathTypeColumnTable]: false,
|
119
|
+
[EPathType.EPathTypeDir]: false,
|
120
|
+
[EPathType.EPathTypeTable]: false,
|
121
|
+
[EPathType.EPathTypeSubDomain]: false,
|
122
|
+
[EPathType.EPathTypeTableIndex]: false,
|
123
|
+
[EPathType.EPathTypeExtSubDomain]: false,
|
124
|
+
[EPathType.EPathTypePersQueueGroup]: false,
|
125
|
+
};
|
126
|
+
|
127
|
+
export const isCdcStreamEntityType = (type?: EPathType) =>
|
128
|
+
(type && pathTypeToIsCdcStream[type]) ?? false;
|
129
|
+
|
130
|
+
// ====================
|
131
|
+
|
132
|
+
const pathTypeToEntityWithMergedImplementation: Record<EPathType, boolean> = {
|
133
|
+
[EPathType.EPathTypeCdcStream]: true,
|
134
|
+
|
135
|
+
[EPathType.EPathTypePersQueueGroup]: false,
|
136
|
+
[EPathType.EPathTypeInvalid]: false,
|
137
|
+
[EPathType.EPathTypeColumnStore]: false,
|
138
|
+
[EPathType.EPathTypeColumnTable]: false,
|
139
|
+
[EPathType.EPathTypeDir]: false,
|
140
|
+
[EPathType.EPathTypeTable]: false,
|
141
|
+
[EPathType.EPathTypeSubDomain]: false,
|
142
|
+
[EPathType.EPathTypeTableIndex]: false,
|
143
|
+
[EPathType.EPathTypeExtSubDomain]: false,
|
144
|
+
};
|
145
|
+
|
146
|
+
export const isEntityWithMergedImplementation = (type?: EPathType) =>
|
147
|
+
(type && pathTypeToEntityWithMergedImplementation[type]) ?? false;
|
148
|
+
|
149
|
+
// ====================
|
150
|
+
|
151
|
+
const pathSubTypeToChildless: Record<EPathSubType, boolean> = {
|
152
|
+
[EPathSubType.EPathSubTypeSyncIndexImplTable]: true,
|
153
|
+
[EPathSubType.EPathSubTypeAsyncIndexImplTable]: true,
|
154
|
+
|
155
|
+
[EPathSubType.EPathSubTypeStreamImpl]: false,
|
156
|
+
[EPathSubType.EPathSubTypeEmpty]: false,
|
157
|
+
};
|
158
|
+
|
159
|
+
const pathTypeToChildless: Record<EPathType, boolean> = {
|
160
|
+
[EPathType.EPathTypeCdcStream]: true,
|
161
|
+
[EPathType.EPathTypePersQueueGroup]: true,
|
162
|
+
|
163
|
+
[EPathType.EPathTypeInvalid]: false,
|
164
|
+
[EPathType.EPathTypeColumnStore]: false,
|
165
|
+
[EPathType.EPathTypeColumnTable]: false,
|
166
|
+
[EPathType.EPathTypeDir]: false,
|
167
|
+
[EPathType.EPathTypeTable]: false,
|
168
|
+
[EPathType.EPathTypeSubDomain]: false,
|
169
|
+
[EPathType.EPathTypeTableIndex]: false,
|
170
|
+
[EPathType.EPathTypeExtSubDomain]: false,
|
171
|
+
};
|
172
|
+
|
173
|
+
export const isChildlessPathType = (type?: EPathType, subType?: EPathSubType) =>
|
174
|
+
((subType && pathSubTypeToChildless[subType]) || (type && pathTypeToChildless[type])) ?? false;
|
@@ -37,9 +37,9 @@ const bindActions = (
|
|
37
37
|
) => {
|
38
38
|
const inputQuery = (tmpl: (path: string) => string) => () => {
|
39
39
|
dispatch(changeUserInput({input: tmpl(path)}));
|
40
|
-
dispatch(setTopLevelTab(TenantGeneralTabsIds.query))
|
40
|
+
dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
|
41
41
|
setActivePath(path);
|
42
|
-
}
|
42
|
+
};
|
43
43
|
|
44
44
|
return {
|
45
45
|
createTable: inputQuery(createTableTemplate),
|
@@ -66,7 +66,7 @@ const bindActions = (
|
|
66
66
|
},
|
67
67
|
openPreview: () => {
|
68
68
|
dispatch(setShowPreview(true));
|
69
|
-
dispatch(setTopLevelTab(TenantGeneralTabsIds.query))
|
69
|
+
dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
|
70
70
|
setActivePath(path);
|
71
71
|
},
|
72
72
|
};
|
@@ -74,27 +74,18 @@ const bindActions = (
|
|
74
74
|
|
75
75
|
type ActionsSet = ReturnType<Required<NavigationTreeProps>['getActions']>;
|
76
76
|
|
77
|
-
export const getActions =
|
78
|
-
dispatch: Dispatch<any>,
|
79
|
-
setActivePath: (path: string) => void,
|
80
|
-
) =>
|
77
|
+
export const getActions =
|
78
|
+
(dispatch: Dispatch<any>, setActivePath: (path: string) => void) =>
|
81
79
|
(path: string, type: NavigationTreeNodeType) => {
|
82
80
|
const actions = bindActions(path, dispatch, setActivePath);
|
83
81
|
const copyItem = {text: 'Copy path', action: actions.copyPath};
|
84
82
|
|
85
83
|
const DIR_SET: ActionsSet = [
|
86
|
-
[
|
87
|
-
|
88
|
-
],
|
89
|
-
[
|
90
|
-
{text: 'Create table...', action: actions.createTable},
|
91
|
-
],
|
84
|
+
[copyItem],
|
85
|
+
[{text: 'Create table...', action: actions.createTable}],
|
92
86
|
];
|
93
87
|
const TABLE_SET: ActionsSet = [
|
94
|
-
[
|
95
|
-
{text: 'Open preview', action: actions.openPreview},
|
96
|
-
copyItem,
|
97
|
-
],
|
88
|
+
[{text: 'Open preview', action: actions.openPreview}, copyItem],
|
98
89
|
[
|
99
90
|
{text: 'Alter table...', action: actions.alterTable},
|
100
91
|
{text: 'Select query...', action: actions.selectQuery},
|
@@ -102,9 +93,7 @@ export const getActions = (
|
|
102
93
|
],
|
103
94
|
];
|
104
95
|
|
105
|
-
const JUST_COPY: ActionsSet = [
|
106
|
-
copyItem,
|
107
|
-
];
|
96
|
+
const JUST_COPY: ActionsSet = [copyItem];
|
108
97
|
|
109
98
|
const EMPTY_SET: ActionsSet = [];
|
110
99
|
|
package/dist/services/api.d.ts
CHANGED
@@ -8,25 +8,29 @@ interface Window {
|
|
8
8
|
params: {path: string},
|
9
9
|
axiosOptions?: AxiosOptions,
|
10
10
|
) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
|
11
|
+
getDescribe: (
|
12
|
+
params: {path: string},
|
13
|
+
axiosOptions?: AxiosOptions,
|
14
|
+
) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
|
11
15
|
getStorageInfo: (
|
12
16
|
params: {
|
13
|
-
tenant: string
|
14
|
-
filter: string
|
15
|
-
nodeId: string
|
16
|
-
type: 'Groups' | 'Nodes'
|
17
|
+
tenant: string;
|
18
|
+
filter: string;
|
19
|
+
nodeId: string;
|
20
|
+
type: 'Groups' | 'Nodes';
|
17
21
|
},
|
18
22
|
axiosOptions?: AxiosOptions,
|
19
23
|
) => Promise<import('../types/api/storage').TStorageInfo>;
|
20
24
|
sendQuery: <
|
21
25
|
Action extends import('../types/api/query').Actions,
|
22
|
-
Schema extends import('../types/api/query').Schemas = undefined
|
26
|
+
Schema extends import('../types/api/query').Schemas = undefined,
|
23
27
|
>(
|
24
28
|
params: {
|
25
|
-
query?: string
|
26
|
-
database?: string
|
27
|
-
action?: Action
|
28
|
-
stats?: string
|
29
|
-
schema?: Schema
|
29
|
+
query?: string;
|
30
|
+
database?: string;
|
31
|
+
action?: Action;
|
32
|
+
stats?: string;
|
33
|
+
schema?: Schema;
|
30
34
|
},
|
31
35
|
axiosOptions?: AxiosOptions,
|
32
36
|
) => Promise<import('../types/api/query').QueryAPIResponse<Action, Schema>>;
|
@@ -38,7 +42,9 @@ interface Window {
|
|
38
42
|
query: string,
|
39
43
|
database: string,
|
40
44
|
) => Promise<import('../types/api/query').QueryAPIExplainResponse<'explain-ast'>>;
|
41
|
-
getHealthcheckInfo: (
|
45
|
+
getHealthcheckInfo: (
|
46
|
+
database: string,
|
47
|
+
) => Promise<import('../types/api/healthcheck').HealthCheckAPIResponse>;
|
42
48
|
[method: string]: Function;
|
43
49
|
};
|
44
50
|
}
|
@@ -1,7 +1,11 @@
|
|
1
|
-
import {createRequestActionTypes, createApiRequest} from '../utils';
|
2
1
|
import {createSelector} from 'reselect';
|
2
|
+
|
3
3
|
import '../../services/api';
|
4
4
|
import {ALL} from '../../utils/constants';
|
5
|
+
import {createRequestActionTypes, createApiRequest} from '../utils';
|
6
|
+
|
7
|
+
import {filterByUptime} from './storage';
|
8
|
+
import {getNodesUptimeFilter} from './nodes';
|
5
9
|
|
6
10
|
const FETCH_NODES_LIST = createRequestActionTypes('tenants', 'FETCH_NODES_LIST');
|
7
11
|
|
@@ -47,23 +51,38 @@ export function getNodesList() {
|
|
47
51
|
});
|
48
52
|
}
|
49
53
|
|
54
|
+
const filterByProblemsStatus = (nodes = [], problemFilter) => {
|
55
|
+
if (problemFilter === ALL) {
|
56
|
+
return nodes;
|
57
|
+
}
|
58
|
+
|
59
|
+
return nodes.filter(({Overall}) => {
|
60
|
+
return Overall && Overall !== 'Green';
|
61
|
+
});
|
62
|
+
};
|
63
|
+
|
64
|
+
export const filterNodesByStatusAndUptime = (nodes = [], problemFilter, uptimeFilter) => {
|
65
|
+
let result = filterByProblemsStatus(nodes, problemFilter);
|
66
|
+
result = filterByUptime(result, uptimeFilter);
|
67
|
+
|
68
|
+
return result;
|
69
|
+
};
|
70
|
+
|
50
71
|
export const getFilteredNodes = createSelector(
|
51
|
-
|
52
|
-
|
53
|
-
|
72
|
+
[
|
73
|
+
(state) => state.nodes.data?.Tenants,
|
74
|
+
(state) => state.settings.problemFilter,
|
75
|
+
getNodesUptimeFilter,
|
76
|
+
],
|
77
|
+
(tenants, problemFilter, uptimeFilter) => {
|
54
78
|
const nodes = tenants?.reduce((acc, item) => {
|
55
79
|
if (Array.isArray(item.Nodes)) {
|
56
80
|
return [...acc, ...item.Nodes.map((node) => ({...node, TenantName: item.Name}))];
|
57
81
|
}
|
58
82
|
return acc;
|
59
83
|
}, []);
|
60
|
-
if (filter === ALL) {
|
61
|
-
return nodes;
|
62
|
-
}
|
63
84
|
|
64
|
-
return nodes
|
65
|
-
return Overall && Overall !== 'Green';
|
66
|
-
});
|
85
|
+
return filterNodesByStatusAndUptime(nodes, problemFilter, uptimeFilter);
|
67
86
|
},
|
68
87
|
);
|
69
88
|
|