ydb-embedded-ui 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. package/dist/components/BasicNodeViewer/BasicNodeViewer.d.ts +2 -2
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.js +1 -1
  3. package/dist/components/EntityStatus/EntityStatus.scss +1 -1
  4. package/dist/components/FullNodeViewer/FullNodeViewer.d.ts +2 -2
  5. package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
  6. package/dist/components/LagImages/LagImages.js +2 -2
  7. package/dist/components/ProgressViewer/ProgressViewer.js +6 -5
  8. package/dist/components/ProgressViewer/ProgressViewer.scss +33 -17
  9. package/dist/components/TabletsOverall/TabletsOverall.js +6 -6
  10. package/dist/containers/App/App.js +2 -1
  11. package/dist/containers/App/Content.js +6 -12
  12. package/dist/containers/App/Providers.js +2 -1
  13. package/dist/containers/App/appSlots.d.ts +7 -7
  14. package/dist/containers/AppIcons/AppIcons.js +1 -1
  15. package/dist/containers/Cluster/Cluster.js +45 -27
  16. package/dist/containers/Cluster/Cluster.scss +15 -0
  17. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +4 -18
  18. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +0 -40
  19. package/dist/containers/Cluster/utils.d.ts +6 -1
  20. package/dist/containers/Cluster/utils.js +11 -3
  21. package/dist/containers/Clusters/Clusters.js +4 -3
  22. package/dist/containers/Clusters/columns.js +1 -1
  23. package/dist/containers/Clusters/constants.d.ts +1 -1
  24. package/dist/containers/Clusters/i18n/en.json +2 -1
  25. package/dist/containers/Clusters/i18n/index.d.ts +1 -1
  26. package/dist/containers/Clusters/i18n/index.js +2 -4
  27. package/dist/containers/Clusters/i18n/ru.json +2 -1
  28. package/dist/containers/Node/Node.js +11 -13
  29. package/dist/containers/Node/NodePages.js +4 -1
  30. package/dist/containers/Node/i18n/index.d.ts +1 -1
  31. package/dist/containers/Node/i18n/index.js +2 -4
  32. package/dist/containers/Nodes/getNodesColumns.js +2 -1
  33. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.d.ts +1 -1
  34. package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.d.ts +1 -1
  35. package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.js +2 -1
  36. package/dist/containers/Tablet/Tablet.js +24 -20
  37. package/dist/containers/Tablet/i18n/index.d.ts +1 -1
  38. package/dist/containers/Tablet/i18n/index.js +2 -4
  39. package/dist/containers/TabletsFilters/TabletsFilters.d.ts +2 -0
  40. package/dist/containers/TabletsFilters/TabletsFilters.js +25 -19
  41. package/dist/containers/TabletsFilters/i18n/en.json +3 -0
  42. package/dist/containers/TabletsFilters/i18n/index.d.ts +2 -0
  43. package/dist/containers/TabletsFilters/i18n/index.js +5 -0
  44. package/dist/containers/TabletsFilters/i18n/ru.json +3 -0
  45. package/dist/containers/Tenant/Diagnostics/Diagnostics.js +12 -11
  46. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.d.ts +19 -0
  47. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.js +2 -1
  48. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.d.ts +7 -25
  49. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +88 -92
  50. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss +1 -33
  51. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/en.json +4 -0
  52. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.d.ts +2 -0
  53. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.js +5 -0
  54. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.js +4 -1
  55. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.js +3 -4
  56. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +12 -5
  57. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.d.ts +2 -2
  58. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.js +7 -10
  59. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -5
  60. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.js +0 -2
  61. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +10 -0
  62. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.d.ts +1 -1
  63. package/dist/containers/Tenant/Query/Query.d.ts +2 -2
  64. package/dist/containers/Tenant/Query/Query.js +5 -2
  65. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +29 -31
  66. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +150 -167
  67. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.d.ts +2 -2
  68. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +3 -3
  69. package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.d.ts +10 -0
  70. package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.js +1 -1
  71. package/dist/containers/Tenant/Query/utils/getPreparedResult.d.ts +1 -1
  72. package/dist/containers/Tenant/Query/utils/getPreparedResult.js +18 -16
  73. package/dist/containers/Tenant/Tenant.js +4 -1
  74. package/dist/containers/Tenant/i18n/en.json +1 -0
  75. package/dist/containers/Tenant/i18n/index.d.ts +1 -1
  76. package/dist/containers/Tenant/i18n/index.js +2 -4
  77. package/dist/containers/Tenant/i18n/ru.json +1 -0
  78. package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.scss +1 -1
  79. package/dist/routes.d.ts +5 -0
  80. package/dist/routes.js +4 -0
  81. package/dist/services/api.d.ts +2 -1
  82. package/dist/services/api.js +2 -2
  83. package/dist/services/settings.d.ts +0 -1
  84. package/dist/services/settings.js +1 -14
  85. package/dist/store/index.d.ts +1 -1
  86. package/dist/store/reducers/cluster/cluster.d.ts +8 -2
  87. package/dist/store/reducers/cluster/cluster.js +29 -1
  88. package/dist/store/reducers/cluster/types.d.ts +4 -2
  89. package/dist/store/reducers/executeQuery.d.ts +1 -10
  90. package/dist/store/reducers/executeQuery.js +26 -29
  91. package/dist/store/reducers/executeTopQueries/executeTopQueries.js +2 -1
  92. package/dist/store/reducers/executeTopQueries/utils.js +7 -4
  93. package/dist/store/reducers/hotKeys/hotKeys.d.ts +25 -0
  94. package/dist/store/reducers/hotKeys/hotKeys.js +49 -0
  95. package/dist/store/reducers/hotKeys/types.d.ts +10 -0
  96. package/dist/store/reducers/hotKeys/types.js +1 -0
  97. package/dist/store/reducers/index.d.ts +2 -6
  98. package/dist/store/reducers/index.js +1 -1
  99. package/dist/store/reducers/node/node.d.ts +1 -1
  100. package/dist/store/reducers/node/node.js +2 -0
  101. package/dist/store/reducers/node/selectors.js +1 -1
  102. package/dist/store/reducers/node/types.d.ts +7 -3
  103. package/dist/store/reducers/node/utils.d.ts +3 -0
  104. package/dist/store/reducers/node/utils.js +8 -0
  105. package/dist/store/reducers/nodes/types.d.ts +1 -1
  106. package/dist/store/reducers/nodes/utils.js +3 -3
  107. package/dist/store/reducers/storage/types.d.ts +2 -0
  108. package/dist/store/reducers/storage/utils.js +3 -3
  109. package/dist/store/reducers/tenants/utils.d.ts +4 -3
  110. package/dist/store/reducers/tenants/utils.js +17 -12
  111. package/dist/store/reducers/tooltip.d.ts +1 -1
  112. package/dist/types/api/hotkeys.d.ts +7 -0
  113. package/dist/types/api/hotkeys.js +1 -0
  114. package/dist/types/api/nodes.d.ts +2 -1
  115. package/dist/types/store/executeQuery.d.ts +3 -6
  116. package/dist/types/store/explainQuery.d.ts +1 -0
  117. package/dist/utils/constants.d.ts +1 -1
  118. package/dist/utils/constants.js +1 -1
  119. package/dist/utils/diagnostics.d.ts +1 -0
  120. package/dist/utils/diagnostics.js +1 -0
  121. package/dist/utils/i18n/i18n.d.ts +2 -1
  122. package/dist/utils/i18n/i18n.js +15 -2
  123. package/dist/utils/monitoring.js +1 -3
  124. package/dist/utils/versions/getVersionsColors.js +1 -1
  125. package/package.json +9 -8
  126. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +0 -26
  127. package/dist/store/reducers/hotKeys.d.ts +0 -11
  128. package/dist/store/reducers/hotKeys.js +0 -34
