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.
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
  />