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
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
 
3
3
  import {ArrowLeft} from '@gravity-ui/icons';
4
- import {Button, ClipboardButton, Flex, Icon, Text} from '@gravity-ui/uikit';
4
+ import {Button, Flex, Icon, Text} from '@gravity-ui/uikit';
5
5
  import {skipToken} from '@reduxjs/toolkit/query';
6
6
  import {Helmet} from 'react-helmet-async';
7
7
  import {useHistory} from 'react-router-dom';
8
8
  import {StringParam, useQueryParams} from 'use-query-params';
9
9
 
10
10
  import {AutoRefreshControl} from '../../components/AutoRefreshControl/AutoRefreshControl';
11
+ import {CopyableValue} from '../../components/CopyableValue/CopyableValue';
11
12
  import {ResponseError} from '../../components/Errors/ResponseError';
12
13
  import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton';
13
14
  import {StorageGroupInfo} from '../../components/StorageGroupInfo/StorageGroupInfo';
@@ -36,6 +37,8 @@ export function StorageGroupPage() {
36
37
  const containerRef = React.useRef<HTMLDivElement>(null);
37
38
 
38
39
  const [{groupId}] = useQueryParams({groupId: StringParam});
40
+ const showBackButton = Boolean(groupId) && history.length > 1;
41
+ const showRefreshInTitle = Boolean(groupId) && !showBackButton;
39
42
 
40
43
  const [autoRefreshInterval] = useAutoRefreshInterval();
41
44
  const capabilitiesLoaded = useCapabilitiesLoaded();
@@ -73,49 +76,55 @@ export function StorageGroupPage() {
73
76
  };
74
77
 
75
78
  const renderPageMeta = () => {
76
- if (!groupId) {
79
+ if (!showBackButton) {
77
80
  return null;
78
81
  }
79
82
 
80
- const hasPreviousPage = history.length > 1;
81
-
82
83
  return (
83
84
  <Flex
84
85
  className={storageGroupPageCn('meta')}
85
86
  alignItems="center"
86
- justifyContent={hasPreviousPage ? 'space-between' : 'flex-end'}
87
+ justifyContent="space-between"
87
88
  gap={2}
88
89
  >
89
- {hasPreviousPage && (
90
- <Button view="outlined" onClick={() => history.goBack()}>
91
- <Icon data={ArrowLeft} />
92
- {storageGroupPageKeyset('action_back')}
93
- </Button>
94
- )}
95
- <AutoRefreshControl />
90
+ <Button view="outlined" onClick={() => history.goBack()}>
91
+ <Icon data={ArrowLeft} />
92
+ {storageGroupPageKeyset('action_back')}
93
+ </Button>
94
+ <AutoRefreshControl className={storageGroupPageCn('refresh-control')} />
96
95
  </Flex>
97
96
  );
98
97
  };
99
98
 
100
99
  const renderPageTitle = () => {
101
100
  return (
102
- <Flex className={storageGroupPageCn('title')} alignItems="center" gap={2} wrap="wrap">
103
- <Text variant="header-1">{storageGroupPageKeyset('storage-group')}</Text>
104
- <Flex alignItems="center" gap={1}>
105
- <Text variant="header-1" color="hint">
106
- {groupId || EMPTY_DATA_PLACEHOLDER}
107
- </Text>
108
- {groupId && (
109
- <ClipboardButton
110
- text={groupId}
111
- view="flat-secondary"
112
- size="s"
113
- aria-label={storageGroupPageKeyset('action_copy-group-id-from-title')}
114
- tooltipInitialText={storageGroupPageKeyset('action_copy-group-id')}
115
- />
116
- )}
101
+ <Flex
102
+ className={storageGroupPageCn('title')}
103
+ alignItems="flex-start"
104
+ gap={2}
105
+ wrap="nowrap"
106
+ >
107
+ <Flex
108
+ className={storageGroupPageCn('title-content')}
109
+ alignItems="center"
110
+ gap={2}
111
+ wrap="wrap"
112
+ >
113
+ <Text variant="header-1">{storageGroupPageKeyset('storage-group')}</Text>
114
+ <CopyableValue
115
+ copyText={groupId}
116
+ fieldName={storageGroupPageKeyset('storage-group')}
117
+ copyButtonLabel={storageGroupPageKeyset('action_copy-group-id-from-title')}
118
+ >
119
+ <Text variant="header-1" color="hint">
120
+ {groupId || EMPTY_DATA_PLACEHOLDER}
121
+ </Text>
122
+ </CopyableValue>
123
+ <StorageGroupStateLabel state={state} />
117
124
  </Flex>
118
- <StorageGroupStateLabel state={state} />
125
+ {showRefreshInTitle && (
126
+ <AutoRefreshControl className={storageGroupPageCn('refresh-control')} />
127
+ )}
119
128
  </Flex>
120
129
  );
121
130
  };
@@ -2,6 +2,5 @@
2
2
  "storage-group": "Storage Group",
3
3
  "storage": "Storage",
4
4
  "action_back": "Back",
5
- "action_copy-group-id": "Copy Storage Group ID",
6
5
  "action_copy-group-id-from-title": "Copy Storage Group ID from page title"
7
6
  }
@@ -31,6 +31,7 @@ import {getInfoTabLinks} from '../../../../utils/additionalProps';
31
31
  import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
32
32
  import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
33
33
  import {useClusterNameFromQuery} from '../../../../utils/hooks/useDatabaseFromQuery';
34
+ import {useDatabaseHealthcheckAvailable} from '../../../../utils/hooks/useDatabaseHealthcheckAvailable';
34
35
  import {useDatabasesV2} from '../../../../utils/hooks/useDatabasesV2';
35
36
  import {canShowTenantMonitoringTab} from '../../../../utils/monitoringVisibility';
36
37
  import {useTenantPage} from '../../TenantNavigation/useTenantNavigation';
@@ -64,18 +65,6 @@ function isTenantLoading(isFetching: boolean, tenant: TTenant | undefined, error
64
65
  return isFetching && tenant === undefined && !error;
65
66
  }
66
67
 
67
- function shouldSkipHealthcheck({
68
- isServerless,
69
- isV2NavigationEnabled,
70
- tenant,
71
- }: {
72
- isServerless: boolean;
73
- isV2NavigationEnabled: boolean;
74
- tenant?: TTenant;
75
- }) {
76
- return isServerless || isV2NavigationEnabled || tenant === undefined;
77
- }
78
-
79
68
  function getDatabaseStatus(overall?: EFlag, selfCheckResult?: SelfCheckResult) {
80
69
  const healthcheckStatus =
81
70
  selfCheckResult === undefined ? undefined : selfCheckResultToHcStatus[selfCheckResult];
@@ -128,20 +117,6 @@ function renderTenantError(error: unknown, defaultMessage: string) {
128
117
  return error ? <ResponseError error={error} defaultMessage={defaultMessage} /> : null;
129
118
  }
130
119
 
131
- function renderHealthcheckPreview({
132
- database,
133
- isServerless,
134
- isV2NavigationEnabled,
135
- }: {
136
- database: string;
137
- isServerless: boolean;
138
- isV2NavigationEnabled: boolean;
139
- }) {
140
- return !isServerless && !isV2NavigationEnabled ? (
141
- <HealthcheckPreview database={database} />
142
- ) : null;
143
- }
144
-
145
120
  function renderOverviewHead({
146
121
  databaseStatus,
147
122
  handleOpenMonitoring,
@@ -308,6 +283,8 @@ export function TenantOverview({
308
283
  const tenantLoading = isTenantLoading(isFetching, tenant, error);
309
284
  const {Name, Type, Overall, CoresTotal} = tenant || {};
310
285
  const isServerless = Type === 'Serverless';
286
+ const healthcheckAvailable = useDatabaseHealthcheckAvailable(Type);
287
+ const showHealthcheck = healthcheckAvailable && !isV2NavigationEnabled;
311
288
 
312
289
  // Use healthcheck self_check_result as the database status color when available;
313
290
  // fall back to tenantinfo.Overall (e.g. for Serverless databases where healthcheck is skipped).
@@ -317,7 +294,7 @@ export function TenantOverview({
317
294
  const {currentData: healthcheckData} = healthcheckApi.useGetHealthcheckInfoQuery(
318
295
  {database, clusterName},
319
296
  {
320
- skip: shouldSkipHealthcheck({isServerless, isV2NavigationEnabled, tenant}),
297
+ skip: !showHealthcheck || tenant === undefined,
321
298
  },
322
299
  );
323
300
  const databaseStatus = getDatabaseStatus(Overall, healthcheckData?.self_check_result);
@@ -404,11 +381,7 @@ export function TenantOverview({
404
381
  tenantType,
405
382
  })}
406
383
  <Flex direction="column" gap={4}>
407
- {renderHealthcheckPreview({
408
- database,
409
- isServerless,
410
- isV2NavigationEnabled,
411
- })}
384
+ {showHealthcheck && <HealthcheckPreview database={database} />}
412
385
  <QueriesActivityBar database={database} />
413
386
  <MetricsTabs
414
387
  metrics={metricOverview}
@@ -93,7 +93,12 @@
93
93
  }
94
94
  }
95
95
  &__issue-status {
96
- text-align: start;
96
+ display: flex;
97
+ flex-shrink: 0;
98
+ }
99
+ &__issue-title {
100
+ min-width: 0;
101
+ overflow-wrap: anywhere;
97
102
  }
98
103
  &__issue-content {
99
104
  --g-definition-list-item-gap: var(--g-spacing-3);
@@ -80,17 +80,26 @@ export function HealthcheckIssue({
80
80
  justifyContent="space-between"
81
81
  className={b('issue-summary')}
82
82
  >
83
- <Flex direction="column" gap={1} alignSelf="center">
84
- <Text variant="subheader-2">{issue.message}</Text>
85
-
83
+ <Flex
84
+ gap={2}
85
+ alignItems="center"
86
+ className={b('issue-message')}
87
+ >
86
88
  {issue.status && (
87
89
  <div className={b('issue-status')}>
88
90
  <EntityStatus.Label
91
+ view="compact"
89
92
  size="s"
90
93
  status={hcStatusToColorFlag[issue.status]}
91
94
  />
92
95
  </div>
93
96
  )}
97
+ <Text
98
+ variant="subheader-2"
99
+ className={b('issue-title')}
100
+ >
101
+ {issue.message}
102
+ </Text>
94
103
  </Flex>
95
104
  <Flex
96
105
  wrap="nowrap"
@@ -124,21 +133,22 @@ export function HealthcheckIssue({
124
133
  >
125
134
  <Flex
126
135
  id={id}
127
- direction="column"
128
- gap={1}
129
- alignSelf="center"
136
+ gap={2}
137
+ alignItems="center"
130
138
  className={b('issue-message')}
131
139
  >
132
- <Text variant="subheader-2">{issue.message}</Text>
133
-
134
140
  {issue.status && (
135
141
  <div className={b('issue-status')}>
136
142
  <EntityStatus.Label
143
+ view="compact"
137
144
  size="s"
138
145
  status={hcStatusToColorFlag[issue.status]}
139
146
  />
140
147
  </div>
141
148
  )}
149
+ <Text variant="subheader-2" className={b('issue-title')}>
150
+ {issue.message}
151
+ </Text>
142
152
  </Flex>
143
153
  <div
144
154
  className={b('issue-action')}
@@ -5,6 +5,7 @@ import {
5
5
  selectCheckStatus,
6
6
  } from '../../store/reducers/healthcheckInfo/healthcheckInfo';
7
7
  import {useTypedSelector} from '../../utils/hooks';
8
+ import {useDatabaseHealthcheckAvailable} from '../../utils/hooks/useDatabaseHealthcheckAvailable';
8
9
 
9
10
  import {Healthcheck} from './Healthcheck/Healthcheck';
10
11
  import {HealthcheckDrawer} from './Healthcheck/components/HealthcheckDrawer';
@@ -19,12 +20,15 @@ interface TenantDrawerHealthcheckProps {
19
20
  }
20
21
 
21
22
  export function TenantDrawerHealthcheck({children, clusterName}: TenantDrawerHealthcheckProps) {
23
+ const healthcheckAvailable = useDatabaseHealthcheckAvailable();
22
24
  const {database} = useCurrentSchema();
23
25
  const {
24
26
  handleShowHealthcheckChange,
25
27
  showHealthcheck,
26
28
  handleIssuesFilterChange,
27
29
  handleHealthcheckViewChange,
30
+ issuesFilter,
31
+ view,
28
32
  } = useTenantQueryParams();
29
33
 
30
34
  const healthcheckStatus = useTypedSelector((state) =>
@@ -41,6 +45,15 @@ export function TenantDrawerHealthcheck({children, clusterName}: TenantDrawerHea
41
45
  handleHealthcheckViewChange(undefined);
42
46
  }, [handleShowHealthcheckChange, handleIssuesFilterChange, handleHealthcheckViewChange]);
43
47
 
48
+ React.useEffect(() => {
49
+ if (
50
+ healthcheckAvailable === false &&
51
+ (showHealthcheck !== undefined || view !== undefined || issuesFilter !== undefined)
52
+ ) {
53
+ handleCloseDrawer();
54
+ }
55
+ }, [healthcheckAvailable, showHealthcheck, view, issuesFilter, handleCloseDrawer]);
56
+
44
57
  const renderDrawerContent = React.useCallback(() => {
45
58
  return <Healthcheck database={database} clusterName={clusterName} />;
46
59
  }, [database, clusterName]);
@@ -56,7 +69,7 @@ export function TenantDrawerHealthcheck({children, clusterName}: TenantDrawerHea
56
69
  })
57
70
  : undefined
58
71
  }
59
- isDrawerVisible={Boolean(showHealthcheck)}
72
+ isDrawerVisible={Boolean(healthcheckAvailable && showHealthcheck)}
60
73
  onCloseDrawer={handleCloseDrawer}
61
74
  renderDrawerContent={renderDrawerContent}
62
75
  drawerId="tenant-healthcheck-details"
@@ -1,17 +1,17 @@
1
- @use '../../styles//mixins.scss';
2
-
3
1
  .ydb-vdisk-page {
4
2
  --g-definition-list-item-gap: var(--g-spacing-3);
5
3
  position: relative;
6
4
 
7
5
  overflow: auto;
6
+ overflow-anchor: none;
8
7
 
9
8
  height: 100%;
10
- padding: 0 20px;
9
+ padding: 20px 20px 0;
11
10
 
12
11
  &__meta,
13
12
  &__title,
14
13
  &__controls,
14
+ &__storage-details,
15
15
  &__info,
16
16
  &__tabs {
17
17
  position: sticky;
@@ -20,22 +20,35 @@
20
20
  margin-bottom: 20px;
21
21
  }
22
22
 
23
- &__info {
24
- @include mixins.body-2-typography();
23
+ &__heading {
24
+ margin: 0;
25
+ overflow-wrap: anywhere;
26
+ }
27
+
28
+ &__pool-name {
29
+ min-width: 0;
30
+ overflow-wrap: anywhere;
31
+ }
32
+
33
+ &__title-content {
34
+ flex: 1;
35
+
36
+ min-width: 0;
25
37
  }
26
38
 
27
- &__meta {
28
- margin-top: 20px;
39
+ &__refresh-control {
40
+ flex-shrink: 0;
29
41
  }
30
42
 
31
43
  &__controls {
32
44
  display: flex;
45
+ flex-wrap: wrap;
33
46
  align-items: center;
34
47
  gap: var(--g-spacing-2);
35
48
  }
36
49
 
37
50
  &__storage-details {
38
- margin-bottom: var(--g-spacing-5);
51
+ margin-bottom: var(--g-spacing-4);
39
52
  }
40
53
 
41
54
  &__tablets-content {
@@ -1,11 +1,15 @@
1
1
  import React from 'react';
2
2
 
3
- import {Flex, Icon, Label, Tab, TabList, TabProvider} from '@gravity-ui/uikit';
3
+ import {ArrowLeft, Wrench} from '@gravity-ui/icons';
4
+ import {Button, Flex, Icon, Tab, TabList, TabProvider, Text} from '@gravity-ui/uikit';
4
5
  import {skipToken} from '@reduxjs/toolkit/query';
5
6
  import {isNil} from 'lodash';
6
7
  import {Helmet} from 'react-helmet-async';
8
+ import {useHistory} from 'react-router-dom';
7
9
 
8
- import {EntityPageTitle} from '../../components/EntityPageTitle/EntityPageTitle';
10
+ import {AutoRefreshControl} from '../../components/AutoRefreshControl/AutoRefreshControl';
11
+ import {CopyableValue} from '../../components/CopyableValue/CopyableValue';
12
+ import {DiskTypeLabel} from '../../components/DiskStatus/DiskStatus';
9
13
  import {ResponseError} from '../../components/Errors/ResponseError';
10
14
  import {
11
15
  EvictVDiskButton,
@@ -13,18 +17,22 @@ import {
13
17
  } from '../../components/EvictVDiskButton/EvictVDiskButton';
14
18
  import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton';
15
19
  import {InternalLink} from '../../components/InternalLink/InternalLink';
16
- import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta';
20
+ import {LinkWithIcon} from '../../components/LinkWithIcon/LinkWithIcon';
17
21
  import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo';
22
+ import {vDiskInfoKeyset} from '../../components/VDiskInfo/i18n';
23
+ import {
24
+ VDiskDonorLabel,
25
+ VDiskReplicationStatus,
26
+ VDiskStateLabel,
27
+ } from '../../components/VDiskStatus';
18
28
  import {useVDiskPagePath} from '../../routes';
19
29
  import {api} from '../../store/reducers/api';
20
- import {useNewStorageViewEnabled} from '../../store/reducers/capabilities/hooks';
21
30
  import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
22
31
  import {vDiskApi} from '../../store/reducers/vdisk/vdisk';
23
32
  import {cn} from '../../utils/cn';
33
+ import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
24
34
  import {parseVdiskId} from '../../utils/dataFormatters/dataFormatters';
25
- import {VDISK_LABEL_CONFIG} from '../../utils/disks/constants';
26
- import {formatPDiskType} from '../../utils/disks/getPDiskType';
27
- import {getDataSeverityColor} from '../../utils/disks/helpers';
35
+ import {createVDiskDeveloperUILink, useHasDeveloperUi} from '../../utils/developerUI/developerUI';
28
36
  import {useAutoRefreshInterval, useTypedDispatch} from '../../utils/hooks';
29
37
  import {useAppTitle} from '../App/AppTitleContext';
30
38
  import {PaginatedStorage} from '../Storage/PaginatedStorage';
@@ -40,12 +48,14 @@ const vDiskPageCn = cn('ydb-vdisk-page');
40
48
 
41
49
  export function VDiskPage() {
42
50
  const dispatch = useTypedDispatch();
51
+ const history = useHistory();
52
+ const showBackButton = history.length > 1;
43
53
  const getVDiskPagePath = useVDiskPagePath();
44
54
 
45
55
  const containerRef = React.useRef<HTMLDivElement>(null);
46
56
 
47
57
  const {nodeId, vDiskId: vDiskIdParam, database, vDiskTab, vDiskTabs} = useVDiskQueryParams();
48
- const newStorageViewEnabled = useNewStorageViewEnabled();
58
+ const hasDeveloperUi = useHasDeveloperUi();
49
59
 
50
60
  const [autoRefreshInterval] = useAutoRefreshInterval();
51
61
 
@@ -77,17 +87,7 @@ export function VDiskPage() {
77
87
  }, [dispatch, database, vDiskData?.VDiskId?.GroupID, vDiskData?.StringifiedId]);
78
88
 
79
89
  const loading = isFetching && vDiskData === undefined;
80
- const {
81
- NodeHost,
82
- NodeId,
83
- NodeType,
84
- NodeDC,
85
- PDiskId,
86
- PDiskType,
87
- Severity,
88
- VDiskId,
89
- StringifiedId,
90
- } = vDiskData || {};
90
+ const {NodeHost, NodeId, PDiskId, PDiskType, VDiskId, StringifiedId} = vDiskData || {};
91
91
 
92
92
  const resolvedVDiskId = VDiskId || (!loading && parseVdiskId(vDiskIdParam)) || undefined;
93
93
  const {GroupID} = resolvedVDiskId || {};
@@ -115,52 +115,76 @@ export function VDiskPage() {
115
115
  };
116
116
 
117
117
  const renderPageMeta = () => {
118
- const hostItem = NodeHost ? `${vDiskPageKeyset('fqdn')}: ${NodeHost}` : undefined;
119
- const nodeIdItem = NodeId ? `${vDiskPageKeyset('node')}: ${NodeId}` : undefined;
120
- const pDiskIdItem = NodeId ? `${vDiskPageKeyset('pdisk')}: ${PDiskId}` : undefined;
118
+ if (!showBackButton) {
119
+ return null;
120
+ }
121
121
 
122
122
  return (
123
- <PageMetaWithAutorefresh
123
+ <Flex
124
124
  className={vDiskPageCn('meta')}
125
- loading={loading}
126
- items={[
127
- hostItem,
128
- nodeIdItem,
129
- NodeType,
130
- NodeDC,
131
- pDiskIdItem,
132
- formatPDiskType(PDiskType),
133
- ]}
134
- />
125
+ alignItems="center"
126
+ justifyContent="space-between"
127
+ gap={1}
128
+ >
129
+ <Button size="m" view="outlined" onClick={() => history.goBack()}>
130
+ <Icon data={ArrowLeft} size={16} />
131
+ {vDiskPageKeyset('action_back')}
132
+ </Button>
133
+ <AutoRefreshControl className={vDiskPageCn('refresh-control')} />
134
+ </Flex>
135
135
  );
136
136
  };
137
137
 
138
138
  const renderTitleMeta = () => {
139
- if (!vDiskData?.DonorMode) {
140
- return null;
141
- }
142
- const donorLabelConfig = VDISK_LABEL_CONFIG.donor;
143
139
  return (
144
- <Label
145
- theme={donorLabelConfig.theme}
146
- icon={donorLabelConfig.icon ? <Icon data={donorLabelConfig.icon} /> : undefined}
147
- size="m"
148
- >
149
- {vDiskPageKeyset('label_donor')}
150
- </Label>
140
+ <Flex gap={2} wrap="wrap" alignItems="center">
141
+ <VDiskStateLabel state={vDiskData?.VDiskState} size="s" />
142
+ {vDiskData?.DonorMode ? (
143
+ <VDiskDonorLabel donorMode size="s" />
144
+ ) : (
145
+ <VDiskReplicationStatus data={vDiskData || {}} size="s" />
146
+ )}
147
+ <DiskTypeLabel type={PDiskType} size="s" />
148
+ </Flex>
151
149
  );
152
150
  };
153
151
 
154
152
  const renderPageTitle = () => {
155
153
  return (
156
- <Flex gap={2} alignItems="center">
157
- <EntityPageTitle
158
- className={vDiskPageCn('title')}
159
- entityName={vDiskPageKeyset('vdisk')}
160
- status={getDataSeverityColor(Severity)}
161
- id={vDiskId}
162
- metaInfo={renderTitleMeta()}
163
- />
154
+ <Flex
155
+ className={vDiskPageCn('title')}
156
+ alignItems="flex-start"
157
+ gap={2}
158
+ wrap="nowrap"
159
+ qa="vdisk-header"
160
+ >
161
+ <Flex direction="column" gap={1} className={vDiskPageCn('title-content')}>
162
+ <Flex gap={3} alignItems="center" wrap="wrap">
163
+ <CopyableValue copyText={vDiskId} fieldName={vDiskPageKeyset('vdisk')}>
164
+ <Text as="h1" variant="header-1" className={vDiskPageCn('heading')}>
165
+ {vDiskPageKeyset('vdisk')}{' '}
166
+ <Text color="hint" variant="header-1">
167
+ {vDiskId || EMPTY_DATA_PLACEHOLDER}
168
+ </Text>
169
+ </Text>
170
+ </CopyableValue>
171
+ {renderTitleMeta()}
172
+ </Flex>
173
+ <Flex gap={1} alignItems="center" className={vDiskPageCn('pool')}>
174
+ <Text color="secondary">{vDiskInfoKeyset('pool-name')}:</Text>
175
+ <CopyableValue
176
+ copyText={vDiskData?.StoragePoolName}
177
+ fieldName={vDiskInfoKeyset('pool-name')}
178
+ >
179
+ <Text color="secondary" className={vDiskPageCn('pool-name')}>
180
+ {vDiskData?.StoragePoolName || EMPTY_DATA_PLACEHOLDER}
181
+ </Text>
182
+ </CopyableValue>
183
+ </Flex>
184
+ </Flex>
185
+ {!showBackButton && (
186
+ <AutoRefreshControl className={vDiskPageCn('refresh-control')} />
187
+ )}
164
188
  </Flex>
165
189
  );
166
190
  };
@@ -178,29 +202,44 @@ export function VDiskPage() {
178
202
  }, [dispatch, vDiskId]);
179
203
 
180
204
  const renderControls = () => {
181
- if (!isAllVdiskParamsDefined(resolvedVDiskId)) {
205
+ const canEvict = isAllVdiskParamsDefined(resolvedVDiskId) && !vDiskData?.DonorMode;
206
+ const developerUILink =
207
+ hasDeveloperUi && !isNil(NodeId) && !isNil(PDiskId) && !isNil(vDiskSlotId)
208
+ ? createVDiskDeveloperUILink({
209
+ nodeId: NodeId,
210
+ pDiskId: PDiskId,
211
+ vDiskSlotId,
212
+ })
213
+ : undefined;
214
+ if (!canEvict && !developerUILink) {
182
215
  return null;
183
216
  }
184
217
  return (
185
218
  <div className={vDiskPageCn('controls')} data-qa="vdisk-controls">
186
- <EvictVDiskButton
187
- vDiskId={resolvedVDiskId}
188
- donorMode={vDiskData?.DonorMode}
189
- onSuccess={handleAfterEvictVDisk}
190
- />
219
+ {canEvict && isAllVdiskParamsDefined(resolvedVDiskId) && (
220
+ <EvictVDiskButton
221
+ vDiskId={resolvedVDiskId}
222
+ view="action"
223
+ onSuccess={handleAfterEvictVDisk}
224
+ />
225
+ )}
226
+ {developerUILink && (
227
+ <LinkWithIcon
228
+ title={vDiskPageKeyset('action_open-in-developer-ui')}
229
+ url={developerUILink}
230
+ icon={Wrench}
231
+ hideEndIcon
232
+ />
233
+ )}
191
234
  </div>
192
235
  );
193
236
  };
194
237
 
195
238
  const renderInfo = () => {
196
- return <VDiskInfo data={vDiskData} className={vDiskPageCn('info')} wrap />;
239
+ return <VDiskInfo key={vDiskId} data={vDiskData} className={vDiskPageCn('info')} />;
197
240
  };
198
241
 
199
242
  const renderStorageDetails = () => {
200
- if (!newStorageViewEnabled) {
201
- return null;
202
- }
203
-
204
243
  return <VDiskStorageDetails data={vDiskData} className={vDiskPageCn('storage-details')} />;
205
244
  };
206
245
 
@@ -284,8 +323,8 @@ export function VDiskPage() {
284
323
  return (
285
324
  <React.Fragment>
286
325
  {error ? <ResponseError error={error} /> : null}
287
- {renderInfo()}
288
326
  {renderStorageDetails()}
327
+ {renderInfo()}
289
328
  {renderTabs()}
290
329
  {renderTabsContent()}
291
330
  </React.Fragment>