ydb-embedded-ui 6.3.0 → 6.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. package/README.md +39 -17
  2. package/dist/assets/icons/disableFullscreen.svg +4 -0
  3. package/dist/assets/icons/emptyState.svg +13 -0
  4. package/dist/assets/icons/key.svg +6 -0
  5. package/dist/assets/icons/monitoring.svg +9 -0
  6. package/dist/assets/icons/network.svg +21 -0
  7. package/dist/components/AsyncReplicationState/AsyncReplicationState.d.ts +6 -0
  8. package/dist/components/AsyncReplicationState/AsyncReplicationState.js +20 -0
  9. package/dist/components/AsyncReplicationState/index.d.ts +1 -0
  10. package/dist/components/AsyncReplicationState/index.js +1 -0
  11. package/dist/components/BasicNodeViewer/BasicNodeViewer.js +11 -5
  12. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.d.ts +6 -2
  13. package/dist/components/ButtonWithConfirmDialog/ButtonWithConfirmDialog.js +12 -3
  14. package/dist/components/CriticalActionDialog/CriticalActionDialog.js +3 -4
  15. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +2 -0
  16. package/dist/components/EmptyState/EmptyState.js +3 -2
  17. package/dist/components/EnableFullscreenButton/EnableFullscreenButton.js +3 -3
  18. package/dist/components/Errors/ResponseError/ResponseError.js +3 -0
  19. package/dist/components/Fullscreen/Fullscreen.js +3 -3
  20. package/dist/components/MonitoringButton/MonitoringButton.js +3 -3
  21. package/dist/components/NodeHostWrapper/NodeHostWrapper.js +3 -3
  22. package/dist/components/PDiskInfo/i18n/index.d.ts +1 -1
  23. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.d.ts +1 -2
  24. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.js +6 -6
  25. package/dist/components/StatusIcon/StatusIcon.js +5 -7
  26. package/dist/components/VDiskInfo/i18n/index.d.ts +1 -1
  27. package/dist/containers/App/App.js +1 -2
  28. package/dist/containers/AsideNavigation/AsideNavigation.js +4 -9
  29. package/dist/containers/AsideNavigation/YdbInternalUser/YdbInternalUser.js +2 -3
  30. package/dist/containers/AsideNavigation/useNavigationMenuItems.js +5 -6
  31. package/dist/containers/Authentication/Authentication.js +2 -4
  32. package/dist/containers/Clusters/Clusters.js +7 -2
  33. package/dist/containers/Clusters/constants.d.ts +1 -3
  34. package/dist/containers/Clusters/constants.js +0 -18
  35. package/dist/containers/Node/NodeStructure/Pdisk.js +4 -4
  36. package/dist/containers/Nodes/Nodes.js +19 -15
  37. package/dist/containers/Nodes/VirtualNodes.js +23 -6
  38. package/dist/containers/PDiskPage/PDiskPage.js +3 -2
  39. package/dist/containers/PDiskPage/i18n/en.json +2 -1
  40. package/dist/containers/PDiskPage/i18n/index.d.ts +1 -1
  41. package/dist/containers/Storage/Storage.js +50 -22
  42. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.js +2 -2
  43. package/dist/containers/Storage/VirtualStorage.js +32 -10
  44. package/dist/containers/Storage/utils/index.d.ts +4 -1
  45. package/dist/containers/Storage/utils/index.js +29 -0
  46. package/dist/containers/Tablet/Tablet.js +3 -3
  47. package/dist/containers/Tablet/TabletControls/TabletControls.js +3 -1
  48. package/dist/containers/Tablet/i18n/en.json +3 -0
  49. package/dist/containers/Tablet/i18n/index.d.ts +1 -1
  50. package/dist/containers/Tablet/i18n/index.js +1 -2
  51. package/dist/containers/Tablets/Tablets.d.ts +1 -2
  52. package/dist/containers/Tablets/Tablets.js +113 -53
  53. package/dist/containers/Tablets/i18n/en.json +10 -4
  54. package/dist/containers/Tablets/i18n/index.d.ts +1 -1
  55. package/dist/containers/Tablets/i18n/index.js +1 -2
  56. package/dist/containers/Tenant/Diagnostics/Diagnostics.js +5 -5
  57. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.d.ts +7 -0
  58. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.js +2 -0
  59. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +31 -19
  60. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss +14 -4
  61. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/en.json +2 -1
  62. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.d.ts +1 -1
  63. package/dist/containers/Tenant/Diagnostics/Network/Network.js +3 -3
  64. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/AsyncReplicationInfo.d.ts +7 -0
  65. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/AsyncReplicationInfo.js +39 -0
  66. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/Credentials.d.ts +6 -0
  67. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/Credentials.js +14 -0
  68. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/i18n/en.json +7 -0
  69. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/i18n/index.d.ts +2 -0
  70. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/i18n/index.js +4 -0
  71. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/index.d.ts +1 -0
  72. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/index.js +1 -0
  73. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/AsyncReplicationPaths.d.ts +7 -0
  74. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/AsyncReplicationPaths.js +34 -0
  75. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/AsyncReplicationPaths.scss +7 -0
  76. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/i18n/en.json +7 -0
  77. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/i18n/index.d.ts +2 -0
  78. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/i18n/index.js +4 -0
  79. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/index.d.ts +1 -0
  80. package/dist/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/index.js +1 -0
  81. package/dist/containers/Tenant/Diagnostics/Overview/Overview.js +2 -0
  82. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js +2 -2
  83. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.js +2 -1
  84. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.js +2 -1
  85. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.js +2 -1
  86. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.d.ts +1 -1
  87. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +3 -3
  88. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +3 -3
  89. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.js +2 -8
  90. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.js +23 -9
  91. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.d.ts +2 -2
  92. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.js +5 -6
  93. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +6 -14
  94. package/dist/containers/Tenant/Query/Issues/Issues.js +6 -9
  95. package/dist/containers/Tenant/Query/Preview/Preview.js +5 -5
  96. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +2 -8
  97. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +18 -19
  98. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +4 -4
  99. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.js +3 -3
  100. package/dist/containers/Tenant/Schema/SchemaViewer/helpers.js +3 -2
  101. package/dist/containers/Tenant/Tenant.js +3 -2
  102. package/dist/containers/Tenant/utils/ToggleButton.scss +0 -2
  103. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.js +4 -4
  104. package/dist/containers/Tenant/utils/schema.js +8 -0
  105. package/dist/containers/Tenant/utils/schemaActions.js +1 -0
  106. package/dist/containers/Tenant/utils/schemaControls.js +4 -3
  107. package/dist/containers/VDiskPage/VDiskPage.js +3 -2
  108. package/dist/containers/VDiskPage/i18n/en.json +2 -1
  109. package/dist/containers/VDiskPage/i18n/index.d.ts +1 -1
  110. package/dist/routes.d.ts +1 -1
  111. package/dist/services/api.d.ts +3 -3
  112. package/dist/services/settings.d.ts +19 -1
  113. package/dist/services/settings.js +2 -1
  114. package/dist/store/configureStore.d.ts +0 -12
  115. package/dist/store/defaultStore.d.ts +0 -6
  116. package/dist/store/reducers/authentication/authentication.d.ts +187 -13
  117. package/dist/store/reducers/authentication/authentication.js +12 -3
  118. package/dist/store/reducers/authentication/types.d.ts +5 -1
  119. package/dist/store/reducers/cluster/cluster.js +4 -0
  120. package/dist/store/reducers/executeQuery.d.ts +4 -65
  121. package/dist/store/reducers/executeQuery.js +38 -34
  122. package/dist/store/reducers/executeTopQueries/executeTopQueries.js +4 -1
  123. package/dist/store/reducers/explainQuery/explainQuery.d.ts +9 -0
  124. package/dist/store/reducers/explainQuery/explainQuery.js +32 -0
  125. package/dist/store/reducers/explainQuery/types.d.ts +12 -0
  126. package/dist/store/reducers/explainQuery/utils.d.ts +6 -0
  127. package/dist/store/reducers/explainQuery/utils.js +40 -0
  128. package/dist/store/reducers/healthcheckInfo/healthcheckInfo.d.ts +0 -60
  129. package/dist/store/reducers/host.d.ts +61 -4
  130. package/dist/store/reducers/index.d.ts +0 -9
  131. package/dist/store/reducers/index.js +0 -6
  132. package/dist/store/reducers/node/selectors.d.ts +0 -3
  133. package/dist/store/reducers/nodes/nodes.d.ts +1 -5
  134. package/dist/store/reducers/nodes/nodes.js +0 -27
  135. package/dist/store/reducers/nodes/types.d.ts +4 -13
  136. package/dist/store/reducers/nodesList.d.ts +0 -3
  137. package/dist/store/reducers/olapStats.js +4 -1
  138. package/dist/store/reducers/preview.js +4 -1
  139. package/dist/store/reducers/schema/schema.d.ts +61 -4
  140. package/dist/store/reducers/schemaAcl/schemaAcl.d.ts +61 -4
  141. package/dist/store/reducers/shardsWorkload/shardsWorkload.js +4 -1
  142. package/dist/store/reducers/storage/selectors.d.ts +2 -17
  143. package/dist/store/reducers/storage/selectors.js +1 -36
  144. package/dist/store/reducers/storage/storage.d.ts +2 -6
  145. package/dist/store/reducers/storage/storage.js +0 -44
  146. package/dist/store/reducers/storage/types.d.ts +15 -22
  147. package/dist/store/reducers/storage/types.js +4 -1
  148. package/dist/store/reducers/tablets.d.ts +91 -1
  149. package/dist/store/reducers/tablets.js +16 -1
  150. package/dist/store/reducers/tabletsFilters.d.ts +61 -4
  151. package/dist/store/reducers/tenant/tenant.d.ts +2 -2
  152. package/dist/store/reducers/tenant/tenant.js +10 -1
  153. package/dist/store/reducers/tenant/types.d.ts +8 -3
  154. package/dist/store/reducers/tenant/types.js +3 -1
  155. package/dist/store/reducers/tenantOverview/executeTopTables/executeTopTables.js +6 -3
  156. package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.js +6 -3
  157. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.js +6 -3
  158. package/dist/store/reducers/tenants/selectors.d.ts +0 -27
  159. package/dist/store/reducers/tenants/utils.d.ts +4 -4
  160. package/dist/store/reducers/tenants/utils.js +8 -8
  161. package/dist/store/reducers/topic.d.ts +0 -45
  162. package/dist/store/state-url-mapping.js +0 -22
  163. package/dist/store/utils.d.ts +2 -3
  164. package/dist/store/utils.js +1 -1
  165. package/dist/types/api/schema/replication.d.ts +74 -0
  166. package/dist/types/api/schema/replication.js +7 -0
  167. package/dist/types/api/schema/schema.d.ts +4 -1
  168. package/dist/types/api/schema/schema.js +1 -0
  169. package/dist/types/api/whoami.d.ts +6 -0
  170. package/dist/types/store/executeQuery.d.ts +2 -9
  171. package/dist/utils/constants.d.ts +1 -0
  172. package/dist/utils/constants.js +1 -0
  173. package/dist/utils/monaco/yql/constants.d.ts +2 -0
  174. package/dist/utils/monaco/yql/constants.js +33 -0
  175. package/dist/utils/monaco/yql/generateSuggestions.d.ts +1 -0
  176. package/dist/utils/monaco/yql/generateSuggestions.js +28 -11
  177. package/dist/utils/monaco/yql/yqlSuggestions.js +6 -1
  178. package/dist/utils/nodes.d.ts +2 -0
  179. package/dist/utils/nodes.js +4 -0
  180. package/dist/utils/query.d.ts +5 -3
  181. package/dist/utils/query.js +27 -4
  182. package/dist/utils/response.d.ts +4 -0
  183. package/dist/utils/response.js +9 -0
  184. package/dist/utils/tablet.d.ts +2 -0
  185. package/dist/utils/tablet.js +14 -0
  186. package/package.json +4 -3
  187. package/dist/assets/icons/bug.svg +0 -1
  188. package/dist/assets/icons/circle-exclamation.svg +0 -1
  189. package/dist/assets/icons/circle-info.svg +0 -1
  190. package/dist/assets/icons/circle-xmark.svg +0 -1
  191. package/dist/assets/icons/close.svg +0 -1
  192. package/dist/assets/icons/control-menu-button.svg +0 -1
  193. package/dist/assets/icons/dots.svg +0 -1
  194. package/dist/assets/icons/hide.svg +0 -1
  195. package/dist/assets/icons/question.svg +0 -1
  196. package/dist/assets/icons/server.svg +0 -1
  197. package/dist/assets/icons/settings-with-dot.svg +0 -1
  198. package/dist/assets/icons/settings.svg +0 -1
  199. package/dist/assets/icons/shield.svg +0 -3
  200. package/dist/assets/icons/show.svg +0 -1
  201. package/dist/assets/icons/signIn.svg +0 -1
  202. package/dist/assets/icons/signOut.svg +0 -1
  203. package/dist/assets/icons/storage.svg +0 -1
  204. package/dist/assets/icons/support.svg +0 -1
  205. package/dist/assets/icons/triangle-exclamation.svg +0 -1
  206. package/dist/assets/icons/update-arrow.svg +0 -6
  207. package/dist/components/Icon/Icon.d.ts +0 -14
  208. package/dist/components/Icon/Icon.js +0 -16
  209. package/dist/components/Icon/index.d.ts +0 -1
  210. package/dist/components/Icon/index.js +0 -1
  211. package/dist/containers/AppIcons/AppIcons.d.ts +0 -2
  212. package/dist/containers/AppIcons/AppIcons.js +0 -9
  213. package/dist/containers/Tablet/i18n/ru.json +0 -10
  214. package/dist/containers/Tablets/Tablets.scss +0 -35
  215. package/dist/containers/Tablets/i18n/ru.json +0 -6
  216. package/dist/store/reducers/explainQuery.d.ts +0 -149
  217. package/dist/store/reducers/explainQuery.js +0 -94
  218. package/dist/types/store/explainQuery.d.ts +0 -27
  219. package/dist/utils/error.d.ts +0 -2
  220. package/dist/utils/error.js +0 -13
  221. /package/dist/{types/store/explainQuery.js → store/reducers/explainQuery/types.js} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowRightFromSquare, ArrowRightToSquare } from '@gravity-ui/icons';
