ydb-embedded-ui 21.1.0 → 22.0.0

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 (214) hide show
  1. package/dist/components/ComponentsProvider/ComponentsProvider.d.ts +0 -4
  2. package/dist/components/ComponentsProvider/componentsRegistry.d.ts +0 -2
  3. package/dist/components/ComponentsProvider/componentsRegistry.js +1 -3
  4. package/dist/components/ComponentsProvider/componentsRegistry.js.map +1 -1
  5. package/dist/components/ContentWithPopup/ContentWithPopup.d.ts +1 -1
  6. package/dist/components/ContentWithPopup/ContentWithPopup.js +4 -2
  7. package/dist/components/ContentWithPopup/ContentWithPopup.js.map +1 -1
  8. package/dist/components/FullNodeViewer/i18n/index.d.ts +1 -1
  9. package/dist/components/HoverPopup/HoverPopup.js +27 -4
  10. package/dist/components/HoverPopup/HoverPopup.js.map +1 -1
  11. package/dist/components/HoverPopup/getPopupScrollContainer.d.ts +1 -0
  12. package/dist/components/HoverPopup/getPopupScrollContainer.js +20 -0
  13. package/dist/components/HoverPopup/getPopupScrollContainer.js.map +1 -0
  14. package/dist/components/MetricChart/reducer.d.ts +2 -2
  15. package/dist/components/SegmentedProgress/SegmentedProgress.d.ts +22 -1
  16. package/dist/components/SegmentedProgress/SegmentedProgress.js +44 -3
  17. package/dist/components/SegmentedProgress/SegmentedProgress.js.map +1 -1
  18. package/dist/components/SegmentedProgress/SegmentedProgress.scss +5 -0
  19. package/dist/components/StorageGroupInfo/StorageGroupInfo.js +1 -13
  20. package/dist/components/StorageGroupInfo/StorageGroupInfo.js.map +1 -1
  21. package/dist/components/StorageGroupInfo/i18n/en.json +0 -1
  22. package/dist/components/StorageGroupInfo/i18n/index.d.ts +1 -1
  23. package/dist/components/nodesColumns/i18n/index.d.ts +1 -1
  24. package/dist/containers/App/App.js +3 -3
  25. package/dist/containers/App/App.js.map +1 -1
  26. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +8 -5
  27. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js.map +1 -1
  28. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +8 -0
  29. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.d.ts +4 -3
  30. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.js +62 -25
  31. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.js.map +1 -1
  32. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.scss +18 -0
  33. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/utils.d.ts +22 -0
  34. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/utils.js +49 -0
  35. package/dist/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/utils.js.map +1 -0
  36. package/dist/containers/Cluster/i18n/en.json +13 -4
  37. package/dist/containers/Cluster/i18n/index.d.ts +1 -1
  38. package/dist/containers/Node/Node.js +20 -17
  39. package/dist/containers/Node/Node.js.map +1 -1
  40. package/dist/containers/Node/NodePages.d.ts +3 -9
  41. package/dist/containers/Node/NodePages.js +2 -10
  42. package/dist/containers/Node/NodePages.js.map +1 -1
  43. package/dist/containers/Node/i18n/en.json +0 -3
  44. package/dist/containers/Node/i18n/index.d.ts +1 -1
  45. package/dist/containers/Nodes/NodesTable.js +2 -2
  46. package/dist/containers/Nodes/NodesTable.js.map +1 -1
  47. package/dist/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.js +0 -1
  48. package/dist/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.js.map +1 -1
  49. package/dist/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.js +2 -3
  50. package/dist/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.js.map +1 -1
  51. package/dist/containers/Storage/PaginatedStorageGroupsTable/columns/constants.d.ts +2 -2
  52. package/dist/containers/Storage/PaginatedStorageGroupsTable/getGroups.d.ts +1 -1
  53. package/dist/containers/Storage/PaginatedStorageGroupsTable/getGroups.js +2 -3
  54. package/dist/containers/Storage/PaginatedStorageGroupsTable/getGroups.js.map +1 -1
  55. package/dist/containers/StorageGroupPage/StorageGroupPage.js +2 -3
  56. package/dist/containers/StorageGroupPage/StorageGroupPage.js.map +1 -1
  57. package/dist/containers/Tenant/Diagnostics/Partitions/utils/constants.d.ts +2 -2
  58. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.js +1 -3
  59. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.js.map +1 -1
  60. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/useTenantStorageNewData.d.ts +5 -5
  61. package/dist/containers/Tenant/Diagnostics/useDiagnosticsPages.js +2 -4
  62. package/dist/containers/Tenant/Diagnostics/useDiagnosticsPages.js.map +1 -1
  63. package/dist/routes.d.ts +1 -0
  64. package/dist/routes.js.map +1 -1
  65. package/dist/services/api/viewer.d.ts +1 -2
  66. package/dist/services/api/viewer.js +0 -11
  67. package/dist/services/api/viewer.js.map +1 -1
  68. package/dist/store/configureStore.d.ts +12 -12
  69. package/dist/store/defaultStore.d.ts +6 -6
  70. package/dist/store/reducers/api.d.ts +1 -1
  71. package/dist/store/reducers/api.js +3 -0
  72. package/dist/store/reducers/api.js.map +1 -1
  73. package/dist/store/reducers/authentication/authentication.d.ts +4 -4
  74. package/dist/store/reducers/cancelQuery.d.ts +2 -2
  75. package/dist/store/reducers/capabilities/capabilities.d.ts +43 -43
  76. package/dist/store/reducers/capabilities/hooks.d.ts +5 -6
  77. package/dist/store/reducers/capabilities/hooks.js +0 -3
  78. package/dist/store/reducers/capabilities/hooks.js.map +1 -1
  79. package/dist/store/reducers/cluster/cluster.d.ts +5 -5
  80. package/dist/store/reducers/cluster/cluster.js +3 -2
  81. package/dist/store/reducers/cluster/cluster.js.map +1 -1
  82. package/dist/store/reducers/clusters/clusters.d.ts +2 -2
  83. package/dist/store/reducers/clusters/clusters.js +2 -1
  84. package/dist/store/reducers/clusters/clusters.js.map +1 -1
  85. package/dist/store/reducers/codeAssist/codeAssist.d.ts +6 -6
  86. package/dist/store/reducers/configs.d.ts +3 -3
  87. package/dist/store/reducers/entityDataTags.d.ts +21 -0
  88. package/dist/store/reducers/entityDataTags.js +24 -0
  89. package/dist/store/reducers/entityDataTags.js.map +1 -0
  90. package/dist/store/reducers/environments/environments.d.ts +2 -2
  91. package/dist/store/reducers/executeTopQueries/executeTopQueries.d.ts +4 -4
  92. package/dist/store/reducers/healthcheckInfo/healthcheckInfo.d.ts +111 -111
  93. package/dist/store/reducers/heatmap.d.ts +2 -2
  94. package/dist/store/reducers/hotKeys/hotKeys.d.ts +2 -2
  95. package/dist/store/reducers/index.d.ts +8 -8
  96. package/dist/store/reducers/network/network.d.ts +2 -2
  97. package/dist/store/reducers/node/node.d.ts +2 -5
  98. package/dist/store/reducers/node/node.js +0 -12
  99. package/dist/store/reducers/node/node.js.map +1 -1
  100. package/dist/store/reducers/node/types.d.ts +0 -14
  101. package/dist/store/reducers/nodes/nodes.d.ts +2 -2
  102. package/dist/store/reducers/nodesList.d.ts +12 -12
  103. package/dist/store/reducers/operations.d.ts +5 -5
  104. package/dist/store/reducers/overview/overview.d.ts +2 -2
  105. package/dist/store/reducers/partitions/partitions.d.ts +3 -3
  106. package/dist/store/reducers/pdisk/pdisk.d.ts +2 -2
  107. package/dist/store/reducers/planToSvg.d.ts +2 -2
  108. package/dist/store/reducers/preview.d.ts +2 -2
  109. package/dist/store/reducers/query/api.d.ts +4 -4
  110. package/dist/store/reducers/replication.d.ts +2 -2
  111. package/dist/store/reducers/schema/schema.d.ts +16 -16
  112. package/dist/store/reducers/schemaAcl/schemaAcl.d.ts +40 -40
  113. package/dist/store/reducers/settings/api.d.ts +4 -4
  114. package/dist/store/reducers/settings/settings.d.ts +1 -1
  115. package/dist/store/reducers/shardsWorkload/shardsWorkload.d.ts +2 -2
  116. package/dist/store/reducers/showCreateTable/showCreateTable.d.ts +2 -2
  117. package/dist/store/reducers/storage/requestStorageData.d.ts +2 -4
  118. package/dist/store/reducers/storage/requestStorageData.js +4 -10
  119. package/dist/store/reducers/storage/requestStorageData.js.map +1 -1
  120. package/dist/store/reducers/storage/storage.d.ts +4 -6
  121. package/dist/store/reducers/storage/storage.js.map +1 -1
  122. package/dist/store/reducers/storage/types.d.ts +0 -9
  123. package/dist/store/reducers/storage/utils.d.ts +1 -2
  124. package/dist/store/reducers/storage/utils.js +0 -111
  125. package/dist/store/reducers/storage/utils.js.map +1 -1
  126. package/dist/store/reducers/storageUsage/StorageUsage.d.ts +2 -2
  127. package/dist/store/reducers/streamingQuery/streamingQuery.d.ts +2 -2
  128. package/dist/store/reducers/table/table.d.ts +4 -4
  129. package/dist/store/reducers/tableData.d.ts +1 -1
  130. package/dist/store/reducers/tablePartitioning/tablePartitioning.d.ts +2 -2
  131. package/dist/store/reducers/tableSchemaData.d.ts +2 -2
  132. package/dist/store/reducers/tablet.d.ts +8 -8
  133. package/dist/store/reducers/tablets.d.ts +3 -3
  134. package/dist/store/reducers/tenant/tenant.d.ts +2 -2
  135. package/dist/store/reducers/tenant/tenant.js +14 -1
  136. package/dist/store/reducers/tenant/tenant.js.map +1 -1
  137. package/dist/store/reducers/tenantOverview/executeTopTables/executeTopTables.d.ts +2 -2
  138. package/dist/store/reducers/tenantOverview/storage/tenantOverviewStorage.d.ts +2 -2
  139. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.d.ts +2 -2
  140. package/dist/store/reducers/tenants/tenants.d.ts +3 -3
  141. package/dist/store/reducers/tenants/tenants.js +2 -1
  142. package/dist/store/reducers/tenants/tenants.js.map +1 -1
  143. package/dist/store/reducers/topic/topic.d.ts +84 -84
  144. package/dist/store/reducers/vdisk/vdisk.d.ts +3 -3
  145. package/dist/store/reducers/viewSchema/viewSchema.d.ts +2 -2
  146. package/dist/store/state-url-mapping.js +5 -1
  147. package/dist/store/state-url-mapping.js.map +1 -1
  148. package/dist/types/api/storage.d.ts +2 -111
  149. package/dist/types/api/storage.js.map +1 -1
  150. package/dist/uiFactory/types.d.ts +2 -0
  151. package/dist/utils/hooks/useWhoami.d.ts +5 -5
  152. package/package.json +1 -1
  153. package/src/components/ComponentsProvider/componentsRegistry.ts +1 -4
  154. package/src/components/ContentWithPopup/ContentWithPopup.tsx +7 -0
  155. package/src/components/HoverPopup/HoverPopup.tsx +32 -3
  156. package/src/components/HoverPopup/getPopupScrollContainer.ts +20 -0
  157. package/src/components/SegmentedProgress/SegmentedProgress.scss +5 -0
  158. package/src/components/SegmentedProgress/SegmentedProgress.tsx +99 -10
  159. package/src/components/StorageGroupInfo/StorageGroupInfo.tsx +0 -13
  160. package/src/components/StorageGroupInfo/i18n/en.json +0 -1
  161. package/src/containers/App/App.tsx +3 -3
  162. package/src/containers/Cluster/ClusterInfo/ClusterInfo.scss +8 -0
  163. package/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx +12 -11
  164. package/src/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.scss +18 -0
  165. package/src/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.tsx +143 -58
  166. package/src/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/utils.ts +89 -0
  167. package/src/containers/Cluster/i18n/en.json +13 -4
  168. package/src/containers/Node/Node.tsx +32 -18
  169. package/src/containers/Node/NodePages.ts +5 -10
  170. package/src/containers/Node/i18n/en.json +0 -4
  171. package/src/containers/Nodes/NodesTable.tsx +7 -1
  172. package/src/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.tsx +0 -1
  173. package/src/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.tsx +2 -6
  174. package/src/containers/Storage/PaginatedStorageGroupsTable/columns/constants.ts +2 -2
  175. package/src/containers/Storage/PaginatedStorageGroupsTable/getGroups.ts +40 -47
  176. package/src/containers/StorageGroupPage/StorageGroupPage.tsx +2 -6
  177. package/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +1 -6
  178. package/src/containers/Tenant/Diagnostics/useDiagnosticsPages.ts +1 -4
  179. package/src/routes.ts +1 -1
  180. package/src/services/api/viewer.ts +1 -25
  181. package/src/store/reducers/api.ts +4 -0
  182. package/src/store/reducers/capabilities/hooks.ts +0 -4
  183. package/src/store/reducers/cluster/cluster.ts +3 -2
  184. package/src/store/reducers/clusters/clusters.ts +2 -1
  185. package/src/store/reducers/entityDataTags.ts +34 -0
  186. package/src/store/reducers/node/node.ts +0 -11
  187. package/src/store/reducers/node/types.ts +0 -18
  188. package/src/store/reducers/storage/requestStorageData.ts +5 -17
  189. package/src/store/reducers/storage/storage.ts +2 -6
  190. package/src/store/reducers/storage/types.ts +0 -9
  191. package/src/store/reducers/storage/utils.ts +2 -175
  192. package/src/store/reducers/tenant/tenant.ts +17 -1
  193. package/src/store/reducers/tenants/tenants.ts +2 -1
  194. package/src/store/state-url-mapping.ts +5 -1
  195. package/src/types/api/storage.ts +7 -131
  196. package/src/uiFactory/types.ts +3 -0
  197. package/dist/containers/Node/NodeStructure/NodeStructure.d.ts +0 -7
  198. package/dist/containers/Node/NodeStructure/NodeStructure.js +0 -76
  199. package/dist/containers/Node/NodeStructure/NodeStructure.js.map +0 -1
  200. package/dist/containers/Node/NodeStructure/NodeStructure.scss +0 -155
  201. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.d.ts +0 -7
  202. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.js +0 -7
  203. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.js.map +0 -1
  204. package/dist/containers/Node/NodeStructure/Pdisk.d.ts +0 -10
  205. package/dist/containers/Node/NodeStructure/Pdisk.js +0 -125
  206. package/dist/containers/Node/NodeStructure/Pdisk.js.map +0 -1
  207. package/dist/store/reducers/node/selectors.d.ts +0 -47
  208. package/dist/store/reducers/node/selectors.js +0 -43
  209. package/dist/store/reducers/node/selectors.js.map +0 -1
  210. package/src/containers/Node/NodeStructure/NodeStructure.scss +0 -155
  211. package/src/containers/Node/NodeStructure/NodeStructure.tsx +0 -121
  212. package/src/containers/Node/NodeStructure/PDiskTitleBadge.tsx +0 -18
  213. package/src/containers/Node/NodeStructure/Pdisk.tsx +0 -274
  214. package/src/store/reducers/node/selectors.ts +0 -68
