ydb-embedded-ui 22.4.0 → 22.5.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 (266) hide show
  1. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.d.ts +3 -2
  2. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.js +19 -4
  3. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.js.map +1 -1
  4. package/dist/components/CopyableValue/CopyableValue.d.ts +10 -0
  5. package/dist/components/CopyableValue/CopyableValue.js +10 -0
  6. package/dist/components/CopyableValue/CopyableValue.js.map +1 -0
  7. package/dist/components/CopyableValue/CopyableValue.scss +16 -0
  8. package/dist/components/CopyableValue/i18n/en.json +3 -0
  9. package/dist/components/CopyableValue/i18n/index.d.ts +2 -0
  10. package/dist/components/CopyableValue/i18n/index.js +6 -0
  11. package/dist/components/CopyableValue/i18n/index.js.map +1 -0
  12. package/dist/components/CriticalActionDialog/CriticalActionDialog.d.ts +2 -1
  13. package/dist/components/CriticalActionDialog/CriticalActionDialog.js +2 -1
  14. package/dist/components/CriticalActionDialog/CriticalActionDialog.js.map +1 -1
  15. package/dist/components/DiskCapacityInfo/DiskCapacityInfo.d.ts +1 -21
  16. package/dist/components/DiskCapacityInfo/DiskCapacityInfo.js +40 -126
  17. package/dist/components/DiskCapacityInfo/DiskCapacityInfo.js.map +1 -1
  18. package/dist/components/DiskCapacityInfo/i18n/en.json +0 -1
  19. package/dist/components/DiskCapacityInfo/i18n/index.d.ts +1 -1
  20. package/dist/components/EntityStatus/EntityStatus.d.ts +18 -6
  21. package/dist/components/EntityStatus/EntityStatus.js +5 -1
  22. package/dist/components/EntityStatus/EntityStatus.js.map +1 -1
  23. package/dist/components/EntityStatus/EntityStatus.scss +5 -0
  24. package/dist/components/EvictVDiskButton/EvictVDiskButton.d.ts +5 -2
  25. package/dist/components/EvictVDiskButton/EvictVDiskButton.js +3 -2
  26. package/dist/components/EvictVDiskButton/EvictVDiskButton.js.map +1 -1
  27. package/dist/components/EvictVDiskButton/i18n/en.json +2 -2
  28. package/dist/components/FullNodeViewer/FullNodeViewer.js +4 -7
  29. package/dist/components/FullNodeViewer/FullNodeViewer.js.map +1 -1
  30. package/dist/components/FullNodeViewer/i18n/index.d.ts +1 -1
  31. package/dist/components/HoverPopup/HoverPopup.d.ts +1 -0
  32. package/dist/components/HoverPopup/HoverPopup.js +87 -16
  33. package/dist/components/HoverPopup/HoverPopup.js.map +1 -1
  34. package/dist/components/MemoryViewer/MemoryViewer.d.ts +3 -1
  35. package/dist/components/MemoryViewer/MemoryViewer.js +25 -16
  36. package/dist/components/MemoryViewer/MemoryViewer.js.map +1 -1
  37. package/dist/components/MemoryViewer/i18n/en.json +4 -3
  38. package/dist/components/MemoryViewer/i18n/index.d.ts +1 -1
  39. package/dist/components/MemoryViewer/utils.d.ts +4 -2
  40. package/dist/components/MemoryViewer/utils.js +11 -11
  41. package/dist/components/MemoryViewer/utils.js.map +1 -1
  42. package/dist/components/PDiskInfo/PDiskInfo.d.ts +4 -9
  43. package/dist/components/PDiskInfo/PDiskInfo.js +32 -144
  44. package/dist/components/PDiskInfo/PDiskInfo.js.map +1 -1
  45. package/dist/components/PDiskInfo/PDiskInfo.scss +15 -0
  46. package/dist/components/PDiskInfo/PDiskLogSize.js +1 -1
  47. package/dist/components/PDiskInfo/PDiskLogSize.js.map +1 -1
  48. package/dist/components/PDiskInfo/i18n/en.json +6 -3
  49. package/dist/components/PDiskInfo/i18n/index.d.ts +1 -1
  50. package/dist/components/PDiskInfo/statuses.js +12 -3
  51. package/dist/components/PDiskInfo/statuses.js.map +1 -1
  52. package/dist/components/Search/Search.js +3 -1
  53. package/dist/components/Search/Search.js.map +1 -1
  54. package/dist/components/StorageGroupInfo/StorageGroupInfo.js +4 -9
  55. package/dist/components/StorageGroupInfo/StorageGroupInfo.js.map +1 -1
  56. package/dist/components/StorageGroupInfo/i18n/index.d.ts +1 -1
  57. package/dist/components/TenantNameWrapper/i18n/index.d.ts +1 -1
  58. package/dist/components/VDisk/VDisk.js +2 -2
  59. package/dist/components/VDisk/VDisk.js.map +1 -1
  60. package/dist/components/VDiskInfo/VDiskInfo.d.ts +3 -7
  61. package/dist/components/VDiskInfo/VDiskInfo.js +57 -235
  62. package/dist/components/VDiskInfo/VDiskInfo.js.map +1 -1
  63. package/dist/components/VDiskInfo/VDiskInfo.scss +19 -3
  64. package/dist/components/VDiskInfo/getVDiskDetails.d.ts +7 -1
  65. package/dist/components/VDiskInfo/getVDiskDetails.js +14 -1
  66. package/dist/components/VDiskInfo/getVDiskDetails.js.map +1 -1
  67. package/dist/components/VDiskInfo/i18n/en.json +4 -13
  68. package/dist/components/VDiskInfo/i18n/index.d.ts +1 -1
  69. package/dist/components/VDiskPopup/VDiskPopup.d.ts +2 -1
  70. package/dist/components/VDiskPopup/VDiskPopup.js +10 -26
  71. package/dist/components/VDiskPopup/VDiskPopup.js.map +1 -1
  72. package/dist/components/VDiskPopup/i18n/en.json +0 -2
  73. package/dist/components/VDiskPopup/i18n/index.d.ts +1 -1
  74. package/dist/components/VDiskStatus/VDiskReplicationStatus.js +1 -1
  75. package/dist/components/VDiskStatus/VDiskReplicationStatus.js.map +1 -1
  76. package/dist/components/VDiskStatus/VDiskStatus.js +2 -2
  77. package/dist/components/VDiskStatus/VDiskStatus.js.map +1 -1
  78. package/dist/components/VDiskStatus/VDiskStatus.scss +4 -0
  79. package/dist/components/VDiskStatus/statuses.js +2 -2
  80. package/dist/components/VDiskStatus/statuses.js.map +1 -1
  81. package/dist/components/nodesColumns/columns.d.ts +1 -0
  82. package/dist/components/nodesColumns/columns.js +13 -6
  83. package/dist/components/nodesColumns/columns.js.map +1 -1
  84. package/dist/containers/Clusters/Clusters.js +35 -6
  85. package/dist/containers/Clusters/Clusters.js.map +1 -1
  86. package/dist/containers/Clusters/Clusters.scss +24 -6
  87. package/dist/containers/Clusters/columns.js +9 -4
  88. package/dist/containers/Clusters/columns.js.map +1 -1
  89. package/dist/containers/Clusters/i18n/en.json +6 -0
  90. package/dist/containers/Clusters/i18n/index.d.ts +1 -1
  91. package/dist/containers/Header/Header.js +8 -0
  92. package/dist/containers/Header/Header.js.map +1 -1
  93. package/dist/containers/Header/HeaderLeftControls.js +3 -1
  94. package/dist/containers/Header/HeaderLeftControls.js.map +1 -1
  95. package/dist/containers/Header/PDiskLeftControls.d.ts +1 -0
  96. package/dist/containers/Header/PDiskLeftControls.js +24 -0
  97. package/dist/containers/Header/PDiskLeftControls.js.map +1 -0
  98. package/dist/containers/Header/VDiskLeftControls.d.ts +1 -0
  99. package/dist/containers/Header/VDiskLeftControls.js +23 -0
  100. package/dist/containers/Header/VDiskLeftControls.js.map +1 -0
  101. package/dist/containers/Header/breadcrumbs.js +5 -2
  102. package/dist/containers/Header/breadcrumbs.js.map +1 -1
  103. package/dist/containers/Header/i18n/en.json +4 -1
  104. package/dist/containers/Header/i18n/index.d.ts +1 -1
  105. package/dist/containers/Nodes/NodesControls/NodesControls.js +1 -1
  106. package/dist/containers/Nodes/NodesControls/NodesControls.js.map +1 -1
  107. package/dist/containers/Nodes/PaginatedNodes/GroupedNodesComponent.js +5 -3
  108. package/dist/containers/Nodes/PaginatedNodes/GroupedNodesComponent.js.map +1 -1
  109. package/dist/containers/Nodes/PaginatedNodes/NodesComponent.js +4 -2
  110. package/dist/containers/Nodes/PaginatedNodes/NodesComponent.js.map +1 -1
  111. package/dist/containers/Nodes/useDebouncedSearch.d.ts +2 -0
  112. package/dist/containers/Nodes/useDebouncedSearch.js +11 -0
  113. package/dist/containers/Nodes/useDebouncedSearch.js.map +1 -0
  114. package/dist/containers/PDiskPage/PDiskPage.js +30 -31
  115. package/dist/containers/PDiskPage/PDiskPage.js.map +1 -1
  116. package/dist/containers/PDiskPage/PDiskPage.scss +22 -11
  117. package/dist/containers/PDiskPage/PDiskSpaceDistribution/PDiskSpaceDistribution.js +3 -3
  118. package/dist/containers/PDiskPage/PDiskSpaceDistribution/PDiskSpaceDistribution.js.map +1 -1
  119. package/dist/containers/PDiskPage/PDiskStorageDetails.d.ts +6 -0
  120. package/dist/containers/PDiskPage/PDiskStorageDetails.js +28 -0
  121. package/dist/containers/PDiskPage/PDiskStorageDetails.js.map +1 -0
  122. package/dist/containers/PDiskPage/PDiskStorageDetails.scss +51 -0
  123. package/dist/containers/PDiskPage/i18n/en.json +2 -0
  124. package/dist/containers/PDiskPage/i18n/index.d.ts +1 -1
  125. package/dist/containers/Storage/PaginatedStorageGroupsTable/columns/i18n/index.d.ts +1 -1
  126. package/dist/containers/Storage/StorageExpertModePanel/constants.d.ts +1 -1
  127. package/dist/containers/Storage/StorageExpertModePanel/i18n/index.d.ts +1 -1
  128. package/dist/containers/Storage/useStorageQueryParams.d.ts +4 -4
  129. package/dist/containers/StorageGroupPage/StorageGroupPage.js +7 -5
  130. package/dist/containers/StorageGroupPage/StorageGroupPage.js.map +1 -1
  131. package/dist/containers/StorageGroupPage/StorageGroupPage.scss +10 -0
  132. package/dist/containers/StorageGroupPage/i18n/en.json +0 -1
  133. package/dist/containers/StorageGroupPage/i18n/index.d.ts +1 -1
  134. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/ManagePartitioningDialog/i18n/index.d.ts +1 -1
  135. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +5 -12
  136. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js.map +1 -1
  137. package/dist/containers/Tenant/Diagnostics/TopQueries/columns/i18n/index.d.ts +1 -1
  138. package/dist/containers/Tenant/Healthcheck/Healthcheck.scss +6 -1
  139. package/dist/containers/Tenant/Healthcheck/components/HealthcheckIssue.js +2 -2
  140. package/dist/containers/Tenant/Healthcheck/components/HealthcheckIssue.js.map +1 -1
  141. package/dist/containers/Tenant/TenantDrawerHealthcheck.js +10 -2
  142. package/dist/containers/Tenant/TenantDrawerHealthcheck.js.map +1 -1
  143. package/dist/containers/VDiskPage/VDiskPage.js +33 -33
  144. package/dist/containers/VDiskPage/VDiskPage.js.map +1 -1
  145. package/dist/containers/VDiskPage/VDiskPage.scss +21 -8
  146. package/dist/containers/VDiskPage/VDiskStorageDetails.js +27 -29
  147. package/dist/containers/VDiskPage/VDiskStorageDetails.js.map +1 -1
  148. package/dist/containers/VDiskPage/VDiskStorageDetails.scss +24 -93
  149. package/dist/containers/VDiskPage/i18n/en.json +3 -12
  150. package/dist/containers/VDiskPage/i18n/index.d.ts +1 -1
  151. package/dist/store/reducers/cluster/parseFields.js +1 -0
  152. package/dist/store/reducers/cluster/parseFields.js.map +1 -1
  153. package/dist/store/reducers/clusters/clusters.js +1 -0
  154. package/dist/store/reducers/clusters/clusters.js.map +1 -1
  155. package/dist/store/reducers/clusters/selectors.d.ts +1 -0
  156. package/dist/store/reducers/clusters/selectors.js +4 -1
  157. package/dist/store/reducers/clusters/selectors.js.map +1 -1
  158. package/dist/store/reducers/clusters/types.d.ts +2 -0
  159. package/dist/store/reducers/storage/prepareGroupsDisks.d.ts +1 -1
  160. package/dist/store/reducers/storage/prepareGroupsDisks.js +2 -1
  161. package/dist/store/reducers/storage/prepareGroupsDisks.js.map +1 -1
  162. package/dist/store/reducers/storage/utils.js +10 -3
  163. package/dist/store/reducers/storage/utils.js.map +1 -1
  164. package/dist/store/reducers/vdisk/types.d.ts +1 -1
  165. package/dist/store/reducers/vdisk/utils.js +5 -5
  166. package/dist/store/reducers/vdisk/utils.js.map +1 -1
  167. package/dist/types/api/meta.d.ts +1 -0
  168. package/dist/types/api/nodesList.d.ts +2 -0
  169. package/dist/utils/hooks/useDatabaseHealthcheckAvailable.d.ts +2 -0
  170. package/dist/utils/hooks/useDatabaseHealthcheckAvailable.js +6 -0
  171. package/dist/utils/hooks/useDatabaseHealthcheckAvailable.js.map +1 -0
  172. package/dist/utils/memory.d.ts +5 -0
  173. package/dist/utils/memory.js +9 -0
  174. package/dist/utils/memory.js.map +1 -0
  175. package/dist/utils/nodes.js +3 -3
  176. package/dist/utils/nodes.js.map +1 -1
  177. package/dist/utils/storageMetrics.d.ts +1 -0
  178. package/dist/utils/storageMetrics.js +8 -0
  179. package/dist/utils/storageMetrics.js.map +1 -1
  180. package/package.json +1 -1
  181. package/src/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.tsx +22 -3
  182. package/src/components/CopyableValue/CopyableValue.scss +16 -0
  183. package/src/components/CopyableValue/CopyableValue.tsx +40 -0
  184. package/src/components/CopyableValue/i18n/en.json +3 -0
  185. package/src/components/CopyableValue/i18n/index.ts +8 -0
  186. package/src/components/CriticalActionDialog/CriticalActionDialog.tsx +3 -0
  187. package/src/components/DiskCapacityInfo/DiskCapacityInfo.tsx +40 -185
  188. package/src/components/DiskCapacityInfo/i18n/en.json +0 -1
  189. package/src/components/EntityStatus/EntityStatus.scss +5 -0
  190. package/src/components/EntityStatus/EntityStatus.tsx +38 -5
  191. package/src/components/EvictVDiskButton/EvictVDiskButton.tsx +10 -2
  192. package/src/components/EvictVDiskButton/i18n/en.json +2 -2
  193. package/src/components/FullNodeViewer/FullNodeViewer.tsx +4 -9
  194. package/src/components/HoverPopup/HoverPopup.tsx +95 -19
  195. package/src/components/MemoryViewer/MemoryViewer.tsx +30 -17
  196. package/src/components/MemoryViewer/i18n/en.json +4 -3
  197. package/src/components/MemoryViewer/utils.ts +19 -12
  198. package/src/components/PDiskInfo/PDiskInfo.scss +15 -0
  199. package/src/components/PDiskInfo/PDiskInfo.tsx +51 -243
  200. package/src/components/PDiskInfo/PDiskLogSize.tsx +12 -8
  201. package/src/components/PDiskInfo/i18n/en.json +6 -3
  202. package/src/components/PDiskInfo/statuses.ts +16 -3
  203. package/src/components/Search/Search.tsx +5 -2
  204. package/src/components/StorageGroupInfo/StorageGroupInfo.tsx +8 -13
  205. package/src/components/VDisk/VDisk.tsx +3 -2
  206. package/src/components/VDiskInfo/VDiskInfo.scss +19 -3
  207. package/src/components/VDiskInfo/VDiskInfo.tsx +119 -341
  208. package/src/components/VDiskInfo/getVDiskDetails.tsx +24 -2
  209. package/src/components/VDiskInfo/i18n/en.json +4 -13
  210. package/src/components/VDiskPopup/VDiskPopup.tsx +16 -24
  211. package/src/components/VDiskPopup/i18n/en.json +0 -2
  212. package/src/components/VDiskStatus/VDiskReplicationStatus.tsx +1 -1
  213. package/src/components/VDiskStatus/VDiskStatus.scss +4 -0
  214. package/src/components/VDiskStatus/VDiskStatus.tsx +13 -2
  215. package/src/components/VDiskStatus/statuses.ts +2 -2
  216. package/src/components/nodesColumns/columns.tsx +26 -12
  217. package/src/containers/Clusters/Clusters.scss +24 -6
  218. package/src/containers/Clusters/Clusters.tsx +74 -5
  219. package/src/containers/Clusters/columns.tsx +36 -6
  220. package/src/containers/Clusters/i18n/en.json +6 -0
  221. package/src/containers/Header/Header.tsx +8 -0
  222. package/src/containers/Header/HeaderLeftControls.tsx +3 -1
  223. package/src/containers/Header/PDiskLeftControls.tsx +41 -0
  224. package/src/containers/Header/VDiskLeftControls.tsx +40 -0
  225. package/src/containers/Header/breadcrumbs.tsx +4 -2
  226. package/src/containers/Header/i18n/en.json +4 -1
  227. package/src/containers/Nodes/NodesControls/NodesControls.tsx +1 -0
  228. package/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx +5 -3
  229. package/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx +4 -2
  230. package/src/containers/Nodes/useDebouncedSearch.ts +13 -0
  231. package/src/containers/PDiskPage/PDiskPage.scss +22 -11
  232. package/src/containers/PDiskPage/PDiskPage.tsx +88 -56
  233. package/src/containers/PDiskPage/PDiskSpaceDistribution/PDiskSpaceDistribution.tsx +3 -9
  234. package/src/containers/PDiskPage/PDiskStorageDetails.scss +51 -0
  235. package/src/containers/PDiskPage/PDiskStorageDetails.tsx +64 -0
  236. package/src/containers/PDiskPage/i18n/en.json +2 -0
  237. package/src/containers/StorageGroupPage/StorageGroupPage.scss +10 -0
  238. package/src/containers/StorageGroupPage/StorageGroupPage.tsx +37 -28
  239. package/src/containers/StorageGroupPage/i18n/en.json +0 -1
  240. package/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +5 -32
  241. package/src/containers/Tenant/Healthcheck/Healthcheck.scss +6 -1
  242. package/src/containers/Tenant/Healthcheck/components/HealthcheckIssue.tsx +18 -8
  243. package/src/containers/Tenant/TenantDrawerHealthcheck.tsx +14 -1
  244. package/src/containers/VDiskPage/VDiskPage.scss +21 -8
  245. package/src/containers/VDiskPage/VDiskPage.tsx +103 -64
  246. package/src/containers/VDiskPage/VDiskStorageDetails.scss +24 -93
  247. package/src/containers/VDiskPage/VDiskStorageDetails.tsx +50 -158
  248. package/src/containers/VDiskPage/i18n/en.json +3 -14
  249. package/src/store/reducers/cluster/parseFields.ts +1 -0
  250. package/src/store/reducers/clusters/clusters.ts +1 -0
  251. package/src/store/reducers/clusters/selectors.ts +4 -0
  252. package/src/store/reducers/clusters/types.ts +3 -0
  253. package/src/store/reducers/storage/prepareGroupsDisks.ts +2 -0
  254. package/src/store/reducers/storage/utils.ts +13 -3
  255. package/src/store/reducers/vdisk/types.ts +2 -1
  256. package/src/store/reducers/vdisk/utils.ts +4 -5
  257. package/src/types/api/meta.ts +1 -0
  258. package/src/types/api/nodesList.ts +3 -0
  259. package/src/utils/hooks/useDatabaseHealthcheckAvailable.ts +9 -0
  260. package/src/utils/memory.ts +16 -0
  261. package/src/utils/nodes.ts +3 -2
  262. package/src/utils/storageMetrics.ts +11 -0
  263. package/dist/components/VDiskInfo/getVDiskCapacityColumns.d.ts +0 -11
  264. package/dist/components/VDiskInfo/getVDiskCapacityColumns.js +0 -52
  265. package/dist/components/VDiskInfo/getVDiskCapacityColumns.js.map +0 -1
  266. package/src/components/VDiskInfo/getVDiskCapacityColumns.tsx +0 -83