2
3
  import { Button, Icon } from '@gravity-ui/uikit';
3
4
  import { useHistory } from 'react-router';
4
5
  import routes, { createHref } from '../../../routes';
@@ -6,8 +7,6 @@ import { logout } from '../../../store/reducers/authentication/authentication';
6
7
  import { cn } from '../../../utils/cn';
7
8
  import { useTypedDispatch, useTypedSelector } from '../../../utils/hooks';
8
9
  import i18n from '../i18n';
9
- import signOutIcon from '@gravity-ui/icons/svgs/arrow-right-from-square.svg';
10
- import signInIcon from '@gravity-ui/icons/svgs/arrow-right-to-square.svg';
11
10
  import './YdbInternalUser.scss';
12
11
  const b = cn('kv-ydb-internal-user');
13
12
  export function YdbInternalUser() {
@@ -20,5 +19,5 @@ export function YdbInternalUser() {
20
19
  const handleLogout = () => {
21
20
  dispatch(logout);
22
21
  };
23
- 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: signOutIcon, size: 16 }) })) : (_jsx(Button, { view: "flat-secondary", title: i18n('account.login'), onClick: handleLoginClick, children: _jsx(Icon, { data: signInIcon, size: 16 }) }))] }));
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 }) }))] }));
24
23
  }
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { Pulse, Terminal } from '@gravity-ui/icons';
2
3
  import { useHistory, useLocation } from 'react-router';
