ydb-embedded-ui 4.13.0 → 4.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  }