ydb-embedded-ui 6.12.0 → 6.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (254) hide show
  1. package/dist/components/AutoRefreshControl/i18n/index.d.ts +1 -1
  2. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.d.ts +3 -2
  3. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.js +9 -5
  4. package/dist/components/CriticalActionDialog/CriticalActionDialog.d.ts +5 -3
  5. package/dist/components/CriticalActionDialog/CriticalActionDialog.js +8 -7
  6. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +1 -1
  7. package/dist/components/CriticalActionDialog/i18n/en.json +1 -0
  8. package/dist/components/CriticalActionDialog/i18n/index.d.ts +1 -1
  9. package/dist/components/Errors/PageError/PageError.d.ts +11 -0
  10. package/dist/components/Errors/PageError/PageError.js +19 -0
  11. package/dist/components/Errors/i18n/en.json +2 -1
  12. package/dist/components/Errors/i18n/index.d.ts +1 -1
  13. package/dist/components/Errors/i18n/ru.json +2 -1
  14. package/dist/components/Fullscreen/Fullscreen.d.ts +1 -1
  15. package/dist/components/Fullscreen/Fullscreen.js +34 -27
  16. package/dist/components/Fullscreen/Fullscreen.scss +16 -8
  17. package/dist/components/Graph/Graph.d.ts +13 -0
  18. package/dist/components/Graph/Graph.js +41 -0
  19. package/dist/components/LabelWithPopover/LabelWithPopover.d.ts +4 -1
  20. package/dist/components/LabelWithPopover/LabelWithPopover.js +1 -1
  21. package/dist/components/Loader/Loader.d.ts +2 -1
  22. package/dist/components/Loader/Loader.js +6 -1
  23. package/dist/components/LoaderWrapper/LoaderWrapper.d.ts +10 -0
  24. package/dist/components/LoaderWrapper/LoaderWrapper.js +8 -0
  25. package/dist/components/MetricChart/reducer.d.ts +2 -2
  26. package/dist/components/PDiskInfo/PDiskInfo.d.ts +2 -2
  27. package/dist/components/PDiskInfo/PDiskInfo.js +9 -6
  28. package/dist/components/PDiskInfo/i18n/index.d.ts +1 -1
  29. package/dist/components/ProgressViewer/ProgressViewer.js +3 -0
  30. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.js +13 -3
  31. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.scss +4 -0
  32. package/dist/components/QuerySettingsDescription/QuerySettingsDescription.d.ts +7 -0
  33. package/dist/components/QuerySettingsDescription/QuerySettingsDescription.js +8 -0
  34. package/dist/components/QuerySettingsDescription/QuerySettingsDescription.scss +8 -0
  35. package/dist/components/QuerySettingsDescription/index.d.ts +1 -0
  36. package/dist/components/QuerySettingsDescription/index.js +1 -0
  37. package/dist/components/VDisk/VDisk.js +3 -4
  38. package/dist/components/VDiskInfo/VDiskInfo.d.ts +2 -2
  39. package/dist/components/VDiskInfo/VDiskInfo.js +4 -2
  40. package/dist/containers/App/Content.js +15 -19
  41. package/dist/containers/AsideNavigation/AsideNavigation.js +2 -1
  42. package/dist/containers/AsideNavigation/YdbInternalUser/YdbInternalUser.js +4 -4
  43. package/dist/containers/Authentication/Authentication.js +8 -10
  44. package/dist/containers/Authentication/utils.d.ts +8 -0
  45. package/dist/containers/Authentication/utils.js +15 -0
  46. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +6 -6
  47. package/dist/containers/Clusters/constants.d.ts +1 -1
  48. package/dist/containers/Heatmap/Heatmap.js +5 -4
  49. package/dist/containers/Node/Node.js +5 -7
  50. package/dist/containers/Node/Node.scss +4 -0
  51. package/dist/containers/Node/NodeStructure/NodeStructure.js +4 -4
  52. package/dist/containers/Node/NodeStructure/NodeStructure.scss +4 -0
  53. package/dist/containers/Node/NodeStructure/Pdisk.js +2 -2
  54. package/dist/containers/Nodes/Nodes.js +6 -8
  55. package/dist/containers/Nodes/getNodesColumns.js +6 -21
  56. package/dist/containers/PDiskPage/PDiskPage.js +19 -8
  57. package/dist/containers/PDiskPage/i18n/en.json +1 -0
  58. package/dist/containers/PDiskPage/i18n/index.d.ts +1 -1
  59. package/dist/containers/Storage/PDisk/PDisk.js +3 -4
  60. package/dist/containers/Storage/Storage.js +4 -6
  61. package/dist/containers/Tablet/Tablet.js +2 -2
  62. package/dist/containers/Tablet/TabletControls/TabletControls.js +2 -1
  63. package/dist/containers/Tablets/Tablets.js +3 -5
  64. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.js +2 -5
  65. package/dist/containers/Tenant/Diagnostics/Describe/Describe.js +10 -13
  66. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -0
  67. package/dist/containers/Tenant/Diagnostics/Network/Network.js +8 -11
  68. package/dist/containers/Tenant/Diagnostics/Network/Network.scss +1 -0
  69. package/dist/containers/Tenant/Diagnostics/Overview/Overview.d.ts +1 -2
  70. package/dist/containers/Tenant/Diagnostics/Overview/Overview.js +3 -5
  71. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.js +3 -4
  72. package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.js +1 -4
  73. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.js +3 -3
  74. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.d.ts +1 -1
  75. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +4 -3
  76. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +4 -3
  77. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.d.ts +2 -2
  78. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.js +56 -20
  79. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.scss +10 -6
  80. package/dist/containers/Tenant/Query/ExecuteResult/i18n/en.json +7 -0
  81. package/dist/containers/Tenant/Query/ExecuteResult/i18n/index.d.ts +2 -0
  82. package/dist/containers/Tenant/Query/ExecuteResult/i18n/index.js +4 -0
  83. package/dist/containers/Tenant/Query/ExecuteResult/utils.d.ts +18 -0
  84. package/dist/containers/Tenant/Query/ExecuteResult/utils.js +36 -0
  85. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.d.ts +23 -1
  86. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +56 -111
  87. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.scss +1 -30
  88. package/dist/containers/Tenant/Query/ExplainResult/components/Ast/Ast.d.ts +7 -0
  89. package/dist/containers/Tenant/Query/ExplainResult/components/Ast/Ast.js +18 -0
  90. package/dist/containers/Tenant/Query/ExplainResult/components/Ast/Ast.scss +8 -0
  91. package/dist/containers/Tenant/Query/ExplainResult/components/Graph/Graph.d.ts +8 -0
  92. package/dist/containers/Tenant/Query/ExplainResult/components/Graph/Graph.js +14 -0
  93. package/dist/containers/Tenant/Query/ExplainResult/components/Graph/Graph.scss +14 -0
  94. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/MetricsCell.d.ts +6 -0
  95. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/MetricsCell.js +11 -0
  96. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/OperationCell.d.ts +13 -0
  97. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/OperationCell.js +48 -0
  98. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/OperationParams.d.ts +6 -0
  99. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/OperationParams.js +66 -0
  100. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.d.ts +7 -0
  101. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.js +100 -0
  102. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.scss +128 -0
  103. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/types.d.ts +5 -0
  104. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.d.ts +5 -0
  105. package/dist/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.js +59 -0
  106. package/dist/containers/Tenant/Query/ExplainResult/components/TextExplain/TextExplain.d.ts +8 -0
  107. package/dist/containers/Tenant/Query/ExplainResult/components/TextExplain/TextExplain.js +11 -0
  108. package/dist/containers/Tenant/Query/ExplainResult/components/TextExplain/TextExplain.scss +14 -0
  109. package/dist/containers/Tenant/Query/ExplainResult/i18n/en.json +8 -0
  110. package/dist/containers/Tenant/Query/ExplainResult/i18n/index.d.ts +2 -0
  111. package/dist/containers/Tenant/Query/ExplainResult/i18n/index.js +4 -0
  112. package/dist/containers/Tenant/Query/Preview/Preview.js +2 -3
  113. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.js +1 -19
  114. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.js +1 -1
  115. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.scss +11 -0
  116. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +1 -1
  117. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +91 -95
  118. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.d.ts +4 -6
  119. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +18 -49
  120. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.d.ts +2 -0
  121. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.js +5 -0
  122. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.d.ts +1 -0
  123. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.js +42 -0
  124. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.d.ts +5 -0
  125. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.js +19 -0
  126. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.d.ts +1 -0
  127. package/dist/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.js +56 -0
  128. package/dist/containers/Tenant/Query/QuerySettingsBanner/QuerySettingsBanner.d.ts +2 -0
  129. package/dist/containers/Tenant/Query/QuerySettingsBanner/QuerySettingsBanner.js +12 -0
  130. package/dist/containers/Tenant/Query/QuerySettingsBanner/QuerySettingsBanner.scss +3 -0
  131. package/dist/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.js +20 -23
  132. package/dist/containers/Tenant/Query/QuerySettingsDialog/constants.d.ts +123 -7
  133. package/dist/containers/Tenant/Query/QuerySettingsDialog/constants.js +32 -10
  134. package/dist/containers/Tenant/Query/i18n/en.json +3 -1
  135. package/dist/containers/Tenant/Query/i18n/index.d.ts +1 -1
  136. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.js +6 -6
  137. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +5 -2
  138. package/dist/containers/Tenant/Schema/SchemaViewer/columns.d.ts +2 -1
  139. package/dist/containers/Tenant/Schema/SchemaViewer/columns.js +13 -1
  140. package/dist/containers/Tenant/Schema/SchemaViewer/i18n/en.json +1 -0
  141. package/dist/containers/Tenant/Schema/SchemaViewer/i18n/index.d.ts +1 -1
  142. package/dist/containers/Tenant/Schema/SchemaViewer/prepareData.js +3 -2
  143. package/dist/containers/Tenant/Schema/SchemaViewer/types.d.ts +1 -0
  144. package/dist/containers/Tenant/Tenant.js +4 -8
  145. package/dist/containers/Tenant/utils/schemaActions.d.ts +2 -2
  146. package/dist/containers/Tenant/utils/schemaActions.js +2 -2
  147. package/dist/containers/Tenants/Tenants.js +4 -7
  148. package/dist/containers/UserSettings/i18n/en.json +3 -5
  149. package/dist/containers/UserSettings/i18n/index.d.ts +1 -1
  150. package/dist/containers/UserSettings/settings.d.ts +2 -3
  151. package/dist/containers/UserSettings/settings.js +17 -23
  152. package/dist/containers/VDiskPage/VDiskPage.js +27 -13
  153. package/dist/containers/VDiskPage/i18n/en.json +1 -0
  154. package/dist/containers/VDiskPage/i18n/index.d.ts +1 -1
  155. package/dist/services/api.d.ts +21 -8
  156. package/dist/services/api.js +29 -42
  157. package/dist/services/settings.d.ts +11 -4
  158. package/dist/services/settings.js +7 -6
  159. package/dist/store/configureStore.d.ts +7 -7
  160. package/dist/store/defaultStore.d.ts +3 -3
  161. package/dist/store/reducers/api.d.ts +1 -1
  162. package/dist/store/reducers/api.js +1 -1
  163. package/dist/store/reducers/authentication/authentication.d.ts +37 -24
  164. package/dist/store/reducers/authentication/authentication.js +77 -57
  165. package/dist/store/reducers/authentication/types.d.ts +0 -8
  166. package/dist/store/reducers/capabilities/capabilities.d.ts +106 -0
  167. package/dist/store/reducers/capabilities/capabilities.js +22 -0
  168. package/dist/store/reducers/capabilities/hooks.d.ts +2 -0
  169. package/dist/store/reducers/capabilities/hooks.js +13 -0
  170. package/dist/store/reducers/cluster/cluster.d.ts +2 -2
  171. package/dist/store/reducers/clusterNodes/clusterNodes.d.ts +2 -2
  172. package/dist/store/reducers/clusters/clusters.d.ts +2 -2
  173. package/dist/store/reducers/describe.d.ts +2 -2
  174. package/dist/store/reducers/executeQuery.d.ts +7 -14
  175. package/dist/store/reducers/executeQuery.js +19 -14
  176. package/dist/store/reducers/executeTopQueries/executeTopQueries.d.ts +2 -2
  177. package/dist/store/reducers/explainQuery/explainQuery.d.ts +5 -4
  178. package/dist/store/reducers/explainQuery/explainQuery.js +14 -4
  179. package/dist/store/reducers/explainQuery/types.d.ts +13 -1
  180. package/dist/store/reducers/explainQuery/utils.js +7 -2
  181. package/dist/store/reducers/healthcheckInfo/healthcheckInfo.d.ts +58 -58
  182. package/dist/store/reducers/heatmap.d.ts +2 -2
  183. package/dist/store/reducers/hotKeys/hotKeys.d.ts +2 -2
  184. package/dist/store/reducers/index.d.ts +6 -6
  185. package/dist/store/reducers/network/network.d.ts +2 -2
  186. package/dist/store/reducers/node/node.d.ts +3 -3
  187. package/dist/store/reducers/node/selectors.d.ts +1 -1
  188. package/dist/store/reducers/nodes/nodes.d.ts +3 -3
  189. package/dist/store/reducers/nodesList.d.ts +3 -3
  190. package/dist/store/reducers/overview/overview.d.ts +2 -2
  191. package/dist/store/reducers/partitions/partitions.d.ts +2 -2
  192. package/dist/store/reducers/pdisk/pdisk.d.ts +3 -3
  193. package/dist/store/reducers/preview.d.ts +2 -2
  194. package/dist/store/reducers/schema/schema.d.ts +3 -3
  195. package/dist/store/reducers/schema/schema.js +10 -3
  196. package/dist/store/reducers/schemaAcl/schemaAcl.d.ts +2 -2
  197. package/dist/store/reducers/shardsWorkload/shardsWorkload.d.ts +2 -2
  198. package/dist/store/reducers/storage/storage.d.ts +3 -3
  199. package/dist/store/reducers/tablet.d.ts +3 -3
  200. package/dist/store/reducers/tablets.d.ts +13 -13
  201. package/dist/store/reducers/tabletsFilters.d.ts +1 -1
  202. package/dist/store/reducers/tenant/tenant.d.ts +2 -2
  203. package/dist/store/reducers/tenantOverview/executeTopTables/executeTopTables.d.ts +2 -2
  204. package/dist/store/reducers/tenantOverview/topNodes/topNodes.d.ts +2 -2
  205. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.d.ts +2 -2
  206. package/dist/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.d.ts +2 -2
  207. package/dist/store/reducers/tenants/selectors.d.ts +31 -30
  208. package/dist/store/reducers/tenants/selectors.js +8 -2
  209. package/dist/store/reducers/tenants/tenants.d.ts +2 -2
  210. package/dist/store/reducers/topic.d.ts +44 -44
  211. package/dist/store/reducers/vdisk/vdisk.d.ts +2 -2
  212. package/dist/store/reducers/viewSchema/viewSchema.d.ts +2 -2
  213. package/dist/styles/mixins.scss +2 -0
  214. package/dist/types/api/capabilities.d.ts +7 -0
  215. package/dist/types/api/capabilities.js +1 -0
  216. package/dist/types/api/modifyDisk.d.ts +8 -0
  217. package/dist/types/api/modifyDisk.js +1 -0
  218. package/dist/types/api/query.d.ts +39 -3
  219. package/dist/types/api/query.js +9 -1
  220. package/dist/types/api/schema/shared.d.ts +8 -0
  221. package/dist/types/store/query.d.ts +7 -0
  222. package/dist/utils/__test__/prepareQueryExplain.test.d.ts +1 -0
  223. package/dist/utils/__test__/prepareQueryExplain.test.js +115 -0
  224. package/dist/utils/constants.d.ts +13 -4
  225. package/dist/utils/constants.js +15 -4
  226. package/dist/utils/dataFormatters/dataFormatters.d.ts +0 -1
  227. package/dist/utils/dataFormatters/dataFormatters.js +1 -4
  228. package/dist/utils/hooks/index.d.ts +2 -1
  229. package/dist/utils/hooks/index.js +2 -1
  230. package/dist/utils/hooks/useChangedQuerySettings.d.ts +10 -0
  231. package/dist/utils/hooks/useChangedQuerySettings.js +46 -0
  232. package/dist/utils/hooks/useDelayed.d.ts +1 -0
  233. package/dist/utils/hooks/useDelayed.js +13 -0
  234. package/dist/utils/hooks/useEventHandler.d.ts +6 -0
  235. package/dist/utils/hooks/useEventHandler.js +17 -0
  236. package/dist/utils/hooks/useLastQueryExecutionSettings.d.ts +2 -0
  237. package/dist/utils/hooks/useLastQueryExecutionSettings.js +5 -0
  238. package/dist/utils/hooks/useQueryExecutionSettings.d.ts +8 -0
  239. package/dist/utils/hooks/useQueryExecutionSettings.js +15 -0
  240. package/dist/utils/prepareQueryExplain.d.ts +3 -1
  241. package/dist/utils/prepareQueryExplain.js +54 -2
  242. package/dist/utils/query.js +1 -0
  243. package/dist/utils/query.test.js +3 -0
  244. package/dist/utils/utils.d.ts +8 -7
  245. package/dist/utils/utils.js +23 -11
  246. package/package.json +4 -2
  247. package/dist/containers/Tenant/Query/ExplainResult/utils.d.ts +0 -2
  248. package/dist/containers/Tenant/Query/ExplainResult/utils.js +0 -4
  249. package/dist/store/utils.d.ts +0 -23
  250. package/dist/store/utils.js +0 -49
  251. package/dist/types/api/restartPDisk.d.ts +0 -4
  252. package/dist/utils/hooks/useQueryModes.d.ts +0 -2
  253. package/dist/utils/hooks/useQueryModes.js +0 -5
  254. /package/dist/{types/api/restartPDisk.js → containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/types.js} +0 -0