3
4
  import routes, { parseQuery } from '../../routes';
4
5
  import { TENANT_PAGE, TENANT_PAGES_IDS } from '../../store/reducers/tenant/constants';
@@ -6,13 +7,11 @@ import { TENANT_INITIAL_PAGE_KEY } from '../../utils/constants';
6
7
  import { useSetting, useTypedSelector } from '../../utils/hooks';
7
8
  import { getTenantPath } from '../Tenant/TenantPages';
8
9
  import i18n from './i18n';
9
- import pulseIcon from '@gravity-ui/icons/svgs/pulse.svg';
10
- import terminalIcon from '@gravity-ui/icons/svgs/terminal.svg';
11
10
  export function useNavigationMenuItems() {
12
11
  const location = useLocation();
13
12
  const history = useHistory();
14
- const [initialTenantPage, setInitialTenantPage] = useSetting(TENANT_INITIAL_PAGE_KEY);
15
- const { tenantPage = initialTenantPage } = useTypedSelector((state) => state.tenant);
13
+ const [, setInitialTenantPage] = useSetting(TENANT_INITIAL_PAGE_KEY);
14
+ const { tenantPage } = useTypedSelector((state) => state.tenant);
16
15
  const { pathname } = location;
17
16
  const queryParams = parseQuery(location);
18
17
  const isTenantPage = pathname === routes.tenant;
@@ -24,14 +23,14 @@ export function useNavigationMenuItems() {
24
23
  {
25
24
  id: TENANT_PAGES_IDS.query,
26
25
  title: i18n('pages.query'),
27
- icon: terminalIcon,
26
+ icon: Terminal,
28
27
  iconSize: 20,
29
28
  location: getTenantPath(Object.assign(Object.assign({}, queryParams), { [TENANT_PAGE]: TENANT_PAGES_IDS.query })),
30
29
  },
31
30
  {
32
31
  id: TENANT_PAGES_IDS.diagnostics,
33
32
  title: i18n('pages.diagnostics'),
34
- icon: pulseIcon,
33
+ icon: Pulse,
35
34
  iconSize: 20,
36
35
  location: getTenantPath(Object.assign(Object.assign({}, queryParams), { [TENANT_PAGE]: TENANT_PAGES_IDS.diagnostics })),
37
36
  },
@@ -1,14 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
+ import { Eye, EyeSlash, Xmark } from '@gravity-ui/icons';
3
4
  import { Button, Link as ExternalLink, Icon, TextInput } from '@gravity-ui/uikit';
4
5
  import { useHistory, useLocation } from 'react-router';
5
6
  import { parseQuery } from '../../routes';
6
7
  import { authenticate } from '../../store/reducers/authentication/authentication';
7
8
  import { cn } from '../../utils/cn';
8
9
  import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
9
- import closeIcon from '../../assets/icons/close.svg';
10
- import hideIcon from '../../assets/icons/hide.svg';
11
- import showIcon from '../../assets/icons/show.svg';
12
10
  import ydbLogoIcon from '../../assets/icons/ydb.svg';
13
11
  import './Authentication.scss';
14
12
  const b = cn('authentication');
@@ -64,6 +62,6 @@ function Authentication({ closable = false }) {
64
62
  const onTogglePasswordVisibility = () => {
65
63
  setShowPassword((prev) => !prev);
66
64
  };
67
- 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 ? hideIcon : showIcon, 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: closeIcon, size: 24 }) }))] }));
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 }) }))] }));
68
66
  }
69
67
  export default Authentication;
@@ -14,7 +14,7 @@ import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
14
14
  import { getMinorVersion } from '../../utils/versions';
15
15
  import { ClustersStatistics } from './ClustersStatistics';
16
16
  import { CLUSTERS_COLUMNS, CLUSTERS_COLUMNS_WIDTH_LS_KEY } from './columns';
17
- import { CLUSTER_STATUSES, COLUMNS_NAMES, COLUMNS_TITLES, DEFAULT_COLUMNS, SELECTED_COLUMNS_KEY, } from './constants';
17
+ import { COLUMNS_NAMES, COLUMNS_TITLES, DEFAULT_COLUMNS, SELECTED_COLUMNS_KEY } from './constants';
18
18
  import i18n from './i18n';
19
19
  import { b } from './shared';
20
20
  import { useSelectedColumns } from './useSelectedColumns';
@@ -67,10 +67,15 @@ export function Clusters() {
67
67
  return filterClusters(clusters !== null && clusters !== void 0 ? clusters : [], { clusterName, status, service, version });
68
68
  }, [clusterName, clusters, service, status, version]);
69
69
  const aggregation = React.useMemo(() => aggregateClustersInfo(filteredClusters), [filteredClusters]);
70
+ const statuses = React.useMemo(() => {
71
+ return Array.from(new Set((clusters !== null && clusters !== void 0 ? clusters : []).map((cluster) => cluster.status).filter(Boolean)))
72
+ .sort()
73
+ .map((el) => ({ value: el, content: el }));
74
+ }, [clusters]);
70
75
  if (query.isLoading) {
71
76
  return _jsx(Loader, { size: "l" });
72
77
  }
