ydb-embedded-ui 4.13.0 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/Tablet/Tablet.scss +1 -16
  3. package/dist/components/Tablet/Tablet.tsx +5 -5
  4. package/dist/components/TabletIcon/TabletIcon.scss +17 -0
  5. package/dist/components/TabletIcon/TabletIcon.tsx +18 -0
  6. package/dist/containers/App/App.js +1 -1
  7. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -1
  8. package/dist/containers/Authentication/Authentication.tsx +1 -1
  9. package/dist/containers/Header/Header.scss +2 -0
  10. package/dist/containers/Header/Header.tsx +2 -7
  11. package/dist/containers/Header/{breadcrumbs.ts → breadcrumbs.tsx} +19 -8
  12. package/dist/containers/Nodes/Nodes.tsx +53 -16
  13. package/dist/containers/Nodes/getNodesColumns.tsx +31 -13
  14. package/dist/containers/Storage/Storage.tsx +64 -32
  15. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +56 -73
  16. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +33 -43
  17. package/dist/containers/Storage/utils/index.ts +3 -3
  18. package/dist/containers/Tablet/Tablet.tsx +9 -3
  19. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.scss +8 -0
  20. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +13 -1
  21. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +3 -1
  22. package/dist/containers/Tenant/Query/i18n/en.json +6 -4
  23. package/dist/containers/Tenant/Query/i18n/ru.json +6 -4
  24. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +4 -0
  25. package/dist/containers/Tenant/i18n/en.json +3 -0
  26. package/dist/containers/Tenant/i18n/ru.json +3 -0
  27. package/dist/containers/Tenant/utils/queryTemplates.ts +89 -0
  28. package/dist/containers/Tenant/utils/schema.ts +1 -1
  29. package/dist/containers/Tenant/utils/schemaActions.ts +30 -54
  30. package/dist/containers/Tenant/utils/schemaControls.tsx +69 -0
  31. package/dist/containers/UserSettings/i18n/en.json +3 -0
  32. package/dist/containers/UserSettings/i18n/ru.json +3 -0
  33. package/dist/containers/UserSettings/settings.ts +12 -1
  34. package/dist/{reportWebVitals.js → reportWebVitals.ts} +3 -1
  35. package/dist/services/api.ts +30 -16
  36. package/dist/store/reducers/{authentication.js → authentication/authentication.ts} +14 -7
  37. package/dist/store/reducers/authentication/types.ts +15 -0
  38. package/dist/store/reducers/describe.ts +1 -16
  39. package/dist/store/reducers/header/types.ts +2 -0
  40. package/dist/store/reducers/index.ts +1 -1
  41. package/dist/store/reducers/nodes/nodes.ts +23 -6
  42. package/dist/store/reducers/nodes/selectors.ts +2 -2
  43. package/dist/store/reducers/nodes/types.ts +15 -5
  44. package/dist/store/reducers/settings/settings.ts +5 -0
  45. package/dist/store/reducers/storage/selectors.ts +50 -150
  46. package/dist/store/reducers/storage/storage.ts +73 -25
  47. package/dist/store/reducers/storage/types.ts +49 -17
  48. package/dist/store/reducers/storage/utils.ts +207 -0
  49. package/dist/store/utils.ts +1 -1
  50. package/dist/types/api/compute.ts +0 -12
  51. package/dist/types/api/error.ts +4 -0
  52. package/dist/types/api/nodes.ts +0 -12
  53. package/dist/types/api/storage.ts +32 -4
  54. package/dist/types/window.d.ts +1 -0
  55. package/dist/utils/constants.ts +3 -0
  56. package/dist/utils/filters.ts +23 -0
  57. package/dist/utils/hooks/index.ts +4 -0
  58. package/dist/utils/hooks/useNodesRequestParams.ts +46 -0
  59. package/dist/utils/hooks/useStorageRequestParams.ts +28 -0
  60. package/dist/utils/hooks/useTableSort.ts +37 -0
  61. package/dist/utils/nodes.ts +25 -0
  62. package/dist/utils/storage.ts +31 -3
  63. package/package.json +2 -6
  64. package/dist/HOCS/WithSearch/WithSearch.js +0 -26
  65. package/dist/HOCS/index.js +0 -1
  66. package/dist/components/Hotkey/Hotkey.js +0 -102
  67. package/dist/components/Pagination/Pagination.js +0 -63
  68. package/dist/components/Pagination/Pagination.scss +0 -28
  69. package/dist/types/store/storage.ts +0 -12
  70. /package/dist/{index.js → index.tsx} +0 -0
  71. /package/dist/utils/{monaco.js → monaco.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.15.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.14.0...v4.15.0) (2023-08-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * **SchemaTree:** add actions for topic ([#507](https://github.com/ydb-platform/ydb-embedded-ui/issues/507)) ([6700136](https://github.com/ydb-platform/ydb-embedded-ui/commit/670013629cb68425e670969323a2ef466ef7c018))
9
+ * **Storage:** sort on backend ([#510](https://github.com/ydb-platform/ydb-embedded-ui/issues/510)) ([034a89a](https://github.com/ydb-platform/ydb-embedded-ui/commit/034a89a9844021c5ea3a73c8f6456e35128078c0))
10
+ * **Storage:** v2 api and backend filters ([#506](https://github.com/ydb-platform/ydb-embedded-ui/issues/506)) ([ce4bf6d](https://github.com/ydb-platform/ydb-embedded-ui/commit/ce4bf6d0ef154b87a7b3a44d56281230b2b5b554))
11
+
12
+ ## [4.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.13.0...v4.14.0) (2023-08-11)
13
+
14
+
15
+ ### Features
16
+
17
+ * **Nodes:** filter and sort on backend ([#503](https://github.com/ydb-platform/ydb-embedded-ui/issues/503)) ([2e8ab8e](https://github.com/ydb-platform/ydb-embedded-ui/commit/2e8ab8e9965db61ec281f7340b89dd3967b639df))
18
+ * **Query:** add explanation to query duration ([#501](https://github.com/ydb-platform/ydb-embedded-ui/issues/501)) ([a5f5140](https://github.com/ydb-platform/ydb-embedded-ui/commit/a5f5140a23864147d8495e3c6b94709e5e710a9b))
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * **Header:** add icons for nodes and tablets ([#500](https://github.com/ydb-platform/ydb-embedded-ui/issues/500)) ([862660c](https://github.com/ydb-platform/ydb-embedded-ui/commit/862660c1928c2c2b626e4417cd043f0bd5a65df9))
24
+ * **Query:** fix query method selector help text ([#504](https://github.com/ydb-platform/ydb-embedded-ui/issues/504)) ([65cdf9e](https://github.com/ydb-platform/ydb-embedded-ui/commit/65cdf9ee93277c193cc1ad036b2cb38d2ae15b71))
25
+ * **Query:** transfer API calls to a new line ([#499](https://github.com/ydb-platform/ydb-embedded-ui/issues/499)) ([de3d540](https://github.com/ydb-platform/ydb-embedded-ui/commit/de3d5404310f32ba05598bb99a1afb1b65ab45a1))
26
+ * **SchemaTree:** transfer Show Preview to SchemaTree ([#505](https://github.com/ydb-platform/ydb-embedded-ui/issues/505)) ([46220c4](https://github.com/ydb-platform/ydb-embedded-ui/commit/46220c4b2cd111acf12712b4693744c52aaf7231))
27
+
3
28
  ## [4.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.12.0...v4.13.0) (2023-08-04)
4
29
 
5
30
 
@@ -1,17 +1,8 @@
1
1
  .tablet {
2
- display: flex;
3
- justify-content: center;
4
-
5
- width: 23px;
6
- height: 18px;
7
-
8
- font-size: 10px;
9
2
  cursor: pointer;
10
- text-transform: uppercase;
11
3
 
12
4
  color: var(--yc-color-text-complementary);
13
- border: 1px solid var(--yc-color-base-generic-medium-hover);
14
- border-radius: 4px;
5
+ border-color: var(--yc-color-base-generic-medium-hover);
15
6
 
16
7
  &__wrapper {
17
8
  margin-right: 2px;
@@ -25,12 +16,6 @@
25
16
  padding: 10px;
26
17
  }
27
18
 
28
- &__type {
29
- line-height: 17px;
30
-
31
- color: var(--yc-color-text-complementary);
32
- }
33
-
34
19
  &_status_gray {
35
20
  background-color: var(--yc-color-text-complementary);
36
21
  }
@@ -5,6 +5,7 @@ import {getTabletLabel} from '../../utils/constants';
5
5
  import routes, {createHref} from '../../routes';
6
6
 
7
7
  import {ContentWithPopup} from '../ContentWithPopup/ContentWithPopup';
8
+ import {TabletIcon} from '../TabletIcon/TabletIcon';
8
9
  import {InternalLink} from '../InternalLink';
9
10
  import {TabletTooltipContent} from '../TooltipsContent';
10
11
 
@@ -18,10 +19,11 @@ interface TabletProps {
18
19
  }
19
20
 
20
21
  export const Tablet = ({tablet = {}, tenantName}: TabletProps) => {
21
- const {TabletId: id, NodeId} = tablet;
22
+ const {TabletId: id, NodeId, Type} = tablet;
22
23
  const status = tablet.Overall?.toLowerCase();
23
24
 
24
- const tabletPath = id && createHref(routes.tablet, {id}, {nodeId: NodeId, tenantName});
25
+ const tabletPath =
26
+ id && createHref(routes.tablet, {id}, {nodeId: NodeId, tenantName, type: Type});
25
27
 
26
28
  return (
27
29
  <ContentWithPopup
@@ -29,9 +31,7 @@ export const Tablet = ({tablet = {}, tenantName}: TabletProps) => {
29
31
  content={<TabletTooltipContent data={tablet} className={b('popup-content')} />}
30
32
  >
31
33
  <InternalLink to={tabletPath}>
32
- <div className={b({status})}>
33
- <div className={b('type')}>{[getTabletLabel(tablet.Type)]}</div>
34
- </div>
34
+ <TabletIcon className={b({status})} text={getTabletLabel(tablet.Type)} />
35
35
  </InternalLink>
36
36
  </ContentWithPopup>
37
37
  );
@@ -0,0 +1,17 @@
1
+ .tablet-icon {
2
+ display: flex;
3
+ justify-content: center;
4
+
5
+ width: 23px;
6
+ height: 16px;
7
+
8
+ font-size: 10px;
9
+ text-transform: uppercase;
10
+
11
+ border: 1px solid;
12
+ border-radius: 4px;
13
+
14
+ &__type {
15
+ line-height: 14px;
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import './TabletIcon.scss';
4
+
5
+ interface TabletIconProps {
6
+ text?: string;
7
+ className?: string;
8
+ }
9
+
10
+ const b = cn('tablet-icon');
11
+
12
+ export const TabletIcon = ({text, className}: TabletIconProps) => {
13
+ return (
14
+ <div className={b(null, className)}>
15
+ <div className={b('type')}>{text || 'T'}</div>
16
+ </div>
17
+ );
18
+ };
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
5
5
  import ContentWrapper, {Content} from './Content';
6
6
  import AsideNavigation from '../AsideNavigation/AsideNavigation';
7
7
 
8
- import {getUser} from '../../store/reducers/authentication';
8
+ import {getUser} from '../../store/reducers/authentication/authentication';
9
9
  import {registerLanguages} from '../../utils/monaco';
10
10
 
11
11
  import './App.scss';
@@ -18,7 +18,7 @@ import userChecked from '../../assets/icons/user-check.svg';
18
18
  import settingsIcon from '../../assets/icons/settings.svg';
19
19
  import supportIcon from '../../assets/icons/support.svg';
20
20
 
21
- import {logout} from '../../store/reducers/authentication';
21
+ import {logout} from '../../store/reducers/authentication/authentication';
22
22
  import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
23
23
  import {TENANT_PAGE, TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
24
24
  import routes, {TENANT, createHref, parseQuery} from '../../routes';
@@ -5,7 +5,7 @@ import cn from 'bem-cn-lite';
5
5
 
6
6
  import {Button, TextInput, Icon, Link as ExternalLink} from '@gravity-ui/uikit';
7
7
 
8
- import {authenticate} from '../../store/reducers/authentication';
8
+ import {authenticate} from '../../store/reducers/authentication/authentication';
9
9
  import {useTypedSelector} from '../../utils/hooks';
10
10
 
11
11
  import ydbLogoIcon from '../../assets/icons/ydb.svg';
@@ -15,6 +15,8 @@
15
15
  align-items: center;
16
16
 
17
17
  &__icon {
18
+ display: flex;
19
+
18
20
  margin-right: 3px;
19
21
  }
20
22
  }
@@ -3,7 +3,7 @@ import {useHistory, useLocation} from 'react-router';
3
3
  import {useDispatch} from 'react-redux';
4
4
  import block from 'bem-cn-lite';
5
5
 
6
- import {Breadcrumbs, Icon} from '@gravity-ui/uikit';
6
+ import {Breadcrumbs} from '@gravity-ui/uikit';
7
7
 
8
8
  import {ExternalLinkWithIcon} from '../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
9
9
 
@@ -91,12 +91,7 @@ function Header({mainPage}: HeaderProps) {
91
91
  }
92
92
  return (
93
93
  <span className={b('breadcrumb')}>
94
- <Icon
95
- width={16}
96
- height={16}
97
- data={icon}
98
- className={b('breadcrumb__icon')}
99
- />
94
+ <div className={b('breadcrumb__icon')}>{icon}</div>
100
95
  {text}
101
96
  </span>
102
97
  );
@@ -1,5 +1,9 @@
1
- import nodesRightIcon from '@gravity-ui/icons/svgs/nodes-right.svg';
2
- import databaseIcon from '@gravity-ui/icons/svgs/database.svg';
1
+ import {
2
+ NodesRight as ClusterIcon,
3
+ Database as DatabaseIcon,
4
+ Cpu as ComputeNodeIcon,
5
+ HardDrive as StorageNodeIcon,
6
+ } from '@gravity-ui/icons';
3
7
 
4
8
  import type {
5
9
  BreadcrumbsOptions,
@@ -15,8 +19,9 @@ import {
15
19
  TENANT_PAGE,
16
20
  TENANT_PAGES_IDS,
17
21
  } from '../../store/reducers/tenant/constants';
22
+ import {TabletIcon} from '../../components/TabletIcon/TabletIcon';
18
23
  import routes, {createHref} from '../../routes';
19
- import {CLUSTER_DEFAULT_TITLE} from '../../utils/constants';
24
+ import {CLUSTER_DEFAULT_TITLE, getTabletLabel} from '../../utils/constants';
20
25
 
21
26
  import {getClusterPath} from '../Cluster/utils';
22
27
  import {TenantTabsGroups, getTenantPath} from '../Tenant/TenantPages';
@@ -29,7 +34,7 @@ const prepareTenantName = (tenantName: string) => {
29
34
  export interface RawBreadcrumbItem {
30
35
  text: string;
31
36
  link?: string;
32
- icon?: SVGIconData;
37
+ icon?: JSX.Element;
33
38
  }
34
39
 
35
40
  const getClusterBreadcrumbs = (
@@ -42,7 +47,7 @@ const getClusterBreadcrumbs = (
42
47
  {
43
48
  text: clusterName || CLUSTER_DEFAULT_TITLE,
44
49
  link: getClusterPath(clusterTab, query),
45
- icon: nodesRightIcon,
50
+ icon: <ClusterIcon />,
46
51
  },
47
52
  ];
48
53
  };
@@ -56,7 +61,7 @@ const getTenantBreadcrumbs = (
56
61
  const text = tenantName ? prepareTenantName(tenantName) : 'Tenant';
57
62
  const link = tenantName ? getTenantPath({...query, name: tenantName}) : undefined;
58
63
 
59
- return [...getClusterBreadcrumbs(options, query), {text, link, icon: databaseIcon}];
64
+ return [...getClusterBreadcrumbs(options, query), {text, link, icon: <DatabaseIcon />}];
60
65
  };
61
66
 
62
67
  const getNodeBreadcrumbs = (options: NodeBreadcrumbsOptions, query = {}): RawBreadcrumbItem[] => {
@@ -81,8 +86,13 @@ const getNodeBreadcrumbs = (options: NodeBreadcrumbsOptions, query = {}): RawBre
81
86
 
82
87
  const text = nodeId ? `Node ${nodeId}` : 'Node';
83
88
  const link = nodeId ? getDefaultNodePath(nodeId, query) : undefined;
89
+ const icon = isStorageNode ? <StorageNodeIcon /> : <ComputeNodeIcon />;
84
90
 
85
- breadcrumbs.push({text, link});
91
+ breadcrumbs.push({
92
+ text,
93
+ link,
94
+ icon,
95
+ });
86
96
 
87
97
  return breadcrumbs;
88
98
  };
@@ -123,12 +133,13 @@ const getTabletBreadcrubms = (
123
133
  options: TabletBreadcrumbsOptions,
124
134
  query = {},
125
135
  ): RawBreadcrumbItem[] => {
126
- const {tabletId} = options;
136
+ const {tabletId, tabletType} = options;
127
137
 
128
138
  const breadcrumbs = getTabletsBreadcrubms(options, query);
129
139
 
130
140
  breadcrumbs.push({
131
141
  text: tabletId || 'Tablet',
142
+ icon: <TabletIcon text={getTabletLabel(tabletType)} />,
132
143
  });
133
144
 
134
145
  return breadcrumbs;
@@ -3,9 +3,11 @@ import cn from 'bem-cn-lite';
3
3
  import {useDispatch} from 'react-redux';
4
4
 
5
5
  import DataTable from '@gravity-ui/react-data-table';
6
+ import {ASCENDING} from '@gravity-ui/react-data-table/build/esm/lib/constants';
6
7
 
7
8
  import type {EPathType} from '../../types/api/schema';
8
9
  import type {ProblemFilterValue} from '../../store/reducers/settings/types';
10
+ import type {NodesSortParams} from '../../store/reducers/nodes/types';
9
11
 
10
12
  import {AccessDenied} from '../../components/Errors/403';
11
13
  import {Illustration} from '../../components/Illustration';
@@ -17,7 +19,13 @@ import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/
17
19
  import {ResponseError} from '../../components/Errors/ResponseError';
18
20
 
19
21
  import {DEFAULT_TABLE_SETTINGS, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY} from '../../utils/constants';
20
- import {useAutofetcher, useSetting, useTypedSelector} from '../../utils/hooks';
22
+ import {
23
+ useAutofetcher,
24
+ useSetting,
25
+ useTypedSelector,
26
+ useNodesRequestParams,
27
+ useTableSort,
28
+ } from '../../utils/hooks';
21
29
  import {AdditionalNodesInfo, isUnavailableNode, NodesUptimeFilterValues} from '../../utils/nodes';
22
30
 
23
31
  import {
@@ -26,6 +34,8 @@ import {
26
34
  setSearchValue,
27
35
  resetNodesState,
28
36
  getComputeNodes,
37
+ setDataWasNotLoaded,
38
+ setSort,
29
39
  } from '../../store/reducers/nodes/nodes';
30
40
  import {selectFilteredNodes} from '../../store/reducers/nodes/selectors';
31
41
  import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
@@ -58,8 +68,16 @@ export const Nodes = ({path, type, additionalNodesInfo = {}}: NodesProps) => {
58
68
  dispatch(resetNodesState());
59
69
  }, [dispatch, path]);
60
70
 
61
- const {wasLoaded, loading, error, nodesUptimeFilter, searchValue, totalNodes} =
62
- useTypedSelector((state) => state.nodes);
71
+ const {
72
+ wasLoaded,
73
+ loading,
74
+ error,
75
+ nodesUptimeFilter,
76
+ searchValue,
77
+ sortOrder = ASCENDING,
78
+ sortValue = 'NodeId',
79
+ totalNodes,
80
+ } = useTypedSelector((state) => state.nodes);
63
81
  const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
64
82
  const {autorefresh} = useTypedSelector((state) => state.schema);
65
83
 
@@ -67,18 +85,39 @@ export const Nodes = ({path, type, additionalNodesInfo = {}}: NodesProps) => {
67
85
 
68
86
  const [useNodesEndpoint] = useSetting(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY);
69
87
 
70
- const fetchNodes = useCallback(() => {
71
- // For not DB entities we always use /compute endpoint instead of /nodes
72
- // since /nodes can return data only for tenants
73
- if (path && (!useNodesEndpoint || !isDatabaseEntityType(type))) {
74
- dispatch(getComputeNodes({path}));
75
- } else {
76
- dispatch(getNodes({tenant: path}));
77
- }
78
- }, [dispatch, path, type, useNodesEndpoint]);
88
+ const requestParams = useNodesRequestParams({
89
+ filter: searchValue,
90
+ problemFilter,
91
+ nodesUptimeFilter,
92
+ sortOrder,
93
+ sortValue,
94
+ });
95
+
96
+ const fetchNodes = useCallback(
97
+ (isBackground) => {
98
+ if (!isBackground) {
99
+ dispatch(setDataWasNotLoaded());
100
+ }
101
+
102
+ const params = requestParams || {};
103
+
104
+ // For not DB entities we always use /compute endpoint instead of /nodes
105
+ // since /nodes can return data only for tenants
106
+ if (path && (!useNodesEndpoint || !isDatabaseEntityType(type))) {
107
+ dispatch(getComputeNodes({path, ...params}));
108
+ } else {
109
+ dispatch(getNodes({tenant: path, ...params}));
110
+ }
111
+ },
112
+ [dispatch, path, type, useNodesEndpoint, requestParams],
113
+ );
79
114
 
80
115
  useAutofetcher(fetchNodes, [fetchNodes], isClusterNodes ? true : autorefresh);
81
116
 
117
+ const [sort, handleSort] = useTableSort({sortValue, sortOrder}, (sortParams) =>
118
+ dispatch(setSort(sortParams as NodesSortParams)),
119
+ );
120
+
82
121
  const handleSearchQueryChange = (value: string) => {
83
122
  dispatch(setSearchValue(value));
84
123
  };
@@ -132,10 +171,8 @@ export const Nodes = ({path, type, additionalNodesInfo = {}}: NodesProps) => {
132
171
  data={nodes || []}
133
172
  columns={columns}
134
173
  settings={DEFAULT_TABLE_SETTINGS}
135
- initialSortOrder={{
136
- columnId: 'NodeId',
137
- order: DataTable.ASCENDING,
138
- }}
174
+ sortOrder={sort}
175
+ onSort={handleSort}
139
176
  emptyDataMessage={i18n('empty.default')}
140
177
  rowClassName={(row) => b('node', {unavailable: isUnavailableNode(row)})}
141
178
  />
@@ -6,26 +6,42 @@ import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
6
6
  import {TabletsStatistic} from '../../components/TabletsStatistic';
7
7
  import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
8
8
 
9
- import type {NodeAddress} from '../../utils/nodes';
9
+ import {isSortableNodesProperty, type NodeAddress} from '../../utils/nodes';
10
10
  import {formatBytesToGigabyte} from '../../utils/index';
11
11
 
12
12
  import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
13
13
 
14
+ const NODES_COLUMNS_IDS = {
15
+ NodeId: 'NodeId',
16
+ Host: 'Host',
17
+ DC: 'DC',
18
+ Rack: 'Rack',
19
+ Version: 'Version',
20
+ Uptime: 'Uptime',
21
+ Memory: 'Memory',
22
+ CPU: 'CPU',
23
+ LoadAverage: 'LoadAverage',
24
+ Tablets: 'Tablets',
25
+ };
26
+
14
27
  interface GetNodesColumnsProps {
15
28
  tabletsPath?: string;
16
29
  getNodeRef?: (node?: NodeAddress) => string | null;
17
30
  }
18
31
 
19
- export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps) {
32
+ export function getNodesColumns({
33
+ tabletsPath,
34
+ getNodeRef,
35
+ }: GetNodesColumnsProps): Column<NodesPreparedEntity>[] {
20
36
  const columns: Column<NodesPreparedEntity>[] = [
21
37
  {
22
- name: 'NodeId',
38
+ name: NODES_COLUMNS_IDS.NodeId,
23
39
  header: '#',
24
40
  width: '80px',
25
41
  align: DataTable.RIGHT,
26
42
  },
27
43
  {
28
- name: 'Host',
44
+ name: NODES_COLUMNS_IDS.Host,
29
45
  render: ({row}) => {
30
46
  return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
31
47
  },
@@ -33,21 +49,21 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
33
49
  align: DataTable.LEFT,
34
50
  },
35
51
  {
36
- name: 'DataCenter',
52
+ name: NODES_COLUMNS_IDS.DC,
37
53
  header: 'DC',
38
54
  align: DataTable.LEFT,
39
55
  render: ({row}) => (row.DataCenter ? row.DataCenter : '—'),
40
56
  width: '60px',
41
57
  },
42
58
  {
43
- name: 'Rack',
59
+ name: NODES_COLUMNS_IDS.Rack,
44
60
  header: 'Rack',
45
61
  align: DataTable.LEFT,
46
62
  render: ({row}) => (row.Rack ? row.Rack : '—'),
47
63
  width: '80px',
48
64
  },
49
65
  {
50
- name: 'Version',
66
+ name: NODES_COLUMNS_IDS.Version,
51
67
  width: '200px',
52
68
  align: DataTable.LEFT,
53
69
  render: ({row}) => {
@@ -55,14 +71,14 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
55
71
  },
56
72
  },
57
73
  {
58
- name: 'Uptime',
74
+ name: NODES_COLUMNS_IDS.Uptime,
59
75
  header: 'Uptime',
60
76
  sortAccessor: ({StartTime}) => StartTime && -StartTime,
61
77
  align: DataTable.RIGHT,
62
78
  width: '110px',
63
79
  },
64
80
  {
65
- name: 'MemoryUsed',
81
+ name: NODES_COLUMNS_IDS.Memory,
66
82
  header: 'Memory',
67
83
  sortAccessor: ({MemoryUsed = 0}) => Number(MemoryUsed),
68
84
  defaultOrder: DataTable.DESCENDING,
@@ -77,7 +93,7 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
77
93
  width: '120px',
78
94
  },
79
95
  {
80
- name: 'PoolStats',
96
+ name: NODES_COLUMNS_IDS.CPU,
81
97
  header: 'CPU',
82
98
  sortAccessor: ({PoolStats = []}) =>
83
99
  PoolStats.reduce((acc, item) => {
@@ -93,7 +109,7 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
93
109
  width: '120px',
94
110
  },
95
111
  {
96
- name: 'LoadAverage',
112
+ name: NODES_COLUMNS_IDS.LoadAverage,
97
113
  header: 'Load average',
98
114
  sortAccessor: ({LoadAverage = []}) =>
99
115
  LoadAverage.slice(0, 1).reduce((acc, item) => acc + item, 0),
@@ -112,7 +128,7 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
112
128
  width: '140px',
113
129
  },
114
130
  {
115
- name: 'Tablets',
131
+ name: NODES_COLUMNS_IDS.Tablets,
116
132
  width: '430px',
117
133
  render: ({row}) => {
118
134
  return row.Tablets ? (
@@ -129,5 +145,7 @@ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps)
129
145
  },
130
146
  ];
131
147
 
132
- return columns;
148
+ return columns.map((column) => {
149
+ return {...column, sortable: isSortableNodesProperty(column.name)};
150
+ });
133
151
  }