ydb-embedded-ui 2.4.3 → 2.5.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 +33 -0
- package/dist/components/InfoViewer/formatters/schema.ts +2 -1
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +3 -16
- 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/Storage.js +35 -10
- 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 +1 -1
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +34 -8
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +87 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +0 -7
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +5 -7
- 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 +16 -30
- 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 -7
- package/dist/containers/Tenant/Tenant.tsx +8 -5
- package/dist/containers/Tenant/TenantPages.tsx +1 -1
- package/dist/containers/Tenant/utils/schemaActions.ts +9 -20
- package/dist/services/api.js +14 -5
- package/dist/store/reducers/clusterNodes.js +29 -10
- package/dist/store/reducers/describe.ts +60 -30
- package/dist/store/reducers/nodes.js +24 -3
- package/dist/store/reducers/{schema.js → schema.ts} +22 -14
- package/dist/store/reducers/storage.js +46 -5
- package/dist/types/api/error.ts +4 -2
- package/dist/types/store/describe.ts +21 -1
- package/dist/types/store/schema.ts +46 -0
- package/dist/utils/index.js +6 -2
- package/dist/utils/nodes.ts +9 -0
- package/package.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.js +0 -130
@@ -0,0 +1,87 @@
|
|
1
|
+
import {useCallback} from 'react';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import cn from 'bem-cn-lite';
|
4
|
+
// @ts-ignore
|
5
|
+
import JSONTree from 'react-json-inspector';
|
6
|
+
import 'react-json-inspector/json-inspector.css';
|
7
|
+
|
8
|
+
import {Loader} from '../../../../components/Loader';
|
9
|
+
|
10
|
+
import {prepareQueryError} from '../../../../utils/query';
|
11
|
+
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
12
|
+
import {
|
13
|
+
getDescribe,
|
14
|
+
setDataWasNotLoaded,
|
15
|
+
setCurrentDescribePath,
|
16
|
+
} from '../../../../store/reducers/describe';
|
17
|
+
|
18
|
+
import './Describe.scss';
|
19
|
+
|
20
|
+
const b = cn('kv-describe');
|
21
|
+
|
22
|
+
const expandMap = new Map();
|
23
|
+
|
24
|
+
interface IDescribeProps {
|
25
|
+
tenant: string;
|
26
|
+
}
|
27
|
+
|
28
|
+
const Describe = ({tenant}: IDescribeProps) => {
|
29
|
+
const dispatch = useDispatch();
|
30
|
+
|
31
|
+
const {currentDescribe, error, loading, wasLoaded} = useTypedSelector(
|
32
|
+
(state) => state.describe,
|
33
|
+
);
|
34
|
+
|
35
|
+
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
36
|
+
|
37
|
+
const fetchData = useCallback(
|
38
|
+
(isBackground: boolean) => {
|
39
|
+
if (!isBackground) {
|
40
|
+
dispatch(setDataWasNotLoaded());
|
41
|
+
}
|
42
|
+
|
43
|
+
const path = currentSchemaPath || tenant;
|
44
|
+
|
45
|
+
dispatch(setCurrentDescribePath(path));
|
46
|
+
dispatch(getDescribe({path}));
|
47
|
+
},
|
48
|
+
[currentSchemaPath, tenant, dispatch],
|
49
|
+
);
|
50
|
+
|
51
|
+
useAutofetcher(fetchData, [fetchData], autorefresh);
|
52
|
+
|
53
|
+
if (loading && !wasLoaded) {
|
54
|
+
return <Loader size="m" />;
|
55
|
+
}
|
56
|
+
|
57
|
+
if (error) {
|
58
|
+
return <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
|
59
|
+
}
|
60
|
+
|
61
|
+
if (!loading && !currentDescribe) {
|
62
|
+
return <div className={b('message-container')}>Empty</div>;
|
63
|
+
}
|
64
|
+
|
65
|
+
return (
|
66
|
+
<div className={b()}>
|
67
|
+
<div className={b('result')}>
|
68
|
+
<JSONTree
|
69
|
+
data={currentDescribe}
|
70
|
+
className={b('tree')}
|
71
|
+
onClick={({path}: {path: string}) => {
|
72
|
+
const newValue = !(expandMap.get(path) || false);
|
73
|
+
expandMap.set(path, newValue);
|
74
|
+
}}
|
75
|
+
searchOptions={{
|
76
|
+
debounceTime: 300,
|
77
|
+
}}
|
78
|
+
isExpanded={(keypath: string) => {
|
79
|
+
return expandMap.get(keypath) || false;
|
80
|
+
}}
|
81
|
+
/>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
);
|
85
|
+
};
|
86
|
+
|
87
|
+
export default Describe;
|
@@ -5,7 +5,9 @@ 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 {
|
8
|
+
import {Switch, Tabs} from '@gravity-ui/uikit';
|
9
|
+
|
10
|
+
import {Loader} from '../../../components/Loader';
|
9
11
|
|
10
12
|
//@ts-ignore
|
11
13
|
import TopQueries from './TopQueries/TopQueries';
|
@@ -153,7 +155,7 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
153
155
|
return <Heatmap path={currentItem.Path} />;
|
154
156
|
}
|
155
157
|
case GeneralPagesIds.consumers: {
|
156
|
-
return <Consumers path={
|
158
|
+
return <Consumers path={currentSchemaPath} />;
|
157
159
|
}
|
158
160
|
default: {
|
159
161
|
return <div>No data...</div>;
|
@@ -196,11 +198,7 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
196
198
|
// After tabs are initially loaded it is no longer needed
|
197
199
|
// Thus there is no also "loading" check as in other parts of the project
|
198
200
|
if (!wasLoaded) {
|
199
|
-
return
|
200
|
-
<div className={b('loader')}>
|
201
|
-
<Loader size="l" />
|
202
|
-
</div>
|
203
|
-
);
|
201
|
+
return <Loader size="l" />;
|
204
202
|
}
|
205
203
|
|
206
204
|
return (
|
@@ -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();
|
@@ -25,20 +25,6 @@ import {disableFullscreen} from '../../../../store/reducers/fullscreen';
|
|
25
25
|
|
26
26
|
const b = cn('kv-query-explain');
|
27
27
|
|
28
|
-
const DARK_COLORS = {
|
29
|
-
success: 'rgba(59,201,53,0.75)',
|
30
|
-
error: '#bf3230',
|
31
|
-
warning: '#cc6810',
|
32
|
-
mute: 'rgba(255,255,255,0.15)',
|
33
|
-
stroke: 'rgba(255,255,255,0.17)',
|
34
|
-
fill: '#313037',
|
35
|
-
nodeFill: '#3b3a41',
|
36
|
-
nodeShadow: 'rgba(0,0,0,0.2)',
|
37
|
-
titleColor: 'rgba(255,255,255,0.7)',
|
38
|
-
textColor: 'rgba(255,255,255,0.55)',
|
39
|
-
buttonBorderColor: 'rgba(255,255,255,0.07)',
|
40
|
-
};
|
41
|
-
|
42
28
|
const EDITOR_OPTIONS = {
|
43
29
|
automaticLayout: true,
|
44
30
|
selectOnLineNumbers: true,
|
@@ -64,9 +50,15 @@ const explainOptions = [
|
|
64
50
|
function GraphRoot(props) {
|
65
51
|
const paranoid = useRef();
|
66
52
|
|
67
|
-
const
|
68
|
-
|
53
|
+
const {data, opts, shapes, version, theme} = props;
|
54
|
+
|
55
|
+
const [componentTheme, updateComponentTheme] = useState(theme);
|
69
56
|
|
57
|
+
useEffect(() => {
|
58
|
+
updateComponentTheme(theme);
|
59
|
+
}, [theme]);
|
60
|
+
|
61
|
+
const render = () => {
|
70
62
|
if (version === explainVersions.v2) {
|
71
63
|
paranoid.current = getTopology('graphRoot', data, opts, shapes);
|
72
64
|
paranoid.current.render();
|
@@ -74,7 +66,7 @@ function GraphRoot(props) {
|
|
74
66
|
paranoid.current = getCompactTopology('graphRoot', data, opts);
|
75
67
|
paranoid.current.renderCompactTopology();
|
76
68
|
}
|
77
|
-
}
|
69
|
+
};
|
78
70
|
|
79
71
|
useEffect(() => {
|
80
72
|
render();
|
@@ -94,7 +86,7 @@ function GraphRoot(props) {
|
|
94
86
|
graphRoot.innerHTML = '';
|
95
87
|
|
96
88
|
render();
|
97
|
-
}, [
|
89
|
+
}, [componentTheme]);
|
98
90
|
|
99
91
|
useEffect(() => {
|
100
92
|
paranoid.current?.updateData?.(props.data);
|
@@ -134,11 +126,7 @@ function QueryExplain(props) {
|
|
134
126
|
};
|
135
127
|
|
136
128
|
const renderStub = () => {
|
137
|
-
return (
|
138
|
-
<div className={b('text-message')}>
|
139
|
-
There is no explanation for the request
|
140
|
-
</div>
|
141
|
-
);
|
129
|
+
return <div className={b('text-message')}>There is no explanation for the request</div>;
|
142
130
|
};
|
143
131
|
|
144
132
|
const hasContent = () => {
|
@@ -204,12 +192,12 @@ function QueryExplain(props) {
|
|
204
192
|
})}
|
205
193
|
>
|
206
194
|
<GraphRoot
|
195
|
+
theme={theme}
|
207
196
|
version={version}
|
208
197
|
data={{links, nodes}}
|
209
198
|
opts={{
|
210
199
|
renderNodeTitle: renderExplainNode,
|
211
200
|
textOverflow: TextOverflow.Normal,
|
212
|
-
colors: theme === 'dark' ? DARK_COLORS : {},
|
213
201
|
initialZoomFitsCanvas: true,
|
214
202
|
}}
|
215
203
|
shapes={{
|
@@ -237,11 +225,7 @@ function QueryExplain(props) {
|
|
237
225
|
message = error;
|
238
226
|
}
|
239
227
|
|
240
|
-
return (
|
241
|
-
<div className={b('text-message')}>
|
242
|
-
{message}
|
243
|
-
</div>
|
244
|
-
);
|
228
|
+
return <div className={b('text-message')}>{message}</div>;
|
245
229
|
};
|
246
230
|
|
247
231
|
const renderContent = () => {
|
@@ -292,7 +276,9 @@ function QueryExplain(props) {
|
|
292
276
|
)}
|
293
277
|
</div>
|
294
278
|
<div className={b('controls-left')}>
|
295
|
-
<EnableFullscreenButton
|
279
|
+
<EnableFullscreenButton
|
280
|
+
disabled={Boolean(props.error) || !hasContent()}
|
281
|
+
/>
|
296
282
|
<PaneVisibilityToggleButtons
|
297
283
|
onCollapse={props.onCollapseResults}
|
298
284
|
onExpand={props.onExpandResults}
|
@@ -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
|
}
|
@@ -3,9 +3,7 @@ import {useDispatch} from 'react-redux';
|
|
3
3
|
|
4
4
|
import {NavigationTree} from 'ydb-ui-components';
|
5
5
|
|
6
|
-
import {setCurrentSchemaPath,
|
7
|
-
import {getDescribe} from '../../../../store/reducers/describe';
|
8
|
-
import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
|
6
|
+
import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema';
|
9
7
|
import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
|
10
8
|
|
11
9
|
import {mapPathTypeToNavigationTreeType} from '../../utils/schema';
|
@@ -30,7 +28,7 @@ export function SchemaTree(props: SchemaTreeProps) {
|
|
30
28
|
const {PathDescription: {Children = []} = {}} = data;
|
31
29
|
|
32
30
|
const preloadedData: Record<string, TEvDescribeSchemeResult> = {
|
33
|
-
[path]: data
|
31
|
+
[path]: data,
|
34
32
|
};
|
35
33
|
|
36
34
|
const childItems = Children.map((childData) => {
|
@@ -55,9 +53,6 @@ export function SchemaTree(props: SchemaTreeProps) {
|
|
55
53
|
|
56
54
|
const handleActivePathUpdate = (activePath: string) => {
|
57
55
|
dispatch(setCurrentSchemaPath(activePath));
|
58
|
-
dispatch(getSchema({path: activePath}));
|
59
|
-
dispatch(getDescribe({path: activePath}));
|
60
|
-
dispatch(getSchemaAcl({path: activePath}));
|
61
56
|
};
|
62
57
|
|
63
58
|
useEffect(() => {
|
@@ -78,12 +78,15 @@ function Tenant(props: TenantProps) {
|
|
78
78
|
const tenantName = name as string;
|
79
79
|
|
80
80
|
useEffect(() => {
|
81
|
-
const schemaPath = currentSchemaPath || tenantName;
|
82
|
-
dispatch(resetLoadingState());
|
83
81
|
dispatch(getSchema({path: tenantName}));
|
84
|
-
dispatch(
|
85
|
-
|
86
|
-
|
82
|
+
dispatch(getSchemaAcl({path: tenantName}));
|
83
|
+
}, [tenantName, dispatch]);
|
84
|
+
|
85
|
+
useEffect(() => {
|
86
|
+
dispatch(resetLoadingState());
|
87
|
+
dispatch(getSchema({path: currentSchemaPath}));
|
88
|
+
dispatch(getSchemaAcl({path: currentSchemaPath}));
|
89
|
+
}, [currentSchemaPath, dispatch]);
|
87
90
|
|
88
91
|
useEffect(() => {
|
89
92
|
dispatch(disableAutorefresh());
|
@@ -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.js
CHANGED
@@ -83,17 +83,26 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
83
83
|
path,
|
84
84
|
enums: true,
|
85
85
|
backup: false,
|
86
|
+
private: true,
|
87
|
+
partition_config: false,
|
86
88
|
partition_stats: false,
|
87
89
|
partitioning_info: false,
|
90
|
+
subs: 1,
|
88
91
|
},
|
89
92
|
{concurrentId: concurrentId || `getSchema|${path}`},
|
90
93
|
);
|
91
94
|
}
|
92
|
-
getDescribe({path}) {
|
93
|
-
return this.get(
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
getDescribe({path}, {concurrentId} = {}) {
|
96
|
+
return this.get(
|
97
|
+
this.getPath('/viewer/json/describe'),
|
98
|
+
{
|
99
|
+
path,
|
100
|
+
enums: true,
|
101
|
+
partition_stats: true,
|
102
|
+
subs: 0,
|
103
|
+
},
|
104
|
+
{concurrentId: concurrentId || `getDescribe|${path}`},
|
105
|
+
);
|
97
106
|
}
|
98
107
|
getSchemaAcl({path}) {
|
99
108
|
return this.get(
|
@@ -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
|
|