@@ -1,13 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef } from 'react';
3
- import { useLocation, useRouteMatch } from 'react-router';
3
+ import { Redirect, Switch, Route, useLocation, useRouteMatch } from 'react-router';
4
4
  import { useDispatch } from 'react-redux';
5
+ import { Helmet } from 'react-helmet-async';
5
6
  import cn from 'bem-cn-lite';
6
7
  import qs from 'qs';
7
- import { Tabs } from '@gravity-ui/uikit';
8
- import routes from '../../routes';
8
+ import { Skeleton, Tabs } from '@gravity-ui/uikit';
9
+ import routes, { getLocationObjectFromHref } from '../../routes';
9
10
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
10
- import { getClusterInfo } from '../../store/reducers/cluster/cluster';
11
+ import { getClusterInfo, updateDefaultClusterTab } from '../../store/reducers/cluster/cluster';
11
12
  import { getClusterNodes } from '../../store/reducers/clusterNodes/clusterNodes';
12
13
  import { parseNodesToVersionsValues, parseVersionsToVersionToColorMap } from '../../utils/versions';
13
14
  import { useAutofetcher, useTypedSelector } from '../../utils/hooks';
@@ -16,15 +17,17 @@ import { Tenants } from '../Tenants/Tenants';
16
17
  import { StorageWrapper } from '../Storage/StorageWrapper';
17
18
  import { NodesWrapper } from '../Nodes/NodesWrapper';
18
19
  import { Versions } from '../Versions/Versions';
20
+ import EntityStatus from '../../components/EntityStatus/EntityStatus';
21
+ import { CLUSTER_DEFAULT_TITLE } from '../../utils/constants';
19
22
  import { ClusterInfo } from './ClusterInfo/ClusterInfo';
20
- import { clusterTabs, clusterTabsIds, getClusterPath } from './utils';
23
+ import { clusterTabs, clusterTabsIds, getClusterPath, isClusterTab } from './utils';
21
24
  import './Cluster.scss';
22
25
  const b = cn('cluster');