@@ -2,12 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { STRUCTURE } from '../../containers/Node/NodePages';
4
4
  import routes, { createHref, getVDiskPagePath } from '../../routes';
5
+ import { useDiskPagesAvailable } from '../../store/reducers/capabilities/hooks';
5
6
  import { valueIsDefined } from '../../utils';
6
7
  import { cn } from '../../utils/cn';
7
- import { USE_SEPARATE_DISKS_PAGES_KEY } from '../../utils/constants';
8
8
  import { stringifyVdiskId } from '../../utils/dataFormatters/dataFormatters';
9
9
  import { isFullVDiskData } from '../../utils/disks/helpers';
10
- import { useSetting } from '../../utils/hooks';
11
10
  import { DiskStateProgressBar } from '../DiskStateProgressBar/DiskStateProgressBar';
12
11
  import { InternalLink } from '../InternalLink';
13
12
  import { VDiskPopup } from '../VDiskPopup/VDiskPopup';
@@ -15,7 +14,7 @@ import './VDisk.scss';
15
14
  const b = cn('ydb-vdisk-component');
16
15
  export const VDisk = ({ data = {}, nodes, compact }) => {
17
16
  const isFullData = isFullVDiskData(data);
18
- const [useSeparateDisksPages] = useSetting(USE_SEPARATE_DISKS_PAGES_KEY);
17
+ const diskPagesAvailable = useDiskPagesAvailable();
19
18
  const [isPopupVisible, setIsPopupVisible] = React.useState(false);
20
19
  const anchor = React.useRef(null);
21
20
  const showPopup = () => {
@@ -25,7 +24,7 @@ export const VDisk = ({ data = {}, nodes, compact }) => {
25
24
  setIsPopupVisible(false);
26
25
  };
27
26
  let vDiskPath;
28
- if (useSeparateDisksPages &&
27
+ if (diskPagesAvailable &&
29
28
  valueIsDefined(data.VDiskSlotId) &&
30
29
  valueIsDefined(data.PDiskId) &&
31
30
  valueIsDefined(data.NodeId)) {
@@ -3,8 +3,8 @@ import type { InfoViewerProps } from '../InfoViewer/InfoViewer';
3
3
  import './VDiskInfo.scss';
4
4
  interface VDiskInfoProps<T extends PreparedVDisk> extends Omit<InfoViewerProps, 'info'> {
5
5
  data?: T;
6
- isVDiskPage?: boolean;
6
+ withVDiskPageLink?: boolean;
7
7
  withTitle?: boolean;
8
8
  }
9
- export declare function VDiskInfo<T extends PreparedVDisk>({ data, isVDiskPage, withTitle, ...infoViewerProps }: VDiskInfoProps<T>): import("react/jsx-runtime").JSX.Element;
9
+ export declare function VDiskInfo<T extends PreparedVDisk>({ data, withVDiskPageLink, withTitle, ...infoViewerProps }: VDiskInfoProps<T>): import("react/jsx-runtime").JSX.Element;
10
10
  export {};
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getVDiskPagePath } from '../../routes';
3
+ import { useDiskPagesAvailable } from '../../store/reducers/capabilities/hooks';
3
4
  import { valueIsDefined } from '../../utils';
4
5
  import { cn } from '../../utils/cn';
5
6
  import { formatStorageValuesToGb, stringifyVdiskId } from '../../utils/dataFormatters/dataFormatters';
@@ -14,8 +15,9 @@ import { vDiskInfoKeyset } from './i18n';
14
15
  import './VDiskInfo.scss';
15
16
  const b = cn('ydb-vdisk-info');
16
17
  // eslint-disable-next-line complexity
17
- export function VDiskInfo({ data, isVDiskPage, withTitle, ...infoViewerProps }) {
18
+ export function VDiskInfo({ data, withVDiskPageLink, withTitle, ...infoViewerProps }) {
18
19
  var _a, _b, _c, _d;
20
+ const diskPagesAvailable = useDiskPagesAvailable();
19
21
  const { AllocatedSize, DiskSpace, FrontQueues, Guid, Replicated, VDiskState, VDiskSlotId, Kind, SatisfactionRank, AvailableSize, HasUnreadableBlobs, IncarnationGuid, InstanceGuid, StoragePoolName, ReadThroughput, WriteThroughput, PDiskId, NodeId, } = data || {};
20
22
  const vdiskInfo = [];
21
23
  if (valueIsDefined(VDiskSlotId)) {
@@ -105,7 +107,7 @@ export function VDiskInfo({ data, isVDiskPage, withTitle, ...infoViewerProps })
105
107
  });
106
108
  vdiskInfo.push({
107
109
  label: vDiskInfoKeyset('links'),
108
- value: (_jsxs("span", { className: b('links'), children: [!isVDiskPage && (_jsx(LinkWithIcon, { title: vDiskInfoKeyset('vdisk-page'), url: vDiskPagePath, external: false })), _jsx(LinkWithIcon, { title: vDiskInfoKeyset('developer-ui'), url: vDiskInternalViewerPath })] })),
110
+ value: (_jsxs("span", { className: b('links'), children: [withVDiskPageLink && diskPagesAvailable && (_jsx(LinkWithIcon, { title: vDiskInfoKeyset('vdisk-page'), url: vDiskPagePath, external: false })), _jsx(LinkWithIcon, { title: vDiskInfoKeyset('developer-ui'), url: vDiskInternalViewerPath })] })),
109
111
  });
110
112
  }
111
113
  const title = data && withTitle ? _jsx(VDiskTitle, { data: data }) : null;
@@ -1,13 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { connect, shallowEqual } from 'react-redux';
2
+ import { connect } from 'react-redux';
4
3
  import { Redirect, Route, Switch } from 'react-router-dom';
4
+ import { PageError } from '../../components/Errors/PageError/PageError';
5
+ import { LoaderWrapper } from '../../components/LoaderWrapper/LoaderWrapper';
5
6
  import { useSlots } from '../../components/slots';
6
7
  import routes from '../../routes';
7
- import { getUser } from '../../store/reducers/authentication/authentication';
8
+ import { authenticationApi } from '../../store/reducers/authentication/authentication';
9
+ import { capabilitiesApi } from '../../store/reducers/capabilities/capabilities';
8
10
  import { nodesListApi } from '../../store/reducers/nodesList';
9
11
  import { cn } from '../../utils/cn';
10
- import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
11
12
  import { lazyComponent } from '../../utils/lazyComponent';
12
13
  import Authentication from '../Authentication/Authentication';
13
14
  import { getClusterPath } from '../Cluster/utils';
@@ -89,27 +90,22 @@ export function Content(props) {
89
90
  exact: true,
90
91
  component: Clusters,
91
92
  slot: ClustersSlot,
92
- }), additionalRoutes === null || additionalRoutes === void 0 ? void 0 : additionalRoutes.rendered, _jsxs(Route, { children: [_jsx(GetUser, {}), _jsx(GetNodesList, {}), _jsx(Header, { mainPage: mainPage }), _jsxs(Switch, { children: [routesSlots.map((route) => {
93
- return renderRouteSlot(slots, route);
94
- }), _jsx(Route, { path: redirectProps.from || redirectProps.path, exact: redirectProps.exact, strict: redirectProps.strict, render: () => _jsx(Redirect, { to: redirectProps.to, push: redirectProps.push }) })] })] }, "single-cluster")] }));
93
+ }), additionalRoutes === null || additionalRoutes === void 0 ? void 0 : additionalRoutes.rendered, _jsx(Route, { children: _jsxs(GetUser, { children: [_jsx(GetNodesList, {}), _jsx(GetCapabilities, {}), _jsx(Header, { mainPage: mainPage }), _jsxs(Switch, { children: [routesSlots.map((route) => {
94
+ return renderRouteSlot(slots, route);
95
+ }), _jsx(Route, { path: redirectProps.from || redirectProps.path, exact: redirectProps.exact, strict: redirectProps.strict, render: () => (_jsx(Redirect, { to: redirectProps.to, push: redirectProps.push })) })] })] }) }, "single-cluster")] }));
95
96
  }
