ydb-embedded-ui 6.3.0 → 6.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. package/README.md +38 -16
  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/BasicNodeViewer/BasicNodeViewer.js +11 -5
  8. package/dist/components/CriticalActionDialog/CriticalActionDialog.js +3 -4
  9. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +2 -0
  10. package/dist/components/EmptyState/EmptyState.js +3 -2
  11. package/dist/components/EnableFullscreenButton/EnableFullscreenButton.js +3 -3
  12. package/dist/components/Fullscreen/Fullscreen.js +3 -3
  13. package/dist/components/MonitoringButton/MonitoringButton.js +3 -3
  14. package/dist/components/NodeHostWrapper/NodeHostWrapper.js +3 -3
  15. package/dist/components/PDiskInfo/i18n/index.d.ts +1 -1
  16. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.js +4 -5
  17. package/dist/components/StatusIcon/StatusIcon.js +5 -7
  18. package/dist/containers/App/App.js +1 -2
  19. package/dist/containers/AsideNavigation/AsideNavigation.js +4 -9
  20. package/dist/containers/AsideNavigation/YdbInternalUser/YdbInternalUser.js +2 -3
  21. package/dist/containers/AsideNavigation/useNavigationMenuItems.js +5 -6
  22. package/dist/containers/Authentication/Authentication.js +2 -4
  23. package/dist/containers/Node/NodeStructure/Pdisk.js +4 -4
  24. package/dist/containers/Nodes/Nodes.js +19 -15
  25. package/dist/containers/Nodes/VirtualNodes.js +23 -6
  26. package/dist/containers/PDiskPage/PDiskPage.js +2 -2
  27. package/dist/containers/PDiskPage/i18n/index.d.ts +1 -1
  28. package/dist/containers/Storage/Storage.js +50 -22
  29. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.js +2 -2
  30. package/dist/containers/Storage/VirtualStorage.js +32 -10
  31. package/dist/containers/Storage/utils/index.d.ts +4 -1
  32. package/dist/containers/Storage/utils/index.js +29 -0
  33. package/dist/containers/Tablet/Tablet.js +3 -3
  34. package/dist/containers/Tablet/i18n/index.d.ts +1 -1
  35. package/dist/containers/Tablets/Tablets.d.ts +1 -2
  36. package/dist/containers/Tablets/Tablets.js +112 -53
  37. package/dist/containers/Tablets/i18n/en.json +9 -4
  38. package/dist/containers/Tablets/i18n/index.d.ts +1 -1
  39. package/dist/containers/Tablets/i18n/index.js +1 -2
  40. package/dist/containers/Tenant/Diagnostics/Diagnostics.js +5 -5
  41. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -2
  42. package/dist/containers/Tenant/Diagnostics/Network/Network.js +3 -3
  43. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js +2 -2
  44. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.js +2 -8
  45. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.js +3 -3
  46. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +1 -1
  47. package/dist/containers/Tenant/Query/Issues/Issues.js +6 -9
  48. package/dist/containers/Tenant/Query/Preview/Preview.js +3 -3
  49. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +1 -1
  50. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +4 -4
  51. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.js +3 -3
  52. package/dist/containers/Tenant/Schema/SchemaViewer/helpers.js +3 -2
  53. package/dist/containers/Tenant/utils/ToggleButton.scss +0 -2
  54. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.js +4 -4
  55. package/dist/containers/Tenant/utils/schemaControls.js +3 -3
  56. package/dist/containers/VDiskPage/VDiskPage.js +2 -2
  57. package/dist/containers/VDiskPage/i18n/index.d.ts +1 -1
  58. package/dist/routes.d.ts +1 -1
  59. package/dist/services/settings.d.ts +18 -1
  60. package/dist/store/configureStore.d.ts +0 -8
  61. package/dist/store/defaultStore.d.ts +0 -4
  62. package/dist/store/reducers/authentication/authentication.d.ts +0 -6
  63. package/dist/store/reducers/executeQuery.d.ts +0 -2
  64. package/dist/store/reducers/explainQuery.d.ts +0 -4
  65. package/dist/store/reducers/healthcheckInfo/healthcheckInfo.d.ts +0 -40
  66. package/dist/store/reducers/host.d.ts +0 -2
  67. package/dist/store/reducers/index.d.ts +0 -6
  68. package/dist/store/reducers/index.js +0 -4
  69. package/dist/store/reducers/node/selectors.d.ts +0 -2
  70. package/dist/store/reducers/nodes/nodes.d.ts +1 -5
  71. package/dist/store/reducers/nodes/nodes.js +0 -27
  72. package/dist/store/reducers/nodes/types.d.ts +4 -13
  73. package/dist/store/reducers/nodesList.d.ts +0 -2
  74. package/dist/store/reducers/schema/schema.d.ts +0 -2
  75. package/dist/store/reducers/schemaAcl/schemaAcl.d.ts +0 -2
  76. package/dist/store/reducers/storage/selectors.d.ts +2 -17
  77. package/dist/store/reducers/storage/selectors.js +1 -36
  78. package/dist/store/reducers/storage/storage.d.ts +2 -6
  79. package/dist/store/reducers/storage/storage.js +0 -44
  80. package/dist/store/reducers/storage/types.d.ts +15 -22
  81. package/dist/store/reducers/storage/types.js +4 -1
  82. package/dist/store/reducers/tablets.d.ts +92 -1
  83. package/dist/store/reducers/tablets.js +16 -1
  84. package/dist/store/reducers/tabletsFilters.d.ts +0 -2
  85. package/dist/store/reducers/tenant/tenant.d.ts +2 -2
  86. package/dist/store/reducers/tenant/tenant.js +10 -1
  87. package/dist/store/reducers/tenant/types.d.ts +8 -3
  88. package/dist/store/reducers/tenant/types.js +3 -1
  89. package/dist/store/reducers/tenants/selectors.d.ts +0 -18
  90. package/dist/store/reducers/tenants/utils.d.ts +4 -4
  91. package/dist/store/reducers/tenants/utils.js +8 -8
  92. package/dist/store/reducers/topic.d.ts +0 -30
  93. package/dist/store/state-url-mapping.js +0 -22
  94. package/dist/utils/nodes.d.ts +2 -0
  95. package/dist/utils/nodes.js +4 -0
  96. package/dist/utils/tablet.d.ts +2 -0
  97. package/dist/utils/tablet.js +14 -0
  98. package/package.json +3 -2
  99. package/dist/assets/icons/bug.svg +0 -1
  100. package/dist/assets/icons/circle-exclamation.svg +0 -1
  101. package/dist/assets/icons/circle-info.svg +0 -1
  102. package/dist/assets/icons/circle-xmark.svg +0 -1
  103. package/dist/assets/icons/close.svg +0 -1
  104. package/dist/assets/icons/control-menu-button.svg +0 -1
  105. package/dist/assets/icons/dots.svg +0 -1
  106. package/dist/assets/icons/hide.svg +0 -1
  107. package/dist/assets/icons/question.svg +0 -1
  108. package/dist/assets/icons/server.svg +0 -1
  109. package/dist/assets/icons/settings-with-dot.svg +0 -1
  110. package/dist/assets/icons/settings.svg +0 -1
  111. package/dist/assets/icons/shield.svg +0 -3
  112. package/dist/assets/icons/show.svg +0 -1
  113. package/dist/assets/icons/signIn.svg +0 -1
  114. package/dist/assets/icons/signOut.svg +0 -1
  115. package/dist/assets/icons/storage.svg +0 -1
  116. package/dist/assets/icons/support.svg +0 -1
  117. package/dist/assets/icons/triangle-exclamation.svg +0 -1
  118. package/dist/assets/icons/update-arrow.svg +0 -6
  119. package/dist/components/Icon/Icon.d.ts +0 -14
  120. package/dist/components/Icon/Icon.js +0 -16
  121. package/dist/components/Icon/index.d.ts +0 -1
  122. package/dist/components/Icon/index.js +0 -1
  123. package/dist/containers/AppIcons/AppIcons.d.ts +0 -2
  124. package/dist/containers/AppIcons/AppIcons.js +0 -9
  125. package/dist/containers/Tablets/Tablets.scss +0 -35
  126. package/dist/containers/Tablets/i18n/ru.json +0 -6