23
26
  function Cluster({ additionalClusterProps, additionalTenantsProps, additionalNodesProps, additionalVersionsProps, }) {
27
+ var _a, _b;
24
28
  const container = useRef(null);
25
29
  const dispatch = useDispatch();
26
- const match = useRouteMatch(routes.cluster);
27
- const { activeTab = clusterTabsIds.tenants } = (match === null || match === void 0 ? void 0 : match.params) || {};
30
+ const activeTabId = useClusterTab();
28
31
  const location = useLocation();
29
32
  const queryParams = qs.parse(location.search, {
30
33
  ignoreQueryPrefix: true,
@@ -50,28 +53,43 @@ function Cluster({ additionalClusterProps, additionalTenantsProps, additionalNod
50
53
  const versionsValues = useMemo(() => {
51
54
  return parseNodesToVersionsValues(nodes, versionToColor);
52
55
  }, [nodes, versionToColor]);
53
- const renderTab = () => {
54
- switch (activeTab) {
55
- case clusterTabsIds.tenants: {
56
- return _jsx(Tenants, { additionalTenantsProps: additionalTenantsProps });
57
- }
58
- case clusterTabsIds.nodes: {
59
- return (_jsx(NodesWrapper, { parentContainer: container.current, additionalNodesProps: additionalNodesProps }));
60
- }
61
- case clusterTabsIds.storage: {
62
- return (_jsx(StorageWrapper, { parentContainer: container.current, additionalNodesProps: additionalNodesProps }));
63
- }
64
- case clusterTabsIds.versions: {
65
- return _jsx(Versions, { versionToColor: versionToColor });
66
- }
67
- default: {
68
- return null;
69
- }
56
+ const getClusterTitle = () => {
57
+ var _a;
58
+ if (infoLoading) {
59
+ return _jsx(Skeleton, { className: b('title-skeleton') });
70
60
  }
61
+ return (_jsx(EntityStatus, { size: "m", status: cluster === null || cluster === void 0 ? void 0 : cluster.Overall, name: (_a = cluster === null || cluster === void 0 ? void 0 : cluster.Name) !== null && _a !== void 0 ? _a : CLUSTER_DEFAULT_TITLE, className: b('title') }));
71
62
  };
72
- return (_jsxs("div", Object.assign({ className: b(), ref: container }, { children: [_jsx(ClusterInfo, { cluster: cluster, groupsStats: groupsStats, versionsValues: versionsValues, loading: infoLoading, error: clusterError, additionalClusterProps: additionalClusterProps }), _jsx("div", Object.assign({ className: b('tabs') }, { children: _jsx(Tabs, { size: "l", allowNotSelected: true, activeTab: activeTab, items: clusterTabs, wrapTo: ({ id }, node) => {
63
+ const clusterTitle = (_b = (_a = cluster === null || cluster === void 0 ? void 0 : cluster.Name) !== null && _a !== void 0 ? _a : clusterName) !== null && _b !== void 0 ? _b : CLUSTER_DEFAULT_TITLE;
64
+ const activeTab = useMemo(() => clusterTabs.find(({ id }) => id === activeTabId), [activeTabId]);
65
+ return (_jsxs("div", Object.assign({ className: b(), ref: container }, { children: [_jsx(Helmet, Object.assign({ defaultTitle: `${clusterTitle} — YDB Monitoring`, titleTemplate: `%s — ${clusterTitle} — YDB Monitoring` }, { children: activeTab ? _jsx("title", { children: activeTab.title }) : null })), _jsx("div", Object.assign({ className: b('header') }, { children: getClusterTitle() })), _jsx("div", Object.assign({ className: b('tabs') }, { children: _jsx(Tabs, { size: "l", allowNotSelected: true, activeTab: activeTabId, items: clusterTabs, wrapTo: ({ id }, node) => {
73
66
  const path = getClusterPath(id, queryParams);
74
- return (_jsx(InternalLink, Object.assign({ to: path }, { children: node }), id));
75
- } }) })), _jsx("div", { children: renderTab() })] })));
67
+ return (_jsx(InternalLink, Object.assign({ to: path, onClick: () => {
68
+ dispatch(updateDefaultClusterTab(id));
69
+ } }, { children: node }), id));
70
+ } }) })), _jsx("div", { children: _jsxs(Switch, { children: [_jsx(Route, Object.assign({ path: getLocationObjectFromHref(getClusterPath(clusterTabsIds.overview))
71
+ .pathname }, { children: _jsx(ClusterInfo, { cluster: cluster, groupsStats: groupsStats, versionsValues: versionsValues, loading: infoLoading, error: clusterError, additionalClusterProps: additionalClusterProps }) })), _jsx(Route, Object.assign({ path: getLocationObjectFromHref(getClusterPath(clusterTabsIds.tenants))
72
+ .pathname }, { children: _jsx(Tenants, { additionalTenantsProps: additionalTenantsProps }) })), _jsx(Route, Object.assign({ path: getLocationObjectFromHref(getClusterPath(clusterTabsIds.nodes)).pathname }, { children: _jsx(NodesWrapper, { parentContainer: container.current, additionalNodesProps: additionalNodesProps }) })), _jsx(Route, Object.assign({ path: getLocationObjectFromHref(getClusterPath(clusterTabsIds.storage))
73
+ .pathname }, { children: _jsx(StorageWrapper, { parentContainer: container.current, additionalNodesProps: additionalNodesProps }) })), _jsx(Route, Object.assign({ path: getLocationObjectFromHref(getClusterPath(clusterTabsIds.versions))
74
+ .pathname }, { children: _jsx(Versions, { versionToColor: versionToColor }) })), _jsx(Redirect, { to: getLocationObjectFromHref(getClusterPath(activeTabId)) })] }) })] })));
75
+ }
76
+ function useClusterTab() {
77
+ const dispatch = useDispatch();
78
+ const defaultTab = useTypedSelector((state) => state.cluster.defaultClusterTab);
79
+ const match = useRouteMatch(routes.cluster);
80
+ const { activeTab: activeTabFromParams } = (match === null || match === void 0 ? void 0 : match.params) || {};
81
+ let activeTab;
82
+ if (isClusterTab(activeTabFromParams)) {
83
+ activeTab = activeTabFromParams;
84
+ }
85
+ else {
86
+ activeTab = defaultTab;
87
+ }
88
+ useEffect(() => {
89
+ if (activeTab !== defaultTab) {
90
+ dispatch(updateDefaultClusterTab(activeTab));
91
+ }
92
+ }, [activeTab, defaultTab, dispatch]);
93
+ return activeTab;
76
94
  }
77
95
  export default Cluster;
@@ -9,6 +9,21 @@
9
9
 
10
10
  @include flex-container();
11
11
 
12
+ &__header {
13
+ padding: 20px 0;
14
+ }
15
+
16
+ &__title {
17
+ font-weight: var(--g-text-header-font-weight);
18
+ @include header-1-typography();
19
+ }
20
+
21
+ &__title-skeleton {
22
+ width: 20%;
23
+ min-width: 200px;
24
+ height: var(--g-text-header-1-line-height);
25
+ }
26
+
12
27
  &__tabs {
13
28
  position: sticky;
14
29
  left: 0;
@@ -1,20 +1,17 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import block from 'bem-cn-lite';
3
- import { Skeleton } from '@gravity-ui/uikit';
4
- import EntityStatus from '../../../components/EntityStatus/EntityStatus';
5
3
  import { ProgressViewer } from '../../../components/ProgressViewer/ProgressViewer';
6
4
  import InfoViewer from '../../../components/InfoViewer/InfoViewer';
7
5
  import { Tags } from '../../../components/Tags';
8
6
  import { Tablet } from '../../../components/Tablet';
9
7
  import { ResponseError } from '../../../components/Errors/ResponseError';
10
8
  import { ExternalLinkWithIcon } from '../../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
11
- import { Icon } from '../../../components/Icon/Icon';
12
9
  import { ContentWithPopup } from '../../../components/ContentWithPopup/ContentWithPopup';
13
10
  import { backend, customBackend } from '../../../store';
14
11
  import { formatStorageValues } from '../../../utils/dataFormatters/dataFormatters';
15
- import { useSetting, useTypedSelector } from '../../../utils/hooks';
12
+ import { useTypedSelector } from '../../../utils/hooks';
16
13
  import { formatBytes, getSizeWithSignificantDigits } from '../../../utils/bytesParsers';
17
- import { CLUSTER_DEFAULT_TITLE, CLUSTER_INFO_HIDDEN_KEY, DEVELOPER_UI_TITLE, } from '../../../utils/constants';
14
+ import { DEVELOPER_UI_TITLE } from '../../../utils/constants';
18
15
  import { VersionsBar } from '../VersionsBar/VersionsBar';
19
16
  import { ClusterInfoSkeleton } from '../ClusterInfoSkeleton/ClusterInfoSkeleton';
20
17
  import i18n from '../i18n';
@@ -106,10 +103,6 @@ const getInfo = (cluster, versionsValues, groupsStats, additionalInfo, links) =>
106
103
  };
107
104
  export const ClusterInfo = ({ cluster = {}, versionsValues = [], groupsStats = {}, loading, error, additionalClusterProps = {}, }) => {
108
105
  const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
109
- const [clusterInfoHidden, setClusterInfoHidden] = useSetting(CLUSTER_INFO_HIDDEN_KEY);
110
- const togleClusterInfoVisibility = () => {
111
- setClusterInfoHidden(!clusterInfoHidden);
112
- };
113
106
  let internalLink = backend + '/internal';
114
107
  if (singleClusterMode && !customBackend) {
115
108
  internalLink = `/internal`;
@@ -128,12 +121,5 @@ export const ClusterInfo = ({ cluster = {}, versionsValues = [], groupsStats = {
128
121
  }
129
122
  return _jsx(InfoViewer, { dots: true, info: clusterInfo });
130
123
  };
131
- const getClusterTitle = () => {
132
- var _a;
133
- if (loading) {
134
- return _jsx(Skeleton, { className: b('title-skeleton') });
135
- }
136
- return (_jsx(EntityStatus, { size: "m", status: cluster === null || cluster === void 0 ? void 0 : cluster.Overall, name: (_a = cluster === null || cluster === void 0 ? void 0 : cluster.Name) !== null && _a !== void 0 ? _a : CLUSTER_DEFAULT_TITLE, className: b('title') }));
137
- };
138
- return (_jsxs("div", Object.assign({ className: b() }, { children: [_jsxs("div", Object.assign({ className: b('header'), onClick: togleClusterInfoVisibility }, { children: [getClusterTitle(), _jsx(Icon, { name: "chevron-down", width: 24, height: 24, className: b('header__expand-button', { rotate: clusterInfoHidden }) })] })), _jsx("div", Object.assign({ className: b('info', { hidden: clusterInfoHidden }) }, { children: getContent() }))] })));
124
+ return (_jsx("div", Object.assign({ className: b() }, { children: _jsx("div", Object.assign({ className: b('info') }, { children: getContent() })) })));
139
125
  };
@@ -1,52 +1,12 @@
1
1
  @import '../../../styles/mixins';
2
2
 
3
3
  .cluster-info {
4
- position: sticky;
5
- left: 0;
6
-
7
- width: 100%;
8
4
  padding-top: 20px;
9
5
 
10
- &__header {
11
- display: flex;
12
-
13
- width: fit-content;
14
- margin-bottom: 20px;
15
-
16
- cursor: pointer;
17
-
18
- &__expand-button {
19
- margin-left: 6px;
20
-
21
- &_rotate {
22
- transform: rotate(180deg);
23
- }
24
- }
25
- }
26
-
27
- &__title .entity-status__name {
28
- font-weight: var(--g-text-header-font-weight);
29
- @include header-1-typography();
30
- }
31
-
32
- &__title-skeleton {
33
- width: 20%;
34
- min-width: 200px;
35
- height: var(--g-text-header-1-line-height);
36
- }
37
-
38
6
  &__error {
39
7
  @include body-2-typography();
40
8
  }
41
9
 
42
- &__info {
43
- margin-bottom: 20px;
44
-
45
- &_hidden {
46
- display: none;
47
- }
48
- }
49
-
50
10
  &__system-tablets {
51
11
  display: flex;
52
12
  flex-wrap: wrap;
@@ -1,5 +1,6 @@
1
1
  import type { ValueOf } from '../../types/common';
2
2
  export declare const clusterTabsIds: {
3
+ readonly overview: "overview";
3
4
  readonly tenants: "tenants";
4
5
  readonly nodes: "nodes";
5
6
  readonly storage: "storage";
@@ -7,6 +8,9 @@ export declare const clusterTabsIds: {
7
8
  };
8
9
  export declare type ClusterTab = ValueOf<typeof clusterTabsIds>;
9
10
  export declare const clusterTabs: ({
11
+ id: "overview";
12
+ title: string;
13
+ } | {
10
14
  id: "tenants";
11
15
  title: string;
12
16
  } | {
@@ -19,4 +23,5 @@ export declare const clusterTabs: ({
19
23
  id: "versions";
20
24
  title: string;
21
25
  })[];
22
- export declare const getClusterPath: (activeTab?: ClusterTab, query?: {}) => string;
26
+ export declare function isClusterTab(tab: any): tab is ClusterTab;
27
+ export declare const getClusterPath: (activeTab?: ClusterTab | undefined, query?: {}) => string;
@@ -1,10 +1,15 @@
1
1
  import routes, { createHref } from '../../routes';
2
2
  export const clusterTabsIds = {
3
+ overview: 'overview',
3
4
  tenants: 'tenants',
4
5
  nodes: 'nodes',
5
6
  storage: 'storage',
6
7
  versions: 'versions',
7
8
  };
9
+ const overview = {
10
+ id: clusterTabsIds.overview,
11
+ title: 'Overview',
12
+ };
8
13
  const tenants = {
9
14
  id: clusterTabsIds.tenants,
10
15
  title: 'Databases',
@@ -21,7 +26,10 @@ const versions = {
21
26
  id: clusterTabsIds.versions,
22
27
  title: 'Versions',
23
28
  };
24
- export const clusterTabs = [tenants, nodes, storage, versions];
25
- export const getClusterPath = (activeTab = clusterTabsIds.tenants, query = {}) => {
26
- return createHref(routes.cluster, { activeTab }, query);
29
+ export const clusterTabs = [overview, tenants, nodes, storage, versions];
30
+ export function isClusterTab(tab) {
31
+ return Object.values(clusterTabsIds).includes(tab);
32
+ }
33
+ export const getClusterPath = (activeTab, query = {}) => {
34
+ return createHref(routes.cluster, activeTab ? { activeTab } : undefined, query);
27
35
  };
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useMemo } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
+ import { Helmet } from 'react-helmet-async';
4
5
  import DataTable from '@gravity-ui/react-data-table';
5
6
  import { TableColumnSetup, Select } from '@gravity-ui/uikit';
6
7
  import { Search } from '../../components/Search';
8
+ import { Loader } from '../../components/Loader';
7
9
  import { DEFAULT_TABLE_SETTINGS } from '../../utils/constants';
8
10
  import { useAutofetcher } from '../../utils/hooks';
9
11
  import { useTypedSelector } from '../../utils/hooks/useTypedSelector';
@@ -14,9 +16,8 @@ import { ClustersStatistics } from './ClustersStatistics';
14
16
  import { CLUSTERS_COLUMNS } from './columns';
15
17
  import { useSelectedColumns } from './useSelectedColumns';
16
18
  import { b } from './shared';
17
- import './Clusters.scss';
18
- import { Loader } from '../../components/Loader';
19
19
  import i18n from './i18n';
20
+ import './Clusters.scss';
20
21
  export function Clusters() {
21
22
  const dispatch = useDispatch();
22
23
  const loading = useTypedSelector(selectLoadingFlag);
@@ -62,7 +63,7 @@ export function Clusters() {
62
63
  if (loading && !clusters.length) {
63
64
  return _jsx(Loader, { size: "l" });
64
65
  }
65
- return (_jsxs("div", Object.assign({ className: b() }, { children: [_jsx(ClustersStatistics, { stats: aggregation, count: filteredClusters.length }), _jsxs("div", Object.assign({ className: b('controls') }, { children: [_jsx("div", Object.assign({ className: b('control', { wide: true }) }, { children: _jsx(Search, { placeholder: i18n('controls_search-placeholder'), onChange: changeClusterName, value: clusterName }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_status-select-label'), value: status, options: CLUSTER_STATUSES, onUpdate: changeStatus, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_service-select-label'), value: service, options: servicesToSelect, onUpdate: changeService, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_version-select-label'), value: version, options: versions, onUpdate: changeVersion, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx("div", { children: _jsx(TableColumnSetup, { popupWidth: "242px", items: columnsToSelect, showStatus: true, onUpdate: setColumns, className: b('table-settings') }, "TableColumnSetup") }) }))] })), _jsx("div", Object.assign({ className: b('table-wrapper') }, { children: _jsx("div", Object.assign({ className: b('table-content') }, { children: _jsx(DataTable, { theme: "yandex-cloud", data: filteredClusters, columns: columnsToShow, settings: Object.assign(Object.assign({}, DEFAULT_TABLE_SETTINGS), { dynamicRender: false }), initialSortOrder: {
66
+ return (_jsxs("div", Object.assign({ className: b() }, { children: [_jsx(Helmet, { children: _jsx("title", { children: i18n('page_title') }) }), _jsx(ClustersStatistics, { stats: aggregation, count: filteredClusters.length }), _jsxs("div", Object.assign({ className: b('controls') }, { children: [_jsx("div", Object.assign({ className: b('control', { wide: true }) }, { children: _jsx(Search, { placeholder: i18n('controls_search-placeholder'), onChange: changeClusterName, value: clusterName }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_status-select-label'), value: status, options: CLUSTER_STATUSES, onUpdate: changeStatus, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_service-select-label'), value: service, options: servicesToSelect, onUpdate: changeService, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_version-select-label'), value: version, options: versions, onUpdate: changeVersion, width: "max" }) })), _jsx("div", Object.assign({ className: b('control') }, { children: _jsx("div", { children: _jsx(TableColumnSetup, { popupWidth: "242px", items: columnsToSelect, showStatus: true, onUpdate: setColumns, className: b('table-settings') }, "TableColumnSetup") }) }))] })), _jsx("div", Object.assign({ className: b('table-wrapper') }, { children: _jsx("div", Object.assign({ className: b('table-content') }, { children: _jsx(DataTable, { theme: "yandex-cloud", data: filteredClusters, columns: columnsToShow, settings: Object.assign(Object.assign({}, DEFAULT_TABLE_SETTINGS), { dynamicRender: false }), initialSortOrder: {
66
67
  columnId: COLUMNS_NAMES.TITLE,
67
68
  order: DataTable.ASCENDING,
68
69
  } }) })) }))] })));
@@ -20,7 +20,7 @@ export const CLUSTERS_COLUMNS = [
20
20
  var _a, _b;
21
21
  const { balancer, name: clusterName } = row;
22
22
  const backend = balancer && removeViewerPathname(balancer);
23
- const clusterPath = getClusterPath(clusterTabsIds.tenants, { backend, clusterName });
23
+ const clusterPath = getClusterPath(undefined, { backend, clusterName });
24
24
  const clusterStatus = (_a = row.cluster) === null || _a === void 0 ? void 0 : _a.Overall;
25
25
  return (_jsxs("div", Object.assign({ className: b('cluster') }, { children: [clusterStatus ? (_jsx(ExternalLink, Object.assign({ href: clusterPath }, { children: _jsx("div", { className: b('cluster-status', {
26
26
  type: clusterStatus && clusterStatus.toLowerCase(),
@@ -15,7 +15,7 @@ export declare const COLUMNS_NAMES: {
15
15
  readonly DESCRIPTION: "description";
16
16
  readonly BALANCER: "balancer";
17
17
  };
18
- export declare const DEFAULT_COLUMNS: ("nodes" | "storage" | "title" | "status" | "tenants" | "service" | "versions" | "hosts" | "balancer" | "load" | "owner")[];
18
+ export declare const DEFAULT_COLUMNS: ("nodes" | "storage" | "title" | "status" | "tenants" | "versions" | "service" | "hosts" | "balancer" | "load" | "owner")[];
19
19
  export declare const COLUMNS_TITLES: {
20
20
  readonly title: "Cluster";
21
21
  readonly versions: "Versions";
@@ -10,5 +10,6 @@
10
10
  "statistics_nodes": "Nodes",
11
11
  "statistics_load": "Load",
12
12
  "statistics_storage": "Storage",
13
- "tooltip_no-cluster-data": "No cluster data"
13
+ "tooltip_no-cluster-data": "No cluster data",
14
+ "page_title": "Clusters"
14
15
  }
@@ -1,2 +1,2 @@
1
- declare const _default: (key: string, params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "controls_status-select-label" | "controls_service-select-label" | "controls_version-select-label" | "controls_search-placeholder" | "controls_select-placeholder" | "statistics_clusters" | "statistics_hosts" | "statistics_tenants" | "statistics_nodes" | "statistics_load" | "statistics_storage" | "tooltip_no-cluster-data" | "page_title", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;
@@ -1,7 +1,5 @@
1
- import { Lang, i18n } from '../../../utils/i18n';
1
+ import { registerKeysets } from '../../../utils/i18n';
2
2
  import en from './en.json';
3
3
  import ru from './ru.json';
4
4
  const COMPONENT = 'ydb-clusters-page';
5
- i18n.registerKeyset(Lang.En, COMPONENT, en);
6
- i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
7
- export default i18n.keyset(COMPONENT);
5
+ export default registerKeysets(COMPONENT, { ru, en });
@@ -10,5 +10,6 @@
10
10
  "statistics_nodes": "Узлы",
11
11
  "statistics_load": "Нагрузка",
12
12
  "statistics_storage": "Хранилище",
13
- "tooltip_no-cluster-data": "Нет данных кластера"
13
+ "tooltip_no-cluster-data": "Нет данных кластера",
14
+ "page_title": "Кластеры"
14
15
  }
@@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef } from 'react';
3
3
  import { useLocation, useRouteMatch } from 'react-router';
4
4
  import cn from 'bem-cn-lite';
5
5
  import { useDispatch } from 'react-redux';
6
+ import { Helmet } from 'react-helmet-async';
6
7
  import { Tabs } from '@gravity-ui/uikit';
7
8
  import { Link } from 'react-router-dom';
8
9
  import { TABLETS, STORAGE, NODE_PAGES, OVERVIEW, STRUCTURE } from './NodePages';
@@ -17,39 +18,36 @@ import routes, { createHref, parseQuery } from '../../routes';
17
18
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
18
19
  import { AutoFetcher } from '../../utils/autofetcher';
19
20
  import { useTypedSelector } from '../../utils/hooks';
20
- import { clusterTabsIds } from '../Cluster/utils';
21
21
  import './Node.scss';
22
22
  const b = cn('node');
23
23
  export const STORAGE_ROLE = 'Storage';
24
24
  const autofetcher = new AutoFetcher();
25
25
  function Node(props) {
26
- var _a, _b;
26
+ var _a;
27
27
  const container = useRef(null);
28
28
  const dispatch = useDispatch();
29
29
  const location = useLocation();
30
- const { loading, wasLoaded, error, data } = useTypedSelector((state) => state.node);
31
- const node = (_a = data === null || data === void 0 ? void 0 : data.SystemStateInfo) === null || _a === void 0 ? void 0 : _a[0];
32
- const match = (_b = useRouteMatch(routes.node)) !== null && _b !== void 0 ? _b : Object.create(null);
30
+ const { loading, wasLoaded, error, data: node } = useTypedSelector((state) => state.node);
31
+ const match = (_a = useRouteMatch(routes.node)) !== null && _a !== void 0 ? _a : Object.create(null);
33
32
  const { id: nodeId, activeTab } = match.params;
34
33
  const { tenantName: tenantNameFromQuery } = parseQuery(location);
35
34
  const { activeTabVerified, nodeTabs } = useMemo(() => {
36
35
  var _a;
37
36
  const hasStorage = (_a = node === null || node === void 0 ? void 0 : node.Roles) === null || _a === void 0 ? void 0 : _a.find((el) => el === STORAGE_ROLE);
38
- let actualActiveTab = activeTab;
39
- if (!hasStorage && activeTab === STORAGE) {
40
- actualActiveTab = OVERVIEW;
41
- }
42
37
  const nodePages = hasStorage ? NODE_PAGES : NODE_PAGES.filter((el) => el.id !== STORAGE);
43
38
  const actualNodeTabs = nodePages.map((page) => {
44
39
  return Object.assign(Object.assign({}, page), { title: page.name });
45
40
  });
41
+ let actualActiveTab = actualNodeTabs.find(({ id }) => id === activeTab);
42
+ if (!actualActiveTab) {
43
+ actualActiveTab = actualNodeTabs[0];
44
+ }
46
45
  return { activeTabVerified: actualActiveTab, nodeTabs: actualNodeTabs };
47
46
  }, [activeTab, node]);
48
47
  useEffect(() => {
49
48
  var _a;
50
49
  const tenantName = ((_a = node === null || node === void 0 ? void 0 : node.Tenants) === null || _a === void 0 ? void 0 : _a[0]) || (tenantNameFromQuery === null || tenantNameFromQuery === void 0 ? void 0 : tenantNameFromQuery.toString());
51
50
  dispatch(setHeaderBreadcrumbs('node', {
52
- clusterTab: clusterTabsIds.nodes,
53
51
  tenantName,
54
52
  nodeId,
55
53
  }));
@@ -65,10 +63,10 @@ function Node(props) {
65
63
  };
66
64
  }, [dispatch, nodeId]);
67
65
  const renderTabs = () => {
68
- return (_jsx("div", Object.assign({ className: b('tabs') }, { children: _jsx(Tabs, { size: "l", items: nodeTabs, activeTab: activeTabVerified, wrapTo: ({ id }, tabNode) => (_jsx(Link, Object.assign({ to: createHref(routes.node, { id: nodeId, activeTab: id }), className: b('tab') }, { children: tabNode }), id)), allowNotSelected: true }) })));
66
+ return (_jsx("div", Object.assign({ className: b('tabs') }, { children: _jsx(Tabs, { size: "l", items: nodeTabs, activeTab: activeTabVerified.id, wrapTo: ({ id }, tabNode) => (_jsx(Link, Object.assign({ to: createHref(routes.node, { id: nodeId, activeTab: id }), className: b('tab') }, { children: tabNode }), id)), allowNotSelected: true }) })));
69
67
  };
70
68
  const renderTabContent = () => {
71
- switch (activeTab) {
69
+ switch (activeTabVerified.id) {
72
70
  case STORAGE: {
73
71
  return (_jsx("div", Object.assign({ className: b('storage') }, { children: _jsx(StorageWrapper, { nodeId: nodeId, parentContainer: container.current }) })));
74
72
  }
@@ -93,7 +91,7 @@ function Node(props) {
93
91
  }
94
92
  else {
95
93
  if (node) {
96
- return (_jsxs("div", Object.assign({ className: b(null, props.className), ref: container }, { children: [_jsx(BasicNodeViewer, { node: node, additionalNodesProps: props.additionalNodesProps, className: b('header') }), renderTabs(), _jsx("div", Object.assign({ className: b('content') }, { children: renderTabContent() }))] })));
94
+ return (_jsxs("div", Object.assign({ className: b(null, props.className), ref: container }, { children: [_jsx(Helmet, Object.assign({ titleTemplate: `%s — ${node.Host} — YDB Monitoring`, defaultTitle: `${node.Host} — YDB Monitoring` }, { children: _jsx("title", { children: activeTabVerified.title }) })), _jsx(BasicNodeViewer, { node: node, additionalNodesProps: props.additionalNodesProps, className: b('header') }), renderTabs(), _jsx("div", Object.assign({ className: b('content') }, { children: renderTabContent() }))] })));
97
95
  }
98
96
  return _jsx("div", Object.assign({ className: "error" }, { children: "no node data" }));
99
97
  }
@@ -12,7 +12,10 @@ export const NODE_PAGES = [
12
12
  id: STORAGE,
13
13
  name: 'Storage',
14
14
  },
15
- { id: STRUCTURE, name: 'Structure' },
15
+ {
16
+ id: STRUCTURE,
17
+ name: 'Structure',
18
+ },
16
19
  {
17
20
  id: TABLETS,
18
21
  name: 'Tablets',
@@ -1,2 +1,2 @@
1
- declare const _default: (key: string, params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "pdisk.developer-ui-button-title" | "vdisk.developer-ui-button-title", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;
@@ -1,7 +1,5 @@
1
- import { i18n, Lang } from '../../../utils/i18n';
1
+ import { registerKeysets } from '../../../utils/i18n';
2
2
  import en from './en.json';
3
3
  import ru from './ru.json';
4
4
  const COMPONENT = 'ydb-node-page';
5
- i18n.registerKeyset(Lang.En, COMPONENT, en);
6
- i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
7
- export default i18n.keyset(COMPONENT);
5
+ export default registerKeysets(COMPONENT, { en, ru });
@@ -8,6 +8,7 @@ import { formatBytesToGigabyte, formatStorageValuesToGb, } from '../../utils/dat
8
8
  import { getLoadSeverityForNode } from '../../store/reducers/nodes/utils';
9
9
  import { UsageLabel } from '../../components/UsageLabel/UsageLabel';
10
10
  import { CellWithPopover } from '../../components/CellWithPopover/CellWithPopover';
11
+ import { EMPTY_DATA_PLACEHOLDER } from '../../utils/constants';
11
12
  const NODES_COLUMNS_IDS = {
12
13
  NodeId: 'NodeId',
13
14
  Host: 'Host',
@@ -49,7 +50,7 @@ const dataCenterColumn = {
49
50
  name: NODES_COLUMNS_IDS.DC,
50
51
  header: 'DC',
51
52
  align: DataTable.LEFT,
52
- render: ({ row }) => (row.DataCenter ? row.DataCenter : '—'),
53
+ render: ({ row }) => row.DC || EMPTY_DATA_PLACEHOLDER,
53
54
  width: 60,
54
55
  };
55
56
  const rackColumn = {
@@ -46,7 +46,7 @@ export declare const getPreparedStorageGroupsColumns: (nodesMap: NodesMap | unde
46
46
  index: number;
47
47
  footer?: boolean | undefined;
48
48
  headerData?: boolean | undefined;
49
- }, column: DataTableColumn<PreparedStorageGroup>) => void) | undefined;
49
+ }, column: DataTableColumn<PreparedStorageGroup>, event: import("react").MouseEvent<HTMLTableCellElement, MouseEvent>) => void) | undefined;
50
50
  defaultOrder?: import("@gravity-ui/react-data-table").OrderType | undefined;
51
51
  sortAccessor?: string | ((row: PreparedStorageGroup) => any) | undefined;
52
52
  sortAscending?: import("@gravity-ui/react-data-table").Comparator<PreparedStorageGroup> | undefined;
@@ -37,7 +37,7 @@ export declare const getPreparedStorageNodesColumns: (additionalNodesProps: Addi
37
37
  index: number;
38
38
  footer?: boolean | undefined;
39
39
  headerData?: boolean | undefined;
40
- }, column: DataTableColumn<PreparedStorageNode>) => void) | undefined;
40
+ }, column: DataTableColumn<PreparedStorageNode>, event: import("react").MouseEvent<HTMLTableCellElement, MouseEvent>) => void) | undefined;
41
41
  defaultOrder?: import("@gravity-ui/react-data-table").OrderType | undefined;
42
42
  sortAccessor?: string | ((row: PreparedStorageNode) => any) | undefined;
43
43
  sortAscending?: import("@gravity-ui/react-data-table").Comparator<PreparedStorageNode> | undefined;
@@ -3,6 +3,7 @@ import DataTable from '@gravity-ui/react-data-table';
3
3
  import { VISIBLE_ENTITIES } from '../../../store/reducers/storage/constants';
4
4
  import { NodeHostWrapper } from '../../../components/NodeHostWrapper/NodeHostWrapper';
5
5
  import { isSortableNodesProperty } from '../../../utils/nodes';
6
+ import { EMPTY_DATA_PLACEHOLDER } from '../../../utils/constants';
6
7
  import { PDisk } from '../PDisk/PDisk';
7
8
  import { b } from './shared';
8
9
  export const STORAGE_NODES_COLUMNS_IDS = {
@@ -37,7 +38,7 @@ const getStorageNodesColumns = (additionalNodesProps) => {
37
38
  name: STORAGE_NODES_COLUMNS_IDS.DC,
38
39
  header: 'DC',
39
40
  width: 100,
40
- render: ({ row }) => row.DataCenter || '—',
41
+ render: ({ row }) => row.DC || EMPTY_DATA_PLACEHOLDER,
41
42
  align: DataTable.LEFT,
42
43
  },
43
44
  {
@@ -1,14 +1,15 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
3
  import { useLocation, useParams } from 'react-router';
4
4
  import { useDispatch } from 'react-redux';
5
5
  import cn from 'bem-cn-lite';
6
6
  import { Link as ExternalLink } from '@gravity-ui/uikit';
7
+ import { Helmet } from 'react-helmet-async';
7
8
  import { backend } from '../../store';
8
9
  import { getTablet, getTabletDescribe, clearTabletData } from '../../store/reducers/tablet';
9
10
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
10
11
  import { useAutofetcher, useTypedSelector } from '../../utils/hooks';
11
- import { DEVELOPER_UI_TITLE } from '../../utils/constants';
12
+ import { CLUSTER_DEFAULT_TITLE, DEVELOPER_UI_TITLE } from '../../utils/constants';
12
13
  import { parseQuery } from '../../routes';
13
14
  import EntityStatus from '../../components/EntityStatus/EntityStatus';
14
15
  import { ResponseError } from '../../components/Errors/ResponseError';
@@ -30,7 +31,7 @@ export const Tablet = () => {
30
31
  const params = useParams();
31
32
  const { id } = params;
32
33
  const { data: tablet = {}, loading, id: tabletId, history = [], tenantPath, error, } = useTypedSelector((state) => state.tablet);
33
- const { nodeId: queryNodeId, tenantName: queryTenantName, type: queryTabletType, } = parseQuery(location);
34
+ const { nodeId: queryNodeId, tenantName: queryTenantName, type: queryTabletType, clusterName: queryClusterName, } = parseQuery(location);
34
35
  const nodeId = ((_a = tablet.NodeId) === null || _a === void 0 ? void 0 : _a.toString()) || (queryNodeId === null || queryNodeId === void 0 ? void 0 : queryNodeId.toString());
35
36
  const tenantName = tenantPath || (queryTenantName === null || queryTenantName === void 0 ? void 0 : queryTenantName.toString());
36
37
  const type = tablet.Type || (queryTabletType === null || queryTabletType === void 0 ? void 0 : queryTabletType.toString());
@@ -61,21 +62,24 @@ export const Tablet = () => {
61
62
  const renderExternalLinks = (link, index) => {
62
63
  return (_jsx("li", Object.assign({ className: b('link', { external: true }) }, { children: _jsx(ExternalLink, Object.assign({ href: `${backend}${link.path}`, target: "_blank" }, { children: link.name })) }), index));
63
64
  };
64
- if (loading && id !== tabletId && isFirstDataFetchRef.current) {
65
- return _jsx(Loader, { size: "l" });
66
- }
67
- if (error) {
68
- return _jsx(ResponseError, { error: error });
69
- }
70
- if (!tablet || !Object.keys(tablet).length) {
71
- return (_jsx("div", Object.assign({ className: b('placeholder') }, { children: _jsx(EmptyState, { title: i18n('emptyState') }) })));
72
- }
73
- const { TabletId, Overall, Leader } = tablet;
74
- const externalLinks = [
75
- {
76
- name: `${DEVELOPER_UI_TITLE} - tablet`,
77
- path: `/tablets?TabletID=${TabletId}`,
78
- },
79
- ];
80
- return (_jsx("div", Object.assign({ className: b() }, { children: _jsxs("div", Object.assign({ className: b('pane-wrapper') }, { children: [_jsxs("div", Object.assign({ className: b('left-pane') }, { children: [_jsx("ul", Object.assign({ className: b('links') }, { children: externalLinks.map(renderExternalLinks) })), _jsxs("div", Object.assign({ className: b('row', { header: true }) }, { children: [_jsx("span", Object.assign({ className: b('title') }, { children: i18n('tablet.header') })), _jsx(EntityStatus, { status: Overall, name: TabletId }), _jsx("a", Object.assign({ rel: "noopener noreferrer", className: b('link', { external: true }), href: `${backend}/tablets?TabletID=${TabletId}`, target: "_blank" }, { children: _jsx(Icon, { name: "external" }) })), Leader && _jsx(Tag, { text: "Leader", type: "blue" }), _jsx("span", Object.assign({ className: b('loader') }, { children: loading && _jsx(Loader, { size: "s" }) }))] })), _jsx(TabletInfo, { tablet: tablet, tenantPath: tenantName }), _jsx(TabletControls, { tablet: tablet, fetchData: fetchData })] })), _jsx("div", Object.assign({ className: b('rigth-pane') }, { children: _jsx(TabletTable, { history: history }) }))] })) })));
65
+ const renderView = () => {
66
+ if (loading && id !== tabletId && isFirstDataFetchRef.current) {
67
+ return _jsx(Loader, { size: "l" });
68
+ }
69
+ if (error) {
70
+ return _jsx(ResponseError, { error: error });
71
+ }
72
+ if (!tablet || !Object.keys(tablet).length) {
73
+ return (_jsx("div", Object.assign({ className: b('placeholder') }, { children: _jsx(EmptyState, { title: i18n('emptyState') }) })));
74
+ }
75
+ const { TabletId, Overall, Leader } = tablet;
76
+ const externalLinks = [
77
+ {
78
+ name: `${DEVELOPER_UI_TITLE} - tablet`,
79
+ path: `/tablets?TabletID=${TabletId}`,
80
+ },
81
+ ];
82
+ return (_jsx("div", Object.assign({ className: b() }, { children: _jsxs("div", Object.assign({ className: b('pane-wrapper') }, { children: [_jsxs("div", Object.assign({ className: b('left-pane') }, { children: [_jsx("ul", Object.assign({ className: b('links') }, { children: externalLinks.map(renderExternalLinks) })), _jsxs("div", Object.assign({ className: b('row', { header: true }) }, { children: [_jsx("span", Object.assign({ className: b('title') }, { children: i18n('tablet.header') })), _jsx(EntityStatus, { status: Overall, name: TabletId }), _jsx("a", Object.assign({ rel: "noopener noreferrer", className: b('link', { external: true }), href: `${backend}/tablets?TabletID=${TabletId}`, target: "_blank" }, { children: _jsx(Icon, { name: "external" }) })), Leader && _jsx(Tag, { text: "Leader", type: "blue" }), _jsx("span", Object.assign({ className: b('loader') }, { children: loading && _jsx(Loader, { size: "s" }) }))] })), _jsx(TabletInfo, { tablet: tablet, tenantPath: tenantName }), _jsx(TabletControls, { tablet: tablet, fetchData: fetchData })] })), _jsx("div", Object.assign({ className: b('rigth-pane') }, { children: _jsx(TabletTable, { history: history }) }))] })) })));
83
+ };
84
+ return (_jsxs(_Fragment, { children: [_jsx(Helmet, { children: _jsx("title", { children: `${id} — ${i18n('tablet.header')} — ${tenantName || queryClusterName || CLUSTER_DEFAULT_TITLE}` }) }), renderView()] }));
81
85
  };
@@ -1,2 +1,2 @@
1
- declare const _default: (key: string, params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "emptyState" | "tablet.header" | "controls.kill" | "controls.stop" | "controls.resume" | "dialog.kill" | "dialog.stop" | "dialog.resume", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;