96
- function GetUser() {
97
- const dispatch = useTypedDispatch();
98
- const { isAuthenticated, isInternalUser } = useTypedSelector((state) => ({
99
- isAuthenticated: state.authentication.isAuthenticated,
100
- isInternalUser: Boolean(state.authentication.user),
101
- }), shallowEqual);
102
- React.useEffect(() => {
103
- if (isAuthenticated && !isInternalUser) {
104
- dispatch(getUser());
105
- }
106
- }, [dispatch, isAuthenticated, isInternalUser]);
107
- return null;
97
+ function GetUser({ children }) {
98
+ const { isLoading, error } = authenticationApi.useWhoamiQuery(undefined);
99
+ return (_jsx(LoaderWrapper, { loading: isLoading, size: "l", children: _jsx(PageError, { error: error, children: children }) }));
108
100
  }
109
101
  function GetNodesList() {
110
102
  nodesListApi.useGetNodesListQuery(undefined);
111
103
  return null;
112
104
  }
105
+ function GetCapabilities() {
106
+ capabilitiesApi.useGetClusterCapabilitiesQuery(undefined);
107
+ return null;
108
+ }
113
109
  function ContentWrapper(props) {
114
110
  const { singleClusterMode, isAuthenticated } = props;
115
111
  return (_jsxs(Switch, { children: [_jsx(Route, { path: routes.auth, children: _jsx(Authentication, { closable: true }) }), _jsx(Route, { children: _jsx("div", { className: b({ embedded: singleClusterMode }), children: isAuthenticated ? props.children : _jsx(Authentication, {}) }) })] }));
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { CircleQuestion, Gear, Person } from '@gravity-ui/icons';
4
4
  import { AsideHeader, FooterItem } from '@gravity-ui/navigation';
5
5
  import { useHistory } from 'react-router-dom';
6
+ import { selectUser } from '../../store/reducers/authentication/authentication';
6
7
  import { cn } from '../../utils/cn';
7
8
  import { ASIDE_HEADER_COMPACT_KEY } from '../../utils/constants';
8
9
  import { useSetting, useTypedSelector } from '../../utils/hooks';
@@ -29,7 +30,7 @@ var Panel;
29
30
  export function AsideNavigation(props) {
30
31
  const history = useHistory();
31
32
  const [visiblePanel, setVisiblePanel] = React.useState();
32
- const { user: ydbUser } = useTypedSelector((state) => state.authentication);
33
+ const ydbUser = useTypedSelector(selectUser);
33
34
  const [compact, setIsCompact] = useSetting(ASIDE_HEADER_COMPACT_KEY);
34
35
  return (_jsx(React.Fragment, { children: _jsx(AsideHeader, { logo: {
35
36
  text: 'YDB',
@@ -3,21 +3,21 @@ import { ArrowRightFromSquare, ArrowRightToSquare } from '@gravity-ui/icons';
3
3
  import { Button, Icon } from '@gravity-ui/uikit';
4
4
  import { useHistory } from 'react-router-dom';
5
5
  import routes, { createHref } from '../../../routes';
6
- import { logout } from '../../../store/reducers/authentication/authentication';
6
+ import { authenticationApi } from '../../../store/reducers/authentication/authentication';
7
7
  import { cn } from '../../../utils/cn';
8
- import { useTypedDispatch, useTypedSelector } from '../../../utils/hooks';
8
+ import { useTypedSelector } from '../../../utils/hooks';
9
9
  import i18n from '../i18n';
10
10
  import './YdbInternalUser.scss';
11
11
  const b = cn('kv-ydb-internal-user');
12
12
  export function YdbInternalUser() {
13
13
  const { user: ydbUser } = useTypedSelector((state) => state.authentication);
14
+ const [logout] = authenticationApi.useLogoutMutation();
14
15
  const history = useHistory();
15
16
  const handleLoginClick = () => {
16
17
  history.push(createHref(routes.auth, undefined, { returnUrl: encodeURIComponent(location.href) }));
17
18
  };
18
- const dispatch = useTypedDispatch();
19
19
  const handleLogout = () => {
20
- dispatch(logout);
20
+ logout(undefined);
21
21
  };
22
22
  return (_jsxs("div", { className: b(), children: [_jsxs("div", { className: b('user-info-wrapper'), children: [_jsx("div", { className: b('ydb-internal-user-title'), children: i18n('account.user') }), ydbUser && _jsx("div", { className: b('username'), children: ydbUser })] }), ydbUser ? (_jsx(Button, { view: "flat-secondary", title: i18n('account.logout'), onClick: handleLogout, children: _jsx(Icon, { data: ArrowRightFromSquare }) })) : (_jsx(Button, { view: "flat-secondary", title: i18n('account.login'), onClick: handleLoginClick, children: _jsx(Icon, { data: ArrowRightToSquare }) }))] }));
23
23
  }
@@ -4,29 +4,27 @@ import { Eye, EyeSlash, Xmark } from '@gravity-ui/icons';
4
4
  import { Button, Link as ExternalLink, Icon, TextInput } from '@gravity-ui/uikit';
5
5
  import { useHistory, useLocation } from 'react-router-dom';
6
6
  import { parseQuery } from '../../routes';
7
- import { authenticate } from '../../store/reducers/authentication/authentication';
7
+ import { authenticationApi } from '../../store/reducers/authentication/authentication';
8
8
  import { cn } from '../../utils/cn';
9
- import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
9
+ import { isPasswordError, isUserError } from './utils';
10
10
  import ydbLogoIcon from '../../assets/icons/ydb.svg';
11
11
  import './Authentication.scss';
12
12
  const b = cn('authentication');
13
13
  function Authentication({ closable = false }) {
14
- const dispatch = useTypedDispatch();
15
14
  const history = useHistory();
16
15
  const location = useLocation();
16
+ const [authenticate, { error, isLoading }] = authenticationApi.useAuthenticateMutation(undefined);
17
17
  const { returnUrl } = parseQuery(location);
18
- const { error } = useTypedSelector((state) => state.authentication);
19
18
  const [login, setLogin] = React.useState('');
20
- const [pass, setPass] = React.useState('');
19
+ const [password, setPass] = React.useState('');
21
20
  const [loginError, setLoginError] = React.useState('');
22
21
  const [passwordError, setPasswordError] = React.useState('');
23
22
  const [showPassword, setShowPassword] = React.useState(false);
24
23
  React.useEffect(() => {
25
- var _a, _b, _c, _d;
26
- if ((_b = (_a = error === null || error === void 0 ? void 0 : error.data) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.includes('user')) {
24
+ if (isUserError(error)) {
27
25
  setLoginError(error.data.error);
28
26
  }
29
- if ((_d = (_c = error === null || error === void 0 ? void 0 : error.data) === null || _c === void 0 ? void 0 : _c.error) === null || _d === void 0 ? void 0 : _d.includes('password')) {
27
+ if (isPasswordError(error)) {
30
28
  setPasswordError(error.data.error);
31
29
  }
32
30
  }, [error]);
@@ -39,7 +37,7 @@ function Authentication({ closable = false }) {
39
37
  setPasswordError('');
40
38
  };
41
39
  const onLoginClick = () => {
42
- dispatch(authenticate(login, pass)).then(() => {
40
+ authenticate({ user: login, password }).then(() => {
43
41
  if (returnUrl) {
44
42
  const decodedUrl = decodeURIComponent(returnUrl.toString());
45
43
  // to prevent page reload we use router history
@@ -62,6 +60,6 @@ function Authentication({ closable = false }) {
62
60
  const onTogglePasswordVisibility = () => {
63
61
  setShowPassword((prev) => !prev);
64
62
  };
65
- return (_jsxs("section", { className: b(), children: [_jsxs("form", { className: b('form-wrapper'), children: [_jsxs("div", { className: b('header'), children: [_jsxs("div", { className: b('logo'), children: [_jsx(Icon, { data: ydbLogoIcon, size: 24 }), "YDB"] }), _jsx(ExternalLink, { href: "http://ydb.tech/docs", target: "_blank", children: "Documentation" })] }), _jsx("h2", { className: b('title'), children: "Sign in" }), _jsx("div", { className: b('field-wrapper'), children: _jsx(TextInput, { value: login, onUpdate: onLoginUpdate, placeholder: 'Username', error: loginError, onKeyDown: onEnterClick, size: "l", autoFocus: true }) }), _jsxs("div", { className: b('field-wrapper'), children: [_jsx(TextInput, { value: pass, onUpdate: onPassUpdate, type: showPassword ? 'text' : 'password', placeholder: 'Password', error: passwordError, onKeyDown: onEnterClick, size: "l" }), _jsx(Button, { onClick: onTogglePasswordVisibility, size: "l", className: b('show-password-button'), children: _jsx(Icon, { data: showPassword ? EyeSlash : Eye, size: 16 }) })] }), _jsx(Button, { view: "action", onClick: onLoginClick, width: "max", size: "l", disabled: Boolean(!login || loginError || passwordError), className: b('button-sign-in'), children: "Sign in" })] }), closable && history.length > 1 && (_jsx(Button, { onClick: onClose, className: b('close'), children: _jsx(Icon, { data: Xmark, size: 24 }) }))] }));
63
+ return (_jsxs("section", { className: b(), children: [_jsxs("form", { className: b('form-wrapper'), children: [_jsxs("div", { className: b('header'), children: [_jsxs("div", { className: b('logo'), children: [_jsx(Icon, { data: ydbLogoIcon, size: 24 }), "YDB"] }), _jsx(ExternalLink, { href: "https://ydb.tech/docs", target: "_blank", children: "Documentation" })] }), _jsx("h2", { className: b('title'), children: "Sign in" }), _jsx("div", { className: b('field-wrapper'), children: _jsx(TextInput, { value: login, onUpdate: onLoginUpdate, placeholder: 'Username', error: loginError, onKeyDown: onEnterClick, size: "l", autoFocus: true }) }), _jsxs("div", { className: b('field-wrapper'), children: [_jsx(TextInput, { value: password, onUpdate: onPassUpdate, type: showPassword ? 'text' : 'password', placeholder: 'Password', error: passwordError, onKeyDown: onEnterClick, size: "l" }), _jsx(Button, { onClick: onTogglePasswordVisibility, size: "l", className: b('show-password-button'), children: _jsx(Icon, { data: showPassword ? EyeSlash : Eye, size: 16 }) })] }), _jsx(Button, { view: "action", onClick: onLoginClick, width: "max", size: "l", disabled: Boolean(!login || loginError || passwordError), loading: isLoading, className: b('button-sign-in'), children: "Sign in" })] }), closable && history.length > 1 && (_jsx(Button, { onClick: onClose, className: b('close'), children: _jsx(Icon, { data: Xmark, size: 24 }) }))] }));
66
64
  }
67
65
  export default Authentication;
@@ -0,0 +1,8 @@
1
+ interface AuthError {
2
+ data: {
3
+ error: string;
4
+ };
5
+ }
6
+ export declare function isUserError(error: unknown): error is AuthError;
7
+ export declare function isPasswordError(error: unknown): error is AuthError;
8
+ export {};
@@ -0,0 +1,15 @@
1
+ function isAuthError(error) {
2
+ return Boolean(error &&
3
+ typeof error === 'object' &&
4
+ 'data' in error &&
5
+ error.data &&
6
+ typeof error.data === 'object' &&
7
+ 'error' in error.data &&
8
+ typeof error.data.error === 'string');
9
+ }
10
+ export function isUserError(error) {
11
+ return isAuthError(error) && error.data.error.includes('user');
12
+ }
13
+ export function isPasswordError(error) {
14
+ return isAuthError(error) && error.data.error.includes('password');
15
+ }
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ContentWithPopup } from '../../../components/ContentWithPopup/ContentWithPopup';
3
3
  import { ResponseError } from '../../../components/Errors/ResponseError';
4
4
  import InfoViewer from '../../../components/InfoViewer/InfoViewer';
@@ -102,14 +102,14 @@ const getInfo = (cluster, versionsValues, groupsStats, additionalInfo, links) =>
102
102
  });
103
103
  return info;
104
104
  };
105
- export const ClusterInfo = ({ cluster = {}, versionsValues = [], groupsStats = {}, loading, error, additionalClusterProps = {}, }) => {
105
+ export const ClusterInfo = ({ cluster, versionsValues = [], groupsStats = {}, loading, error, additionalClusterProps = {}, }) => {
106
106
  const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
107
107
  let internalLink = backend + '/internal';
108
108
  if (singleClusterMode && !customBackend) {
109
109
  internalLink = `/internal`;
110
110
  }
111
111
  const { info = [], links = [] } = additionalClusterProps;
112
- const clusterInfo = getInfo(cluster, versionsValues, groupsStats, info, [
112
+ const clusterInfo = getInfo(cluster !== null && cluster !== void 0 ? cluster : {}, versionsValues, groupsStats, info, [
113
113
  { title: DEVELOPER_UI_TITLE, url: internalLink },
114
114
  ...links,
115
115
  ]);
@@ -117,10 +117,10 @@ export const ClusterInfo = ({ cluster = {}, versionsValues = [], groupsStats = {
117
117
  if (loading) {
118
118
  return _jsx(InfoViewerSkeleton, { className: b('skeleton'), rows: 9 });
119
119
  }
120
- if (error) {
121
- return _jsx(ResponseError, { error: error, className: b('error') });
120
+ if (error && !cluster) {
121
+ return null;
122
122
  }
123
123
  return _jsx(InfoViewer, { dots: true, info: clusterInfo });
124
124
  };
125
- return (_jsx("div", { className: b(), children: _jsx("div", { className: b('info'), children: getContent() }) }));
125
+ return (_jsxs("div", { className: b(), children: [error ? _jsx(ResponseError, { error: error, className: b('error') }) : null, _jsx("div", { className: b('info'), children: getContent() })] }));
126
126
  };
@@ -14,7 +14,7 @@ export declare const COLUMNS_NAMES: {
14
14
  readonly DESCRIPTION: "description";
15
15
  readonly BALANCER: "balancer";
16
16
  };
17
- export declare const DEFAULT_COLUMNS: ("nodes" | "storage" | "status" | "tenants" | "versions" | "service" | "load" | "hosts" | "balancer" | "title" | "owner")[];
17
+ export declare const DEFAULT_COLUMNS: ("status" | "nodes" | "storage" | "tenants" | "versions" | "service" | "load" | "hosts" | "balancer" | "owner" | "title")[];
18
18
  export declare const COLUMNS_TITLES: {
19
19
  readonly title: "Cluster";
20
20
  readonly versions: "Versions";
@@ -68,13 +68,14 @@ export const Heatmap = ({ path, database }) => {
68
68
  };
69
69
  const renderContent = () => {
70
70
  const { min, max } = getCurrentMetricLimits(currentMetric, tablets);
71
- return (_jsxs("div", { className: b(), children: [_jsxs("div", { className: b('filters'), children: [_jsx(Select, { className: b('heatmap-select'), value: currentMetric ? [currentMetric] : [], options: metrics, onUpdate: handleMetricChange, width: 200 }), _jsx("div", { className: b('sort-checkbox'), children: _jsx(Checkbox, { onUpdate: handleCheckboxChange, checked: sort, children: "Sort" }) }), _jsx("div", { className: b('histogram-checkbox'), children: _jsx(Checkbox, { onUpdate: handleHeatmapChange, checked: heatmap, children: "Heatmap" }) }), _jsxs("div", { className: b('limits'), children: [_jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "min:" }), _jsx("div", { className: b('limits-value'), children: Number.isInteger(min) ? formatNumber(min) : '—' })] }), _jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "max:" }), _jsx("div", { className: b('limits-value'), children: Number.isInteger(max) ? formatNumber(max) : '—' })] }), _jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "count:" }), _jsx("div", { className: b('limits-value'), children: formatNumber(tablets.length) })] })] })] }), heatmap ? renderHeatmapCanvas() : renderHistogram()] }));
71
+ let content;
72
+ if (!error || currentData) {
73
+ content = heatmap ? renderHeatmapCanvas() : renderHistogram();
74
+ }
75
+ return (_jsxs("div", { className: b(), children: [_jsxs("div", { className: b('filters'), children: [_jsx(Select, { className: b('heatmap-select'), value: currentMetric ? [currentMetric] : [], options: metrics, onUpdate: handleMetricChange, width: 200 }), _jsx("div", { className: b('sort-checkbox'), children: _jsx(Checkbox, { onUpdate: handleCheckboxChange, checked: sort, children: "Sort" }) }), _jsx("div", { className: b('histogram-checkbox'), children: _jsx(Checkbox, { onUpdate: handleHeatmapChange, checked: heatmap, children: "Heatmap" }) }), _jsxs("div", { className: b('limits'), children: [_jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "min:" }), _jsx("div", { className: b('limits-value'), children: Number.isInteger(min) ? formatNumber(min) : '—' })] }), _jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "max:" }), _jsx("div", { className: b('limits-value'), children: Number.isInteger(max) ? formatNumber(max) : '—' })] }), _jsxs("div", { className: b('limits-block'), children: [_jsx("div", { className: b('limits-title'), children: "count:" }), _jsx("div", { className: b('limits-value'), children: formatNumber(tablets.length) })] })] })] }), error ? _jsx(ResponseError, { error: error }) : null, content] }));
72
76
  };
