ydb-embedded-ui 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +22 -0
- package/dist/components/InfoViewer/InfoViewer.scss +3 -3
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +23 -9
- 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 +11 -1
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +39 -32
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +21 -13
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +22 -6
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +40 -9
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +15 -9
- 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/Schema/SchemaTree/SchemaTree.tsx +2 -2
- package/dist/containers/Tenant/utils/schema.ts +84 -0
- package/dist/services/api.d.ts +17 -11
- 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 +13 -0
- package/dist/store/reducers/schema.ts +84 -11
- package/dist/store/reducers/storage.js +13 -0
- 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 +7 -1
- package/dist/utils/pdisk.ts +1 -1
- package/dist/utils/storage.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.5.0...v2.6.0) (2022-12-05)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **Describe:** add topic data for CDCStream ([3a289d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/3a289d4f6452e3f2d719c0d508f48b389fd044d7))
|
9
|
+
* **Diagnostics:** add consumers tab for CdcStream ([22c6efd](https://github.com/ydb-platform/ydb-embedded-ui/commit/22c6efdd39d85ab1585943bc13d88cf03f9bc2ae))
|
10
|
+
* **Overview:** add topic data for CDCStream ([be80545](https://github.com/ydb-platform/ydb-embedded-ui/commit/be80545df65a03820265875fedd98c6f181af491))
|
11
|
+
|
12
|
+
|
13
|
+
### Bug Fixes
|
14
|
+
|
15
|
+
* **Compute:** update data on path change ([1783240](https://github.com/ydb-platform/ydb-embedded-ui/commit/17832403623ae3e718f47aec508c834cd2e3458c))
|
16
|
+
* **Diagnostics:** render db tabs for not root dbs ([7d46ce2](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d46ce2783a58b1ae6e41cae6592e78f95d61bcc))
|
17
|
+
* **Healthcheck:** render loader on path change ([ec40f19](https://github.com/ydb-platform/ydb-embedded-ui/commit/ec40f19c0b369de0b8d0658b4a1dd68c5c419c1c))
|
18
|
+
* **InfoViewer:** allow multiline values ([17755dc](https://github.com/ydb-platform/ydb-embedded-ui/commit/17755dc2eae7b6fc0a56ff70da95679fc590dccb))
|
19
|
+
* **Network:** update data on path change ([588c53f](https://github.com/ydb-platform/ydb-embedded-ui/commit/588c53f80a81376301216a77d9ead95cdff9812f))
|
20
|
+
* **SchemaTree:** do not expand childless components ([90468de](https://github.com/ydb-platform/ydb-embedded-ui/commit/90468de74b74e00a66255ba042378c9d7e1cbc27))
|
21
|
+
* **Storage:** update data on path change ([f5486bc](https://github.com/ydb-platform/ydb-embedded-ui/commit/f5486bcb2838b9e290c566089980533b4d22d035))
|
22
|
+
* **Tablets:** fix postponed data update on path change ([d474c6c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d474c6cb36597f0c720ef3bb8d0360ec73973e26))
|
23
|
+
* **TopQueries:** update data on path change ([32d7720](https://github.com/ydb-platform/ydb-embedded-ui/commit/32d77208b8ef09682c41160c60a1a7742b0c6c4c))
|
24
|
+
|
3
25
|
## [2.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.4...v2.5.0) (2022-11-25)
|
4
26
|
|
5
27
|
|
@@ -24,10 +24,10 @@
|
|
24
24
|
|
25
25
|
&__row {
|
26
26
|
display: flex;
|
27
|
-
align-items:
|
27
|
+
align-items: baseline;
|
28
28
|
|
29
29
|
max-width: 100%;
|
30
|
-
|
30
|
+
padding-top: 4px;
|
31
31
|
}
|
32
32
|
|
33
33
|
&__label {
|
@@ -54,7 +54,7 @@
|
|
54
54
|
&__value {
|
55
55
|
display: flex;
|
56
56
|
|
57
|
-
|
57
|
+
word-break: break-all;
|
58
58
|
}
|
59
59
|
|
60
60
|
&_size {
|
@@ -1,31 +1,45 @@
|
|
1
1
|
import type {TEvDescribeSchemeResult, TCdcStreamDescription} from '../../../types/api/schema';
|
2
|
+
import {useTypedSelector} from '../../../utils/hooks';
|
3
|
+
import {selectSchemaData} from '../../../store/reducers/schema';
|
2
4
|
|
3
|
-
import {formatCdcStreamItem, formatCommonItem} from '../formatters';
|
5
|
+
import {formatCdcStreamItem, formatPQGroupItem, formatCommonItem} from '../formatters';
|
4
6
|
import {InfoViewer, InfoViewerItem} from '..';
|
5
7
|
|
6
8
|
const DISPLAYED_FIELDS: Set<keyof TCdcStreamDescription> = new Set(['Mode', 'Format']);
|
7
9
|
|
8
10
|
interface CDCStreamInfoProps {
|
9
11
|
data?: TEvDescribeSchemeResult;
|
12
|
+
childrenPaths?: string[];
|
10
13
|
}
|
11
14
|
|
12
|
-
export const CDCStreamInfo = ({data}: CDCStreamInfoProps) => {
|
13
|
-
|
14
|
-
|
15
|
+
export const CDCStreamInfo = ({data, childrenPaths}: CDCStreamInfoProps) => {
|
16
|
+
const pqGroupData = useTypedSelector((state) => selectSchemaData(state, childrenPaths?.[0]));
|
17
|
+
|
18
|
+
if (!data || !pqGroupData) {
|
19
|
+
return <div className="error">No Changefeed data</div>;
|
15
20
|
}
|
16
21
|
|
17
|
-
const
|
22
|
+
const cdcStream = data.PathDescription?.CdcStreamDescription;
|
23
|
+
const pqGroup = pqGroupData?.PathDescription?.PersQueueGroup;
|
24
|
+
|
18
25
|
const info: Array<InfoViewerItem> = [];
|
19
26
|
|
20
|
-
info.push(formatCommonItem('PathType', data.PathDescription?.Self?.PathType));
|
21
27
|
info.push(formatCommonItem('CreateStep', data.PathDescription?.Self?.CreateStep));
|
22
28
|
|
23
29
|
let key: keyof TCdcStreamDescription;
|
24
|
-
for (key in
|
30
|
+
for (key in cdcStream) {
|
25
31
|
if (DISPLAYED_FIELDS.has(key)) {
|
26
|
-
info.push(formatCdcStreamItem(key,
|
32
|
+
info.push(formatCdcStreamItem(key, cdcStream?.[key]));
|
27
33
|
}
|
28
34
|
}
|
29
35
|
|
30
|
-
|
36
|
+
info.push(formatPQGroupItem('Partitions', pqGroup?.Partitions || []));
|
37
|
+
info.push(
|
38
|
+
formatPQGroupItem(
|
39
|
+
'PQTabletConfig',
|
40
|
+
pqGroup?.PQTabletConfig || {PartitionConfig: {LifetimeSeconds: 0}},
|
41
|
+
),
|
42
|
+
);
|
43
|
+
|
44
|
+
return <InfoViewer title={'Changefeed'} info={info} />;
|
31
45
|
};
|
@@ -8,7 +8,7 @@ import InternalLink from '../../../components/InternalLink/InternalLink';
|
|
8
8
|
|
9
9
|
import routes, {createHref} from '../../../routes';
|
10
10
|
import type {RequiredField} from '../../../types';
|
11
|
-
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/
|
11
|
+
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
|
12
12
|
import {getPDiskId} from '../../../utils';
|
13
13
|
import {getPDiskType} from '../../../utils/pdisk';
|
14
14
|
import {bytesToGB} from '../../../utils/utils';
|
@@ -96,9 +96,7 @@ function Pdisk(props: PDiskProps) {
|
|
96
96
|
Realtime &&
|
97
97
|
errorColors.includes(Realtime) &&
|
98
98
|
pdiskData.push({label: 'Realtime', value: Realtime});
|
99
|
-
Device &&
|
100
|
-
errorColors.includes(Device) &&
|
101
|
-
pdiskData.push({label: 'Device', value: Device});
|
99
|
+
Device && errorColors.includes(Device) && pdiskData.push({label: 'Device', value: Device});
|
102
100
|
return pdiskData;
|
103
101
|
};
|
104
102
|
/* eslint-enable */
|
@@ -113,11 +111,7 @@ function Pdisk(props: PDiskProps) {
|
|
113
111
|
// matches the default offset for popup with arrow out of a sense of beauty
|
114
112
|
offset={[0, 12]}
|
115
113
|
>
|
116
|
-
<InfoViewer
|
117
|
-
title="PDisk"
|
118
|
-
info={preparePdiskData()}
|
119
|
-
size="s"
|
120
|
-
/>
|
114
|
+
<InfoViewer title="PDisk" info={preparePdiskData()} size="s" />
|
121
115
|
</Popup>
|
122
116
|
);
|
123
117
|
|
@@ -2,7 +2,7 @@ import {MemoryRouter} from 'react-router-dom';
|
|
2
2
|
|
3
3
|
import {renderWithStore} from '../../../../utils/tests/providers';
|
4
4
|
|
5
|
-
import {TPDiskState} from '../../../../types/api/
|
5
|
+
import {TPDiskState} from '../../../../types/api/pdisk'
|
6
6
|
|
7
7
|
import PDisk from '../Pdisk'
|
8
8
|
|
@@ -25,6 +25,7 @@ import {
|
|
25
25
|
StorageTypes,
|
26
26
|
setStorageType,
|
27
27
|
setNodesUptimeFilter,
|
28
|
+
setDataWasNotLoaded,
|
28
29
|
VisibleEntitiesTitles,
|
29
30
|
getStoragePoolsGroupsCount,
|
30
31
|
getStorageNodesCount,
|
@@ -71,6 +72,7 @@ class Storage extends React.Component {
|
|
71
72
|
nodeId: PropTypes.string,
|
72
73
|
nodesUptimeFilter: PropTypes.string,
|
73
74
|
setNodesUptimeFilter: PropTypes.func,
|
75
|
+
setDataWasNotLoaded: PropTypes.func,
|
74
76
|
};
|
75
77
|
|
76
78
|
componentDidMount() {
|
@@ -106,7 +108,8 @@ class Storage extends React.Component {
|
|
106
108
|
}
|
107
109
|
|
108
110
|
componentDidUpdate(prevProps) {
|
109
|
-
const {visibleEntities, storageType, autorefresh, database} =
|
111
|
+
const {visibleEntities, storageType, autorefresh, database, tenant, setDataWasNotLoaded} =
|
112
|
+
this.props;
|
110
113
|
|
111
114
|
const startFetch = () => {
|
112
115
|
this.getStorageInfo({
|
@@ -144,6 +147,12 @@ class Storage extends React.Component {
|
|
144
147
|
restartAutorefresh();
|
145
148
|
}
|
146
149
|
}
|
150
|
+
|
151
|
+
if (tenant !== prevProps.tenant) {
|
152
|
+
setDataWasNotLoaded();
|
153
|
+
startFetch();
|
154
|
+
restartAutorefresh();
|
155
|
+
}
|
147
156
|
}
|
148
157
|
|
149
158
|
componentWillUnmount() {
|
@@ -367,6 +376,7 @@ const mapDispatchToProps = {
|
|
367
376
|
getNodesList,
|
368
377
|
setStorageType,
|
369
378
|
setHeader,
|
379
|
+
setDataWasNotLoaded,
|
370
380
|
};
|
371
381
|
|
372
382
|
export default connect(mapStateToProps, mapDispatchToProps)(Storage);
|
@@ -9,7 +9,7 @@ import {Stack} from '../../../components/Stack/Stack';
|
|
9
9
|
//@ts-ignore
|
10
10
|
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
11
11
|
|
12
|
-
import {TVDiskStateInfo} from '../../../types/api/
|
12
|
+
import {TVDiskStateInfo} from '../../../types/api/vdisk';
|
13
13
|
//@ts-ignore
|
14
14
|
import {VisibleEntities} from '../../../store/reducers/storage';
|
15
15
|
//@ts-ignore
|
@@ -92,7 +92,13 @@ function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder
|
|
92
92
|
}
|
93
93
|
}
|
94
94
|
|
95
|
-
function StorageGroups({
|
95
|
+
function StorageGroups({
|
96
|
+
data,
|
97
|
+
tableSettings,
|
98
|
+
visibleEntities,
|
99
|
+
nodes,
|
100
|
+
onShowAll,
|
101
|
+
}: StorageGroupsProps) {
|
96
102
|
const allColumns: Column<any>[] = [
|
97
103
|
{
|
98
104
|
name: TableColumnsIds.PoolName,
|
@@ -123,7 +129,7 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
123
129
|
header: tableColumnsNames[TableColumnsIds.Type],
|
124
130
|
render: ({value, row}) => (
|
125
131
|
<>
|
126
|
-
<Label>{value as string || '—'}</Label>
|
132
|
+
<Label>{(value as string) || '—'}</Label>
|
127
133
|
{' '}
|
128
134
|
{row.Encryption && (
|
129
135
|
<Popover
|
@@ -143,9 +149,8 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
143
149
|
name: TableColumnsIds.Missing,
|
144
150
|
header: tableColumnsNames[TableColumnsIds.Missing],
|
145
151
|
width: 100,
|
146
|
-
render: ({value, row}) =>
|
147
|
-
<Label theme={getDegradedSeverity(row)}>Degraded: {value}</Label>
|
148
|
-
) : '-',
|
152
|
+
render: ({value, row}) =>
|
153
|
+
value ? <Label theme={getDegradedSeverity(row)}>Degraded: {value}</Label> : '-',
|
149
154
|
align: DataTable.LEFT,
|
150
155
|
defaultOrder: DataTable.DESCENDING,
|
151
156
|
},
|
@@ -164,10 +169,12 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
164
169
|
>
|
165
170
|
{usage}%
|
166
171
|
</Label>
|
167
|
-
) :
|
172
|
+
) : (
|
173
|
+
'-'
|
174
|
+
);
|
168
175
|
},
|
169
176
|
// without a limit exclude usage from sort to display at the bottom
|
170
|
-
sortAccessor: (row) => row.Limit ? getUsage(row) : null,
|
177
|
+
sortAccessor: (row) => (row.Limit ? getUsage(row) : null),
|
171
178
|
align: DataTable.LEFT,
|
172
179
|
},
|
173
180
|
{
|
@@ -241,35 +248,35 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
241
248
|
render: ({value, row}) => (
|
242
249
|
<div className={b('vdisks-wrapper')}>
|
243
250
|
{_.map(value as TVDiskStateInfo[], (el) => {
|
244
|
-
const donors = Array.isArray(el.Donors)
|
251
|
+
const donors = Array.isArray(el.Donors)
|
252
|
+
? el.Donors.filter(isFullDonorData)
|
253
|
+
: [];
|
245
254
|
|
246
|
-
return (
|
247
|
-
|
248
|
-
<
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
{donors.map((donor) => (
|
255
|
-
<Vdisk
|
256
|
-
{...donor}
|
257
|
-
// donor and acceptor are always in the same group
|
258
|
-
PoolName={row[TableColumnsIds.PoolName]}
|
259
|
-
nodes={nodes}
|
260
|
-
key={stringifyVdiskId(donor.VDiskId)}
|
261
|
-
/>
|
262
|
-
))}
|
263
|
-
</Stack>
|
264
|
-
) : (
|
265
|
-
<div className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
|
255
|
+
return donors.length > 0 ? (
|
256
|
+
<Stack className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
|
257
|
+
<Vdisk
|
258
|
+
{...el}
|
259
|
+
PoolName={row[TableColumnsIds.PoolName]}
|
260
|
+
nodes={nodes}
|
261
|
+
/>
|
262
|
+
{donors.map((donor) => (
|
266
263
|
<Vdisk
|
267
|
-
{...
|
264
|
+
{...donor}
|
265
|
+
// donor and acceptor are always in the same group
|
268
266
|
PoolName={row[TableColumnsIds.PoolName]}
|
269
267
|
nodes={nodes}
|
268
|
+
key={stringifyVdiskId(donor.VDiskId)}
|
270
269
|
/>
|
271
|
-
|
272
|
-
|
270
|
+
))}
|
271
|
+
</Stack>
|
272
|
+
) : (
|
273
|
+
<div className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
|
274
|
+
<Vdisk
|
275
|
+
{...el}
|
276
|
+
PoolName={row[TableColumnsIds.PoolName]}
|
277
|
+
nodes={nodes}
|
278
|
+
/>
|
279
|
+
</div>
|
273
280
|
);
|
274
281
|
})}
|
275
282
|
</div>
|
@@ -2,8 +2,6 @@ import React from 'react';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import PropTypes from 'prop-types';
|
4
4
|
import {connect} from 'react-redux';
|
5
|
-
import {withRouter} from 'react-router-dom';
|
6
|
-
import qs from 'qs';
|
7
5
|
|
8
6
|
import {Loader} from '@gravity-ui/uikit';
|
9
7
|
|
@@ -11,7 +9,7 @@ import NodesViewer from '../../../NodesViewer/NodesViewer';
|
|
11
9
|
|
12
10
|
import {backend} from '../../../../store';
|
13
11
|
import {hideTooltip, showTooltip} from '../../../../store/reducers/tooltip';
|
14
|
-
import {getNodes, clearNodes} from '../../../../store/reducers/nodes';
|
12
|
+
import {getNodes, clearNodes, setDataWasNotLoaded} from '../../../../store/reducers/nodes';
|
15
13
|
|
16
14
|
import './Compute.scss';
|
17
15
|
import {AutoFetcher} from '../../../../utils/autofetcher';
|
@@ -28,6 +26,7 @@ class Compute extends React.Component {
|
|
28
26
|
autorefresh: PropTypes.bool,
|
29
27
|
error: PropTypes.object,
|
30
28
|
wasLoaded: PropTypes.bool,
|
29
|
+
setDataWasNotLoaded: PropTypes.func,
|
31
30
|
getNodes: PropTypes.func,
|
32
31
|
hideTooltip: PropTypes.func,
|
33
32
|
showTooltip: PropTypes.func,
|
@@ -50,12 +49,25 @@ class Compute extends React.Component {
|
|
50
49
|
}
|
51
50
|
|
52
51
|
componentDidUpdate(prevProps) {
|
53
|
-
const {autorefresh, getNodes, tenantName} = this.props;
|
52
|
+
const {autorefresh, getNodes, setDataWasNotLoaded, tenantName} = this.props;
|
54
53
|
|
55
|
-
|
56
|
-
|
54
|
+
const restartAutorefresh = () => {
|
55
|
+
this.autofetcher.stop();
|
57
56
|
this.autofetcher.start();
|
58
57
|
this.autofetcher.fetch(() => getNodes(tenantName));
|
58
|
+
};
|
59
|
+
|
60
|
+
if (tenantName !== prevProps.tenantName) {
|
61
|
+
setDataWasNotLoaded();
|
62
|
+
getNodes(tenantName);
|
63
|
+
if (autorefresh) {
|
64
|
+
restartAutorefresh();
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
if (autorefresh && !prevProps.autorefresh) {
|
69
|
+
getNodes(tenantName);
|
70
|
+
restartAutorefresh();
|
59
71
|
}
|
60
72
|
if (!autorefresh && prevProps.autorefresh) {
|
61
73
|
this.autofetcher.stop();
|
@@ -103,15 +115,10 @@ class Compute extends React.Component {
|
|
103
115
|
function mapStateToProps(state, ownProps) {
|
104
116
|
const {data, loading, wasLoaded, error} = state.nodes;
|
105
117
|
const {autorefresh} = state.schema;
|
106
|
-
const {search} = ownProps.location;
|
107
|
-
const queryParams = qs.parse(search, {
|
108
|
-
ignoreQueryPrefix: true,
|
109
|
-
});
|
110
|
-
const {name: tenantName} = queryParams;
|
111
118
|
const nodes = (data && data.Tenants && data.Tenants[0] && data.Tenants[0].Nodes) || [];
|
112
119
|
return {
|
120
|
+
...ownProps,
|
113
121
|
nodes,
|
114
|
-
tenantName,
|
115
122
|
loading,
|
116
123
|
wasLoaded,
|
117
124
|
error,
|
@@ -124,8 +131,9 @@ const mapDispatchToProps = {
|
|
124
131
|
clearNodes,
|
125
132
|
hideTooltip,
|
126
133
|
showTooltip,
|
134
|
+
setDataWasNotLoaded,
|
127
135
|
};
|
128
136
|
|
129
137
|
const ConnectedCompute = connect(mapStateToProps, mapDispatchToProps)(Compute);
|
130
138
|
|
131
|
-
export default
|
139
|
+
export default ConnectedCompute;
|
@@ -4,7 +4,8 @@ import block from 'bem-cn-lite';
|
|
4
4
|
|
5
5
|
import DataTable, {Column} from '@yandex-cloud/react-data-table';
|
6
6
|
|
7
|
-
import {
|
7
|
+
import type {EPathType} from '../../../../types/api/schema';
|
8
|
+
import {Loader} from '../../../../components/Loader';
|
8
9
|
import {prepareQueryError} from '../../../../utils/query';
|
9
10
|
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
|
10
11
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
@@ -15,6 +16,9 @@ import {
|
|
15
16
|
setCurrentDescribePath,
|
16
17
|
setDataWasNotLoaded,
|
17
18
|
} from '../../../../store/reducers/describe';
|
19
|
+
import {selectSchemaMergedChildrenPaths} from '../../../../store/reducers/schema';
|
20
|
+
|
21
|
+
import {isCdcStreamEntityType} from '../../utils/schema';
|
18
22
|
|
19
23
|
import i18n from './i18n';
|
20
24
|
|
@@ -24,21 +28,33 @@ const b = block('ydb-consumers');
|
|
24
28
|
|
25
29
|
interface ConsumersProps {
|
26
30
|
path: string;
|
31
|
+
type?: EPathType;
|
27
32
|
}
|
28
33
|
|
29
|
-
export const Consumers = ({path}: ConsumersProps) => {
|
34
|
+
export const Consumers = ({path, type}: ConsumersProps) => {
|
30
35
|
const dispatch = useDispatch();
|
31
36
|
|
37
|
+
const isCdcStream = isCdcStreamEntityType(type);
|
38
|
+
|
39
|
+
const mergedChildrenPaths = useTypedSelector((state) =>
|
40
|
+
selectSchemaMergedChildrenPaths(state, path, type),
|
41
|
+
);
|
42
|
+
|
43
|
+
const dataPath = isCdcStream ? mergedChildrenPaths?.[0] : path;
|
44
|
+
|
32
45
|
const fetchData = useCallback(
|
33
46
|
(isBackground: boolean) => {
|
34
47
|
if (!isBackground) {
|
35
48
|
dispatch(setDataWasNotLoaded());
|
36
49
|
}
|
37
|
-
|
38
|
-
|
50
|
+
|
51
|
+
if (dataPath) {
|
52
|
+
dispatch(setCurrentDescribePath(dataPath));
|
53
|
+
dispatch(getDescribe({path: dataPath}));
|
54
|
+
}
|
39
55
|
},
|
40
56
|
|
41
|
-
[
|
57
|
+
[dispatch, dataPath],
|
42
58
|
);
|
43
59
|
|
44
60
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
@@ -46,7 +62,7 @@ export const Consumers = ({path}: ConsumersProps) => {
|
|
46
62
|
useAutofetcher(fetchData, [fetchData], autorefresh);
|
47
63
|
|
48
64
|
const {loading, wasLoaded, error} = useTypedSelector((state) => state.describe);
|
49
|
-
const consumers = useTypedSelector((state) => selectConsumers(state,
|
65
|
+
const consumers = useTypedSelector((state) => selectConsumers(state, dataPath));
|
50
66
|
|
51
67
|
const [consumersToRender, setConsumersToRender] = useState(consumers);
|
52
68
|
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import {useCallback} from 'react';
|
2
|
-
import {useDispatch} from 'react-redux';
|
1
|
+
import {useCallback, useEffect, useState} from 'react';
|
2
|
+
import {shallowEqual, useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
// @ts-ignore
|
5
5
|
import JSONTree from 'react-json-inspector';
|
@@ -13,7 +13,12 @@ import {
|
|
13
13
|
getDescribe,
|
14
14
|
setDataWasNotLoaded,
|
15
15
|
setCurrentDescribePath,
|
16
|
+
getDescribeBatched,
|
16
17
|
} from '../../../../store/reducers/describe';
|
18
|
+
import {selectSchemaMergedChildrenPaths} from '../../../../store/reducers/schema';
|
19
|
+
import type {EPathType} from '../../../../types/api/schema';
|
20
|
+
|
21
|
+
import {isEntityWithMergedImplementation} from '../../utils/schema';
|
17
22
|
|
18
23
|
import './Describe.scss';
|
19
24
|
|
@@ -23,17 +28,39 @@ const expandMap = new Map();
|
|
23
28
|
|
24
29
|
interface IDescribeProps {
|
25
30
|
tenant: string;
|
31
|
+
type?: EPathType;
|
26
32
|
}
|
27
33
|
|
28
|
-
const Describe = ({tenant}: IDescribeProps) => {
|
34
|
+
const Describe = ({tenant, type}: IDescribeProps) => {
|
29
35
|
const dispatch = useDispatch();
|
30
36
|
|
31
37
|
const {currentDescribe, error, loading, wasLoaded} = useTypedSelector(
|
32
38
|
(state) => state.describe,
|
33
39
|
);
|
34
40
|
|
41
|
+
const [preparedDescribeData, setPreparedDescribeData] = useState<Object>();
|
42
|
+
|
43
|
+
useEffect(() => {
|
44
|
+
if (currentDescribe) {
|
45
|
+
const paths = Object.keys(currentDescribe);
|
46
|
+
|
47
|
+
if (paths.length === 1) {
|
48
|
+
setPreparedDescribeData(currentDescribe[paths[0]]);
|
49
|
+
} else {
|
50
|
+
setPreparedDescribeData(currentDescribe);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}, [currentDescribe]);
|
54
|
+
|
35
55
|
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
36
56
|
|
57
|
+
const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
|
58
|
+
|
59
|
+
const mergedChildrenPaths = useTypedSelector(
|
60
|
+
(state) => selectSchemaMergedChildrenPaths(state, currentSchemaPath, type),
|
61
|
+
shallowEqual,
|
62
|
+
);
|
63
|
+
|
37
64
|
const fetchData = useCallback(
|
38
65
|
(isBackground: boolean) => {
|
39
66
|
if (!isBackground) {
|
@@ -41,16 +68,20 @@ const Describe = ({tenant}: IDescribeProps) => {
|
|
41
68
|
}
|
42
69
|
|
43
70
|
const path = currentSchemaPath || tenant;
|
44
|
-
|
45
71
|
dispatch(setCurrentDescribePath(path));
|
46
|
-
|
72
|
+
|
73
|
+
if (!isEntityWithMergedImpl) {
|
74
|
+
dispatch(getDescribe({path}));
|
75
|
+
} else if (mergedChildrenPaths) {
|
76
|
+
dispatch(getDescribeBatched([path, ...mergedChildrenPaths]));
|
77
|
+
}
|
47
78
|
},
|
48
|
-
[currentSchemaPath, tenant, dispatch],
|
79
|
+
[currentSchemaPath, tenant, mergedChildrenPaths, isEntityWithMergedImpl, dispatch],
|
49
80
|
);
|
50
81
|
|
51
82
|
useAutofetcher(fetchData, [fetchData], autorefresh);
|
52
83
|
|
53
|
-
if (loading && !wasLoaded) {
|
84
|
+
if ((loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths)) {
|
54
85
|
return <Loader size="m" />;
|
55
86
|
}
|
56
87
|
|
@@ -58,7 +89,7 @@ const Describe = ({tenant}: IDescribeProps) => {
|
|
58
89
|
return <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
|
59
90
|
}
|
60
91
|
|
61
|
-
if (!loading && !
|
92
|
+
if (!loading && !preparedDescribeData) {
|
62
93
|
return <div className={b('message-container')}>Empty</div>;
|
63
94
|
}
|
64
95
|
|
@@ -66,7 +97,7 @@ const Describe = ({tenant}: IDescribeProps) => {
|
|
66
97
|
<div className={b()}>
|
67
98
|
<div className={b('result')}>
|
68
99
|
<JSONTree
|
69
|
-
data={
|
100
|
+
data={preparedDescribeData}
|
70
101
|
className={b('tree')}
|
71
102
|
onClick={({path}: {path: string}) => {
|
72
103
|
const newValue = !(expandMap.get(path) || false);
|
@@ -38,6 +38,7 @@ import {GeneralPagesIds, DATABASE_PAGES, getPagesByType} from './DiagnosticsPage
|
|
38
38
|
//@ts-ignore
|
39
39
|
import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema';
|
40
40
|
import {setTopLevelTab, setDiagnosticsTab} from '../../../store/reducers/tenant';
|
41
|
+
import {isDatabaseEntityType} from '../utils/schema';
|
41
42
|
|
42
43
|
import './Diagnostics.scss';
|
43
44
|
|
@@ -66,17 +67,17 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
66
67
|
ignoreQueryPrefix: true,
|
67
68
|
});
|
68
69
|
|
69
|
-
const {name:
|
70
|
-
|
71
|
-
const
|
70
|
+
const {name: rootTenantName} = queryParams;
|
71
|
+
const tenantName = isDatabaseEntityType(props.type) ? currentSchemaPath : rootTenantName;
|
72
|
+
const isDatabase = isDatabaseEntityType(props.type) || currentSchemaPath === rootTenantName;
|
72
73
|
|
73
74
|
const pages = useMemo(() => {
|
74
|
-
if (
|
75
|
+
if (isDatabase) {
|
75
76
|
return DATABASE_PAGES;
|
76
77
|
}
|
77
78
|
|
78
79
|
return getPagesByType(props.type);
|
79
|
-
}, [props.type,
|
80
|
+
}, [props.type, isDatabase]);
|
80
81
|
|
81
82
|
const forwardToDiagnosticTab = (tab: GeneralPagesIds) => {
|
82
83
|
dispatch(setDiagnosticsTab(tab));
|
@@ -134,10 +135,15 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
134
135
|
return <TopShards path={tenantNameString} type={type} />;
|
135
136
|
}
|
136
137
|
case GeneralPagesIds.nodes: {
|
137
|
-
return
|
138
|
+
return (
|
139
|
+
<Compute
|
140
|
+
tenantName={tenantNameString}
|
141
|
+
additionalNodesInfo={props.additionalNodesInfo}
|
142
|
+
/>
|
143
|
+
);
|
138
144
|
}
|
139
145
|
case GeneralPagesIds.tablets: {
|
140
|
-
return <Tablets path={
|
146
|
+
return <Tablets path={currentSchemaPath} />;
|
141
147
|
}
|
142
148
|
case GeneralPagesIds.storage: {
|
143
149
|
return <Storage tenant={tenantNameString} database={true} />;
|
@@ -146,7 +152,7 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
146
152
|
return <Network path={tenantNameString} />;
|
147
153
|
}
|
148
154
|
case GeneralPagesIds.describe: {
|
149
|
-
return <Describe tenant={tenantNameString} />;
|
155
|
+
return <Describe tenant={tenantNameString} type={type} />;
|
150
156
|
}
|
151
157
|
case GeneralPagesIds.hotKeys: {
|
152
158
|
return <HotKeys type={type} />;
|
@@ -155,7 +161,7 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
155
161
|
return <Heatmap path={currentItem.Path} />;
|
156
162
|
}
|
157
163
|
case GeneralPagesIds.consumers: {
|
158
|
-
return <Consumers path={currentSchemaPath} />;
|
164
|
+
return <Consumers path={currentSchemaPath} type={type} />;
|
159
165
|
}
|
160
166
|
default: {
|
161
167
|
return <div>No data...</div>;
|
@@ -87,7 +87,7 @@ export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, descri
|
|
87
87
|
|
88
88
|
export const DIR_PAGES = [overview, topShards, describe];
|
89
89
|
|
90
|
-
export const CDC_STREAM_PAGES = [overview, describe];
|
90
|
+
export const CDC_STREAM_PAGES = [overview, consumers, describe];
|
91
91
|
export const TOPIC_PAGES = [overview, consumers, describe];
|
92
92
|
|
93
93
|
// verbose mapping to guarantee correct tabs for new path types
|