@@ -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,7 +20,6 @@ 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;
@@ -74,7 +74,7 @@ export function PDiskPage() {
74
74
  return (_jsx(DiskPageTitle, { entityName: pDiskPageKeyset('pdisk'), status: getSeverityColor(Severity), id: pDiskId, className: pdiskPageCn('title') }));
75
75
  };
76
76
  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')] }) }));
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: ArrowRotateLeft }), pDiskPageKeyset('restart-pdisk-button')] }) }));
78
78
  };
79
79
  const renderInfo = () => {
80
80
  if (pDiskLoading) {
@@ -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", 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;
@@ -1,5 +1,9 @@
1
+ import { ASCENDING, DESCENDING } from '@gravity-ui/react-data-table/build/esm/lib/constants';
2
+ import { VISIBLE_ENTITIES } from '../../../store/reducers/storage/constants';
1
3
  import { EFlag } from '../../../types/api/enums';
2
4
  import { generateEvaluator } from '../../../utils/generateEvaluator';
5
+ import { NODES_SORT_VALUES } from '../../../utils/nodes';
6
+ import { STORAGE_SORT_VALUES } from '../../../utils/storage';
3
7
  const defaultDegradationEvaluator = generateEvaluator(1, 2, ['success', 'warning', 'danger']);
4
8
  const degradationEvaluators = {
5
9
  'block-4-2': generateEvaluator(1, 2, ['success', 'warning', 'danger']),
@@ -22,3 +26,28 @@ export const getUsageSeverityForEntityStatus = generateEvaluator(80, 85, [
22
26
  EFlag.Yellow,
23
27
  EFlag.Red,
24
28
  ]);
29
+ export const defaultSortNode = {
30
+ sortValue: NODES_SORT_VALUES.NodeId,
31
+ sortOrder: ASCENDING,
32
+ };
33
+ const defaultSortGroup = {
34
+ sortValue: STORAGE_SORT_VALUES.PoolName,
35
+ sortOrder: ASCENDING,
36
+ };
37
+ const defaultSortGroupMissing = {
38
+ sortValue: STORAGE_SORT_VALUES.Degraded,
39
+ sortOrder: DESCENDING,
40
+ };
41
+ const defaultSortGroupSpace = {
42
+ sortValue: STORAGE_SORT_VALUES.Usage,
43
+ sortOrder: DESCENDING,
44
+ };
45
+ export function getDefaultSortGroup(visibleEntities) {
46
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
47
+ return defaultSortGroupMissing;
48
+ }
49
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
50
+ return defaultSortGroupSpace;
51
+ }
52
+ return defaultSortGroup;
53
+ }
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { Link as ExternalLink } from '@gravity-ui/uikit';
3
+ import { ArrowUpRightFromSquare } from '@gravity-ui/icons';
4
+ import { Link as ExternalLink, Icon } from '@gravity-ui/uikit';
4
5
  import { skipToken } from '@reduxjs/toolkit/query';
5
6
  import { Helmet } from 'react-helmet-async';
6
7
  import { useLocation, useParams } from 'react-router';
7
8
  import { EmptyState } from '../../components/EmptyState';
8
9
  import { EntityStatus } from '../../components/EntityStatus/EntityStatus';
9
10
  import { ResponseError } from '../../components/Errors/ResponseError';
10
- import { Icon } from '../../components/Icon';
11
11
  import { Loader } from '../../components/Loader';
12
12
  import { Tag } from '../../components/Tag';
13
13
  import { parseQuery } from '../../routes';
@@ -66,7 +66,7 @@ export const Tablet = () => {
66
66
  path: `/tablets?TabletID=${TabletId}`,
67
67
  },
68
68
  ];
