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.
- package/CHANGELOG.md +25 -0
- package/dist/components/Tablet/Tablet.scss +1 -16
- package/dist/components/Tablet/Tablet.tsx +5 -5
- package/dist/components/TabletIcon/TabletIcon.scss +17 -0
- package/dist/components/TabletIcon/TabletIcon.tsx +18 -0
- package/dist/containers/App/App.js +1 -1
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -1
- package/dist/containers/Authentication/Authentication.tsx +1 -1
- package/dist/containers/Header/Header.scss +2 -0
- package/dist/containers/Header/Header.tsx +2 -7
- package/dist/containers/Header/{breadcrumbs.ts → breadcrumbs.tsx} +19 -8
- package/dist/containers/Nodes/Nodes.tsx +53 -16
- package/dist/containers/Nodes/getNodesColumns.tsx +31 -13
- package/dist/containers/Storage/Storage.tsx +64 -32
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +56 -73
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +33 -43
- package/dist/containers/Storage/utils/index.ts +3 -3
- package/dist/containers/Tablet/Tablet.tsx +9 -3
- package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.scss +8 -0
- package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +13 -1
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +3 -1
- package/dist/containers/Tenant/Query/i18n/en.json +6 -4
- package/dist/containers/Tenant/Query/i18n/ru.json +6 -4
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +4 -0
- package/dist/containers/Tenant/i18n/en.json +3 -0
- package/dist/containers/Tenant/i18n/ru.json +3 -0
- package/dist/containers/Tenant/utils/queryTemplates.ts +89 -0
- package/dist/containers/Tenant/utils/schema.ts +1 -1
- package/dist/containers/Tenant/utils/schemaActions.ts +30 -54
- package/dist/containers/Tenant/utils/schemaControls.tsx +69 -0
- package/dist/containers/UserSettings/i18n/en.json +3 -0
- package/dist/containers/UserSettings/i18n/ru.json +3 -0
- package/dist/containers/UserSettings/settings.ts +12 -1
- package/dist/{reportWebVitals.js → reportWebVitals.ts} +3 -1
- package/dist/services/api.ts +30 -16
- package/dist/store/reducers/{authentication.js → authentication/authentication.ts} +14 -7
- package/dist/store/reducers/authentication/types.ts +15 -0
- package/dist/store/reducers/describe.ts +1 -16
- package/dist/store/reducers/header/types.ts +2 -0
- package/dist/store/reducers/index.ts +1 -1
- package/dist/store/reducers/nodes/nodes.ts +23 -6
- package/dist/store/reducers/nodes/selectors.ts +2 -2
- package/dist/store/reducers/nodes/types.ts +15 -5
- package/dist/store/reducers/settings/settings.ts +5 -0
- package/dist/store/reducers/storage/selectors.ts +50 -150
- package/dist/store/reducers/storage/storage.ts +73 -25
- package/dist/store/reducers/storage/types.ts +49 -17
- package/dist/store/reducers/storage/utils.ts +207 -0
- package/dist/store/utils.ts +1 -1
- package/dist/types/api/compute.ts +0 -12
- package/dist/types/api/error.ts +4 -0
- package/dist/types/api/nodes.ts +0 -12
- package/dist/types/api/storage.ts +32 -4
- package/dist/types/window.d.ts +1 -0
- package/dist/utils/constants.ts +3 -0
- package/dist/utils/filters.ts +23 -0
- package/dist/utils/hooks/index.ts +4 -0
- package/dist/utils/hooks/useNodesRequestParams.ts +46 -0
- package/dist/utils/hooks/useStorageRequestParams.ts +28 -0
- package/dist/utils/hooks/useTableSort.ts +37 -0
- package/dist/utils/nodes.ts +25 -0
- package/dist/utils/storage.ts +31 -3
- package/package.json +2 -6
- package/dist/HOCS/WithSearch/WithSearch.js +0 -26
- package/dist/HOCS/index.js +0 -1
- package/dist/components/Hotkey/Hotkey.js +0 -102
- package/dist/components/Pagination/Pagination.js +0 -63
- package/dist/components/Pagination/Pagination.scss +0 -28
- package/dist/types/store/storage.ts +0 -12
- /package/dist/{index.js → index.tsx} +0 -0
- /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:
|
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 =
|
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
|
-
<
|
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,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';
|
@@ -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
|
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
|
-
<
|
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
|
2
|
-
|
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?:
|
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:
|
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:
|
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({
|
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 {
|
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 {
|
62
|
-
|
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
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
136
|
-
|
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
|
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({
|
32
|
+
export function getNodesColumns({
|
33
|
+
tabletsPath,
|
34
|
+
getNodeRef,
|
35
|
+
}: GetNodesColumnsProps): Column<NodesPreparedEntity>[] {
|
20
36
|
const columns: Column<NodesPreparedEntity>[] = [
|
21
37
|
{
|
22
|
-
name:
|
38
|
+
name: NODES_COLUMNS_IDS.NodeId,
|
23
39
|
header: '#',
|
24
40
|
width: '80px',
|
25
41
|
align: DataTable.RIGHT,
|
26
42
|
},
|
27
43
|
{
|
28
|
-
name:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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
|
}
|