@@ -43,7 +43,6 @@ export function StorageGroupInfo({data, className, ...infoViewerProps}: StorageG
43
43
  Read,
44
44
  Write,
45
45
  GroupGeneration,
46
- Latency,
47
46
  AllocationUnits,
48
47
  State,
49
48
  MissingDisks,
@@ -140,12 +139,6 @@ export function StorageGroupInfo({data, className, ...infoViewerProps}: StorageG
140
139
  });
141
140
  }
142
141
  runtimeInfo.push(...toInfoViewerItems(getStorageGroupCapacityInfoItems(data)));
143
- if (valueIsDefined(Latency)) {
144
- runtimeInfo.push({
145
- label: storageGroupInfoKeyset('latency'),
146
- value: <StatusIcon status={Latency} />,
147
- });
148
- }
149
142
  if (valueIsDefined(LatencyPutTabletLogMs)) {
150
143
  runtimeInfo.push({
151
144
  label: storageGroupInfoKeyset('latency-put-tablet-log'),
@@ -258,12 +251,6 @@ export function StorageGroupInfo({data, className, ...infoViewerProps}: StorageG
258
251
  value: <StatusIcon status={DiskSpace} />,
259
252
  });
260
253
  }
261
- if (valueIsDefined(Latency)) {
262
- storageGroupInfoSecondColumn.push({
263
- label: storageGroupInfoKeyset('latency'),
264
- value: <StatusIcon status={Latency} />,
265
- });
266
- }
267
254
  if (valueIsDefined(LatencyPutTabletLogMs)) {
268
255
  storageGroupInfoSecondColumn.push({
269
256
  label: storageGroupInfoKeyset('latency-put-tablet-log'),
@@ -12,7 +12,6 @@
12
12
  "yes": "Yes",
13
13
  "no": "No",
14
14
  "group-generation": "Group Generation",
15
- "latency": "Latency",
16
15
  "allocation-units": "Allocation Units",
17
16
  "context_allocation-units": "The number of channels used by tablets to write data to the storage group.",
18
17
  "state": "State",
@@ -4,9 +4,9 @@ import type {Store} from '@reduxjs/toolkit';
4
4
  import type {History} from 'history';
5
5
  import {Helmet} from 'react-helmet-async';
6
6
 
7
- import {componentsRegistry} from '../../components/ComponentsProvider/componentsRegistry';
8
7
  import {FullscreenProvider} from '../../components/Fullscreen/FullscreenContext';
9
- import {useTypedSelector} from '../../utils/hooks';
8
+ import {uiFactory} from '../../uiFactory/uiFactory';
9
+ import {useTypedSelector} from '../../utils/hooks/useTypedSelector';
10
10
  import type {YDBEmbeddedUISettings} from '../UserSettings/settings';
11
11
 
12
12
  import {useAppTitle} from './AppTitleContext';
@@ -27,7 +27,7 @@ export interface AppProps {
27
27
  }
28
28
 
29
29
  function App({store, history, children, userSettings, appTitle = defaultAppTitle}: AppProps) {
30
- const ChatPanel = componentsRegistry.get('ChatPanel');
30
+ const ChatPanel = uiFactory.renderChatPanel;
31
31
 
32
32
  return (
33
33
  <Providers store={store} history={history} appTitle={appTitle}>
@@ -53,6 +53,14 @@
53
53
 
54
54
  &__storage-section {
55
55
  --g-card-border-radius: var(--g-border-radius-s);
56
+
57
+ width: 100%;
58
+
59
+ @container overview-wrapper (min-width: 804px) {
60
+ width: var(--cluster-overview-section);
61
+ min-width: var(--cluster-overview-section);
62
+ }
63
+
56
64
  @container overview-wrapper (min-width: 1104px) {
57
65
  grid-area: storage;
58
66
  }
@@ -15,6 +15,7 @@ import {BridgeInfoTable} from '../ClusterOverview/components/BridgeInfoTable';
15
15
  import i18n from '../i18n';
16
16
 
17
17
  import {StorageGroupStats} from './components/DiskGroupsStatsBars/DiskGroupsStats';
18
+ import {prepareClusterGroupsStats} from './components/DiskGroupsStatsBars/utils';
18
19
  import {b} from './shared';
19
20
 
20
21
  import './ClusterInfo.scss';
@@ -35,12 +36,16 @@ export const ClusterInfo = ({
35
36
  loading,
36
37
  error,
37
38
  additionalClusterProps = {},
38
- groupStats = {},
39
+ groupStats,
39
40
  bridgePiles,
40
41
  }: ClusterInfoProps) => {
41
42
  const {info = [], links = []} = additionalClusterProps;
42
43
 
43
44
  const clusterLinks = useClusterLinks(links);
45
+ const preparedGroupStats = React.useMemo(
46
+ () => prepareClusterGroupsStats(groupStats ?? {}),
47
+ [groupStats],
48
+ );
44
49
 
45
50
  const noDetails = (error && !cluster) || (!info.length && !clusterLinks.length);
46
51
 
@@ -106,17 +111,12 @@ export const ClusterInfo = ({
106
111
  };
107
112
 
108
113
  const renderStorageGroupsSection = () => {
109
- if (loading || Object.keys(groupStats).length === 0) {
114
+ if (loading || preparedGroupStats.disks.length === 0) {
110
115
  return null;
111
116
  }
112
117
  return (
113
- <InfoSection className={b('storage-section')}>
114
- <Text as="div" variant="subheader-2" className={b('section-title')}>
115
- {i18n('title_storage-groups')}
116
- </Text>
117
- <Card view="filled" className={b('section', {compact: true})}>
118
- <StorageGroupStats groupStats={groupStats} />
119
- </Card>
118
+ <InfoSection className={b('storage-section')} dataQa="cluster-storage-groups">
119
+ <StorageGroupStats stats={preparedGroupStats} />
120
120
  </InfoSection>
121
121
  );
122
122
  };
@@ -157,11 +157,12 @@ export const ClusterInfo = ({
157
157
  interface InfoSectionProps {
158
158
  children: React.ReactNode;
159
159
  className?: string;
160
+ dataQa?: string;
160
161
  }
161
162
 
162
- function InfoSection({children, className}: InfoSectionProps) {
163
+ function InfoSection({children, className, dataQa}: InfoSectionProps) {
163
164
  return (
164
- <Flex direction="column" gap={2} className={className}>
165
+ <Flex direction="column" gap={2} className={className} qa={dataQa}>
165
166
  {children}
166
167
  </Flex>
167
168
  );
@@ -0,0 +1,18 @@
1
+ .ydb-disk-groups-stats {
2
+ &__card {
3
+ padding: var(--g-spacing-3) var(--g-spacing-4);
4
+ }
5
+
6
+ &__available-help {
7
+ color: inherit;
8
+ }
9
+
10
+ &__legend-dot {
11
+ flex: 0 0 8px;
12
+
13
+ width: 8px;
14
+ height: 8px;
15
+
16
+ border-radius: 50%;
17
+ }
18
+ }
@@ -1,81 +1,166 @@
1
1
  import React from 'react';
2
2
 
3
- import {Flex, Label, Text} from '@gravity-ui/uikit';
3
+ import {Card, Flex, HelpMark, Label, Text} from '@gravity-ui/uikit';
4
4
 
5
- import {SegmentedProgress} from '../../../../../components/SegmentedProgress/SegmentedProgress';
6
- import type {
7
- ClusterGroupsStats,
8
- DiskErasureGroupsStats,
9
- } from '../../../../../store/reducers/cluster/types';
5
+ import {
6
+ SegmentedProgress,
7
+ defaultNormalizePercent,
8
+ } from '../../../../../components/SegmentedProgress/SegmentedProgress';
9
+ import {cn} from '../../../../../utils/cn';
10
10
  import {formatNumber} from '../../../../../utils/dataFormatters/dataFormatters';
11
11
  import i18n from '../../../i18n';
12
12
 
13
- interface GroupsStatsPopupContentProps {
14
- stats: DiskErasureGroupsStats;
15
- storageType: string;
13
+ import type {
14
+ PreparedClusterGroupsStats,
15
+ PreparedDiskGroupsStats,
16
+ PreparedErasureGroupsStats,
17
+ } from './utils';
18
+
19
+ import './DiskGroupsStats.scss';
20
+
21
+ const b = cn('ydb-disk-groups-stats');
22
+
23
+ const ERASURE_COLORS: Record<string, string> = {
24
+ 'block-4-2': 'var(--g-color-base-info-heavy)',
25
+ 'mirror-3-dc': 'var(--g-color-base-utility-heavy)',
26
+ 'mirror-3of4': 'var(--g-color-base-utility-heavy)',
27
+ none: 'var(--g-color-base-neutral-heavy)',
28
+ };
29
+
30
+ function getErasureColor(erasure: string) {
31
+ return ERASURE_COLORS[erasure] ?? 'var(--g-color-base-neutral-heavy)';
16
32
  }
17
33
 
18
- function DiskGroupStats({stats, storageType}: GroupsStatsPopupContentProps) {
19
- const {erasure} = stats;
34
+ function formatGroups(count: number) {
35
+ return i18n('value_groups', {
36
+ count,
37
+ formattedCount: formatNumber(count),
38
+ });
39
+ }
20
40
 
21
- const availableGroups = stats.totalGroups - stats.createdGroups;
41
+ function formatAvailableGroups({min, max}: PreparedDiskGroupsStats['availableGroups']) {
42
+ if (min === max) {
43
+ return formatGroups(min);
44
+ }
22
45
 
23
- const availableGroupsString =
24
- availableGroups === 1
25
- ? i18n('title_available-one')
26
- : i18n('title_available-other', {
27
- count: formatNumber(availableGroups),
28
- });
46
+ return i18n('value_available-groups-range', {
47
+ min: formatNumber(min),
48
+ max: formatNumber(max),
49
+ });
50
+ }
51
+
52
+ function getErasureTooltip(stats: PreparedErasureGroupsStats) {
53
+ return i18n('context_available-groups-by-erasure', {
54
+ count: stats.availableGroups,
55
+ formattedCount: formatNumber(stats.availableGroups),
56
+ erasure: stats.erasure,
57
+ });
58
+ }
59
+
60
+ function DiskGroupStats({stats}: {stats: PreparedDiskGroupsStats}) {
61
+ const legendId = React.useId();
62
+ const {allocatedGroups, availableGroups, diskType, erasures, progressTotalGroups} = stats;
63
+ const progressValue = progressTotalGroups > 0 ? allocatedGroups / progressTotalGroups : 0;
64
+ const progressPercent = progressValue * 100;
65
+ const progressLabel = i18n('context_storage-group-allocation-progress', {
66
+ diskType,
67
+ percent: defaultNormalizePercent(progressPercent),
68
+ });
69
+ const availableGroupsContext = i18n('context_available-groups');
70
+
71
+ const segments = erasures.map((erasureStats, index) => ({
72
+ id: erasureStats.erasure,
73
+ value: erasureStats.createdGroups,
74
+ minWidth: 10,
75
+ color: getErasureColor(erasureStats.erasure),
76
+ className: b('progress-segment'),
77
+ dataQa: 'cluster-storage-group-segment',
78
+ tooltip: getErasureTooltip(erasureStats),
79
+ ariaLabelledBy: `${legendId}-${index}`,
80
+ }));
29
81
 
30
82
  return (
31
- <Flex direction="column" gap={2}>
32
- <Flex justifyContent="space-between" alignItems="center">
33
- <Text variant="subheader-1">{storageType}</Text>
34
- <Flex gap={4} wrap="nowrap" alignItems="center">
35
- <Label theme="info">{availableGroupsString}</Label>
36
- <Text color="secondary">
37
- {i18n('title_allocated', {
38
- used: formatNumber(stats.createdGroups),
39
- total: formatNumber(stats.totalGroups),
40
- })}
41
- </Text>
83
+ <Card view="filled" className={b('card')} qa="cluster-storage-group-card">
84
+ <Flex direction="column" gap={1}>
85
+ <Flex direction="column" gap={2}>
86
+ <Flex justifyContent="space-between" alignItems="center" gap={2}>
87
+ <Text variant="subheader-1">{diskType}</Text>
88
+ <Label
89
+ theme="info"
90
+ value={
91
+ <Flex alignItems="center" gap={1}>
92
+ {formatAvailableGroups(availableGroups)}
93
+ <HelpMark
94
+ iconSize="s"
95
+ aria-label={i18n('action_show-available-groups-info', {
96
+ diskType,
97
+ })}
98
+ className={b('available-help')}
99
+ popoverProps={{placement: ['top', 'bottom']}}
100
+ >
101
+ {availableGroupsContext}
102
+ </HelpMark>
103
+ </Flex>
104
+ }
105
+ >
106
+ {i18n('title_available')}
107
+ </Label>
108
+ </Flex>
109
+ <div role="group" aria-label={progressLabel}>
110
+ <SegmentedProgress
111
+ segments={segments}
112
+ total={progressTotalGroups}
113
+ ariaLabel={progressLabel}
114
+ hideLabels
115
+ />
116
+ </div>
117
+ </Flex>
118
+ <Flex justifyContent="space-between" alignItems="center" gap={2} wrap="wrap">
119
+ <Flex alignItems="center" gap={4} wrap="wrap">
120
+ {erasures.map((erasureStats, index) => (
121
+ <Flex
122
+ key={erasureStats.erasure}
123
+ id={`${legendId}-${index}`}
124
+ alignItems="center"
125
+ gap={2}
126
+ >
127
+ <span
128
+ aria-hidden="true"
129
+ className={b('legend-dot')}
130
+ style={{backgroundColor: getErasureColor(erasureStats.erasure)}}
131
+ />
132
+ <Text>{erasureStats.erasure}</Text>
133
+ <Text color="secondary">
134
+ {formatGroups(erasureStats.createdGroups)}
135
+ </Text>
136
+ </Flex>
137
+ ))}
138
+ </Flex>
139
+ <Text color="secondary">{formatGroups(allocatedGroups)}</Text>
42
140
  </Flex>
43
141
  </Flex>
44
- <SegmentedProgress
45
- value={stats.createdGroups}
46
- total={stats.totalGroups}
47
- labelStart={erasure}
48
- ariaLabel={i18n('context_storage-group-allocation-progress')}
49
- />
50
- </Flex>
142
+ </Card>
51
143
  );
52
144
  }
53
145
 
54
146
  interface StorageGroupStatsProps {
55
- groupStats: ClusterGroupsStats;
147
+ stats: PreparedClusterGroupsStats;
56
148
  }
57
149
 
58
- export function StorageGroupStats({groupStats}: StorageGroupStatsProps) {
59
- const stats = React.useMemo(() => {
60
- const result: React.ReactNode[] = [];
61
-
62
- Object.entries(groupStats).forEach(([storageType, stats]) => {
63
- Object.values(stats).forEach((erasureStats) => {
64
- result.push(
65
- <DiskGroupStats
66
- key={`${storageType}|${erasureStats.erasure}`}
67
- stats={erasureStats}
68
- storageType={storageType}
69
- />,
70
- );
71
- });
72
- });
73
- return result;
74
- }, [groupStats]);
75
-
150
+ export function StorageGroupStats({stats}: StorageGroupStatsProps) {
76
151
  return (
77
- <Flex direction="column" gap={5}>
78
- {stats}
79
- </Flex>
152
+ <React.Fragment>
153
+ <Text as="div" variant="subheader-2">
154
+ {i18n('title_storage-groups')}{' '}
155
+ <Text color="secondary" variant="subheader-2">
156
+ {formatNumber(stats.allocatedGroups)}
157
+ </Text>
158
+ </Text>
159
+ <Flex direction="column" gap={1}>
160
+ {stats.disks.map((diskStats) => (
161
+ <DiskGroupStats key={diskStats.diskType} stats={diskStats} />
162
+ ))}
163
+ </Flex>
164
+ </React.Fragment>
80
165
  );
81
166
  }
@@ -0,0 +1,89 @@
1
+ import type {ClusterGroupsStats} from '../../../../../store/reducers/cluster/types';
2
+
3
+ const DISK_TYPE_ORDER = ['HDD', 'SSD'];
4
+ const ERASURE_ORDER = ['block-4-2', 'mirror-3-dc', 'mirror-3of4', 'none'];
5
+
6
+ export interface PreparedErasureGroupsStats {
7
+ erasure: string;
8
+ createdGroups: number;
9
+ availableGroups: number;
10
+ }
11
+
12
+ export interface PreparedDiskGroupsStats {
13
+ diskType: string;
14
+ erasures: PreparedErasureGroupsStats[];
15
+ allocatedGroups: number;
16
+ availableGroups: {
17
+ min: number;
18
+ max: number;
19
+ average: number;
20
+ };
21
+ progressTotalGroups: number;
22
+ }
23
+
24
+ export interface PreparedClusterGroupsStats {
25
+ disks: PreparedDiskGroupsStats[];
26
+ allocatedGroups: number;
27
+ }
28
+
29
+ function getErasureOrder(erasure: string) {
30
+ const index = ERASURE_ORDER.indexOf(erasure);
31
+
32
+ return index === -1 ? ERASURE_ORDER.length : index;
33
+ }
34
+
35
+ function getDiskTypeOrder(diskType: string) {
36
+ const index = DISK_TYPE_ORDER.indexOf(diskType);
37
+
38
+ return index === -1 ? DISK_TYPE_ORDER.length : index;
39
+ }
40
+
41
+ export function prepareClusterGroupsStats(
42
+ groupStats: ClusterGroupsStats,
43
+ ): PreparedClusterGroupsStats {
44
+ let allocatedGroups = 0;
45
+
46
+ const disks = Object.entries(groupStats)
47
+ .flatMap(([diskType, diskStats]) => {
48
+ const erasures = Object.values(diskStats)
49
+ .filter(({createdGroups}) => createdGroups > 0)
50
+ .map((stats) => ({
51
+ erasure: stats.erasure,
52
+ createdGroups: stats.createdGroups,
53
+ availableGroups: stats.totalGroups - stats.createdGroups,
54
+ }))
55
+ .sort((a, b) => getErasureOrder(a.erasure) - getErasureOrder(b.erasure));
56
+
57
+ if (erasures.length === 0) {
58
+ return [];
59
+ }
60
+
61
+ const diskAllocatedGroups = erasures.reduce(
62
+ (sum, stats) => sum + stats.createdGroups,
63
+ 0,
64
+ );
65
+ const availableValues = erasures.map((stats) => stats.availableGroups);
66
+ const minAvailableGroups = Math.min(...availableValues);
67
+ const maxAvailableGroups = Math.max(...availableValues);
68
+ const averageAvailableGroups = (minAvailableGroups + maxAvailableGroups) / 2;
69
+
70
+ allocatedGroups += diskAllocatedGroups;
71
+
72
+ return [
73
+ {
74
+ diskType,
75
+ erasures,
76
+ allocatedGroups: diskAllocatedGroups,
77
+ availableGroups: {
78
+ min: minAvailableGroups,
79
+ max: maxAvailableGroups,
80
+ average: averageAvailableGroups,
81
+ },
82
+ progressTotalGroups: diskAllocatedGroups + averageAvailableGroups,
83
+ },
84
+ ];
85
+ })
86
+ .sort((a, b) => getDiskTypeOrder(a.diskType) - getDiskTypeOrder(b.diskType));
87
+
88
+ return {disks, allocatedGroups};
89
+ }
@@ -1,8 +1,17 @@
1
1
  {
2
- "title_allocated": "Allocated : {{used}} of {{total}} groups",
3
- "title_available-one": "Available : 1 group",
4
- "title_available-other": "Available : {{count}} groups",
5
- "context_storage-group-allocation-progress": "Storage group allocation progress",
2
+ "title_available": "Available",
3
+ "value_groups": {
4
+ "one": "{{formattedCount}} group",
5
+ "other": "{{formattedCount}} groups"
6
+ },
7
+ "value_available-groups-range": "{{min}}–{{max}} groups",
8
+ "context_available-groups": "Estimated number of free groups available for allocation.",
9
+ "action_show-available-groups-info": "About available {{diskType}} storage groups",
10
+ "context_available-groups-by-erasure": {
11
+ "one": "{{formattedCount}} group available if only {{erasure}} is used",
12
+ "other": "{{formattedCount}} groups available if only {{erasure}} is used"
13
+ },
14
+ "context_storage-group-allocation-progress": "{{diskType}} storage group allocation: {{percent}}%",
6
15
  "title_cpu": "CPU",
7
16
  "title_storage-groups": "Allocated Storage Groups",
8
17
  "title_memory": "Memory",
@@ -16,7 +16,6 @@ import routes, {getDefaultNodePath} from '../../routes';
16
16
  import {
17
17
  useCapabilitiesLoaded,
18
18
  useConfigAvailable,
19
- useDiskPagesAvailable,
20
19
  useViewerPeersHandlerAvailable,
21
20
  } from '../../store/reducers/capabilities/hooks';
22
21
  import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
@@ -34,7 +33,6 @@ import {Tablets} from '../Tablets/Tablets';
34
33
 
35
34
  import type {NodeTab} from './NodePages';
36
35
  import {NODE_TABS, nodePageQueryParams, nodePageTabSchema} from './NodePages';
37
- import NodeStructure from './NodeStructure/NodeStructure';
38
36
  import {Threads} from './Threads/Threads';
39
37
  import i18n from './i18n';
40
38
 
@@ -52,12 +50,14 @@ export function Node() {
52
50
  const dispatch = useTypedDispatch();
53
51
  const history = useHistory();
54
52
 
55
- const match = useRouteMatch<{id: string; activeTab: string}>(routes.node);
53
+ const match = useRouteMatch<{id: string; activeTab: string; environment?: string}>(routes.node);
56
54
 
57
55
  const nodeId = match?.params.id;
58
56
  const activeTabIdFromQuery = match?.params.activeTab;
57
+ const environment = match?.params.environment;
59
58
 
60
- const [{database: tenantNameFromQuery}] = useQueryParams(nodePageQueryParams);
59
+ const [{database: tenantNameFromQuery, clusterName, backend}] =
60
+ useQueryParams(nodePageQueryParams);
61
61
  const database = tenantNameFromQuery?.toString();
62
62
 
63
63
  const activeTabId = nodePageTabSchema.parse(activeTabIdFromQuery);
@@ -72,7 +72,6 @@ export function Node() {
72
72
  } = nodeApi.useGetNodeInfoQuery(params, {pollingInterval: autoRefreshInterval});
73
73
 
74
74
  const capabilitiesLoaded = useCapabilitiesLoaded();
75
- const isDiskPagesAvailable = useDiskPagesAvailable();
76
75
  const isPeersHandlerAvailable = useViewerPeersHandlerAvailable();
77
76
 
78
77
  const pageLoading = isLoading || !capabilitiesLoaded;
@@ -89,9 +88,6 @@ export function Node() {
89
88
  if (!configsAvailable) {
90
89
  skippedTabs.push('configs');
91
90
  }
92
- if (isDiskPagesAvailable) {
93
- skippedTabs.push('structure');
94
- }
95
91
  if ((!database && !isViewerUser) || !hasThreads) {
96
92
  skippedTabs.push('threads');
97
93
  }
@@ -111,7 +107,6 @@ export function Node() {
111
107
  return {activeTab: actualActiveTab, nodeTabs: actualNodeTabs};
112
108
  }, [
113
109
  isStorageNode,
114
- isDiskPagesAvailable,
115
110
  isPeersHandlerAvailable,
116
111
  activeTabId,
117
112
  hasThreads,
@@ -142,12 +137,26 @@ export function Node() {
142
137
  return;
143
138
  }
144
139
 
145
- if (activeTab.id !== activeTabId) {
146
- const path = getDefaultNodePath({id: nodeId, activeTab: activeTab.id}, {database});
140
+ if (activeTab.id !== activeTabId || activeTabIdFromQuery === 'structure') {
141
+ const path = getDefaultNodePath(
142
+ {id: nodeId, activeTab: activeTab.id, environment},
143
+ {database, clusterName: clusterName ?? undefined, backend: backend ?? undefined},
144
+ );
147
145
 
148
146
  history.replace(path);
149
147
  }
150
- }, [nodeId, database, activeTab.id, activeTabId, history, activeTab]);
148
+ }, [
149
+ nodeId,
150
+ database,
151
+ clusterName,
152
+ backend,
153
+ environment,
154
+ activeTab.id,
155
+ activeTabId,
156
+ activeTabIdFromQuery,
157
+ history,
158
+ activeTab,
159
+ ]);
151
160
 
152
161
  return (
153
162
  <div className={b(null)} ref={container}>
@@ -160,6 +169,9 @@ export function Node() {
160
169
  <NodePageContent
161
170
  nodeId={nodeId}
162
171
  database={database}
172
+ clusterName={clusterName ?? undefined}
173
+ backend={backend ?? undefined}
174
+ environment={environment}
163
175
  activeTabId={activeTab.id}
164
176
  tabs={nodeTabs}
165
177
  parentContainer={container}
@@ -233,6 +245,9 @@ function NodePageInfo({node, loading}: NodePageInfoProps) {
233
245
  interface NodePageContentProps {
234
246
  nodeId: string;
235
247
  database?: string;
248
+ clusterName?: string;
249
+ backend?: string;
250
+ environment?: string;
236
251
 
237
252
  activeTabId: NodeTab;
238
253
  tabs: {id: string; title: string}[];
@@ -243,6 +258,9 @@ interface NodePageContentProps {
243
258
  function NodePageContent({
244
259
  nodeId,
245
260
  database,
261
+ clusterName,
262
+ backend,
263
+ environment,
246
264
  activeTabId,
247
265
  tabs,
248
266
  parentContainer,
@@ -254,8 +272,8 @@ function NodePageContent({
254
272
  <TabList className={b('tab-list')} size="l">
255
273
  {tabs.map(({id, title}) => {
256
274
  const path = getDefaultNodePath(
257
- {id: nodeId, activeTab: id as NodeTab},
258
- {database},
275
+ {id: nodeId, activeTab: id as NodeTab, environment},
276
+ {database, clusterName, backend},
259
277
  );
260
278
  return (
261
279
  <Tab value={id} key={id}>
@@ -296,10 +314,6 @@ function NodePageContent({
296
314
  );
297
315
  }
298
316
 
299
- case 'structure': {
300
- return <NodeStructure nodeId={nodeId} />;
301
- }
302
-
303
317
  case 'threads': {
304
318
  return (
305
319
  <Threads
@@ -9,7 +9,6 @@ import i18n from './i18n';
9
9
  const NODE_TABS_IDS = {
10
10
  storage: 'storage',
11
11
  tablets: 'tablets',
12
- structure: 'structure',
13
12
  threads: 'threads',
14
13
  network: 'network',
15
14
  configs: 'configs',
@@ -24,12 +23,6 @@ export const NODE_TABS = [
24
23
  return i18n('tabs.storage');
25
24
  },
26
25
  },
27
- {
28
- id: NODE_TABS_IDS.structure,
29
- get title() {
30
- return i18n('tabs.structure');
31
- },
32
- },
33
26
  {
34
27
  id: NODE_TABS_IDS.tablets,
35
28
  get title() {
@@ -56,13 +49,15 @@ export const NODE_TABS = [
56
49
  },
57
50
  ];
58
51
 
59
- export const nodePageTabSchema = z.nativeEnum(NODE_TABS_IDS).catch(NODE_TABS_IDS.tablets);
52
+ export const nodePageTabSchema = z.preprocess(
53
+ (value) => (value === 'structure' ? NODE_TABS_IDS.storage : value),
54
+ z.nativeEnum(NODE_TABS_IDS).catch(NODE_TABS_IDS.tablets),
55
+ );
60
56
 
61
57
  export const nodePageQueryParams = {
62
58
  database: StringParam,
63
- pdiskId: StringParam,
64
- vdiskId: StringParam,
65
59
  clusterName: StringParam,
60
+ backend: StringParam,
66
61
  };
67
62
 
68
63
  export type NodePageQuery = QueryParamsTypeFromQueryObject<typeof nodePageQueryParams>;