69
- return (_jsx("div", { className: b(), children: _jsxs("div", { className: b('pane-wrapper'), children: [_jsxs("div", { className: b('left-pane'), children: [_jsx("ul", { className: b('links'), children: externalLinks.map(renderExternalLinks) }), _jsxs("div", { className: b('row', { header: true }), children: [_jsx("span", { className: b('title'), children: i18n('tablet.header') }), _jsx(EntityStatus, { status: Overall, name: TabletId }), _jsx("a", { rel: "noopener noreferrer", className: b('link', { external: true }), href: `${backend}/tablets?TabletID=${TabletId}`, target: "_blank", children: _jsx(Icon, { name: "external" }) }), Leader && _jsx(Tag, { text: "Leader", type: "blue" }), _jsx("span", { className: b('loader'), children: loading && _jsx(Loader, { size: "s" }) })] }), _jsx(TabletInfo, { tablet: tablet, tenantPath: tenantName }), _jsx(TabletControls, { tablet: tablet, fetchData: refetch })] }), _jsx("div", { className: b('rigth-pane'), children: _jsx(TabletTable, { history: history }) })] }) }));
69
+ return (_jsx("div", { className: b(), children: _jsxs("div", { className: b('pane-wrapper'), children: [_jsxs("div", { className: b('left-pane'), children: [_jsx("ul", { className: b('links'), children: externalLinks.map(renderExternalLinks) }), _jsxs("div", { className: b('row', { header: true }), children: [_jsx("span", { className: b('title'), children: i18n('tablet.header') }), _jsx(EntityStatus, { status: Overall, name: TabletId }), _jsx("a", { rel: "noopener noreferrer", className: b('link', { external: true }), href: `${backend}/tablets?TabletID=${TabletId}`, target: "_blank", children: _jsx(Icon, { data: ArrowUpRightFromSquare }) }), Leader && _jsx(Tag, { text: "Leader", type: "blue" }), _jsx("span", { className: b('loader'), children: loading && _jsx(Loader, { size: "s" }) })] }), _jsx(TabletInfo, { tablet: tablet, tenantPath: tenantName }), _jsx(TabletControls, { tablet: tablet, fetchData: refetch })] }), _jsx("div", { className: b('rigth-pane'), children: _jsx(TabletTable, { history: history }) })] }) }));
70
70
  };
71
71
  return (_jsxs(React.Fragment, { children: [_jsx(Helmet, { children: _jsx("title", { children: `${id} — ${i18n('tablet.header')} — ${tenantName || queryClusterName || CLUSTER_DEFAULT_TITLE}` }) }), renderView()] }));
72
72
  };
@@ -1,2 +1,2 @@
1
- declare const _default: (key: "emptyState" | "tablet.header" | "controls.kill" | "controls.stop" | "controls.resume" | "dialog.kill" | "dialog.stop" | "dialog.resume", params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "dialog.kill" | "tablet.header" | "controls.kill" | "controls.stop" | "controls.resume" | "dialog.stop" | "dialog.resume" | "emptyState", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;
@@ -1,8 +1,7 @@
1
- import './Tablets.scss';
2
1
  interface TabletsProps {
3
2
  path?: string;
4
3
  nodeId?: string | number;
5
4
  className?: string;
6
5
  }
7
- export declare const Tablets: ({ path, nodeId, className }: TabletsProps) => import("react/jsx-runtime").JSX.Element;
6
+ export declare function Tablets({ nodeId, path, className }: TabletsProps): import("react/jsx-runtime").JSX.Element;
8
7
  export {};