73
- return (_jsxs("div", { className: b(), children: [_jsx(Helmet, { children: _jsx("title", { children: i18n('page_title') }) }), _jsx(ClustersStatistics, { stats: aggregation, count: filteredClusters.length }), _jsxs("div", { className: b('controls'), children: [_jsx("div", { className: b('control', { wide: true }), children: _jsx(Search, { placeholder: i18n('controls_search-placeholder'), onChange: changeClusterName, value: clusterName }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_status-select-label'), value: status, options: CLUSTER_STATUSES, onUpdate: changeStatus, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_service-select-label'), value: service, options: servicesToSelect, onUpdate: changeService, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_version-select-label'), value: version, options: versions, onUpdate: changeVersion, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(TableColumnSetup, { popupWidth: 242, items: columnsToSelect, showStatus: true, onUpdate: setColumns, sortable: false }, "TableColumnSetup") })] }), query.isError ? _jsx(ResponseError, { error: query.error, className: b('error') }) : null, _jsx("div", { className: b('table-wrapper'), children: _jsx("div", { className: b('table-content'), children: _jsx(ResizeableDataTable, { columnsWidthLSKey: CLUSTERS_COLUMNS_WIDTH_LS_KEY, wrapperClassName: b('table'), data: filteredClusters, columns: columnsToShow, settings: Object.assign(Object.assign({}, DEFAULT_TABLE_SETTINGS), { dynamicRender: false }), initialSortOrder: {
78
+ return (_jsxs("div", { className: b(), children: [_jsx(Helmet, { children: _jsx("title", { children: i18n('page_title') }) }), _jsx(ClustersStatistics, { stats: aggregation, count: filteredClusters.length }), _jsxs("div", { className: b('controls'), children: [_jsx("div", { className: b('control', { wide: true }), children: _jsx(Search, { placeholder: i18n('controls_search-placeholder'), onChange: changeClusterName, value: clusterName }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_status-select-label'), value: status, options: statuses, onUpdate: changeStatus, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_service-select-label'), value: service, options: servicesToSelect, onUpdate: changeService, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(Select, { multiple: true, filterable: true, hasClear: true, placeholder: i18n('controls_select-placeholder'), label: i18n('controls_version-select-label'), value: version, options: versions, onUpdate: changeVersion, width: "max" }) }), _jsx("div", { className: b('control'), children: _jsx(TableColumnSetup, { popupWidth: 242, items: columnsToSelect, showStatus: true, onUpdate: setColumns, sortable: false }, "TableColumnSetup") })] }), query.isError ? _jsx(ResponseError, { error: query.error, className: b('error') }) : null, _jsx("div", { className: b('table-wrapper'), children: _jsx("div", { className: b('table-content'), children: _jsx(ResizeableDataTable, { columnsWidthLSKey: CLUSTERS_COLUMNS_WIDTH_LS_KEY, wrapperClassName: b('table'), data: filteredClusters, columns: columnsToShow, settings: Object.assign(Object.assign({}, DEFAULT_TABLE_SETTINGS), { dynamicRender: false }), initialSortOrder: {
74
79
  columnId: COLUMNS_NAMES.TITLE,
75
80
  order: DataTable.ASCENDING,
76
81
  } }) }) })] }));
@@ -1,4 +1,3 @@
1
- import type { SelectOption } from '@gravity-ui/uikit';
2
1
  export declare const SELECTED_COLUMNS_KEY = "selectedColumns";
3
2
  export declare const COLUMNS_NAMES: {
4
3
  readonly TITLE: "title";
@@ -15,7 +14,7 @@ export declare const COLUMNS_NAMES: {
15
14
  readonly DESCRIPTION: "description";
16
15
  readonly BALANCER: "balancer";
17
16
  };
18
- export declare const DEFAULT_COLUMNS: ("nodes" | "storage" | "tenants" | "versions" | "status" | "service" | "hosts" | "balancer" | "title" | "owner" | "load")[];
17
+ export declare const DEFAULT_COLUMNS: ("nodes" | "storage" | "status" | "tenants" | "versions" | "service" | "hosts" | "balancer" | "title" | "owner" | "load")[];
19
18
  export declare const COLUMNS_TITLES: {
20
19
  readonly title: "Cluster";
21
20
  readonly versions: "Versions";
@@ -31,4 +30,3 @@ export declare const COLUMNS_TITLES: {
31
30
  readonly description: "Description";
32
31
  readonly balancer: "Balancer";
33
32
  };
34
- export declare const CLUSTER_STATUSES: SelectOption[];
@@ -42,21 +42,3 @@ export const COLUMNS_TITLES = {
42
42
  [COLUMNS_NAMES.DESCRIPTION]: 'Description',
43
43
  [COLUMNS_NAMES.BALANCER]: 'Balancer',
44
44
  };
45
- export const CLUSTER_STATUSES = [
46
- {
47
- value: 'production',
48
- content: 'Production',
49
- },
50
- {
51
- value: 'preprod',
52
- content: 'Preprod',
53
- },
54
- {
55
- value: 'testing',
56
- content: 'Testing',
57
- },
58
- {
59
- value: 'development',
60
- content: 'Development',
61
- },
62
- ];
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
+ import { ArrowUpRightFromSquare, CircleInfoFill } from '@gravity-ui/icons';
3
4
  import DataTable from '@gravity-ui/react-data-table';
4
- import { ArrowToggle, Button, Popover } from '@gravity-ui/uikit';
5
+ import { ArrowToggle, Button, Icon, Popover } from '@gravity-ui/uikit';
5
6
  import isEmpty from 'lodash/isEmpty';
6
7
  import { EntityStatus } from '../../../components/EntityStatus/EntityStatus';
7
- import { Icon } from '../../../components/Icon';
8
8
  import { PDiskInfo } from '../../../components/PDiskInfo/PDiskInfo';
9
9
  import { ProgressViewer } from '../../../components/ProgressViewer/ProgressViewer';
10
10
  import { EFlag } from '../../../types/api/enums';
@@ -49,7 +49,7 @@ function getColumns({ pDiskId, selectedVdiskId, nodeId, }) {
49
49
  vDiskSlotId,
50
50
  });
51
51
  }
52
- return (_jsxs("div", { className: b('vdisk-id', { selected: row.id === selectedVdiskId }), children: [_jsx("span", { children: vDiskSlotId }), vdiskInternalViewerLink && (_jsx(Button, { size: "s", className: b('external-button', { hidden: true }), href: vdiskInternalViewerLink, target: "_blank", title: i18n('vdisk.developer-ui-button-title'), children: _jsx(Icon, { name: "external" }) }))] }));
52
+ return (_jsxs("div", { className: b('vdisk-id', { selected: row.id === selectedVdiskId }), children: [_jsx("span", { children: vDiskSlotId }), vdiskInternalViewerLink && (_jsx(Button, { size: "s", className: b('external-button', { hidden: true }), href: vdiskInternalViewerLink, target: "_blank", title: i18n('vdisk.developer-ui-button-title'), children: _jsx(Icon, { data: ArrowUpRightFromSquare }) }))] }));
53
53
  },
54
54
  align: DataTable.LEFT,
55
55
  },
@@ -80,7 +80,7 @@ function getColumns({ pDiskId, selectedVdiskId, nodeId, }) {
80
80
  render: ({ row }) => {
81
81
  return (_jsx(Popover, { placement: ['right'], content: _jsx(Vdisk, { data: row }), tooltipContentClassName: b('vdisk-details'), children: _jsx(Button, { view: "flat-secondary", className: b('vdisk-details-button', {
82
82
  selected: row.id === selectedVdiskId,
83
- }), children: _jsx(Icon, { name: "information", viewBox: "0 0 512 512", height: 16, width: 16 }) }) }));
83
+ }), children: _jsx(Icon, { data: CircleInfoFill, size: 18 }) }) }));
84
84
  },
85
85
  sortable: false,
86
86
  },
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { ASCENDING } from '@gravity-ui/react-data-table/build/esm/lib/constants';
4
4
  import { skipToken } from '@reduxjs/toolkit/query';
