ydb-embedded-ui 2.3.0 → 2.4.1
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 +24 -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/Schema/SchemaTree/SchemaTree.tsx +11 -7
- 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 +10 -13
- 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,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.0...v2.4.1) (2022-11-01)
|
4
|
+
|
5
|
+
|
6
|
+
### Performance Improvements
|
7
|
+
|
8
|
+
* **SchemaTree:** batch preloaded data dispatch ([c9ac514](https://github.com/ydb-platform/ydb-embedded-ui/commit/c9ac514aabf5e9674aae95956604f47ba8a2d257))
|
9
|
+
|
10
|
+
## [2.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.3.0...v2.4.0) (2022-10-27)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* **Diagnostics:** add consumers tab for topics ([4bb801c](https://github.com/ydb-platform/ydb-embedded-ui/commit/4bb801c0ef19dcda227c59e464b08f5e8f284c38))
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* add checks for fetch failure with no errors ([2c55107](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c55107a7b47b3540ed0af66630ff85591f269a1))
|
21
|
+
* **Nodes:** display access denied on 403 ([7832afe](https://github.com/ydb-platform/ydb-embedded-ui/commit/7832afee601a40fc8b75f83bf0ed18b01c798d71))
|
22
|
+
* **QueryResult:** fix table display in fullscreen ([98674db](https://github.com/ydb-platform/ydb-embedded-ui/commit/98674db26b5fb09ac0d039a7779ae0c58951adde))
|
23
|
+
* **QueryResultTable:** make preview display all rows ([0ac83d0](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ac83d0258b0d0d3d2e14c06be096fe5ddce02da))
|
24
|
+
* **Storage:** display access denied on 403 ([6d20333](https://github.com/ydb-platform/ydb-embedded-ui/commit/6d2033378956a54f05190905b0d537c6bd6c9851))
|
25
|
+
* **TabletsFilters:** display access denied on 403 ([018be19](https://github.com/ydb-platform/ydb-embedded-ui/commit/018be199602123f1d90e58c0b95545f6accc41fb))
|
26
|
+
|
3
27
|
## [2.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.1...v2.3.0) (2022-10-24)
|
4
28
|
|
5
29
|
|
@@ -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
|
/>
|