ydb-embedded-ui 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/assets/icons/shield.svg +3 -0
- package/dist/components/Errors/403/AccessDenied.tsx +19 -0
- package/dist/components/Errors/403/index.ts +1 -0
- package/dist/components/Errors/i18n/en.json +4 -0
- package/dist/components/Errors/i18n/index.ts +11 -0
- package/dist/components/Errors/i18n/ru.json +4 -0
- package/dist/components/NodesViewer/NodesViewer.js +1 -1
- package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
- package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
- package/dist/components/Search/index.ts +1 -0
- package/dist/containers/App/App.scss +5 -1
- package/dist/containers/Nodes/Nodes.js +6 -1
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
- package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
- package/dist/containers/Storage/Storage.js +39 -50
- package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
- package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
- package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
- package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
- package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
- package/dist/containers/TabletsFilters/TabletsFilters.js +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +29 -11
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
- package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
- package/dist/containers/Tenant/Preview/Preview.scss +6 -0
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
- package/dist/containers/Tenant/Tenant.tsx +14 -16
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/store/reducers/describe.ts +71 -0
- package/dist/store/reducers/healthcheckInfo.ts +123 -0
- package/dist/store/reducers/olapStats.js +13 -0
- package/dist/store/reducers/schema.js +43 -1
- package/dist/store/reducers/storage.js +27 -17
- package/dist/store/reducers/tenant.js +3 -1
- package/dist/store/utils.ts +21 -13
- package/dist/styles/mixins.scss +1 -1
- package/dist/types/api/consumers.ts +3 -0
- package/dist/types/api/healthcheck.ts +1 -1
- package/dist/types/api/storage.ts +35 -10
- package/dist/types/store/healthcheck.ts +5 -1
- package/dist/types/store/storage.ts +1 -0
- package/dist/utils/hooks/useAutofetcher.ts +9 -3
- package/package.json +1 -1
- package/dist/containers/Storage/StorageFilter/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
- package/dist/store/reducers/describe.js +0 -45
- package/dist/store/reducers/healthcheckInfo.js +0 -45
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
|
3
3
|
import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
|
|
4
|
-
import {Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
|
4
|
+
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
|
5
|
+
|
|
6
|
+
import shieldIcon from '../../../assets/icons/shield.svg';
|
|
5
7
|
|
|
6
8
|
import {Stack} from '../../../components/Stack/Stack';
|
|
7
9
|
//@ts-ignore
|
|
@@ -25,6 +27,7 @@ import './StorageGroups.scss';
|
|
|
25
27
|
|
|
26
28
|
enum TableColumnsIds {
|
|
27
29
|
PoolName = 'PoolName',
|
|
30
|
+
Type = 'Type',
|
|
28
31
|
GroupID = 'GroupID',
|
|
29
32
|
Used = 'Used',
|
|
30
33
|
Limit = 'Limit',
|
|
@@ -49,6 +52,7 @@ interface StorageGroupsProps {
|
|
|
49
52
|
|
|
50
53
|
const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
|
|
51
54
|
PoolName: 'Pool Name',
|
|
55
|
+
Type: 'Type',
|
|
52
56
|
GroupID: 'Group ID',
|
|
53
57
|
Used: 'Used',
|
|
54
58
|
Limit: 'Limit',
|
|
@@ -100,7 +104,7 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
|
100
104
|
<div className={b('pool-name-wrapper')}>
|
|
101
105
|
{splitted && (
|
|
102
106
|
<Popover
|
|
103
|
-
content={
|
|
107
|
+
content={value as string}
|
|
104
108
|
placement={['right']}
|
|
105
109
|
behavior={PopoverBehavior.Immediate}
|
|
106
110
|
>
|
|
@@ -114,6 +118,27 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
|
|
|
114
118
|
},
|
|
115
119
|
align: DataTable.LEFT,
|
|
116
120
|
},
|
|
121
|
+
{
|
|
122
|
+
name: TableColumnsIds.Type,
|
|
123
|
+
header: tableColumnsNames[TableColumnsIds.Type],
|
|
124
|
+
render: ({value, row}) => (
|
|
125
|
+
<>
|
|
126
|
+
<Label>{value as string || '—'}</Label>
|
|
127
|
+
{' '}
|
|
128
|
+
{row.Encryption && (
|
|
129
|
+
<Popover
|
|
130
|
+
content={i18n('encrypted')}
|
|
131
|
+
placement="right"
|
|
132
|
+
behavior={PopoverBehavior.Immediate}
|
|
133
|
+
>
|
|
134
|
+
<Label>
|
|
135
|
+
<Icon data={shieldIcon} />
|
|
136
|
+
</Label>
|
|
137
|
+
</Popover>
|
|
138
|
+
)}
|
|
139
|
+
</>
|
|
140
|
+
),
|
|
141
|
+
},
|
|
117
142
|
{
|
|
118
143
|
name: TableColumnsIds.Missing,
|
|
119
144
|
header: tableColumnsNames[TableColumnsIds.Missing],
|
|
@@ -7,27 +7,29 @@
|
|
|
7
7
|
|
|
8
8
|
min-width: 500px;
|
|
9
9
|
}
|
|
10
|
-
&
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
&__pdisks-item {
|
|
11
|
+
flex-grow: 1;
|
|
12
|
+
|
|
13
|
+
max-width: 200px;
|
|
14
|
+
margin-right: 10px;
|
|
15
|
+
|
|
16
|
+
&:last-child {
|
|
17
|
+
margin-right: 0px;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
&__fqdn-wrapper {
|
|
21
|
+
width: 330px;
|
|
13
22
|
}
|
|
14
|
-
&
|
|
23
|
+
&__fqdn {
|
|
15
24
|
display: inline-block;
|
|
16
25
|
overflow: hidden;
|
|
17
26
|
|
|
18
|
-
width: 330px;
|
|
19
27
|
max-width: 330px;
|
|
20
28
|
|
|
29
|
+
vertical-align: top;
|
|
21
30
|
text-overflow: ellipsis;
|
|
22
31
|
}
|
|
23
32
|
&__group-id {
|
|
24
33
|
font-weight: 500;
|
|
25
34
|
}
|
|
26
|
-
&__tooltip-wrapper {
|
|
27
|
-
display: flex;
|
|
28
|
-
align-items: center;
|
|
29
|
-
}
|
|
30
|
-
&__tooltip {
|
|
31
|
-
word-break: break-all;
|
|
32
|
-
}
|
|
33
35
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
|
3
|
+
|
|
3
4
|
import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
|
|
4
5
|
import {Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
|
5
6
|
|
|
6
|
-
//@ts-ignore
|
|
7
7
|
import {VisibleEntities} from '../../../store/reducers/storage';
|
|
8
8
|
|
|
9
9
|
import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
|
|
@@ -75,13 +75,13 @@ function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: Storage
|
|
|
75
75
|
width: 350,
|
|
76
76
|
render: ({value}) => {
|
|
77
77
|
return (
|
|
78
|
-
<div className={b('
|
|
78
|
+
<div className={b('fqdn-wrapper')}>
|
|
79
79
|
<Popover
|
|
80
|
-
content={
|
|
80
|
+
content={value as string}
|
|
81
81
|
placement={['right']}
|
|
82
82
|
behavior={PopoverBehavior.Immediate}
|
|
83
83
|
>
|
|
84
|
-
<span className={b('
|
|
84
|
+
<span className={b('fqdn')}>{value as string}</span>
|
|
85
85
|
</Popover>
|
|
86
86
|
</div>
|
|
87
87
|
);
|
|
@@ -108,7 +108,9 @@ function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: Storage
|
|
|
108
108
|
render: ({value, row}) => (
|
|
109
109
|
<div className={b('pdisks-wrapper')}>
|
|
110
110
|
{_.map(value as any, (el) => (
|
|
111
|
-
<
|
|
111
|
+
<div className={b('pdisks-item')}>
|
|
112
|
+
<Pdisk key={el.PDiskId} {...el} NodeId={row.NodeId} />
|
|
113
|
+
</div>
|
|
112
114
|
))}
|
|
113
115
|
</div>
|
|
114
116
|
),
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import React, {useEffect, useState, useRef, useMemo} from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import cn from 'bem-cn-lite';
|
|
4
|
+
|
|
4
5
|
import {Label, Popup} from '@gravity-ui/uikit';
|
|
5
6
|
|
|
6
|
-
import
|
|
7
|
+
import InternalLink from '../../../components/InternalLink/InternalLink';
|
|
8
|
+
import {InfoViewer} from '../../../components/InfoViewer';
|
|
9
|
+
|
|
7
10
|
import routes, {createHref} from '../../../routes';
|
|
8
11
|
import {stringifyVdiskId, getPDiskId} from '../../../utils';
|
|
9
12
|
import {getPDiskType} from '../../../utils/pdisk';
|
|
10
|
-
import {
|
|
13
|
+
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
|
|
14
|
+
|
|
15
|
+
import {STRUCTURE} from '../../Node/NodePages';
|
|
16
|
+
|
|
11
17
|
import DiskStateProgressBar, {
|
|
12
18
|
diskProgressColors,
|
|
13
19
|
} from '../DiskStateProgressBar/DiskStateProgressBar';
|
|
14
|
-
import {STRUCTURE} from '../../Node/NodePages';
|
|
15
20
|
|
|
16
21
|
import {colorSeverity, NOT_AVAILABLE_SEVERITY} from '../utils';
|
|
17
22
|
|
|
@@ -225,33 +230,41 @@ function Vdisk(props) {
|
|
|
225
230
|
const available = AvailableSize ? AvailableSize : PDisk?.AvailableSize;
|
|
226
231
|
|
|
227
232
|
if (!available) {
|
|
228
|
-
return;
|
|
233
|
+
return undefined;
|
|
229
234
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
235
|
+
|
|
236
|
+
return isNaN(Number(AllocatedSize))
|
|
237
|
+
? undefined
|
|
238
|
+
: (Number(AllocatedSize) * 100) / (Number(available) + Number(AllocatedSize));
|
|
233
239
|
}, [props.AllocatedSize, props.AvailableSize, props.PDisk?.AvailableSize]);
|
|
234
240
|
|
|
235
241
|
return (
|
|
236
242
|
<React.Fragment>
|
|
237
243
|
{renderPopup()}
|
|
238
244
|
<div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
245
|
+
{props.NodeId ? (
|
|
246
|
+
<InternalLink
|
|
247
|
+
to={createHref(
|
|
248
|
+
routes.node,
|
|
249
|
+
{id: props.NodeId, activeTab: STRUCTURE},
|
|
250
|
+
{
|
|
251
|
+
pdiskId: props.PDisk?.PDiskId,
|
|
252
|
+
vdiskId: stringifyVdiskId(props.VDiskId),
|
|
253
|
+
},
|
|
254
|
+
)}
|
|
255
|
+
className={b('content')}
|
|
256
|
+
>
|
|
257
|
+
<DiskStateProgressBar
|
|
258
|
+
diskAllocatedPercent={vdiskAllocatedPercent}
|
|
259
|
+
severity={severity}
|
|
260
|
+
/>
|
|
261
|
+
</InternalLink>
|
|
262
|
+
) : (
|
|
263
|
+
<DiskStateProgressBar
|
|
264
|
+
diskAllocatedPercent={vdiskAllocatedPercent}
|
|
265
|
+
severity={severity}
|
|
266
|
+
/>
|
|
267
|
+
)}
|
|
255
268
|
</div>
|
|
256
269
|
</React.Fragment>
|
|
257
270
|
);
|
|
@@ -9,6 +9,7 @@ import {Loader, Select} from '@gravity-ui/uikit';
|
|
|
9
9
|
import ReactList from 'react-list';
|
|
10
10
|
|
|
11
11
|
import Tablet from '../../components/Tablet/Tablet';
|
|
12
|
+
import {AccessDenied} from '../../components/Errors/403';
|
|
12
13
|
|
|
13
14
|
import {TABLET_COLOR_TO_STATES, TABLETS_STATES} from '../../utils/constants';
|
|
14
15
|
import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
|
|
@@ -212,6 +213,10 @@ class TabletsFilters extends React.Component {
|
|
|
212
213
|
if (loading && !wasLoaded) {
|
|
213
214
|
return TabletsFilters.renderLoader();
|
|
214
215
|
} else if (error && typeof error === 'object') {
|
|
216
|
+
if (error.status === 403) {
|
|
217
|
+
return <AccessDenied />;
|
|
218
|
+
}
|
|
219
|
+
|
|
215
220
|
return <div>{error.statusText}</div>;
|
|
216
221
|
} else {
|
|
217
222
|
return this.renderContent();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {useEffect, useState} from 'react';
|
|
2
|
+
import {useDispatch, useSelector} from 'react-redux';
|
|
3
|
+
import block from 'bem-cn-lite';
|
|
4
|
+
|
|
5
|
+
import DataTable, {Column} from '@yandex-cloud/react-data-table';
|
|
6
|
+
|
|
7
|
+
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
|
|
8
|
+
import {useAutofetcher} from '../../../../utils/hooks';
|
|
9
|
+
import {Search} from '../../../../components/Search';
|
|
10
|
+
import {getDescribe, selectConsumers} from '../../../../store/reducers/describe';
|
|
11
|
+
|
|
12
|
+
import i18n from './i18n';
|
|
13
|
+
|
|
14
|
+
import './Consumers.scss';
|
|
15
|
+
|
|
16
|
+
const b = block('ydb-consumers');
|
|
17
|
+
|
|
18
|
+
interface ConsumersProps {
|
|
19
|
+
path: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const Consumers = ({path}: ConsumersProps) => {
|
|
23
|
+
const dispath = useDispatch();
|
|
24
|
+
|
|
25
|
+
const fetchData = () => {
|
|
26
|
+
dispath(getDescribe({path}));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
useAutofetcher(fetchData, [path]);
|
|
30
|
+
|
|
31
|
+
const consumers = useSelector((state) => selectConsumers(state, path));
|
|
32
|
+
|
|
33
|
+
const [consumersToRender, setConsumersToRender] = useState(consumers);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
setConsumersToRender(consumers);
|
|
37
|
+
}, [consumers]);
|
|
38
|
+
|
|
39
|
+
const filterConsumersByName = (search: string) => {
|
|
40
|
+
const filteredConsumers = search
|
|
41
|
+
? consumers.filter((consumer) => {
|
|
42
|
+
const re = new RegExp(search, 'i');
|
|
43
|
+
return re.test(consumer.name);
|
|
44
|
+
})
|
|
45
|
+
: consumers;
|
|
46
|
+
|
|
47
|
+
setConsumersToRender(filteredConsumers);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleSearch = (value: string) => {
|
|
51
|
+
filterConsumersByName(value);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const columns: Column<any>[] = [
|
|
55
|
+
{
|
|
56
|
+
name: 'name',
|
|
57
|
+
header: i18n('table.columns.consumerName'),
|
|
58
|
+
width: 200,
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
if (consumers.length === 0) {
|
|
63
|
+
return <div>{i18n('noConsumersMessage')}</div>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className={b()}>
|
|
68
|
+
<Search
|
|
69
|
+
onChange={handleSearch}
|
|
70
|
+
placeholder={i18n('search.placeholder')}
|
|
71
|
+
className={b('search')}
|
|
72
|
+
/>
|
|
73
|
+
<DataTable
|
|
74
|
+
theme="yandex-cloud"
|
|
75
|
+
settings={DEFAULT_TABLE_SETTINGS}
|
|
76
|
+
columns={columns}
|
|
77
|
+
data={consumersToRender}
|
|
78
|
+
emptyDataMessage={i18n('table.emptyDataMessage')}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {i18n, Lang} from '../../../../../utils/i18n';
|
|
2
|
+
|
|
3
|
+
import en from './en.json';
|
|
4
|
+
import ru from './ru.json';
|
|
5
|
+
|
|
6
|
+
const COMPONENT = 'ydb-diagnostics-consumers';
|
|
7
|
+
|
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
|
10
|
+
|
|
11
|
+
export default i18n.keyset(COMPONENT);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Consumers';
|
|
@@ -5,7 +5,7 @@ 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 {Switch, Tabs} from '@gravity-ui/uikit';
|
|
8
|
+
import {Loader, Switch, Tabs} from '@gravity-ui/uikit';
|
|
9
9
|
|
|
10
10
|
//@ts-ignore
|
|
11
11
|
import TopQueries from './TopQueries/TopQueries';
|
|
@@ -27,6 +27,7 @@ import Heatmap from '../../Heatmap/Heatmap';
|
|
|
27
27
|
import Compute from './Compute/Compute';
|
|
28
28
|
//@ts-ignore
|
|
29
29
|
import Tablets from '../../Tablets/Tablets';
|
|
30
|
+
import {Consumers} from './Consumers';
|
|
30
31
|
|
|
31
32
|
import routes, {createHref} from '../../../routes';
|
|
32
33
|
import type {EPathType} from '../../../types/api/schema';
|
|
@@ -53,9 +54,9 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
|
53
54
|
currentSchema: currentItem = {},
|
|
54
55
|
autorefresh,
|
|
55
56
|
} = useSelector((state: any) => state.schema);
|
|
56
|
-
const {
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const {diagnosticsTab = GeneralPagesIds.overview, wasLoaded} = useSelector(
|
|
58
|
+
(state: any) => state.tenant,
|
|
59
|
+
);
|
|
59
60
|
|
|
60
61
|
const location = useLocation();
|
|
61
62
|
|
|
@@ -79,14 +80,17 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
|
79
80
|
dispatch(setDiagnosticsTab(tab));
|
|
80
81
|
};
|
|
81
82
|
const activeTab = useMemo(() => {
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
if (wasLoaded) {
|
|
84
|
+
if (pages.find((el) => el.id === diagnosticsTab)) {
|
|
85
|
+
return diagnosticsTab;
|
|
86
|
+
} else {
|
|
87
|
+
const newPage = pages[0].id;
|
|
88
|
+
forwardToDiagnosticTab(newPage);
|
|
89
|
+
return newPage;
|
|
90
|
+
}
|
|
88
91
|
}
|
|
89
|
-
|
|
92
|
+
return undefined;
|
|
93
|
+
}, [pages, diagnosticsTab, wasLoaded]);
|
|
90
94
|
|
|
91
95
|
const onAutorefreshToggle = (value: boolean) => {
|
|
92
96
|
if (value) {
|
|
@@ -148,6 +152,9 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
|
148
152
|
case GeneralPagesIds.graph: {
|
|
149
153
|
return <Heatmap path={currentItem.Path} />;
|
|
150
154
|
}
|
|
155
|
+
case GeneralPagesIds.consumers: {
|
|
156
|
+
return <Consumers path={currentItem.Path} />;
|
|
157
|
+
}
|
|
151
158
|
default: {
|
|
152
159
|
return <div>No data...</div>;
|
|
153
160
|
}
|
|
@@ -185,6 +192,17 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
|
185
192
|
);
|
|
186
193
|
};
|
|
187
194
|
|
|
195
|
+
// Loader prevents incorrect loading of tabs
|
|
196
|
+
// After tabs are initially loaded it is no longer needed
|
|
197
|
+
// Thus there is no also "loading" check as in other parts of the project
|
|
198
|
+
if (!wasLoaded) {
|
|
199
|
+
return (
|
|
200
|
+
<div className={b('loader')}>
|
|
201
|
+
<Loader size="l" />
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
188
206
|
return (
|
|
189
207
|
<div className={b()}>
|
|
190
208
|
{renderTabs()}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {EPathType} from
|
|
1
|
+
import {EPathType} from '../../../types/api/schema';
|
|
2
2
|
|
|
3
3
|
export enum GeneralPagesIds {
|
|
4
4
|
'overview' = 'Overview',
|
|
@@ -11,11 +11,12 @@ export enum GeneralPagesIds {
|
|
|
11
11
|
'describe' = 'Describe',
|
|
12
12
|
'hotKeys' = 'hotKeys',
|
|
13
13
|
'graph' = 'graph',
|
|
14
|
+
'consumers' = 'consumers',
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
type Page = {
|
|
17
|
-
id: GeneralPagesIds
|
|
18
|
-
title: string
|
|
18
|
+
id: GeneralPagesIds;
|
|
19
|
+
title: string;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const overview = {
|
|
@@ -66,6 +67,11 @@ const graph = {
|
|
|
66
67
|
title: 'Graph',
|
|
67
68
|
};
|
|
68
69
|
|
|
70
|
+
const consumers = {
|
|
71
|
+
id: GeneralPagesIds.consumers,
|
|
72
|
+
title: 'Consumers',
|
|
73
|
+
};
|
|
74
|
+
|
|
69
75
|
export const DATABASE_PAGES = [
|
|
70
76
|
overview,
|
|
71
77
|
topQueries,
|
|
@@ -81,7 +87,8 @@ export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, descri
|
|
|
81
87
|
|
|
82
88
|
export const DIR_PAGES = [overview, topShards, describe];
|
|
83
89
|
|
|
84
|
-
export const
|
|
90
|
+
export const CDC_STREAM_PAGES = [overview, describe];
|
|
91
|
+
export const TOPIC_PAGES = [overview, consumers, describe];
|
|
85
92
|
|
|
86
93
|
// verbose mapping to guarantee correct tabs for new path types
|
|
87
94
|
// TS will error when a new type is added but not mapped here
|
|
@@ -97,10 +104,10 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
|
|
97
104
|
|
|
98
105
|
[EPathType.EPathTypeDir]: DIR_PAGES,
|
|
99
106
|
[EPathType.EPathTypeTableIndex]: DIR_PAGES,
|
|
100
|
-
|
|
101
|
-
[EPathType.EPathTypeCdcStream]:
|
|
107
|
+
|
|
108
|
+
[EPathType.EPathTypeCdcStream]: CDC_STREAM_PAGES,
|
|
109
|
+
|
|
102
110
|
[EPathType.EPathTypePersQueueGroup]: TOPIC_PAGES,
|
|
103
111
|
};
|
|
104
112
|
|
|
105
|
-
export const getPagesByType = (type?: EPathType) =>
|
|
106
|
-
(type && pathTypeToPages[type]) || DIR_PAGES;
|
|
113
|
+
export const getPagesByType = (type?: EPathType) => (type && pathTypeToPages[type]) || DIR_PAGES;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import cn from 'bem-cn-lite';
|
|
2
|
+
|
|
3
|
+
import {Button, Icon} from '@gravity-ui/uikit';
|
|
4
|
+
|
|
5
|
+
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
|
6
|
+
|
|
7
|
+
import type {IIssuesTree} from '../../../../../types/store/healthcheck';
|
|
8
|
+
|
|
9
|
+
import IssueTree from '../IssuesViewer/IssueTree';
|
|
10
|
+
|
|
11
|
+
import i18n from '../i18n';
|
|
12
|
+
|
|
13
|
+
const b = cn('healthcheck');
|
|
14
|
+
|
|
15
|
+
interface DetailsProps {
|
|
16
|
+
issueTree?: IIssuesTree;
|
|
17
|
+
loading?: boolean;
|
|
18
|
+
onUpdate: VoidFunction;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const Details = (props: DetailsProps) => {
|
|
22
|
+
const {loading, onUpdate, issueTree} = props;
|
|
23
|
+
|
|
24
|
+
if (!issueTree) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const renderHealthcheckHeader = () => {
|
|
29
|
+
return (
|
|
30
|
+
<div className={b('details-header')}>
|
|
31
|
+
<h3 className={b('details-header-title')}>{i18n('title.healthcheck')}</h3>
|
|
32
|
+
<div className={b('details-header-update')}>
|
|
33
|
+
<Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
|
|
34
|
+
<Icon data={updateArrow} height={20} width={20} />
|
|
35
|
+
</Button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const renderHealthcheckIssues = () => {
|
|
42
|
+
return (
|
|
43
|
+
<div className={b('issues-wrapper')}>
|
|
44
|
+
<IssueTree issueTree={issueTree} />
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className={b('details')}>
|
|
51
|
+
{renderHealthcheckHeader()}
|
|
52
|
+
{renderHealthcheckIssues()}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Details';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Thus we will get rid of unneeded layout shift when scrollbar appear
|
|
8
8
|
min-width: 885px;
|
|
9
9
|
|
|
10
|
-
&
|
|
10
|
+
&__details {
|
|
11
11
|
padding: 25px 20px 20px;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
margin-bottom: 15px;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
&__issues {
|
|
18
|
+
&__issues-wrapper {
|
|
19
19
|
overflow-x: hidden;
|
|
20
20
|
overflow-y: auto;
|
|
21
21
|
|
|
@@ -32,20 +32,20 @@
|
|
|
32
32
|
padding: 15px 0;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
&
|
|
35
|
+
&__details-header {
|
|
36
36
|
display: flex;
|
|
37
37
|
align-items: center;
|
|
38
38
|
|
|
39
39
|
margin-bottom: 20px;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
&
|
|
42
|
+
&__details-header-title {
|
|
43
43
|
margin: 0 10px 0 0;
|
|
44
44
|
|
|
45
45
|
@include text-header-1();
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
&
|
|
48
|
+
&__details-header-update {
|
|
49
49
|
margin-left: 10px;
|
|
50
50
|
}
|
|
51
51
|
|