5
+ import { StringParam, useQueryParams } from 'use-query-params';
5
6
  import { EntitiesCount } from '../../components/EntitiesCount';
6
7
  import { AccessDenied } from '../../components/Errors/403';
7
8
  import { ResponseError } from '../../components/Errors/ResponseError';
@@ -11,21 +12,27 @@ import { ResizeableDataTable } from '../../components/ResizeableDataTable/Resize
11
12
  import { Search } from '../../components/Search';
12
13
  import { TableWithControlsLayout } from '../../components/TableWithControlsLayout/TableWithControlsLayout';
13
14
  import { UptimeFilter } from '../../components/UptimeFIlter';
14
- import { nodesApi, setInitialState, setSearchValue, setSort, setUptimeFilter, } from '../../store/reducers/nodes/nodes';
15
+ import { nodesApi } from '../../store/reducers/nodes/nodes';
15
16
  import { filterNodes } from '../../store/reducers/nodes/selectors';
16
17
  import { ProblemFilterValues, changeFilter } from '../../store/reducers/settings/settings';
17
18
  import { cn } from '../../utils/cn';
18
19
  import { DEFAULT_POLLING_INTERVAL, DEFAULT_TABLE_SETTINGS, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../../utils/constants';
19
20
  import { useSetting, useTableSort, useTypedDispatch, useTypedSelector } from '../../utils/hooks';
20
- import { NodesUptimeFilterValues, isSortableNodesProperty, isUnavailableNode, } from '../../utils/nodes';
21
+ import { NodesUptimeFilterValues, isSortableNodesProperty, isUnavailableNode, nodesUptimeFilterValuesSchema, } from '../../utils/nodes';
21
22
  import { NODES_COLUMNS_WIDTH_LS_KEY, getNodesColumns } from './getNodesColumns';
22
23
  import i18n from './i18n';
23
24
  import './Nodes.scss';
24
25
  const b = cn('ydb-nodes');
25
26
  export const Nodes = ({ path, additionalNodesProps = {} }) => {
27
+ var _a;
28
+ const [queryParams, setQueryParams] = useQueryParams({
29
+ uptimeFilter: StringParam,
30
+ search: StringParam,
31
+ });
32
+ const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
33
+ const searchValue = (_a = queryParams.search) !== null && _a !== void 0 ? _a : '';
26
34
  const dispatch = useTypedDispatch();
27
35
  const isClusterNodes = !path;
28
- const { uptimeFilter, searchValue, sortOrder = ASCENDING, sortValue = 'NodeId', } = useTypedSelector((state) => state.nodes);
29
36
  const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
30
37
  const { autorefresh } = useTypedSelector((state) => state.schema);
31
38
  const [useNodesEndpoint] = useSetting(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY);
@@ -39,25 +46,22 @@ export const Nodes = ({ path, additionalNodesProps = {} }) => {
39
46
  pollingInterval: autoRefreshInterval,
40
47
  });
41
48
  const { currentData: data, isLoading, error } = useGetComputeNodes ? computeQuery : nodesQuery;
42
- const [sort, handleSort] = useTableSort({ sortValue, sortOrder }, (sortParams) => dispatch(setSort(sortParams)));
49
+ const [sortValue, setSortValue] = React.useState({
50
+ sortValue: 'NodeId',
51
+ sortOrder: ASCENDING,
52
+ });
53
+ const [sort, handleSort] = useTableSort(sortValue, (sortParams) => {
54
+ setSortValue(sortParams);
55
+ });
43
56
  const handleSearchQueryChange = (value) => {
44
- dispatch(setSearchValue(value));
57
+ setQueryParams({ search: value || undefined }, 'replaceIn');
45
58
  };
46
59
  const handleProblemFilterChange = (value) => {
47
60
  dispatch(changeFilter(value));
48
61
  };
49
62
  const handleUptimeFilterChange = (value) => {
50
- dispatch(setUptimeFilter(value));
63
+ setQueryParams({ uptimeFilter: value }, 'replaceIn');
51
64
  };
52
- // Since Nodes component is used in several places,
53
- // we need to reset filters, searchValue
54
- // in nodes reducer when path changes
55
- React.useEffect(() => {
56
- return () => {
57
- // Clean data on component unmount
58
- dispatch(setInitialState());
59
- };
60
- }, [dispatch, path]);
61
65
  const nodes = React.useMemo(() => {
62
66
  return filterNodes(data === null || data === void 0 ? void 0 : data.Nodes, { searchValue, uptimeFilter, problemFilter });
63
67
  }, [data, searchValue, uptimeFilter, problemFilter]);
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
+ import { StringParam, useQueryParams } from 'use-query-params';
3
4
  import { EntitiesCount } from '../../components/EntitiesCount';
4
5
  import { AccessDenied } from '../../components/Errors/403';
5
6
  import { ResponseError } from '../../components/Errors/ResponseError';
@@ -8,18 +9,25 @@ import { ProblemFilter } from '../../components/ProblemFilter';
8
9
  import { Search } from '../../components/Search';
9
10
  import { UptimeFilter } from '../../components/UptimeFIlter';
10
11
  import { ResizeableVirtualTable } from '../../components/VirtualTable/ResizeableVirtualTable';
11
- import { ProblemFilterValues } from '../../store/reducers/settings/settings';
12
+ import { ProblemFilterValues, changeFilter } from '../../store/reducers/settings/settings';
12
13
  import { cn } from '../../utils/cn';
13
- import { NodesUptimeFilterValues, getProblemParamValue, getUptimeParamValue, isSortableNodesProperty, isUnavailableNode, } from '../../utils/nodes';
14
+ import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
15
+ import { NodesUptimeFilterValues, getProblemParamValue, getUptimeParamValue, isSortableNodesProperty, isUnavailableNode, nodesUptimeFilterValuesSchema, } from '../../utils/nodes';
14
16
  import { getNodes } from './getNodes';
15
17
  import { NODES_COLUMNS_WIDTH_LS_KEY, getNodesColumns } from './getNodesColumns';
16
18
  import i18n from './i18n';
17
19
  import './Nodes.scss';
18
20
  const b = cn('ydb-nodes');
19
21
  export const VirtualNodes = ({ path, parentContainer, additionalNodesProps }) => {
20
- const [searchValue, setSearchValue] = React.useState('');
21
- const [problemFilter, setProblemFilter] = React.useState(ProblemFilterValues.ALL);
22
- const [uptimeFilter, setUptimeFilter] = React.useState(NodesUptimeFilterValues.All);
22
+ var _a;
23
+ const [queryParams, setQueryParams] = useQueryParams({
24
+ uptimeFilter: StringParam,
25
+ search: StringParam,
26
+ });
27
+ const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
28
+ const searchValue = (_a = queryParams.search) !== null && _a !== void 0 ? _a : '';
29
+ const dispatch = useTypedDispatch();
30
+ const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
23
31
  const filters = React.useMemo(() => {
24
32
  return [path, searchValue, problemFilter, uptimeFilter];
25
33
  }, [path, searchValue, problemFilter, uptimeFilter]);
@@ -39,7 +47,16 @@ export const VirtualNodes = ({ path, parentContainer, additionalNodesProps }) =>
39
47
  return b('node', { unavailable: isUnavailableNode(row) });
40
48
  };
41
49
  const renderControls = ({ totalEntities, foundEntities, inited }) => {
42
- return (_jsxs(React.Fragment, { children: [_jsx(Search, { onChange: setSearchValue, placeholder: "Host name", className: b('search'), value: searchValue }), _jsx(ProblemFilter, { value: problemFilter, onChange: setProblemFilter }), _jsx(UptimeFilter, { value: uptimeFilter, onChange: setUptimeFilter }), _jsx(EntitiesCount, { total: totalEntities, current: foundEntities, label: 'Nodes', loading: !inited })] }));
50
+ const handleSearchQueryChange = (value) => {
51
+ setQueryParams({ search: value || undefined }, 'replaceIn');
52
+ };
53
+ const handleProblemFilterChange = (value) => {
54
+ dispatch(changeFilter(value));
55
+ };
56
+ const handleUptimeFilterChange = (value) => {
57
+ setQueryParams({ uptimeFilter: value }, 'replaceIn');
58
+ };
59
+ 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: totalEntities, current: foundEntities, label: 'Nodes', loading: !inited })] }));
43
60
  };
