ydb-embedded-ui 2.5.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +40 -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 +3 -2
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,45 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.6.0...v3.0.0) (2022-12-05)
|
4
|
+
|
5
|
+
|
6
|
+
### ⚠ BREAKING CHANGES
|
7
|
+
|
8
|
+
Updated build config ([11e02c6](https://github.com/ydb-platform/ydb-embedded-ui/commit/11e02c668ef186f058b2ece9d5f1082d0e96e23d))
|
9
|
+
|
10
|
+
**Before the change**
|
11
|
+
- the target dir for the production build was `build/resources`
|
12
|
+
- `favicon.png` was placed directly in `build`
|
13
|
+
|
14
|
+
**After the change**
|
15
|
+
- the target dir is `build/static`
|
16
|
+
- `favicon.png` is in `build/static`
|
17
|
+
|
18
|
+
This change is intended to simplify build config and make it closer to the default one. Previously there were some custom tweaks after the build, they caused bugs and were hard to maintain. Now the application builds using the default `create-react-app` config.
|
19
|
+
|
20
|
+
|
21
|
+
## [2.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.5.0...v2.6.0) (2022-12-05)
|
22
|
+
|
23
|
+
|
24
|
+
### Features
|
25
|
+
|
26
|
+
* **Describe:** add topic data for CDCStream ([3a289d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/3a289d4f6452e3f2d719c0d508f48b389fd044d7))
|
27
|
+
* **Diagnostics:** add consumers tab for CdcStream ([22c6efd](https://github.com/ydb-platform/ydb-embedded-ui/commit/22c6efdd39d85ab1585943bc13d88cf03f9bc2ae))
|
28
|
+
* **Overview:** add topic data for CDCStream ([be80545](https://github.com/ydb-platform/ydb-embedded-ui/commit/be80545df65a03820265875fedd98c6f181af491))
|
29
|
+
|
30
|
+
|
31
|
+
### Bug Fixes
|
32
|
+
|
33
|
+
* **Compute:** update data on path change ([1783240](https://github.com/ydb-platform/ydb-embedded-ui/commit/17832403623ae3e718f47aec508c834cd2e3458c))
|
34
|
+
* **Diagnostics:** render db tabs for not root dbs ([7d46ce2](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d46ce2783a58b1ae6e41cae6592e78f95d61bcc))
|
35
|
+
* **Healthcheck:** render loader on path change ([ec40f19](https://github.com/ydb-platform/ydb-embedded-ui/commit/ec40f19c0b369de0b8d0658b4a1dd68c5c419c1c))
|
36
|
+
* **InfoViewer:** allow multiline values ([17755dc](https://github.com/ydb-platform/ydb-embedded-ui/commit/17755dc2eae7b6fc0a56ff70da95679fc590dccb))
|
37
|
+
* **Network:** update data on path change ([588c53f](https://github.com/ydb-platform/ydb-embedded-ui/commit/588c53f80a81376301216a77d9ead95cdff9812f))
|
38
|
+
* **SchemaTree:** do not expand childless components ([90468de](https://github.com/ydb-platform/ydb-embedded-ui/commit/90468de74b74e00a66255ba042378c9d7e1cbc27))
|
39
|
+
* **Storage:** update data on path change ([f5486bc](https://github.com/ydb-platform/ydb-embedded-ui/commit/f5486bcb2838b9e290c566089980533b4d22d035))
|
40
|
+
* **Tablets:** fix postponed data update on path change ([d474c6c](https://github.com/ydb-platform/ydb-embedded-ui/commit/d474c6cb36597f0c720ef3bb8d0360ec73973e26))
|
41
|
+
* **TopQueries:** update data on path change ([32d7720](https://github.com/ydb-platform/ydb-embedded-ui/commit/32d77208b8ef09682c41160c60a1a7742b0c6c4c))
|
42
|
+
|
3
43
|
## [2.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.4...v2.5.0) (2022-11-25)
|
4
44
|
|
5
45
|
|
@@ -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
|