ydb-embedded-ui 4.12.0 → 4.14.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +29 -0
- package/dist/components/InfoViewer/formatters/common.ts +4 -2
- package/dist/components/InfoViewer/i18n/en.json +4 -0
- package/dist/components/InfoViewer/i18n/index.ts +11 -0
- package/dist/components/InfoViewer/i18n/ru.json +4 -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/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/Tablet/Tablet.tsx +9 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +5 -2
- package/dist/containers/Tenant/Info/ExternalDataSource/ExternalDataSource.scss +5 -0
- package/dist/containers/Tenant/Info/ExternalDataSource/ExternalDataSource.tsx +81 -0
- package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.scss +5 -0
- package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +103 -0
- package/dist/containers/Tenant/Info/i18n/en.json +8 -0
- package/dist/containers/Tenant/Info/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Info/i18n/ru.json +8 -0
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +4 -4
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +10 -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/QueryEditor/QueryEditor.js +4 -6
- 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 +12 -2
- package/dist/containers/Tenant/i18n/en.json +12 -2
- package/dist/containers/Tenant/i18n/ru.json +11 -1
- package/dist/containers/Tenant/utils/schemaActions.ts +76 -28
- 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/index.js +7 -3
- package/dist/services/api.ts +24 -12
- package/dist/store/reducers/header/types.ts +2 -0
- 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/styles/constants.scss +3 -0
- package/dist/types/api/compute.ts +0 -12
- package/dist/types/api/nodes.ts +0 -12
- package/dist/utils/constants.ts +3 -0
- package/dist/utils/filters.ts +23 -0
- package/dist/utils/hooks/i18n/en.json +3 -0
- package/dist/utils/hooks/i18n/index.ts +11 -0
- package/dist/utils/hooks/i18n/ru.json +3 -0
- package/dist/utils/hooks/index.ts +4 -0
- package/dist/utils/hooks/useNodesRequestParams.ts +46 -0
- package/dist/utils/hooks/useQueryModes.ts +34 -0
- package/dist/utils/hooks/useTableSort.ts +37 -0
- package/dist/utils/nodes.ts +25 -0
- package/dist/utils/query.ts +5 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.14.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.13.0...v4.14.0) (2023-08-11)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **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))
|
9
|
+
* **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))
|
10
|
+
|
11
|
+
|
12
|
+
### Bug Fixes
|
13
|
+
|
14
|
+
* **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))
|
15
|
+
* **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))
|
16
|
+
* **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))
|
17
|
+
* **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))
|
18
|
+
|
19
|
+
## [4.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.12.0...v4.13.0) (2023-08-04)
|
20
|
+
|
21
|
+
|
22
|
+
### Features
|
23
|
+
|
24
|
+
* info and summary tabs for external objects ([#493](https://github.com/ydb-platform/ydb-embedded-ui/issues/493)) ([88d9041](https://github.com/ydb-platform/ydb-embedded-ui/commit/88d9041f080f13046aeaf55765609dbc13b87285))
|
25
|
+
|
26
|
+
|
27
|
+
### Bug Fixes
|
28
|
+
|
29
|
+
* **SchemaTree:** add actions to external objects ([#497](https://github.com/ydb-platform/ydb-embedded-ui/issues/497)) ([5029579](https://github.com/ydb-platform/ydb-embedded-ui/commit/5029579796dd5fb985005f39e9ef8daf142366d0))
|
30
|
+
* **SchemaTree:** set required query mode for tree actions ([#491](https://github.com/ydb-platform/ydb-embedded-ui/issues/491)) ([ccd1eda](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccd1edac0d84357cd605c9d131c99890449d8bd8))
|
31
|
+
|
3
32
|
## [4.12.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.11.1...v4.12.0) (2023-08-02)
|
4
33
|
|
5
34
|
|
@@ -3,13 +3,15 @@ import {formatDateTime} from '../../../utils';
|
|
3
3
|
|
4
4
|
import {createInfoFormatter} from '../utils';
|
5
5
|
|
6
|
+
import i18n from '../i18n';
|
7
|
+
|
6
8
|
export const formatCommonItem = createInfoFormatter<TDirEntry>({
|
7
9
|
values: {
|
8
10
|
PathType: (value) => value?.substring('EPathType'.length),
|
9
11
|
CreateStep: formatDateTime,
|
10
12
|
},
|
11
13
|
labels: {
|
12
|
-
PathType: '
|
13
|
-
CreateStep: '
|
14
|
+
PathType: i18n('common.type'),
|
15
|
+
CreateStep: i18n('common.created'),
|
14
16
|
},
|
15
17
|
});
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../../utils/i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-components-info-viewer';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -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
|
+
};
|
@@ -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
|
}
|
@@ -13,6 +13,7 @@ import {DEVELOPER_UI_TITLE} from '../../utils/constants';
|
|
13
13
|
import '../../services/api';
|
14
14
|
import {parseQuery} from '../../routes';
|
15
15
|
|
16
|
+
import type {EType} from '../../types/api/tablet';
|
16
17
|
import EntityStatus from '../../components/EntityStatus/EntityStatus';
|
17
18
|
import {ResponseError} from '../../components/Errors/ResponseError';
|
18
19
|
import {Tag} from '../../components/Tag';
|
@@ -48,10 +49,14 @@ export const Tablet = () => {
|
|
48
49
|
error,
|
49
50
|
} = useTypedSelector((state) => state.tablet);
|
50
51
|
|
51
|
-
const {
|
52
|
-
|
52
|
+
const {
|
53
|
+
nodeId: queryNodeId,
|
54
|
+
tenantName: queryTenantName,
|
55
|
+
type: queryTabletType,
|
56
|
+
} = parseQuery(location);
|
53
57
|
const nodeId = tablet.NodeId?.toString() || queryNodeId?.toString();
|
54
58
|
const tenantName = tenantPath || queryTenantName?.toString();
|
59
|
+
const type = tablet.Type || (queryTabletType?.toString() as EType | undefined);
|
55
60
|
|
56
61
|
// NOTE: should be reviewed when migrating to React 18
|
57
62
|
useEffect(() => {
|
@@ -79,9 +84,10 @@ export const Tablet = () => {
|
|
79
84
|
nodeIds: nodeId ? [nodeId] : [],
|
80
85
|
tenantName,
|
81
86
|
tabletId: id,
|
87
|
+
tabletType: type,
|
82
88
|
}),
|
83
89
|
);
|
84
|
-
}, [dispatch, tenantName, id, nodeId]);
|
90
|
+
}, [dispatch, tenantName, id, nodeId, type]);
|
85
91
|
|
86
92
|
const renderExternalLinks = (link: {name: string; path: string}, index: number) => {
|
87
93
|
return (
|
@@ -27,6 +27,9 @@ import {
|
|
27
27
|
isPathTypeWithTopic,
|
28
28
|
} from '../../utils/schema';
|
29
29
|
|
30
|
+
import {ExternalTableInfo} from '../../Info/ExternalTable/ExternalTable';
|
31
|
+
import {ExternalDataSourceInfo} from '../../Info/ExternalDataSource/ExternalDataSource';
|
32
|
+
|
30
33
|
import {TopicInfo} from './TopicInfo';
|
31
34
|
import {ChangefeedInfo} from './ChangefeedInfo';
|
32
35
|
import {TableInfo} from './TableInfo';
|
@@ -124,8 +127,8 @@ function Overview({type, tenantName}: OverviewProps) {
|
|
124
127
|
<ChangefeedInfo data={data} topic={additionalData?.[0]} />
|
125
128
|
),
|
126
129
|
[EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={data} />,
|
127
|
-
[EPathType.EPathTypeExternalTable]:
|
128
|
-
[EPathType.EPathTypeExternalDataSource]:
|
130
|
+
[EPathType.EPathTypeExternalTable]: () => <ExternalTableInfo data={data} />,
|
131
|
+
[EPathType.EPathTypeExternalDataSource]: () => <ExternalDataSourceInfo data={data} />,
|
129
132
|
};
|
130
133
|
|
131
134
|
return (
|