73
77
  if (loading) {
74
78
  return _jsx(Loader, {});
75
79
  }
76
- if (error) {
77
- return _jsx(ResponseError, { error: error });
78
- }
79
80
  return renderContent();
80
81
  };
@@ -80,13 +80,11 @@ export function Node(props) {
80
80
  if (loading) {
81
81
  return _jsx(Loader, { size: "l" });
82
82
  }
83
- else if (error) {
84
- return _jsx(ResponseError, { error: error });
83
+ if (node) {
84
+ return (_jsxs("div", { className: b(null, props.className), ref: container, children: [_jsx(Helmet, { titleTemplate: `%s — ${node.Host} — YDB Monitoring`, defaultTitle: `${node.Host} — YDB Monitoring`, children: _jsx("title", { children: activeTabVerified.title }) }), _jsx(BasicNodeViewer, { node: node, additionalNodesProps: props.additionalNodesProps, className: b('header') }), error ? _jsx(ResponseError, { error: error, className: b('error') }) : null, renderTabs(), _jsx("div", { className: b('content'), children: renderTabContent() })] }));
85
85
  }
86
- else {
87
- if (node) {
88
- return (_jsxs("div", { className: b(null, props.className), ref: container, children: [_jsx(Helmet, { titleTemplate: `%s — ${node.Host} — YDB Monitoring`, defaultTitle: `${node.Host} — YDB Monitoring`, children: _jsx("title", { children: activeTabVerified.title }) }), _jsx(BasicNodeViewer, { node: node, additionalNodesProps: props.additionalNodesProps, className: b('header') }), renderTabs(), _jsx("div", { className: b('content'), children: renderTabContent() })] }));
89
- }
90
- return _jsx("div", { className: "error", children: "no node data" });
86
+ if (error) {
87
+ return _jsx(ResponseError, { error: error });
91
88
  }
89
+ return _jsx("div", { className: "error", children: "no node data" });
92
90
  }
@@ -53,4 +53,8 @@
53
53
  height: 100%;
54
54
  padding: 20px;
55
55
  }
56
+
57
+ &__error {
58
+ padding: 0 20px;
59
+ }
56
60
  }
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import url from 'url';
3
3
  import React from 'react';
