ydb-embedded-ui 2.3.0 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/components/Errors/403/AccessDenied.tsx +19 -0
  3. package/dist/components/Errors/403/index.ts +1 -0
  4. package/dist/components/Errors/i18n/en.json +4 -0
  5. package/dist/components/Errors/i18n/index.ts +11 -0
  6. package/dist/components/Errors/i18n/ru.json +4 -0
  7. package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
  8. package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
  9. package/dist/components/Search/index.ts +1 -0
  10. package/dist/containers/Nodes/Nodes.js +5 -0
  11. package/dist/containers/Storage/Storage.js +11 -3
  12. package/dist/containers/TabletsFilters/TabletsFilters.js +5 -0
  13. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
  14. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
  15. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
  16. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
  17. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
  18. package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
  19. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -0
  20. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
  21. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
  22. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
  23. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
  24. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
  25. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
  26. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
  27. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
  28. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
  29. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
  30. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
  31. package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
  32. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
  33. package/dist/containers/Tenant/Preview/Preview.scss +6 -0
  34. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
  35. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
  36. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +11 -7
  37. package/dist/containers/Tenant/Tenant.tsx +2 -7
  38. package/dist/store/reducers/describe.ts +71 -0
  39. package/dist/store/reducers/healthcheckInfo.ts +123 -0
  40. package/dist/store/reducers/schema.js +10 -13
  41. package/dist/store/reducers/storage.js +6 -6
  42. package/dist/store/utils.ts +21 -13
  43. package/dist/types/api/consumers.ts +3 -0
  44. package/dist/types/api/healthcheck.ts +1 -1
  45. package/dist/types/store/healthcheck.ts +5 -1
  46. package/package.json +1 -1
  47. package/dist/containers/Storage/StorageFilter/index.ts +0 -1
  48. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
  49. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
  50. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
  51. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
  52. package/dist/store/reducers/describe.js +0 -45
  53. 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,4 @@
1
+ {
2
+ "403.title": "Access denied",
3
+ "403.description": "You don’t have the necessary roles to view this page."
4
+ }
@@ -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);
@@ -0,0 +1,4 @@
1
+ {
2
+ "403.title": "Доступ запрещен",
3
+ "403.description": "У вас недостаточно прав для просмотра данной страницы."
4
+ }
@@ -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 extends Omit<DataTableProps<KeyValueRow>, 'data' | 'columns' | 'theme'> {
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
- ...TABLE_SETTINGS,
87
- ...settingsMix,
88
- }), [settingsMix]);
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 (
@@ -1,28 +1,28 @@
1
- import {useEffect, useRef, useState} from 'react';
1
+ import {useRef, useEffect, useState} from 'react';
2
2
 
3
3
  import {TextInput} from '@gravity-ui/uikit';
4
4
 
5
- interface StorageFilterProps {
6
- className?: string;
5
+ interface SearchProps {
6
+ onChange: (value: string) => void;
7
7
  value?: string;
8
- placeholder?: string;
9
- onChange?: (value: string) => void;
8
+ className?: string;
10
9
  debounce?: number;
10
+ placeholder?: string;
11
11
  }
12
12
 
13
- export const StorageFilter = (props: StorageFilterProps) => {
14
- const {
15
- className,
16
- value = '',
17
- placeholder,
18
- onChange,
19
- debounce = 200,
20
- } = props;
21
- const [filterValue, setFilterValue] = useState(value);
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
- setFilterValue((prevValue) => {
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 changeFilter = (newValue: string) => {
35
- setFilterValue(newValue);
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 {StorageFilter} from './StorageFilter';
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
- <StorageFilter
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,6 @@
1
+ .ydb-consumers {
2
+ &__search {
3
+ width: 200px;
4
+ margin-bottom: 20px;
5
+ }
6
+ }
@@ -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,6 @@
1
+ {
2
+ "search.placeholder": "Consumer name",
3
+ "table.emptyDataMessage": "No consumers match the current search",
4
+ "table.columns.consumerName": "Consumer",
5
+ "noConsumersMessage": "This topic has no consumers"
6
+ }
@@ -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,6 @@
1
+ {
2
+ "search.placeholder": "Название читателя",
3
+ "table.emptyDataMessage": "По заданному поиску нет читателей",
4
+ "table.columns.consumerName": "Читатель",
5
+ "noConsumersMessage": "У этого топика нет читателей"
6
+ }
@@ -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 "../../../types/api/schema";
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 TOPIC_PAGES = [overview, describe];
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]: TOPIC_PAGES,
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
- &__issues-list {
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
- &__issues-list-header {
35
+ &__details-header {
36
36
  display: flex;
37
37
  align-items: center;
38
38
 
39
39
  margin-bottom: 20px;
40
40
  }
41
41
 
42
- &__issues-list-header-title {
42
+ &__details-header-title {
43
43
  margin: 0 10px 0 0;
44
44
 
45
45
  @include text-header-1();
46
46
  }
47
47
 
48
- &__issues-list-header-update {
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 {getHealthcheckInfo} from '../../../../store/reducers/healthcheckInfo';
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 {IssuesList} from './IssuesList';
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
- data={data}
74
+ issuesTrees={issuesTreesRoots}
75
+ selfCheckResult={selfCheckResult}
65
76
  loading={loading}
66
77
  onShowMore={showMoreHandler}
67
78
  onUpdate={fetchHealthcheck}
68
79
  />
69
80
  ) : (
70
- <IssuesList
71
- data={data}
72
- expandedIssueId={expandedIssueId}
81
+ <Details
82
+ issueTree={expandedIssueTree}
73
83
  loading={loading}
74
84
  onUpdate={fetchHealthcheck}
75
85
  />