44
61
  const renderEmptyDataMessage = () => {
45
62
  if (problemFilter !== ProblemFilterValues.ALL ||
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
+ import { ArrowRotateLeft } from '@gravity-ui/icons';
3
4
  import { Icon } from '@gravity-ui/uikit';
4
5
  import { skipToken } from '@reduxjs/toolkit/query';
5
6
  import { Helmet } from 'react-helmet-async';
@@ -19,12 +20,12 @@ import { useTypedDispatch, useTypedSelector } from '../../utils/hooks';
19
20
  import { PDiskGroups } from './PDiskGroups';
20
21
  import { pDiskPageKeyset } from './i18n';
21
22
  import { pdiskPageCn } from './shared';
22
- import ArrowRotateLeftIcon from '@gravity-ui/icons/svgs/arrow-rotate-left.svg';
23
23
  import './PDiskPage.scss';
24
24
  export function PDiskPage() {
25
25
  var _a;
26
26
  const dispatch = useTypedDispatch();
27
27
  const nodesMap = useTypedSelector(selectNodesMap);
28
+ const { isUserAllowedToMakeChanges } = useTypedSelector((state) => state.authentication);
28
29
  const [{ nodeId, pDiskId }] = useQueryParams({
29
30
  nodeId: StringParam,
30
31
  pDiskId: StringParam,
@@ -74,7 +75,7 @@ export function PDiskPage() {
74
75
  return (_jsx(DiskPageTitle, { entityName: pDiskPageKeyset('pdisk'), status: getSeverityColor(Severity), id: pDiskId, className: pdiskPageCn('title') }));
75
76
  };
76
77
  const renderControls = () => {
77
- return (_jsx("div", { className: pdiskPageCn('controls'), children: _jsxs(ButtonWithConfirmDialog, { onConfirmAction: handleRestart, onConfirmActionSuccess: handleAfterRestart, buttonDisabled: !nodeId || !pDiskId, buttonView: "normal", dialogContent: pDiskPageKeyset('restart-pdisk-dialog'), children: [_jsx(Icon, { data: ArrowRotateLeftIcon }), pDiskPageKeyset('restart-pdisk-button')] }) }));
78
+ 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')] }) }));
78
79
  };
79
80
  const renderInfo = () => {
80
81
  if (pDiskLoading) {
@@ -4,5 +4,6 @@
4
4
  "groups": "Groups",
5
5
  "node": "Node",
6
6
  "restart-pdisk-button": "Restart PDisk",
7
- "restart-pdisk-dialog": "PDisk will be restarted. Do you want to proceed?"
7
+ "restart-pdisk-dialog": "PDisk will be restarted. Do you want to proceed?",
8
+ "restart-pdisk-not-allowed": "You don't have enough rights to restart PDisk"
8
9
  }
@@ -1 +1 @@
1
- export declare const pDiskPageKeyset: (key: "groups" | "node" | "pdisk" | "fqdn" | "restart-pdisk-button" | "restart-pdisk-dialog", params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ export declare const pDiskPageKeyset: (key: "node" | "groups" | "fqdn" | "pdisk" | "restart-pdisk-button" | "restart-pdisk-dialog" | "restart-pdisk-not-allowed", params?: import("@gravity-ui/i18n").Params | undefined) => string;
@@ -1,28 +1,62 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from 'react';
4
+ import { ArrayParam, StringParam, useQueryParams, withDefault } from 'use-query-params';
4
5
  import { AccessDenied } from '../../components/Errors/403';
5
6
  import { ResponseError } from '../../components/Errors/ResponseError';
6
7
  import { TableWithControlsLayout } from '../../components/TableWithControlsLayout/TableWithControlsLayout';
7
8
  import { selectNodesMap } from '../../store/reducers/nodesList';
8
9
  import { STORAGE_TYPES, VISIBLE_ENTITIES } from '../../store/reducers/storage/constants';
9
- import { filterGroups, filterNodes, getUsageFilterOptions, selectGroupsSortParams, selectNodesSortParams, } from '../../store/reducers/storage/selectors';
10
- import { setGroupsSortParams, setInitialState, setNodesSortParams, setStorageTextFilter, setStorageType, setUptimeFilter, setUsageFilter, setVisibleEntities, storageApi, } from '../../store/reducers/storage/storage';
10
+ import { filterGroups, filterNodes, getUsageFilterOptions, } from '../../store/reducers/storage/selectors';
11
+ import { storageApi } from '../../store/reducers/storage/storage';
12
+ import { storageTypeSchema, visibleEntitiesSchema } from '../../store/reducers/storage/types';
11
13
  import { DEFAULT_POLLING_INTERVAL, DEFAULT_TABLE_SETTINGS } from '../../utils/constants';
12
- import { useNodesRequestParams, useStorageRequestParams, useTableSort, useTypedDispatch, useTypedSelector, } from '../../utils/hooks';
13
- import { NodesUptimeFilterValues } from '../../utils/nodes';
14
+ import { useNodesRequestParams, useStorageRequestParams, useTableSort, useTypedSelector, } from '../../utils/hooks';
15
+ import { NodesUptimeFilterValues, nodesUptimeFilterValuesSchema } from '../../utils/nodes';
14
16
  import { StorageControls } from './StorageControls/StorageControls';
15
17
  import { StorageGroups } from './StorageGroups/StorageGroups';
16
18
  import { StorageNodes } from './StorageNodes/StorageNodes';
17
19
  import { b } from './shared';
20
+ import { defaultSortNode, getDefaultSortGroup } from './utils';
18
21
  import './Storage.scss';
22
+ const UsageFilterParam = withDefault({
23
+ encode: ArrayParam.encode,
24
+ decode: (input) => {
25
+ if (input === null || input === undefined) {
26
+ return input;
27
+ }
28
+ if (!Array.isArray(input)) {
29
+ return input ? [input] : [];
30
+ }
31
+ return input.filter(Boolean);
32
+ },
33
+ }, []);
19
34
  export const Storage = ({ additionalNodesProps, tenant, nodeId }) => {
20
- const dispatch = useTypedDispatch();
35
+ var _a;
21
36
  const { autorefresh } = useTypedSelector((state) => state.schema);
22
- const { type, visible: visibleEntities, filter, usageFilter, uptimeFilter, } = useTypedSelector((state) => state.storage);
37
+ const [queryParams, setQueryParams] = useQueryParams({
38
+ type: StringParam,
39
+ visible: StringParam,
40
+ search: StringParam,
41
+ uptimeFilter: StringParam,
42
+ usageFilter: UsageFilterParam,
43
+ });
44
+ const type = storageTypeSchema.parse(queryParams.type);
45
+ const visibleEntities = visibleEntitiesSchema.parse(queryParams.visible);
46
+ const filter = (_a = queryParams.search) !== null && _a !== void 0 ? _a : '';
47
+ const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
48
+ const usageFilter = queryParams.usageFilter;
23
49
  const nodesMap = useTypedSelector(selectNodesMap);
24
- const nodesSortParams = useTypedSelector(selectNodesSortParams);
25
- const groupsSortParams = useTypedSelector(selectGroupsSortParams);
50
+ const [nodeSort, setNodeSort] = React.useState({
51
+ sortOrder: undefined,
52
+ sortValue: undefined,
53
+ });
54
+ const nodesSortParams = nodeSort.sortValue ? nodeSort : defaultSortNode;
55
+ const [groupSort, setGroupSort] = React.useState({
56
+ sortOrder: undefined,
57
+ sortValue: undefined,
58
+ });
59
+ const groupsSortParams = groupSort.sortOrder ? groupSort : getDefaultSortGroup(visibleEntities);
26
60
  // Do not display Nodes table for Node page (NodeId present)
27
61
  const isNodePage = nodeId !== undefined;
28
62
  const storageType = isNodePage ? STORAGE_TYPES.groups : type;
@@ -40,33 +74,27 @@ export const Storage = ({ additionalNodesProps, tenant, nodeId }) => {
40
74
  const { currentData, isFetching, error } = storageType === STORAGE_TYPES.nodes ? nodesQuery : groupsQuery;
41
75
  const { currentData: { nodes = [] } = {} } = nodesQuery;
42
76
  const { currentData: { groups = [] } = {} } = groupsQuery;
43
- const _a = currentData !== null && currentData !== void 0 ? currentData : { found: 0, total: 0 }, { nodes: _, groups: __ } = _a, entitiesCount = __rest(_a, ["nodes", "groups"]);
77
+ const _b = currentData !== null && currentData !== void 0 ? currentData : { found: 0, total: 0 }, { nodes: _, groups: __ } = _b, entitiesCount = __rest(_b, ["nodes", "groups"]);
44
78
  const isLoading = currentData === undefined && isFetching;
45
79
  const storageNodes = React.useMemo(() => filterNodes(nodes, filter, uptimeFilter), [filter, nodes, uptimeFilter]);
46
80
  const storageGroups = React.useMemo(() => filterGroups(groups, filter, usageFilter), [filter, groups, usageFilter]);
47
81
  const usageFilterOptions = React.useMemo(() => getUsageFilterOptions(groups), [groups]);
48
- React.useEffect(() => {
49
- return () => {
50
- // Clean data on component unmount
51
- dispatch(setInitialState());
52
- };
53
- }, [dispatch]);
54
- const [nodesSort, handleNodesSort] = useTableSort(nodesSortParams, (params) => dispatch(setNodesSortParams(params)));
55
- const [groupsSort, handleGroupsSort] = useTableSort(groupsSortParams, (params) => dispatch(setGroupsSortParams(params)));
82
+ const [nodesSort, handleNodesSort] = useTableSort(nodesSortParams, (params) => setNodeSort(params));
83
+ const [groupsSort, handleGroupsSort] = useTableSort(groupsSortParams, (params) => setGroupSort(params));
56
84
  const handleUsageFilterChange = (value) => {
57
- dispatch(setUsageFilter(value));
85
+ setQueryParams({ usageFilter: value.length ? value : undefined }, 'replaceIn');
58
86
  };
59
87
  const handleTextFilterChange = (value) => {
60
- dispatch(setStorageTextFilter(value));
88
+ setQueryParams({ search: value || undefined }, 'replaceIn');
61
89
  };
62
90
  const handleGroupVisibilityChange = (value) => {
63
- dispatch(setVisibleEntities(value));
91
+ setQueryParams({ visible: value }, 'replaceIn');
64
92
  };
65
93
  const handleStorageTypeChange = (value) => {
66
- dispatch(setStorageType(value));
94
+ setQueryParams({ type: value }, 'replaceIn');
67
95
  };
68
96
  const handleUptimeFilterChange = (value) => {
69
- dispatch(setUptimeFilter(value));
97
+ setQueryParams({ uptimeFilter: value }, 'replaceIn');
70
98
  };
71
99
  const handleShowAllNodes = () => {
72
100
  handleGroupVisibilityChange(VISIBLE_ENTITIES.all);
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
+ import { ShieldKeyhole } from '@gravity-ui/icons';
3
4
  import DataTable from '@gravity-ui/react-data-table';
4
5
  import { Icon, Label, Popover, PopoverBehavior } from '@gravity-ui/uikit';
5
6
  import { CellWithPopover } from '../../../components/CellWithPopover/CellWithPopover';
@@ -14,7 +15,6 @@ import { isSortableStorageProperty } from '../../../utils/storage';
14
15
  import { bytesToGB, bytesToSpeed } from '../../../utils/utils';
15
16
  import { getDegradedSeverity, getUsageSeverityForStorageGroup } from '../utils';
16
17
  import i18n from './i18n';
17
- import shieldIcon from '../../../assets/icons/shield.svg';
18
18
  import './StorageGroups.scss';
19
19
  const b = cn('global-storage-groups');
20
20
  export const STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY = 'storageGroupsColumnsWidth';
@@ -49,7 +49,7 @@ const typeColumn = {
49
49
  width: 100,
50
50
  resizeMinWidth: 100,
51
51
  align: DataTable.LEFT,
52
- render: ({ row }) => (_jsxs(React.Fragment, { children: [_jsx(Label, { children: row.MediaType || '—' }), '\u00a0', row.Encryption && (_jsx(Popover, { content: i18n('encrypted'), placement: "right", behavior: PopoverBehavior.Immediate, children: _jsx(Label, { children: _jsx(Icon, { data: shieldIcon }) }) }))] })),
52
+ render: ({ row }) => (_jsxs(React.Fragment, { children: [_jsx(Label, { children: row.MediaType || '—' }), '\u00a0', row.Encryption && (_jsx(Popover, { content: i18n('encrypted'), placement: "right", behavior: PopoverBehavior.Immediate, children: _jsx(Label, { children: _jsx(Icon, { data: ShieldKeyhole, size: 18 }) }) }))] })),
53
53
  sortable: false,
54
54
  };
55
55
  const erasureColumn = {
@@ -1,29 +1,51 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import React from 'react';
2
+ import { StringParam, useQueryParams } from 'use-query-params';
3
3
  import { AccessDenied } from '../../components/Errors/403/AccessDenied';
4
4
  import { ResponseError } from '../../components/Errors/ResponseError/ResponseError';
5
5
  import { selectNodesMap } from '../../store/reducers/nodesList';
6
6
  import { STORAGE_TYPES, VISIBLE_ENTITIES } from '../../store/reducers/storage/constants';
7
+ import { storageTypeSchema, visibleEntitiesSchema } from '../../store/reducers/storage/types';
7
8
  import { useTypedSelector } from '../../utils/hooks';
8
- import { NodesUptimeFilterValues } from '../../utils/nodes';
9
+ import { NodesUptimeFilterValues, nodesUptimeFilterValuesSchema } from '../../utils/nodes';
9
10
  import { StorageControls } from './StorageControls/StorageControls';
10
11
  import { VirtualStorageGroups } from './StorageGroups/VirtualStorageGroups';
11
12
  import { VirtualStorageNodes } from './StorageNodes/VirtualStorageNodes';
12
13
  export const VirtualStorage = ({ tenant, nodeId, parentContainer, additionalNodesProps, }) => {
13
- const [searchValue, setSearchValue] = React.useState('');
14
- const [storageType, setStorageType] = React.useState(STORAGE_TYPES.groups);
15
- const [visibleEntities, setVisibleEntities] = React.useState(VISIBLE_ENTITIES.all);
16
- const [nodesUptimeFilter, setNodesUptimeFilter] = React.useState(NodesUptimeFilterValues.All);
14
+ var _a;
15
+ const [queryParams, setQueryParams] = useQueryParams({
16
+ type: StringParam,
17
+ visible: StringParam,
18
+ search: StringParam,
19
+ uptimeFilter: StringParam,
20
+ });
21
+ const storageType = storageTypeSchema.parse(queryParams.type);
22
+ const visibleEntities = visibleEntitiesSchema.parse(queryParams.visible);
23
+ const searchValue = (_a = queryParams.search) !== null && _a !== void 0 ? _a : '';
24
+ const nodesUptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
25
+ const handleTextFilterChange = (value) => {
26
+ setQueryParams({ search: value || undefined }, 'replaceIn');
27
+ };
28
+ const handleGroupVisibilityChange = (value) => {
29
+ setQueryParams({ visible: value }, 'replaceIn');
30
+ };
31
+ const handleStorageTypeChange = (value) => {
32
+ setQueryParams({ type: value }, 'replaceIn');
33
+ };
34
+ const handleUptimeFilterChange = (value) => {
35
+ setQueryParams({ uptimeFilter: value }, 'replaceIn');
36
+ };
17
37
  const nodesMap = useTypedSelector(selectNodesMap);
18
38
  const handleShowAllGroups = () => {
19
- setVisibleEntities(VISIBLE_ENTITIES.all);
39
+ handleGroupVisibilityChange(VISIBLE_ENTITIES.all);
20
40
  };
21
41
  const handleShowAllNodes = () => {
22
- setVisibleEntities(VISIBLE_ENTITIES.all);
23
- setNodesUptimeFilter(NodesUptimeFilterValues.All);
42
+ setQueryParams({
43
+ visible: VISIBLE_ENTITIES.all,
44
+ uptimeFilter: NodesUptimeFilterValues.All,
45
+ }, 'replaceIn');
24
46
  };
25
47
  const renderControls = ({ totalEntities, foundEntities, inited }) => {
26
- return (_jsx(StorageControls, { searchValue: searchValue, handleSearchValueChange: setSearchValue, withTypeSelector: !nodeId, storageType: storageType, handleStorageTypeChange: setStorageType, visibleEntities: visibleEntities, handleVisibleEntitiesChange: setVisibleEntities, nodesUptimeFilter: nodesUptimeFilter, handleNodesUptimeFilterChange: setNodesUptimeFilter, withGroupsUsageFilter: false, entitiesCountCurrent: foundEntities, entitiesCountTotal: totalEntities, entitiesLoading: !inited }));
48
+ return (_jsx(StorageControls, { searchValue: searchValue, handleSearchValueChange: handleTextFilterChange, withTypeSelector: !nodeId, storageType: storageType, handleStorageTypeChange: handleStorageTypeChange, visibleEntities: visibleEntities, handleVisibleEntitiesChange: handleGroupVisibilityChange, nodesUptimeFilter: nodesUptimeFilter, handleNodesUptimeFilterChange: handleUptimeFilterChange, withGroupsUsageFilter: false, entitiesCountCurrent: foundEntities, entitiesCountTotal: totalEntities, entitiesLoading: !inited }));
27
49
  };
28
50
  const renderErrorMessage = (error) => {
29
51
  if (error.status === 403) {
@@ -1,5 +1,8 @@
1
- import type { PreparedStorageGroup } from '../../../store/reducers/storage/types';
1
+ import type { NodesSortParams } from '../../../store/reducers/nodes/types';
2
+ import type { PreparedStorageGroup, StorageSortParams, VisibleEntities } from '../../../store/reducers/storage/types';
2
3
  import { EFlag } from '../../../types/api/enums';
3
4
  export declare const getDegradedSeverity: (group: PreparedStorageGroup) => "success" | "danger" | "warning" | undefined;
4
5
  export declare const getUsageSeverityForStorageGroup: (value: number) => "success" | "danger" | "warning" | undefined;
5
6
  export declare const getUsageSeverityForEntityStatus: (value: number) => EFlag.Green | EFlag.Yellow | EFlag.Red | undefined;
7
+ export declare const defaultSortNode: NodesSortParams;
8
+ export declare function getDefaultSortGroup(visibleEntities: VisibleEntities): StorageSortParams;