@@ -9,7 +9,6 @@ import {api} from '../../store/reducers/api';
9
9
  import {useBlobStorageCapacityMetricsEnabled} from '../../store/reducers/capabilities/hooks';
10
10
  import type {TVDiskID} from '../../types/api/vdisk';
11
11
  import type {NodeMetadata} from '../../types/store/nodesList';
12
- import {formatBytes} from '../../utils/bytesParsers';
13
12
  import {cn} from '../../utils/cn';
14
13
  import {BRAND_BUTTON_CLASS, EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
15
14
  import {parseVdiskId} from '../../utils/dataFormatters/dataFormatters';
@@ -19,7 +18,6 @@ import type {PreparedVDisk, UnavailableDonor} from '../../utils/disks/types';
19
18
  import {useTypedDispatch} from '../../utils/hooks';
20
19
  import {useIsViewerUser} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
21
20
  import {useNodeMetadata} from '../../utils/hooks/useNodeMetadata';
22
- import {parseOptionalNonNegativeNumber} from '../../utils/utils';
23
21
  import {getVDiskCapacityItems} from '../DiskCapacityInfo/DiskCapacityInfo';
24
22
  import {
25
23
  DiskPopup,
@@ -32,7 +30,11 @@ import {EvictVDiskButton, isAllVdiskParamsDefined} from '../EvictVDiskButton/Evi
32
30
  import {InternalLinkButton} from '../InternalLinkButton';
33
31
  import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
34
32
  import {PDiskPopupContent} from '../PDiskPopup/PDiskPopup';
35
- import {getVDiskIdentityItems, getVDiskLocationItems} from '../VDiskInfo/getVDiskDetails';
33
+ import {
34
+ getVDiskIdentityItems,
35
+ getVDiskLocationItems,
36
+ getVDiskThroughputItems,
37
+ } from '../VDiskInfo/getVDiskDetails';
36
38
  import {vDiskInfoKeyset} from '../VDiskInfo/i18n';
37
39
  import {
38
40
  VDiskCompactionRankLabel,
@@ -103,24 +105,7 @@ function getRuntimeItems(
103
105
  ),
104
106
  },
105
107
  ];
106
- for (const [name, value] of [
107
- [vDiskPopupKeyset('label_read'), data.ReadThroughput],
108
- [vDiskPopupKeyset('label_write'), data.WriteThroughput],
109
- ] as const) {
110
- const throughput = parseOptionalNonNegativeNumber(value);
111
- items.push({
112
- name,
113
- content:
114
- throughput === undefined
115
- ? EMPTY_DATA_PLACEHOLDER
116
- : formatBytes({
117
- value: throughput,
118
- size: 'mb',
119
- fixedDecimalPlaces: 2,
120
- withSpeedLabel: true,
121
- }),
122
- });
123
- }
108
+ items.push(...getVDiskThroughputItems(data));
124
109
  if (withUnreadableBlobs) {
125
110
  items.push({
126
111
  name: vDiskInfoKeyset('has-unreadable-blobs'),
@@ -198,8 +183,9 @@ function buildVDiskFooter(
198
183
  data: PreparedVDisk,
199
184
  withDeveloperUILink: boolean,
200
185
  getVDiskLinkFn: ReturnType<typeof useVDiskPagePath>,
201
- onSuccess: VoidFunction,
186
+ onSuccess: (isDialogOpen: boolean) => void,
202
187
  withActions: boolean,
188
+ onDialogOpen?: () => VoidFunction,
203
189
  ): React.ReactNode | null {
204
190
  const {NodeId, PDiskId, VDiskSlotId, StringifiedId, DonorMode} = data;
205
191
  const vDiskInternalViewerPath =
@@ -245,6 +231,7 @@ function buildVDiskFooter(
245
231
  vDiskId={resolvedVDiskId}
246
232
  donorMode={DonorMode}
247
233
  onSuccess={onSuccess}
234
+ onDialogOpen={onDialogOpen}
248
235
  />
249
236
  )}
250
237
  </Flex>
@@ -257,6 +244,7 @@ interface VDiskPopupProps {
257
244
  data: PreparedVDisk;
258
245
  nodeData?: NodeMetadata;
259
246
  onClose?: VoidFunction;
247
+ onDialogOpen?: () => VoidFunction;
260
248
  view?: 'default' | 'space-distribution';
261
249
  }
262
250
 
@@ -264,6 +252,7 @@ export function VDiskPopup({
264
252
  data,
265
253
  nodeData: parentNodeData,
266
254
  onClose,
255
+ onDialogOpen,
267
256
  view = 'default',
268
257
  }: VDiskPopupProps) {
269
258
  const dispatch = useTypedDispatch();
@@ -274,7 +263,7 @@ export function VDiskPopup({
274
263
  const getVDiskLink = useVDiskPagePath();
275
264
  const fullData = isFullVDiskData(data) ? data : undefined;
276
265
  const vdiskId = fullData?.StringifiedId;
277
- const handleAfterEvictVDisk = () => {
266
+ const handleAfterEvictVDisk = (isDialogOpen: boolean) => {
278
267
  dispatch(
279
268
  api.util.invalidateTags([
280
269
  'TableData',
@@ -283,7 +272,9 @@ export function VDiskPopup({
283
272
  {type: 'VDiskData', id: vdiskId},
284
273
  ]),
285
274
  );
286
- onClose?.();
275
+ if (isDialogOpen) {
276
+ onClose?.();
277
+ }
287
278
  };
288
279
  const isSpaceDistribution = view === 'space-distribution';
289
280
  const runtimeItems = fullData ? getRuntimeItems(fullData, isSpaceDistribution) : [];
@@ -297,6 +288,7 @@ export function VDiskPopup({
297
288
  getVDiskLink,
298
289
  handleAfterEvictVDisk,
299
290
  !isSpaceDistribution,
291
+ onDialogOpen,
300
292
  )
301
293
  : buildUnavailableVDiskFooter(data, hasDeveloperUi);
302
294
  const locationItems = getLocationItems(data, nodeData, Boolean(pdisk));
@@ -2,8 +2,6 @@
2
2
  "label_storage-pool": "Storage Pool Name",
3
3
  "label_vdisk": "VDisk",
4
4
  "label_front-queues": "Front Queues",
5
- "label_read": "Read Throughput",
6
- "label_write": "Write Throughput",
7
5
  "action_open-in-developer-ui": "Open in Developer UI",
8
6
  "action_go-to-vdisk": "Go to VDisk",
9
7
  "label_compaction": "Compaction"
@@ -36,7 +36,7 @@ export function VDiskReplicationStatus({data, size}: VDiskReplicationStatusProps
36
36
 
37
37
  return (
38
38
  <React.Fragment>
39
- {label && <DiskStatusLabel {...label} size={size} />}
39
+ {label && <DiskStatusLabel {...label} size={size} iconSize={size === 'xs' ? 12 : 14} />}
40
40
  {showProgress && <ReplicationProgress data={data} size={size} />}
41
41
  </React.Fragment>
42
42
  );
@@ -11,6 +11,10 @@
11
11
  background-color: var(--g-color-base-selection);
12
12
  @include mixins.text-body-short();
13
13
 
14
+ &_size_s {
15
+ border-radius: var(--g-border-radius-s);
16
+ }
17
+
14
18
  &_size_xs {
15
19
  min-height: 20px;
16
20
  padding: 2px 6px;
@@ -10,7 +10,13 @@ import {vDiskStatusKeyset as i18n} from './i18n';
10
10
  import {getVDiskStateLabel} from './statuses';
11
11
 
12
12
  export function VDiskStateLabel({state, size}: {state?: EVDiskState} & Pick<LabelProps, 'size'>) {
13
- return <DiskStatusLabel {...getVDiskStateLabel({VDiskState: state})} size={size} />;
13
+ return (
14
+ <DiskStatusLabel
15
+ {...getVDiskStateLabel({VDiskState: state})}
16
+ size={size}
17
+ iconSize={size === 'xs' ? 12 : 14}
18
+ />
19
+ );
14
20
  }
15
21
 
16
22
  export function VDiskDonorLabel({
@@ -18,7 +24,12 @@ export function VDiskDonorLabel({
18
24
  size,
19
25
  }: {donorMode?: boolean} & Pick<LabelProps, 'size'>) {
20
26
  return donorMode ? (
21
- <DiskStatusLabel value={i18n('label_donor')} {...VDISK_LABEL_CONFIG.donor} size={size} />
27
+ <DiskStatusLabel
28
+ value={i18n('label_donor')}
29
+ {...VDISK_LABEL_CONFIG.donor}
30
+ size={size}
31
+ iconSize={size === 'xs' ? 12 : 14}
32
+ />
22
33
  ) : null;
23
34
  }
24
35
 
@@ -3,7 +3,7 @@ import {
3
3
  ArrowsRotateLeftSlash,
4
4
  Check,
5
5
  CirclePause,
6
- CircleQuestion,
6
+ CircleQuestionFill,
7
7
  CircleStop,
8
8
  } from '@gravity-ui/icons';
9
9
 
@@ -29,7 +29,7 @@ export function getVDiskStateLabel(data: PreparedVDisk): DiskStatusLabelData {
29
29
  return {
30
30
  value: i18n('value_no-data'),
31
31
  theme: 'unknown',
32
- icon: CircleQuestion,
32
+ icon: CircleQuestionFill,
33
33
  tooltip: i18n('context_state-no-data'),
34
34
  };
35
35
  }
@@ -13,6 +13,7 @@ import {
13
13
  formatStorageValuesToGb,
14
14
  } from '../../utils/dataFormatters/dataFormatters';
15
15
  import {getUsageSeverity} from '../../utils/generateEvaluator';
16
+ import {getNodeMemory} from '../../utils/memory';
16
17
  import type {Column} from '../../utils/tableUtils/types';
17
18
  import {formatToMs, parseUsToMs} from '../../utils/timeParsers';
18
19
  import {bytesToSpeed, isNumeric} from '../../utils/utils';
@@ -169,22 +170,26 @@ export function getUptimeColumn<
169
170
  };
170
171
  }
171
172
 
172
- export function getRAMColumn<T extends {MemoryUsed?: string; MemoryLimit?: string}>(): Column<T> {
173
+ export function getRAMColumn<
174
+ T extends {MemoryStats?: TMemoryStats; MemoryUsed?: string; MemoryLimit?: string},
175
+ >(): Column<T> {
173
176
  return {
174
177
  name: NODES_COLUMNS_IDS.RAM,
175
178
  header: NODES_COLUMNS_TITLES.RAM,
176
- sortAccessor: ({MemoryUsed = 0}) => Number(MemoryUsed),
179
+ sortAccessor: (row) => getNodeMemory(row).memoryUsed ?? 0,
177
180
  defaultOrder: DataTable.DESCENDING,
178
181
  render: ({row}) => {
182
+ const {memoryUsed: used, memoryLimit: limit} = getNodeMemory(row);
179
183
  const [memoryUsed, memoryLimit] = formatStorageValues(
180
- isNumeric(row.MemoryUsed) ? Number(row.MemoryUsed) : undefined,
181
- isNumeric(row.MemoryLimit) ? Number(row.MemoryLimit) : undefined,
184
+ used,
185
+ limit,
182
186
  'gb',
183
187
  undefined,
184
188
  true,
185
189
  );
186
190
 
187
191
  const hasData = memoryUsed || memoryLimit;
192
+ const memoryContent = used === undefined ? EMPTY_DATA_PLACEHOLDER : memoryUsed;
188
193
 
189
194
  return (
190
195
  <CellWithPopover
@@ -206,10 +211,10 @@ export function getRAMColumn<T extends {MemoryUsed?: string; MemoryLimit?: strin
206
211
  </DefinitionList>
207
212
  }
208
213
  >
209
- {isNumeric(row.MemoryUsed) ? (
214
+ {used !== undefined && limit !== undefined ? (
210
215
  <ProgressViewer
211
- value={row.MemoryUsed}
212
- capacity={row.MemoryLimit}
216
+ value={used}
217
+ capacity={limit}
213
218
  formatValues={(value, total) =>
214
219
  formatStorageValues(value, total, 'gb', undefined, true)
215
220
  }
@@ -218,7 +223,7 @@ export function getRAMColumn<T extends {MemoryUsed?: string; MemoryLimit?: strin
218
223
  hideCapacity
219
224
  />
220
225
  ) : (
221
- EMPTY_DATA_PLACEHOLDER
226
+ memoryContent
222
227
  )}
223
228
  </CellWithPopover>
224
229
  );
@@ -238,18 +243,27 @@ export function getMemoryColumn<
238
243
  render: ({row}) => {
239
244
  if (row.MemoryStats) {
240
245
  return (
241
- <MemoryViewer formatValues={formatStorageValuesToGb} stats={row.MemoryStats} />
246
+ <MemoryViewer
247
+ formatValues={formatStorageValuesToGb}
248
+ stats={row.MemoryStats}
249
+ memoryUsed={row.MemoryUsed}
250
+ memoryLimit={row.MemoryLimit}
251
+ />
242
252
  );
243
253
  }
244
254
 
245
- if (!isNumeric(row.MemoryUsed)) {
255
+ const {memoryUsed, memoryLimit} = getNodeMemory(row);
256
+ if (memoryUsed === undefined) {
246
257
  return EMPTY_DATA_PLACEHOLDER;
247
258
  }
259
+ if (memoryLimit === undefined) {
260
+ return formatStorageValuesToGb(memoryUsed)[0];
261
+ }
248
262
 
249
263
  return (
250
264
  <ProgressViewer
251
- value={row.MemoryUsed}
252
- capacity={row.MemoryLimit}
265
+ value={memoryUsed}
266
+ capacity={memoryLimit}
253
267
  formatValues={formatStorageValuesToGb}
254
268
  colorizeProgress={true}
255
269
  />
@@ -3,19 +3,37 @@
3
3
  .ydb-clusters {
4
4
  @include mixins.body-2-typography();
5
5
 
6
- &__controls {
6
+ &__clusters-count {
7
7
  padding-bottom: var(--g-spacing-2);
8
8
  }
9
9
 
10
- &__clusters-count {
11
- padding-bottom: var(--g-spacing-2);
10
+ &__availability-popup .g-select-list__option {
11
+ align-items: flex-start;
12
+
13
+ padding-block: var(--g-spacing-2);
14
+ }
15
+
16
+ &__cluster-name-wrapper {
17
+ min-width: 0;
12
18
  }
13
19
 
14
20
  &__cluster-name {
15
- white-space: normal;
16
- text-decoration: none;
21
+ overflow: hidden;
22
+
23
+ white-space: nowrap;
24
+ text-overflow: ellipsis;
25
+ }
26
+
27
+ &__unavailable-label {
28
+ display: inline-flex;
29
+ flex-shrink: 0;
30
+
31
+ border-radius: var(--g-focus-border-radius);
17
32
 
18
- color: var(--g-color-text-link);
33
+ &:focus-visible {
34
+ outline: 2px solid var(--g-color-line-focus);
35
+ outline-offset: 2px;
36
+ }
19
37
  }
20
38
  &__cluster-versions {
21
39
  text-decoration: none;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
 
3
3
  import {Magnifier} from '@gravity-ui/icons';
4
4
  import DataTable from '@gravity-ui/react-data-table';
5
- import {Icon, Select, Text} from '@gravity-ui/uikit';
5
+ import {Flex, Icon, Select, Text} from '@gravity-ui/uikit';
6
6
 
7
7
  import {ResponseError} from '../../components/Errors/ResponseError';
8
8
  import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable';
@@ -13,13 +13,14 @@ import {useEmMetaAvailable} from '../../store/reducers/capabilities/hooks';
13
13
  import {changeClustersFilters, clustersApi} from '../../store/reducers/clusters/clusters';
14
14
  import {
15
15
  filterClusters,
16
+ selectAvailabilityFilter,
16
17
  selectClusterNameFilter,
17
18
  selectGalaxyFilter,
18
19
  selectServiceFilter,
19
20
  selectStatusFilter,
20
21
  selectVersionFilter,
21
22
  } from '../../store/reducers/clusters/selectors';
22
- import type {PreparedCluster} from '../../store/reducers/clusters/types';
23
+ import type {ClusterAvailability, PreparedCluster} from '../../store/reducers/clusters/types';
23
24
  import {uiFactory} from '../../uiFactory/uiFactory';
24
25
  import {DEFAULT_TABLE_SETTINGS, EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
25
26
  import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../utils/hooks';
@@ -61,6 +62,7 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
61
62
  const service = useTypedSelector(selectServiceFilter);
62
63
  const version = useTypedSelector(selectVersionFilter);
63
64
  const galaxy = useTypedSelector(selectGalaxyFilter);
65
+ const availability = useTypedSelector(selectAvailabilityFilter);
64
66
 
65
67
  const changeStatus = (value: string[]) => {
66
68
  dispatch(changeClustersFilters({status: value}));
@@ -77,6 +79,16 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
77
79
  const changeGalaxy = (value: string[]) => {
78
80
  dispatch(changeClustersFilters({galaxy: value}));
79
81
  };
82
+ const changeAvailability = (value: string[]) => {
83
+ dispatch(
84
+ changeClustersFilters({
85
+ availability: value.filter(
86
+ (item): item is ClusterAvailability =>
87
+ item === 'available' || item === 'unavailable',
88
+ ),
89
+ }),
90
+ );
91
+ };
80
92
 
81
93
  const [healthcheckClusterName, setHealthcheckClusterName] = React.useState<string | undefined>(
82
94
  undefined,
@@ -101,6 +113,19 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
101
113
  }, [isDeleteClusterAvailable, isEditClusterAvailable, handleStatusClick]);
102
114
 
103
115
  const clusters = query.data;
116
+ const hasUnavailableClusters = clusters?.some(
117
+ (cluster) => cluster.settings?.unavailable === true,
118
+ );
119
+ const showAvailabilityFilter =
120
+ hasUnavailableClusters || availability.length !== 1 || availability[0] !== 'available';
121
+ const availabilityOptions = [
122
+ {value: 'available', content: i18n('value_available')},
123
+ {value: 'unavailable', content: i18n('value_unavailable')},
124
+ ];
125
+ const availabilitySummary =
126
+ availability.length === availabilityOptions.length
127
+ ? i18n('controls_select-placeholder')
128
+ : availabilityOptions.find((option) => option.value === availability[0])?.content;
104
129
 
105
130
  // Check which columns have data across all clusters
106
131
  const {hasAnyStatus, hasAnyService, hasAnyGalaxy} = React.useMemo(() => {
@@ -184,8 +209,15 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
184
209
  }, [clusters]);
185
210
 
186
211
  const filteredClusters = React.useMemo(() => {
187
- return filterClusters(clusters ?? [], {clusterName, status, service, version, galaxy});
188
- }, [clusterName, clusters, service, status, version, galaxy]);
212
+ return filterClusters(clusters ?? [], {
213
+ clusterName,
214
+ status,
215
+ service,
216
+ version,
217
+ galaxy,
218
+ availability,
219
+ });
220
+ }, [clusterName, clusters, service, status, version, galaxy, availability]);
189
221
 
190
222
  const statuses = React.useMemo(() => {
191
223
  return Array.from(
@@ -260,6 +292,37 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
260
292
  width={200}
261
293
  />
262
294
  ) : null}
295
+ {showAvailabilityFilter ? (
296
+ <Select
297
+ multiple
298
+ label={i18n('controls_availability-select-label')}
299
+ placeholder={i18n('value_none')}
300
+ value={availability}
301
+ options={availabilityOptions}
302
+ onUpdate={changeAvailability}
303
+ width={200}
304
+ popupWidth={280}
305
+ popupClassName={b('availability-popup')}
306
+ hasCounter={false}
307
+ qa="clusters-availability"
308
+ getOptionHeight={(option) => (option.value === 'unavailable' ? 56 : 36)}
309
+ renderOption={(option) => (
310
+ <Flex direction="column">
311
+ <Text>{option.content}</Text>
312
+ {option.value === 'unavailable' ? (
313
+ <Text color="secondary" variant="body-1">
314
+ {i18n('context_unavailable-admin')}
315
+ </Text>
316
+ ) : null}
317
+ </Flex>
318
+ )}
319
+ renderSelectedOption={(_option, index) => (
320
+ <React.Fragment>
321
+ {index === 0 ? availabilitySummary : null}
322
+ </React.Fragment>
323
+ )}
324
+ />
325
+ ) : null}
263
326
  </React.Fragment>
264
327
  );
265
328
  };
@@ -320,7 +383,13 @@ export function Clusters({scrollContainerRef}: ClustersProps) {
320
383
  <TableWithControlsLayout
321
384
  fullHeight
322
385
  className={b(null)}
323
- keyboardNavigationResetKey={JSON.stringify([status, service, version, galaxy])}
386
+ keyboardNavigationResetKey={JSON.stringify([
387
+ status,
388
+ service,
389
+ version,
390
+ galaxy,
391
+ availability,
392
+ ])}
324
393
  >
325
394
  <TableWithControlsLayout.Controls
326
395
  className={b('controls')}
@@ -1,13 +1,15 @@
1
- import {Pencil, TrashBin} from '@gravity-ui/icons';
1
+ import {CircleXmark, Pencil, TrashBin} from '@gravity-ui/icons';
2
2
  import DataTable from '@gravity-ui/react-data-table';
3
3
  import type {Column} from '@gravity-ui/react-data-table';
4
4
  import {
5
5
  ClipboardButton,
6
6
  Link as ExternalLink,
7
7
  Flex,
8
+ Icon,
8
9
  Label,
9
10
  Progress,
10
11
  Text,
12
+ Tooltip,
11
13
  } from '@gravity-ui/uikit';
12
14
 
13
15
  import type {DropdownMenuItemWithDescription} from '../../components/DropdownMenu';
@@ -240,9 +242,9 @@ function getTitleColumn({
240
242
 
241
243
  return (
242
244
  <Flex direction={'column'} gap={0.5}>
243
- <Flex alignItems={'flex-start'} justifyContent={'space-between'} gap={1}>
245
+ <Flex alignItems="center" justifyContent="space-between" gap={1}>
244
246
  {renderName()}
245
- <Flex gap={1}>
247
+ <Flex alignItems="center" gap={1}>
246
248
  {renderStatus()}
247
249
  {renderActions()}
248
250
  </Flex>
@@ -262,9 +264,37 @@ function ClusterName({row}: ClusterNameProps) {
262
264
  const clusterPath = calculateClusterPath(row);
263
265
 
264
266
  return (
265
- <div className={b('cluster-name')}>
266
- <ExternalLink href={clusterPath}>{row.title || row.name}</ExternalLink>
267
- </div>
267
+ <Flex alignItems="center" gap={1} className={b('cluster-name-wrapper')}>
268
+ <ExternalLink
269
+ href={clusterPath}
270
+ className={b('cluster-name')}
271
+ title={row.title || row.name}
272
+ >
273
+ {row.title || row.name}
274
+ </ExternalLink>
275
+ {row.settings?.unavailable === true ? (
276
+ <Tooltip content={i18n('tooltip_unavailable')}>
277
+ <span
278
+ className={b('unavailable-label')}
279
+ tabIndex={0}
280
+ data-qa="cluster-unavailable-label"
281
+ onKeyDown={(event) => {
282
+ if (['ArrowUp', 'ArrowDown', 'Enter'].includes(event.key)) {
283
+ event.stopPropagation();
284
+ }
285
+ }}
286
+ >
287
+ <Label
288
+ theme="unknown"
289
+ size="xs"
290
+ icon={<Icon data={CircleXmark} size={12} />}
291
+ >
292
+ {i18n('value_unavailable')}
293
+ </Label>
294
+ </span>
295
+ </Tooltip>
296
+ ) : null}
297
+ </Flex>
268
298
  );
269
299
  }
270
300
 
@@ -3,6 +3,11 @@
3
3
  "controls_service-select-label": "Service:",
4
4
  "controls_version-select-label": "Version:",
5
5
  "controls_galaxy-select-label": "Galaxy:",
6
+ "controls_availability-select-label": "Availability:",
7
+ "value_available": "Available",
8
+ "value_unavailable": "Unavailable",
9
+ "value_none": "None",
10
+ "context_unavailable-admin": "Marked by an administrator",
6
11
 
7
12
  "controls_search-placeholder": "Cluster name, version, domain, host...",
8
13
  "controls_select-placeholder": "All",
@@ -14,6 +19,7 @@
14
19
  "statistics_storage": "Storage",
15
20
 
16
21
  "tooltip_no-cluster-data": "No cluster data",
22
+ "tooltip_unavailable": "Marked as unavailable by an administrator. This is independent of healthcheck. You can still open the cluster",
17
23
 
18
24
  "clusters-count": {
19
25
  "one": "{{count}} cluster found",
@@ -1,7 +1,9 @@
1
1
  import {HeaderBreadcrumbs} from './HeaderBreadcrumbs';
2
2
  import {HeaderLeftControls} from './HeaderLeftControls';
3
3
  import {HeaderRightControls} from './HeaderRightControls';
4
+ import {PDiskLeftControls} from './PDiskLeftControls';
4
5
  import {StorageGroupLeftControls} from './StorageGroupLeftControls';
6
+ import {VDiskLeftControls} from './VDiskLeftControls';
5
7
  import {b} from './constants';
6
8
  import {useHeaderBreadcrumbs} from './hooks/useHeaderBreadcrumbs';
7
9
  import {useHeaderData} from './hooks/useHeaderData';
@@ -71,6 +73,12 @@ export function Header() {
71
73
  if (page === 'storageGroup') {
72
74
  return <StorageGroupLeftControls />;
73
75
  }
76
+ if (page === 'vDisk') {
77
+ return <VDiskLeftControls />;
78
+ }
79
+ if (page === 'pDisk') {
80
+ return <PDiskLeftControls />;
81
+ }
74
82
  return database && isDatabasePage && isV2NavigationEnabled ? (
75
83
  <HeaderLeftControls
76
84
  database={database}
@@ -4,6 +4,7 @@ import {ActionTooltip, Button, ClipboardButton, Flex, Icon} from '@gravity-ui/ui
4
4
  import {getConnectToDBDialog} from '../../components/ConnectToDB/ConnectToDBDialog';
5
5
  import {ServerlessDBLabel} from '../../components/ServerlessDBLabel/ServerlessDBLabel';
6
6
  import type {PreparedTenant} from '../../store/reducers/tenants/types';
7
+ import {useDatabaseHealthcheckAvailable} from '../../utils/hooks/useDatabaseHealthcheckAvailable';
7
8
  import {HealthcheckPreview} from '../Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview';
8
9
 
9
10
  import {b} from './constants';
@@ -20,9 +21,10 @@ export function HeaderLeftControls({
20
21
  databaseData,
21
22
  isDatabaseDataLoading,
22
23
  }: HeaderLeftControlsProps) {
24
+ const healthcheckAvailable = useDatabaseHealthcheckAvailable(databaseData?.Type);
23
25
  const showCopyButton = Boolean(databaseData?.Name);
24
26
  const isServerless = databaseData?.Type === 'Serverless';
25
- const showHealthcheck = !isServerless && !isDatabaseDataLoading;
27
+ const showHealthcheck = healthcheckAvailable && !isDatabaseDataLoading;
26
28
 
27
29
  return (
28
30
  <Flex direction="row" alignItems={'center'} gap={2} className={b('left-controls')}>
@@ -0,0 +1,41 @@
1
+ import {ClipboardButton, Flex} from '@gravity-ui/uikit';
2
+ import {skipToken} from '@reduxjs/toolkit/query';
3
+ import {StringParam, useQueryParams} from 'use-query-params';
4
+
5
+ import {DiskStatusLabel} from '../../components/DiskStatus/DiskStatus';
6
+ import {getPDiskStateLabel} from '../../components/PDiskInfo/statuses';
7
+ import {pDiskApi} from '../../store/reducers/pdisk/pdisk';
8
+ import {valueIsDefined} from '../../utils';
9
+ import {getPDiskId} from '../../utils/disks/helpers';
10
+
11
+ import {b} from './constants';
12
+ import {headerKeyset} from './i18n';
13
+
14
+ export function PDiskLeftControls() {
15
+ const [{nodeId, pDiskId}] = useQueryParams({
16
+ nodeId: StringParam,
17
+ pDiskId: StringParam,
18
+ });
19
+ const {currentData} = pDiskApi.endpoints.getPdiskInfo.useQueryState(
20
+ valueIsDefined(nodeId) && valueIsDefined(pDiskId) ? {nodeId, pDiskId} : skipToken,
21
+ );
22
+ const diskId = getPDiskId({nodeId, pDiskId});
23
+
24
+ if (!diskId) {
25
+ return null;
26
+ }
27
+
28
+ return (
29
+ <Flex alignItems="center" gap={2} className={b('left-controls')}>
30
+ <ClipboardButton
31
+ text={diskId}
32
+ size="s"
33
+ view="flat-secondary"
34
+ color="secondary"
35
+ aria-label={headerKeyset('action_copy-pdisk-id-from-breadcrumb')}
36
+ tooltipInitialText={headerKeyset('action_copy-pdisk-id')}
37
+ />
38
+ <DiskStatusLabel {...getPDiskStateLabel(currentData?.State)} size="xs" iconSize={12} />
39
+ </Flex>
40
+ );
41
+ }