4
4
  import isEmpty from 'lodash/isEmpty';
@@ -59,11 +59,11 @@ function NodeStructure({ nodeId, className }) {
59
59
  if (loadingStructure) {
60
60
  return _jsx(Loader, { size: "m" });
61
61
  }
62
- if (error) {
63
- return _jsx(ResponseError, { error: error });
62
+ if (error && !currentData) {
63
+ return null;
64
64
  }
65
65
  return renderStructure();
66
66
  };
67
- return (_jsx("div", { className: b(), ref: scrollContainerRef, children: _jsx("div", { className: className, children: renderContent() }) }));
67
+ return (_jsxs("div", { className: b(), ref: scrollContainerRef, children: [error ? _jsx(ResponseError, { error: error, className: b('error') }) : null, _jsx("div", { className: className, children: renderContent() })] }));
68
68
  }
69
69
  export default NodeStructure;
@@ -10,6 +10,10 @@
10
10
  @include flex-container();
11
11
  @include body-2-typography();
12
12
 
13
+ &__error {
14
+ padding: 20px 20px 0;
15
+ }
16
+
13
17
  &__pdisk {
14
18
  display: flex;
15
19
  flex-direction: column;
@@ -78,7 +78,7 @@ function getColumns({ pDiskId, selectedVdiskId, nodeId, }) {
78
78
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.Info],
79
79
  width: 70,
80
80
  render: ({ row }) => {
81
- return (_jsx(Popover, { placement: ['right'], content: _jsx(VDiskInfo, { data: row, withTitle: true }), tooltipContentClassName: b('vdisk-details'), children: _jsx(Button, { view: "flat-secondary", className: b('vdisk-details-button', {
81
+ return (_jsx(Popover, { placement: ['right'], content: _jsx(VDiskInfo, { data: row, withTitle: true, withVDiskPageLink: true }), tooltipContentClassName: b('vdisk-details'), children: _jsx(Button, { view: "flat-secondary", className: b('vdisk-details-button', {
82
82
  selected: row.id === selectedVdiskId,
83
83
  }), children: _jsx(Icon, { data: CircleInfoFill, size: 18 }) }) }));
84
84
  },
@@ -107,7 +107,7 @@ export function PDisk({ id, data, selectedVdiskId, nodeId, unfolded: unfoldedFro
107
107
  if (isEmpty(data)) {
108
108
  return _jsx("div", { children: "No information about PDisk" });
109
109
  }
110
- return (_jsxs("div", { children: [_jsx(PDiskInfo, { pDisk: data, nodeId: nodeId, className: b('pdisk-details') }), _jsxs("div", { className: b('vdisks-container'), children: [_jsx("div", { className: b('vdisks-header'), children: "VDisks" }), renderVDisks()] })] }));
110
+ return (_jsxs("div", { children: [_jsx(PDiskInfo, { pDisk: data, nodeId: nodeId, className: b('pdisk-details'), withPDiskPageLink: true }), _jsxs("div", { className: b('vdisks-container'), children: [_jsx("div", { className: b('vdisks-header'), children: "VDisks" }), renderVDisks()] })] }));
111
111
  };
112
112
  return (_jsxs("div", { className: b('pdisk'), id: id, children: [_jsxs("div", { className: b('pdisk-header'), children: [_jsxs("div", { className: b('pdisk-title-wrapper'), children: [_jsx(EntityStatus, { status: Device }), _jsx(PDiskTitleBadge, { label: "PDiskID", value: PDiskId, className: b('pdisk-title-id') }), _jsx(PDiskTitleBadge, { value: Type, className: b('pdisk-title-type') }), _jsx(ProgressViewer, { value: total - available, capacity: total, formatValues: formatStorageValuesToGb, colorizeProgress: true, className: b('pdisk-title-size') }), _jsx(PDiskTitleBadge, { label: "VDisks", value: vDisks.length })] }), _jsx(Button, { onClick: unfolded ? onClosePDiskDetails : onOpenPDiskDetails, view: "flat-secondary", children: _jsx(ArrowToggle, { direction: unfolded ? 'top' : 'bottom' }) })] }), unfolded && renderPDiskDetails()] }));
113
113
  }
@@ -5,6 +5,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
5
5
  import { StringParam, useQueryParams } from 'use-query-params';
6
6
  import { EntitiesCount } from '../../components/EntitiesCount';
7
7
  import { AccessDenied } from '../../components/Errors/403';
8
+ import { isAccessError } from '../../components/Errors/PageError/PageError';
8
9
  import { ResponseError } from '../../components/Errors/ResponseError';
9
10
  import { Illustration } from '../../components/Illustration';
10
11
  import { ProblemFilter } from '../../components/ProblemFilter';
@@ -65,7 +66,7 @@ export const Nodes = ({ path, additionalNodesProps = {} }) => {
65
66
  }, [data, searchValue, uptimeFilter, problemFilter]);
66
67
  const totalNodes = (data === null || data === void 0 ? void 0 : data.TotalNodes) || 0;
67
68
  const renderControls = () => {
68
- return (_jsxs(React.Fragment, { children: [_jsx(Search, { onChange: handleSearchQueryChange, placeholder: "Host name", className: b('search'), value: searchValue }), _jsx(ProblemFilter, { value: problemFilter, onChange: handleProblemFilterChange }), _jsx(UptimeFilter, { value: uptimeFilter, onChange: handleUptimeFilterChange }), _jsx(EntitiesCount, { total: totalNodes, current: (nodes === null || nodes === void 0 ? void 0 : nodes.length) || 0, label: 'Nodes', loading: isLoading })] }));
69
+ return (_jsxs(React.Fragment, { children: [_jsx(Search, { onChange: handleSearchQueryChange, placeholder: "Host name", className: b('search'), value: searchValue }), _jsx(ProblemFilter, { value: problemFilter, onChange: handleProblemFilterChange }), _jsx(UptimeFilter, { value: uptimeFilter, onChange: handleUptimeFilterChange }), _jsx(EntitiesCount, { total: totalNodes, current: nodes.length, label: 'Nodes', loading: isLoading })] }));
69
70
  };
70
71
  const renderTable = () => {
71
72
  const rawColumns = getNodesColumns({
@@ -74,7 +75,7 @@ export const Nodes = ({ path, additionalNodesProps = {} }) => {
74
75
  const columns = rawColumns.map((column) => {
75
76
  return { ...column, sortable: isSortableNodesProperty(column.name) };
76
77
  });
77
- if (nodes && nodes.length === 0) {
78
+ if (nodes.length === 0) {
78
79
  if (problemFilter !== ProblemFilterValues.ALL ||
79
80
  uptimeFilter !== NodesUptimeFilterValues.All) {
80
81
  return _jsx(Illustration, { name: "thumbsUp", width: "200" });
@@ -82,11 +83,8 @@ export const Nodes = ({ path, additionalNodesProps = {} }) => {
82
83
  }
83
84
  return (_jsx(ResizeableDataTable, { columnsWidthLSKey: NODES_COLUMNS_WIDTH_LS_KEY, data: nodes || [], columns: columns, settings: DEFAULT_TABLE_SETTINGS, sortOrder: sort, onSort: handleSort, emptyDataMessage: i18n('empty.default'), rowClassName: (row) => b('node', { unavailable: isUnavailableNode(row) }) }));
84
85
  };
85
- if (error) {
86
- if (error.status === 403) {
87
- return _jsx(AccessDenied, {});
88
- }
89
- return _jsx(ResponseError, { error: error });
86
+ if (isAccessError(error)) {
87
+ return _jsx(AccessDenied, {});
90
88
  }
91
- return (_jsxs(TableWithControlsLayout, { children: [_jsx(TableWithControlsLayout.Controls, { children: renderControls() }), _jsx(TableWithControlsLayout.Table, { loading: isLoading, children: renderTable() })] }));
89
+ return (_jsxs(TableWithControlsLayout, { children: [_jsx(TableWithControlsLayout.Controls, { children: renderControls() }), error ? _jsx(ResponseError, { error: error }) : null, _jsx(TableWithControlsLayout.Table, { loading: isLoading, children: data ? renderTable() : null })] }));
92
90
  };
@@ -8,7 +8,7 @@ import { TabletsStatistic } from '../../components/TabletsStatistic';
8
8
  import { UsageLabel } from '../../components/UsageLabel/UsageLabel';
9
9
  import { getLoadSeverityForNode } from '../../store/reducers/nodes/utils';
10
10
  import { EMPTY_DATA_PLACEHOLDER } from '../../utils/constants';
11
- import { formatBytesToGigabyte, formatStorageValuesToGb, } from '../../utils/dataFormatters/dataFormatters';
11
+ import { formatStorageValuesToGb } from '../../utils/dataFormatters/dataFormatters';
12
12
  export const NODES_COLUMNS_WIDTH_LS_KEY = 'nodesTableColumnsWidth';
13
13
  const NODES_COLUMNS_IDS = {
14
14
  NodeId: 'NodeId',
@@ -84,14 +84,7 @@ const memoryColumn = {
84
84
  header: 'Memory',
85
85
  sortAccessor: ({ MemoryUsed = 0 }) => Number(MemoryUsed),
86
86
  defaultOrder: DataTable.DESCENDING,
87
- render: ({ row }) => {
88
- if (row.MemoryUsed) {
89
- return formatBytesToGigabyte(row.MemoryUsed);
90
- }
91
- else {
92
- return '—';
93
- }
94
- },
87
+ render: ({ row }) => (_jsx(ProgressViewer, { value: row.MemoryUsed, capacity: row.MemoryLimit, formatValues: formatStorageValuesToGb, colorizeProgress: true })),
95
88
  align: DataTable.RIGHT,
96
89
  width: 120,
97
90
  };
@@ -111,7 +104,9 @@ const loadAverageColumn = {
111
104
  header: 'Load average',
112
105
  sortAccessor: ({ LoadAveragePercents = [] }) => LoadAveragePercents[0],
113
106
  defaultOrder: DataTable.DESCENDING,
114
- render: ({ row }) => row.LoadAveragePercents && row.LoadAveragePercents.length > 0 ? (_jsx(ProgressViewer, { value: row.LoadAveragePercents[0], percents: true, colorizeProgress: true, capacity: 100 })) : ('—'),
107
+ render: ({ row }) => (_jsx(ProgressViewer, { value: row.LoadAveragePercents && row.LoadAveragePercents.length > 0
108
+ ? row.LoadAveragePercents[0]
109
+ : undefined, percents: true, colorizeProgress: true, capacity: 100 })),
115
110
  align: DataTable.LEFT,
116
111
  width: 140,
117
112
  resizeMinWidth: 140,
@@ -147,22 +142,13 @@ const topNodesMemoryColumn = {
147
142
  };
148
143
  const sharedCacheUsageColumn = {
149
144
  name: NODES_COLUMNS_IDS.SharedCacheUsage,
150
- header: 'Tablet Cache',
145
+ header: 'Caches',
151
146
  render: ({ row }) => (_jsx(ProgressViewer, { value: row.SharedCacheUsed, capacity: row.SharedCacheLimit, formatValues: formatStorageValuesToGb, colorizeProgress: true })),
152
147
  align: DataTable.LEFT,
153
148
  width: 140,
154
149
  resizeMinWidth: 140,
155
150
  sortable: false,
156
151
  };
157
- const memoryUsedInAllocColumn = {
158
- name: NODES_COLUMNS_IDS.MemoryUsedInAlloc,
159
- header: 'Query Runtime',
160
- render: ({ row }) => (_jsx(ProgressViewer, { value: row.MemoryUsedInAlloc, capacity: row.MemoryLimit, formatValues: formatStorageValuesToGb, colorizeProgress: true })),
161
- align: DataTable.LEFT,
162
- width: 140,
163
- resizeMinWidth: 140,
164
- sortable: false,
165
- };
166
152
  const sessionsColumn = {
167
153
  name: NODES_COLUMNS_IDS.TotalSessions,
168
154
  header: 'Sessions',
@@ -204,7 +190,6 @@ export function getTopNodesByMemoryColumns({ tabletsPath, getNodeRef, }) {
204
190
  topNodesLoadAverageColumn,
205
191
  topNodesMemoryColumn,
206
192
  sharedCacheUsageColumn,
207
- memoryUsedInAllocColumn,
208
193
  sessionsColumn,
209
194
  getTabletsColumn(tabletsPath),
210
195
  ];
@@ -9,12 +9,14 @@ import { z } from 'zod';
9
9
  import { AutoRefreshControl } from '../../components/AutoRefreshControl/AutoRefreshControl';
10
10
  import { ButtonWithConfirmDialog } from '../../components/ButtonWithConfirmDialog/ButtonWithConfirmDialog';
11
11
  import { DiskPageTitle } from '../../components/DiskPageTitle/DiskPageTitle';
12
+ import { ResponseError } from '../../components/Errors/ResponseError';
12
13
  import { InfoViewerSkeleton } from '../../components/InfoViewerSkeleton/InfoViewerSkeleton';
13
14
  import { InternalLink } from '../../components/InternalLink/InternalLink';
14
15
  import { PDiskInfo } from '../../components/PDiskInfo/PDiskInfo';
15
16
  import { PageMeta } from '../../components/PageMeta/PageMeta';
16
17
  import { getPDiskPagePath } from '../../routes';
17
18
  import { api } from '../../store/reducers/api';
19
+ import { selectIsUserAllowedToMakeChanges } from '../../store/reducers/authentication/authentication';
18
20
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
19
21
  import { pDiskApi } from '../../store/reducers/pdisk/pdisk';
20
22
  import { valueIsDefined } from '../../utils';
@@ -46,7 +48,7 @@ const PDISK_PAGE_TABS = [
46
48
  const pDiskTabSchema = z.nativeEnum(PDISK_TABS_IDS).catch(PDISK_TABS_IDS.diskDistribution);
47
49
  export function PDiskPage() {
48
50
  const dispatch = useTypedDispatch();
49
- const { isUserAllowedToMakeChanges } = useTypedSelector((state) => state.authentication);
51
+ const isUserAllowedToMakeChanges = useTypedSelector(selectIsUserAllowedToMakeChanges);
50
52
  const [{ nodeId, pDiskId, activeTab }] = useQueryParams({
51
53
  activeTab: StringParam,
52
54
  nodeId: StringParam,
@@ -65,11 +67,14 @@ export function PDiskPage() {
65
67
  const pDiskLoading = pdiskDataQuery.isFetching && pdiskDataQuery.currentData === undefined;
66
68
  const pDiskData = pdiskDataQuery.currentData;
67
69
  const { NodeHost, NodeId, NodeType, NodeDC, Severity } = pDiskData || {};
68
- const handleRestart = async () => {
70
+ const handleRestart = async (isRetry) => {
69
71
  if (pDiskParamsDefined) {
70
- return window.api.restartPDisk(nodeId, pDiskId).then((res) => {
71
- if ((res === null || res === void 0 ? void 0 : res.result) === false) {
72
- const err = { statusText: res.error };
72
+ return window.api.restartPDisk({ nodeId, pDiskId, force: isRetry }).then((response) => {
73
+ if ((response === null || response === void 0 ? void 0 : response.result) === false) {
74
+ const err = {
75
+ statusText: response.error,
76
+ retryPossible: response.forceRetryPossible,
77
+ };
73
78
  throw err;
74
79
  }
75
80
  });
@@ -97,13 +102,13 @@ export function PDiskPage() {
97
102
  return (_jsx(DiskPageTitle, { entityName: pDiskPageKeyset('pdisk'), status: getSeverityColor(Severity), id: pDiskParamsDefined ? getPDiskId(nodeId, pDiskId) : null, className: pdiskPageCn('title') }));
98
103
  };
99
104
  const renderControls = () => {
100
- return (_jsx("div", { className: pdiskPageCn('controls'), children: _jsxs(ButtonWithConfirmDialog, { onConfirmAction: handleRestart, onConfirmActionSuccess: handleAfterRestart, buttonDisabled: !nodeId || !pDiskId || !isUserAllowedToMakeChanges, buttonView: "normal", dialogContent: pDiskPageKeyset('restart-pdisk-dialog'), withPopover: true, popoverContent: pDiskPageKeyset('restart-pdisk-not-allowed'), popoverDisabled: isUserAllowedToMakeChanges, children: [_jsx(Icon, { data: ArrowRotateLeft }), pDiskPageKeyset('restart-pdisk-button')] }) }));
105
+ return (_jsx("div", { className: pdiskPageCn('controls'), children: _jsxs(ButtonWithConfirmDialog, { onConfirmAction: handleRestart, onConfirmActionSuccess: handleAfterRestart, buttonDisabled: !nodeId || !pDiskId || !isUserAllowedToMakeChanges, buttonView: "normal", dialogContent: pDiskPageKeyset('restart-pdisk-dialog'), retryButtonText: pDiskPageKeyset('force-restart-pdisk-button'), withPopover: true, popoverContent: pDiskPageKeyset('restart-pdisk-not-allowed'), popoverDisabled: isUserAllowedToMakeChanges, children: [_jsx(Icon, { data: ArrowRotateLeft }), pDiskPageKeyset('restart-pdisk-button')] }) }));
101
106
  };
102
107
  const renderInfo = () => {
103
108
  if (pDiskLoading) {
104
109
  return _jsx(InfoViewerSkeleton, { className: pdiskPageCn('info'), rows: 10 });
105
110
  }
106
- return (_jsx(PDiskInfo, { pDisk: pDiskData, nodeId: nodeId, className: pdiskPageCn('info'), isPDiskPage: true }));
111
+ return _jsx(PDiskInfo, { pDisk: pDiskData, nodeId: nodeId, className: pdiskPageCn('info') });
107
112
  };
108
113
  const renderTabs = () => {
109
114
  return (_jsx("div", { className: pdiskPageCn('tabs'), children: _jsx(Tabs, { size: "l", items: PDISK_PAGE_TABS, activeTab: pDiskTab, wrapTo: ({ id }, tabNode) => {
@@ -125,5 +130,11 @@ export function PDiskPage() {
125
130
  return null;
126
131
  }
127
132
  };
128
- return (_jsxs("div", { className: pdiskPageCn(null), children: [renderHelmet(), renderPageMeta(), renderPageTitle(), renderControls(), renderInfo(), renderTabs(), renderTabsContent()] }));
133
+ const renderError = () => {
134
+ if (!pdiskDataQuery.error) {
135
+ return null;
136
+ }
137
+ return _jsx(ResponseError, { error: pdiskDataQuery.error });
138
+ };
139
+ return (_jsxs("div", { className: pdiskPageCn(null), children: [renderHelmet(), renderPageMeta(), renderPageTitle(), renderControls(), renderError(), renderInfo(), renderTabs(), renderTabsContent()] }));
129
140
  }
@@ -11,6 +11,7 @@
11
11
  "label.slot-size": "Slot Size",
12
12
  "no-slots-data": "No slots data",
13
13
  "restart-pdisk-button": "Restart PDisk",
14
+ "force-restart-pdisk-button": "Restart anyway",
14
15
  "restart-pdisk-dialog": "PDisk will be restarted. Do you want to proceed?",
15
16
  "restart-pdisk-not-allowed": "You don't have enough rights to restart PDisk"
16
17
  }
@@ -1 +1 @@
1
- export declare const pDiskPageKeyset: (key: "node" | "groups" | "fqdn" | "log" | "pdisk" | "disk-distribution" | "empty-slot" | "label.log-size" | "label.system-size" | "label.slot-size" | "no-slots-data" | "restart-pdisk-button" | "restart-pdisk-dialog" | "restart-pdisk-not-allowed", params?: import("@gravity-ui/i18n").Params) => string;
1
+ export declare const pDiskPageKeyset: (key: "node" | "groups" | "fqdn" | "log" | "pdisk" | "disk-distribution" | "empty-slot" | "label.log-size" | "label.system-size" | "label.slot-size" | "no-slots-data" | "restart-pdisk-button" | "force-restart-pdisk-button" | "restart-pdisk-dialog" | "restart-pdisk-not-allowed", params?: import("@gravity-ui/i18n").Params) => string;