ydb-embedded-ui 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +17 -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/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/Nodes/Nodes.js +5 -0
- package/dist/containers/Storage/Storage.js +11 -3
- 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.tsx +4 -0
- 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/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/Tenant.tsx +2 -7
- package/dist/store/reducers/describe.ts +71 -0
- package/dist/store/reducers/healthcheckInfo.ts +123 -0
- package/dist/store/reducers/schema.js +2 -2
- package/dist/store/reducers/storage.js +6 -6
- package/dist/store/utils.ts +21 -13
- package/dist/types/api/consumers.ts +3 -0
- package/dist/types/api/healthcheck.ts +1 -1
- package/dist/types/store/healthcheck.ts +5 -1
- 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
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.3.0...v2.4.0) (2022-10-27)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **Diagnostics:** add consumers tab for topics ([4bb801c](https://github.com/ydb-platform/ydb-embedded-ui/commit/4bb801c0ef19dcda227c59e464b08f5e8f284c38))
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* add checks for fetch failure with no errors ([2c55107](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c55107a7b47b3540ed0af66630ff85591f269a1))
|
14
|
+
* **Nodes:** display access denied on 403 ([7832afe](https://github.com/ydb-platform/ydb-embedded-ui/commit/7832afee601a40fc8b75f83bf0ed18b01c798d71))
|
15
|
+
* **QueryResult:** fix table display in fullscreen ([98674db](https://github.com/ydb-platform/ydb-embedded-ui/commit/98674db26b5fb09ac0d039a7779ae0c58951adde))
|
16
|
+
* **QueryResultTable:** make preview display all rows ([0ac83d0](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ac83d0258b0d0d3d2e14c06be096fe5ddce02da))
|
17
|
+
* **Storage:** display access denied on 403 ([6d20333](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d2033378956a54f05190905b0d537c6bd6c9851))
|
18
|
+
* **TabletsFilters:** display access denied on 403 ([018be19](https://github.com/ydb-platform/ydb-embedded-ui/commit/018be199602123f1d90e58c0b95545f6accc41fb))
|
19
|
+
|
3
20
|
## [2.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.1...v2.3.0) (2022-10-24)
|
4
21
|
|
5
22
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import EmptyState from '../../EmptyState/EmptyState';
|
2
|
+
import {Illustration} from '../../Illustration';
|
3
|
+
|
4
|
+
import i18n from '../i18n';
|
5
|
+
|
6
|
+
interface AccessDeniedProps {
|
7
|
+
title?: string;
|
8
|
+
description?: string;
|
9
|
+
}
|
10
|
+
|
11
|
+
export const AccessDenied = ({title, description}: AccessDeniedProps) => {
|
12
|
+
return (
|
13
|
+
<EmptyState
|
14
|
+
image={<Illustration name="403" />}
|
15
|
+
title={title || i18n('403.title')}
|
16
|
+
description={description || i18n('403.description')}
|
17
|
+
/>
|
18
|
+
);
|
19
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './AccessDenied';
|
@@ -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-errors-access-denied';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -17,6 +17,8 @@ import './QueryResultTable.scss';
|
|
17
17
|
const TABLE_SETTINGS: Settings = {
|
18
18
|
...DEFAULT_TABLE_SETTINGS,
|
19
19
|
stripedRows: true,
|
20
|
+
dynamicRenderType: 'variable',
|
21
|
+
dynamicItemSizeGetter: () => 40,
|
20
22
|
};
|
21
23
|
|
22
24
|
export const b = cn('ydb-query-result-table');
|
@@ -53,7 +55,7 @@ const prepareGenericColumns = (data: KeyValueRow[]) => {
|
|
53
55
|
const column: Column<KeyValueRow> = {
|
54
56
|
name,
|
55
57
|
align: isNumeric(data[0][name]) ? DataTable.RIGHT : DataTable.LEFT,
|
56
|
-
sortAccessor: (row) => isNumeric(row[name]) ? Number(row[name]) : row[name],
|
58
|
+
sortAccessor: (row) => (isNumeric(row[name]) ? Number(row[name]) : row[name]),
|
57
59
|
render: ({value}) => <Cell value={value as string} />,
|
58
60
|
};
|
59
61
|
|
@@ -61,31 +63,28 @@ const prepareGenericColumns = (data: KeyValueRow[]) => {
|
|
61
63
|
});
|
62
64
|
};
|
63
65
|
|
64
|
-
const getRowIndex = (_: unknown, index: number) => index
|
66
|
+
const getRowIndex = (_: unknown, index: number) => index;
|
65
67
|
|
66
|
-
interface QueryResultTableProps
|
68
|
+
interface QueryResultTableProps
|
69
|
+
extends Omit<DataTableProps<KeyValueRow>, 'data' | 'columns' | 'theme'> {
|
67
70
|
data?: KeyValueRow[];
|
68
71
|
columns?: ColumnType[];
|
69
72
|
}
|
70
73
|
|
71
74
|
export const QueryResultTable = (props: QueryResultTableProps) => {
|
72
|
-
const {
|
73
|
-
columns: rawColumns,
|
74
|
-
data: rawData,
|
75
|
-
settings: settingsMix,
|
76
|
-
...restProps
|
77
|
-
} = props;
|
75
|
+
const {columns: rawColumns, data: rawData, settings: settingsMix, ...restProps} = props;
|
78
76
|
|
79
77
|
const data = useMemo(() => prepareQueryResponse(rawData), [rawData]);
|
80
78
|
const columns = useMemo(() => {
|
81
|
-
return rawColumns ?
|
82
|
-
prepareTypedColumns(rawColumns) :
|
83
|
-
prepareGenericColumns(data);
|
79
|
+
return rawColumns ? prepareTypedColumns(rawColumns) : prepareGenericColumns(data);
|
84
80
|
}, [data, rawColumns]);
|
85
|
-
const settings = useMemo(
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
const settings = useMemo(
|
82
|
+
() => ({
|
83
|
+
...TABLE_SETTINGS,
|
84
|
+
...settingsMix,
|
85
|
+
}),
|
86
|
+
[settingsMix],
|
87
|
+
);
|
89
88
|
|
90
89
|
// empty data is expected to be be an empty array
|
91
90
|
// undefined data is not rendered at all
|
@@ -94,11 +93,7 @@ export const QueryResultTable = (props: QueryResultTableProps) => {
|
|
94
93
|
}
|
95
94
|
|
96
95
|
if (!columns.length) {
|
97
|
-
return (
|
98
|
-
<div className={b('message')}>
|
99
|
-
{i18n('empty')}
|
100
|
-
</div>
|
101
|
-
);
|
96
|
+
return <div className={b('message')}>{i18n('empty')}</div>;
|
102
97
|
}
|
103
98
|
|
104
99
|
return (
|
package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx}
RENAMED
@@ -1,28 +1,28 @@
|
|
1
|
-
import {
|
1
|
+
import {useRef, useEffect, useState} from 'react';
|
2
2
|
|
3
3
|
import {TextInput} from '@gravity-ui/uikit';
|
4
4
|
|
5
|
-
interface
|
6
|
-
|
5
|
+
interface SearchProps {
|
6
|
+
onChange: (value: string) => void;
|
7
7
|
value?: string;
|
8
|
-
|
9
|
-
onChange?: (value: string) => void;
|
8
|
+
className?: string;
|
10
9
|
debounce?: number;
|
10
|
+
placeholder?: string;
|
11
11
|
}
|
12
12
|
|
13
|
-
export const
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
export const Search = ({
|
14
|
+
onChange,
|
15
|
+
value = '',
|
16
|
+
className,
|
17
|
+
debounce = 200,
|
18
|
+
placeholder,
|
19
|
+
}: SearchProps) => {
|
20
|
+
const [searchValue, setSearchValue] = useState<string>(value);
|
21
|
+
|
22
22
|
const timer = useRef<number>();
|
23
23
|
|
24
24
|
useEffect(() => {
|
25
|
-
|
25
|
+
setSearchValue((prevValue) => {
|
26
26
|
if (prevValue !== value) {
|
27
27
|
return value;
|
28
28
|
}
|
@@ -31,8 +31,8 @@ export const StorageFilter = (props: StorageFilterProps) => {
|
|
31
31
|
});
|
32
32
|
}, [value]);
|
33
33
|
|
34
|
-
const
|
35
|
-
|
34
|
+
const onSearchValueChange = (newValue: string) => {
|
35
|
+
setSearchValue(newValue);
|
36
36
|
|
37
37
|
window.clearTimeout(timer.current);
|
38
38
|
timer.current = window.setTimeout(() => {
|
@@ -42,12 +42,12 @@ export const StorageFilter = (props: StorageFilterProps) => {
|
|
42
42
|
|
43
43
|
return (
|
44
44
|
<TextInput
|
45
|
-
className={className}
|
46
|
-
placeholder={placeholder}
|
47
|
-
value={filterValue}
|
48
|
-
onUpdate={changeFilter}
|
49
45
|
hasClear
|
50
46
|
autoFocus
|
47
|
+
className={className}
|
48
|
+
placeholder={placeholder}
|
49
|
+
value={searchValue}
|
50
|
+
onUpdate={onSearchValueChange}
|
51
51
|
/>
|
52
52
|
);
|
53
|
-
}
|
53
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './Search';
|
@@ -8,6 +8,7 @@ import {Loader, TextInput, Label} from '@gravity-ui/uikit';
|
|
8
8
|
|
9
9
|
import ProblemFilter, {problemFilterType} from '../../components/ProblemFilter/ProblemFilter';
|
10
10
|
import {Illustration} from '../../components/Illustration';
|
11
|
+
import {AccessDenied} from '../../components/Errors/403';
|
11
12
|
|
12
13
|
import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
|
13
14
|
import {withSearch} from '../../HOCS';
|
@@ -164,6 +165,10 @@ class Nodes extends React.Component {
|
|
164
165
|
if (loading && !wasLoaded) {
|
165
166
|
return Nodes.renderLoader();
|
166
167
|
} else if (error) {
|
168
|
+
if (error.status === 403) {
|
169
|
+
return <AccessDenied />;
|
170
|
+
}
|
171
|
+
|
167
172
|
return <div>{error.statusText}</div>;
|
168
173
|
} else {
|
169
174
|
return this.renderContent();
|
@@ -5,10 +5,11 @@ import cn from 'bem-cn-lite';
|
|
5
5
|
import DataTable from '@yandex-cloud/react-data-table';
|
6
6
|
import {RadioButton, Label} from '@gravity-ui/uikit';
|
7
7
|
|
8
|
-
import {
|
8
|
+
import {Search} from '../../components/Search';
|
9
9
|
import {UsageFilter} from './UsageFilter';
|
10
10
|
import {AutoFetcher} from '../../utils/autofetcher';
|
11
11
|
import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
|
12
|
+
import {AccessDenied} from '../../components/Errors/403';
|
12
13
|
|
13
14
|
import {
|
14
15
|
getStorageInfo,
|
@@ -236,7 +237,7 @@ class Storage extends React.Component {
|
|
236
237
|
return (
|
237
238
|
<div className={b('controls')}>
|
238
239
|
<div className={b('search')}>
|
239
|
-
<
|
240
|
+
<Search
|
240
241
|
placeholder={
|
241
242
|
storageType === StorageTypes.groups
|
242
243
|
? 'Group ID, Pool name'
|
@@ -287,10 +288,17 @@ class Storage extends React.Component {
|
|
287
288
|
const {loading, wasLoaded, error} = this.props;
|
288
289
|
const showLoader = loading && !wasLoaded;
|
289
290
|
|
291
|
+
if (error) {
|
292
|
+
if (error.status === 403) {
|
293
|
+
return <AccessDenied />;
|
294
|
+
}
|
295
|
+
|
296
|
+
return <div className={b()}>{error.statusText}</div>;
|
297
|
+
}
|
298
|
+
|
290
299
|
return (
|
291
300
|
<div className={b()}>
|
292
301
|
{this.renderControls()}
|
293
|
-
{error && <div>{error.statusText}</div>}
|
294
302
|
{showLoader ? this.renderLoader() : this.renderDataTable()}
|
295
303
|
</div>
|
296
304
|
);
|
@@ -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';
|
@@ -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';
|
@@ -151,6 +152,9 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
151
152
|
case GeneralPagesIds.graph: {
|
152
153
|
return <Heatmap path={currentItem.Path} />;
|
153
154
|
}
|
155
|
+
case GeneralPagesIds.consumers: {
|
156
|
+
return <Consumers path={currentItem.Path} />;
|
157
|
+
}
|
154
158
|
default: {
|
155
159
|
return <div>No data...</div>;
|
156
160
|
}
|
@@ -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
|
|
@@ -4,10 +4,15 @@ import cn from 'bem-cn-lite';
|
|
4
4
|
|
5
5
|
import {Loader} from '@gravity-ui/uikit';
|
6
6
|
|
7
|
-
import {
|
7
|
+
import {SelfCheckResult} from '../../../../types/api/healthcheck';
|
8
|
+
import {
|
9
|
+
getHealthcheckInfo,
|
10
|
+
selectIssuesTreeById,
|
11
|
+
selectIssuesTreesRoots,
|
12
|
+
} from '../../../../store/reducers/healthcheckInfo';
|
8
13
|
import {useAutofetcher} from '../../../../utils/hooks';
|
9
14
|
|
10
|
-
import {
|
15
|
+
import {Details} from './Details';
|
11
16
|
import {Preview} from './Preview';
|
12
17
|
|
13
18
|
import i18n from './i18n';
|
@@ -29,6 +34,11 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
29
34
|
const dispatch = useDispatch();
|
30
35
|
|
31
36
|
const {data, loading, wasLoaded, error} = useSelector((state: any) => state.healthcheckInfo);
|
37
|
+
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
38
|
+
|
39
|
+
const issuesTreesRoots = useSelector(selectIssuesTreesRoots);
|
40
|
+
const expandedIssueTree = useSelector((state) => selectIssuesTreeById(state, expandedIssueId));
|
41
|
+
|
32
42
|
const {autorefresh} = useSelector((state: any) => state.schema);
|
33
43
|
|
34
44
|
const fetchHealthcheck = useCallback(() => {
|
@@ -61,15 +71,15 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
61
71
|
if (data && data['self_check_result']) {
|
62
72
|
return preview ? (
|
63
73
|
<Preview
|
64
|
-
|
74
|
+
issuesTrees={issuesTreesRoots}
|
75
|
+
selfCheckResult={selfCheckResult}
|
65
76
|
loading={loading}
|
66
77
|
onShowMore={showMoreHandler}
|
67
78
|
onUpdate={fetchHealthcheck}
|
68
79
|
/>
|
69
80
|
) : (
|
70
|
-
<
|
71
|
-
|
72
|
-
expandedIssueId={expandedIssueId}
|
81
|
+
<Details
|
82
|
+
issueTree={expandedIssueTree}
|
73
83
|
loading={loading}
|
74
84
|
onUpdate={fetchHealthcheck}
|
75
85
|
/>
|