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.
- 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
@@ -2,8 +2,6 @@ import {useCallback, useEffect} from 'react';
|
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
|
-
import DataTable, {Settings} from '@gravity-ui/react-data-table';
|
6
|
-
|
7
5
|
import {Search} from '../../components/Search';
|
8
6
|
import {UptimeFilter} from '../../components/UptimeFIlter';
|
9
7
|
import {AccessDenied} from '../../components/Errors/403';
|
@@ -11,9 +9,13 @@ import {EntitiesCount} from '../../components/EntitiesCount';
|
|
11
9
|
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
|
12
10
|
import {ResponseError} from '../../components/Errors/ResponseError';
|
13
11
|
|
14
|
-
import type {
|
12
|
+
import type {
|
13
|
+
StorageSortParams,
|
14
|
+
StorageType,
|
15
|
+
VisibleEntities,
|
16
|
+
} from '../../store/reducers/storage/types';
|
17
|
+
import type {NodesSortParams} from '../../store/reducers/nodes/types';
|
15
18
|
import {
|
16
|
-
getStorageInfo,
|
17
19
|
setInitialState,
|
18
20
|
setVisibleEntities,
|
19
21
|
setStorageTextFilter,
|
@@ -21,17 +23,28 @@ import {
|
|
21
23
|
setStorageType,
|
22
24
|
setNodesUptimeFilter,
|
23
25
|
setDataWasNotLoaded,
|
26
|
+
getStorageNodesInfo,
|
27
|
+
getStorageGroupsInfo,
|
28
|
+
setNodesSortParams,
|
29
|
+
setGroupsSortParams,
|
24
30
|
} from '../../store/reducers/storage/storage';
|
25
31
|
import {
|
26
32
|
selectFilteredGroups,
|
27
33
|
selectFilteredNodes,
|
28
|
-
|
29
|
-
selectStorageGroupsCount,
|
34
|
+
selectEntitiesCount,
|
30
35
|
selectUsageFilterOptions,
|
36
|
+
selectNodesSortParams,
|
37
|
+
selectGroupsSortParams,
|
31
38
|
} from '../../store/reducers/storage/selectors';
|
32
39
|
import {VISIBLE_ENTITIES, STORAGE_TYPES} from '../../store/reducers/storage/constants';
|
33
40
|
import {getNodesList, selectNodesMap} from '../../store/reducers/nodesList';
|
34
|
-
import {
|
41
|
+
import {
|
42
|
+
useAutofetcher,
|
43
|
+
useNodesRequestParams,
|
44
|
+
useStorageRequestParams,
|
45
|
+
useTableSort,
|
46
|
+
useTypedSelector,
|
47
|
+
} from '../../utils/hooks';
|
35
48
|
import {AdditionalNodesInfo, NodesUptimeFilterValues} from '../../utils/nodes';
|
36
49
|
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
|
37
50
|
|
@@ -45,11 +58,6 @@ import './Storage.scss';
|
|
45
58
|
|
46
59
|
const b = cn('global-storage');
|
47
60
|
|
48
|
-
const tableSettings: Settings = {
|
49
|
-
...DEFAULT_TABLE_SETTINGS,
|
50
|
-
defaultOrder: DataTable.DESCENDING,
|
51
|
-
};
|
52
|
-
|
53
61
|
interface StorageProps {
|
54
62
|
additionalNodesInfo?: AdditionalNodesInfo;
|
55
63
|
tenant?: string;
|
@@ -72,10 +80,11 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
72
80
|
} = useTypedSelector((state) => state.storage);
|
73
81
|
const storageNodes = useTypedSelector(selectFilteredNodes);
|
74
82
|
const storageGroups = useTypedSelector(selectFilteredGroups);
|
75
|
-
const
|
76
|
-
const groupsCount = useTypedSelector(selectStorageGroupsCount);
|
83
|
+
const entitiesCount = useTypedSelector(selectEntitiesCount);
|
77
84
|
const nodesMap = useTypedSelector(selectNodesMap);
|
78
85
|
const usageFilterOptions = useTypedSelector(selectUsageFilterOptions);
|
86
|
+
const nodesSortParams = useTypedSelector(selectNodesSortParams);
|
87
|
+
const groupsSortParams = useTypedSelector(selectGroupsSortParams);
|
79
88
|
|
80
89
|
useEffect(() => {
|
81
90
|
dispatch(getNodesList());
|
@@ -86,27 +95,47 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
86
95
|
};
|
87
96
|
}, [dispatch]);
|
88
97
|
|
98
|
+
const nodesRequestParams = useNodesRequestParams({
|
99
|
+
filter,
|
100
|
+
nodesUptimeFilter,
|
101
|
+
...nodesSortParams,
|
102
|
+
});
|
103
|
+
const storageRequestParams = useStorageRequestParams({
|
104
|
+
filter,
|
105
|
+
...groupsSortParams,
|
106
|
+
});
|
107
|
+
|
108
|
+
const [nodesSort, handleNodesSort] = useTableSort(nodesSortParams, (params) =>
|
109
|
+
dispatch(setNodesSortParams(params as NodesSortParams)),
|
110
|
+
);
|
111
|
+
const [groupsSort, handleGroupsSort] = useTableSort(groupsSortParams, (params) =>
|
112
|
+
dispatch(setGroupsSortParams(params as StorageSortParams)),
|
113
|
+
);
|
114
|
+
|
89
115
|
const fetchData = useCallback(
|
90
116
|
(isBackground: boolean) => {
|
91
117
|
if (!isBackground) {
|
92
118
|
dispatch(setDataWasNotLoaded());
|
93
119
|
}
|
94
120
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
{
|
104
|
-
concurrentId: 'getStorageInfo',
|
105
|
-
},
|
106
|
-
),
|
107
|
-
);
|
121
|
+
const nodesParams = nodesRequestParams || {};
|
122
|
+
const storageParams = storageRequestParams || {};
|
123
|
+
|
124
|
+
if (storageType === STORAGE_TYPES.nodes) {
|
125
|
+
dispatch(getStorageNodesInfo({tenant, visibleEntities, ...nodesParams}));
|
126
|
+
} else {
|
127
|
+
dispatch(getStorageGroupsInfo({tenant, visibleEntities, nodeId, ...storageParams}));
|
128
|
+
}
|
108
129
|
},
|
109
|
-
[
|
130
|
+
[
|
131
|
+
dispatch,
|
132
|
+
tenant,
|
133
|
+
nodeId,
|
134
|
+
visibleEntities,
|
135
|
+
storageType,
|
136
|
+
storageRequestParams,
|
137
|
+
nodesRequestParams,
|
138
|
+
],
|
110
139
|
);
|
111
140
|
|
112
141
|
const autorefreshEnabled = tenant ? autorefresh : true;
|
@@ -145,9 +174,11 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
145
174
|
<StorageGroups
|
146
175
|
visibleEntities={visibleEntities}
|
147
176
|
data={storageGroups}
|
148
|
-
tableSettings={
|
177
|
+
tableSettings={DEFAULT_TABLE_SETTINGS}
|
149
178
|
nodes={nodesMap}
|
150
179
|
onShowAll={() => handleGroupVisibilityChange(VISIBLE_ENTITIES.all)}
|
180
|
+
sort={groupsSort}
|
181
|
+
handleSort={handleGroupsSort}
|
151
182
|
/>
|
152
183
|
)}
|
153
184
|
{storageType === STORAGE_TYPES.nodes && (
|
@@ -155,9 +186,11 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
155
186
|
visibleEntities={visibleEntities}
|
156
187
|
nodesUptimeFilter={nodesUptimeFilter}
|
157
188
|
data={storageNodes}
|
158
|
-
tableSettings={
|
189
|
+
tableSettings={DEFAULT_TABLE_SETTINGS}
|
159
190
|
onShowAll={handleShowAllNodes}
|
160
191
|
additionalNodesInfo={additionalNodesInfo}
|
192
|
+
sort={nodesSort}
|
193
|
+
handleSort={handleNodesSort}
|
161
194
|
/>
|
162
195
|
)}
|
163
196
|
</>
|
@@ -166,7 +199,6 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
166
199
|
|
167
200
|
const renderEntitiesCount = () => {
|
168
201
|
const entityName = storageType === STORAGE_TYPES.groups ? 'Groups' : 'Nodes';
|
169
|
-
const count = storageType === STORAGE_TYPES.groups ? groupsCount : nodesCount;
|
170
202
|
const current =
|
171
203
|
storageType === STORAGE_TYPES.groups ? storageGroups.length : storageNodes.length;
|
172
204
|
|
@@ -174,7 +206,7 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
174
206
|
<EntitiesCount
|
175
207
|
label={entityName}
|
176
208
|
loading={loading && !wasLoaded}
|
177
|
-
total={
|
209
|
+
total={entitiesCount.total}
|
178
210
|
current={current}
|
179
211
|
/>
|
180
212
|
);
|
@@ -3,13 +3,15 @@ import cn from 'bem-cn-lite';
|
|
3
3
|
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
4
4
|
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
5
5
|
|
6
|
+
import type {ValueOf} from '../../../types/common';
|
6
7
|
import type {NodesMap} from '../../../types/store/nodesList';
|
7
8
|
import type {PreparedStorageGroup, VisibleEntities} from '../../../store/reducers/storage/types';
|
9
|
+
import type {HandleSort} from '../../../utils/hooks/useTableSort';
|
8
10
|
|
9
11
|
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
10
12
|
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
|
11
13
|
import {stringifyVdiskId} from '../../../utils';
|
12
|
-
import {getUsage, isFullVDiskData} from '../../../utils/storage';
|
14
|
+
import {getUsage, isFullVDiskData, isSortableStorageProperty} from '../../../utils/storage';
|
13
15
|
|
14
16
|
import shieldIcon from '../../../assets/icons/shield.svg';
|
15
17
|
import {Stack} from '../../../components/Stack/Stack';
|
@@ -22,23 +24,22 @@ import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
|
|
22
24
|
import i18n from './i18n';
|
23
25
|
import './StorageGroups.scss';
|
24
26
|
|
25
|
-
|
26
|
-
PoolName
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
Used
|
31
|
-
Limit
|
32
|
-
|
33
|
-
UsedSpaceFlag
|
34
|
-
Read
|
35
|
-
Write
|
36
|
-
VDisks
|
37
|
-
|
38
|
-
}
|
27
|
+
const TableColumnsIds = {
|
28
|
+
PoolName: 'PoolName',
|
29
|
+
Kind: 'Kind',
|
30
|
+
Erasure: 'Erasure',
|
31
|
+
GroupId: 'GroupId',
|
32
|
+
Used: 'Used',
|
33
|
+
Limit: 'Limit',
|
34
|
+
Usage: 'Usage',
|
35
|
+
UsedSpaceFlag: 'UsedSpaceFlag',
|
36
|
+
Read: 'Read',
|
37
|
+
Write: 'Write',
|
38
|
+
VDisks: 'VDisks',
|
39
|
+
Degraded: 'Degraded',
|
40
|
+
} as const;
|
39
41
|
|
40
|
-
type
|
41
|
-
type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
|
42
|
+
type TableColumnId = ValueOf<typeof TableColumnsIds>;
|
42
43
|
|
43
44
|
interface StorageGroupsProps {
|
44
45
|
data: PreparedStorageGroup[];
|
@@ -46,59 +47,37 @@ interface StorageGroupsProps {
|
|
46
47
|
tableSettings: Settings;
|
47
48
|
visibleEntities: VisibleEntities;
|
48
49
|
onShowAll?: VoidFunction;
|
50
|
+
sort?: SortOrder;
|
51
|
+
handleSort?: HandleSort;
|
49
52
|
}
|
50
53
|
|
51
|
-
const tableColumnsNames: Record<
|
54
|
+
const tableColumnsNames: Record<TableColumnId, string> = {
|
52
55
|
PoolName: 'Pool Name',
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
Kind: 'Type',
|
57
|
+
Erasure: 'Erasure',
|
58
|
+
GroupId: 'Group ID',
|
56
59
|
Used: 'Used',
|
57
60
|
Limit: 'Limit',
|
58
61
|
UsedSpaceFlag: 'Space',
|
59
|
-
|
62
|
+
Usage: 'Usage',
|
60
63
|
Read: 'Read',
|
61
64
|
Write: 'Write',
|
62
65
|
VDisks: 'VDisks',
|
63
|
-
|
66
|
+
Degraded: 'Degraded',
|
64
67
|
};
|
65
68
|
|
66
69
|
const b = cn('global-storage-groups');
|
67
70
|
|
68
|
-
function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
|
69
|
-
switch (visibleEntities) {
|
70
|
-
case VISIBLE_ENTITIES.all: {
|
71
|
-
return {
|
72
|
-
columnId: TableColumnsIds.PoolName,
|
73
|
-
order: DataTable.ASCENDING,
|
74
|
-
};
|
75
|
-
}
|
76
|
-
case VISIBLE_ENTITIES.missing: {
|
77
|
-
return {
|
78
|
-
columnId: TableColumnsIds.Missing,
|
79
|
-
order: DataTable.DESCENDING,
|
80
|
-
};
|
81
|
-
}
|
82
|
-
case VISIBLE_ENTITIES.space: {
|
83
|
-
return {
|
84
|
-
columnId: TableColumnsIds.UsedSpaceFlag,
|
85
|
-
order: DataTable.DESCENDING,
|
86
|
-
};
|
87
|
-
}
|
88
|
-
default: {
|
89
|
-
return undefined;
|
90
|
-
}
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
71
|
export function StorageGroups({
|
95
72
|
data,
|
96
73
|
tableSettings,
|
97
74
|
visibleEntities,
|
98
75
|
nodes,
|
99
76
|
onShowAll,
|
77
|
+
sort,
|
78
|
+
handleSort,
|
100
79
|
}: StorageGroupsProps) {
|
101
|
-
const
|
80
|
+
const rawColumns: Column<PreparedStorageGroup>[] = [
|
102
81
|
{
|
103
82
|
name: TableColumnsIds.PoolName,
|
104
83
|
header: tableColumnsNames[TableColumnsIds.PoolName],
|
@@ -124,12 +103,12 @@ export function StorageGroups({
|
|
124
103
|
align: DataTable.LEFT,
|
125
104
|
},
|
126
105
|
{
|
127
|
-
name: TableColumnsIds.
|
128
|
-
header: tableColumnsNames[TableColumnsIds.
|
106
|
+
name: TableColumnsIds.Kind,
|
107
|
+
header: tableColumnsNames[TableColumnsIds.Kind],
|
129
108
|
// prettier-ignore
|
130
109
|
render: ({row}) => (
|
131
110
|
<>
|
132
|
-
<Label>{row.
|
111
|
+
<Label>{row.Kind || '—'}</Label>
|
133
112
|
{' '}
|
134
113
|
{row.Encryption && (
|
135
114
|
<Popover
|
@@ -146,18 +125,18 @@ export function StorageGroups({
|
|
146
125
|
),
|
147
126
|
},
|
148
127
|
{
|
149
|
-
name: TableColumnsIds.
|
150
|
-
header: tableColumnsNames[TableColumnsIds.
|
128
|
+
name: TableColumnsIds.Erasure,
|
129
|
+
header: tableColumnsNames[TableColumnsIds.Erasure],
|
151
130
|
render: ({row}) => (row.ErasureSpecies ? row.ErasureSpecies : '-'),
|
152
131
|
align: DataTable.LEFT,
|
153
132
|
},
|
154
133
|
{
|
155
|
-
name: TableColumnsIds.
|
156
|
-
header: tableColumnsNames[TableColumnsIds.
|
134
|
+
name: TableColumnsIds.Degraded,
|
135
|
+
header: tableColumnsNames[TableColumnsIds.Degraded],
|
157
136
|
width: 100,
|
158
137
|
render: ({row}) =>
|
159
|
-
row.
|
160
|
-
<Label theme={getDegradedSeverity(row)}>Degraded: {row.
|
138
|
+
row.Degraded ? (
|
139
|
+
<Label theme={getDegradedSeverity(row)}>Degraded: {row.Degraded}</Label>
|
161
140
|
) : (
|
162
141
|
'-'
|
163
142
|
),
|
@@ -165,19 +144,18 @@ export function StorageGroups({
|
|
165
144
|
defaultOrder: DataTable.DESCENDING,
|
166
145
|
},
|
167
146
|
{
|
168
|
-
name: TableColumnsIds.
|
169
|
-
header: tableColumnsNames[TableColumnsIds.
|
147
|
+
name: TableColumnsIds.Usage,
|
148
|
+
header: tableColumnsNames[TableColumnsIds.Usage],
|
170
149
|
width: 100,
|
171
150
|
render: ({row}) => {
|
172
|
-
const usage = getUsage(row, 5);
|
173
151
|
// without a limit the usage can be evaluated as 0,
|
174
152
|
// but the absence of a value is more clear
|
175
153
|
return row.Limit ? (
|
176
154
|
<Label
|
177
|
-
theme={getUsageSeverityForStorageGroup(
|
178
|
-
className={b('usage-label', {overload:
|
155
|
+
theme={getUsageSeverityForStorageGroup(row.Usage)}
|
156
|
+
className={b('usage-label', {overload: row.Usage >= 90})}
|
179
157
|
>
|
180
|
-
{
|
158
|
+
{row.Usage}%
|
181
159
|
</Label>
|
182
160
|
) : (
|
183
161
|
'-'
|
@@ -188,12 +166,13 @@ export function StorageGroups({
|
|
188
166
|
align: DataTable.LEFT,
|
189
167
|
},
|
190
168
|
{
|
191
|
-
name: TableColumnsIds.
|
192
|
-
header: tableColumnsNames[TableColumnsIds.
|
169
|
+
name: TableColumnsIds.GroupId,
|
170
|
+
header: tableColumnsNames[TableColumnsIds.GroupId],
|
193
171
|
width: 130,
|
194
172
|
render: ({row}) => {
|
195
173
|
return <span className={b('group-id')}>{row.GroupID}</span>;
|
196
174
|
},
|
175
|
+
sortAccessor: (row) => Number(row.GroupID),
|
197
176
|
align: DataTable.RIGHT,
|
198
177
|
},
|
199
178
|
{
|
@@ -297,18 +276,21 @@ export function StorageGroups({
|
|
297
276
|
},
|
298
277
|
];
|
299
278
|
|
300
|
-
let columns =
|
279
|
+
let columns = rawColumns.map((column) => ({
|
280
|
+
...column,
|
281
|
+
sortable: isSortableStorageProperty(column.name),
|
282
|
+
}));
|
301
283
|
|
302
284
|
if (visibleEntities === VISIBLE_ENTITIES.all) {
|
303
|
-
columns =
|
285
|
+
columns = columns.filter((col) => {
|
304
286
|
return (
|
305
|
-
col.name !== TableColumnsIds.
|
287
|
+
col.name !== TableColumnsIds.Degraded && col.name !== TableColumnsIds.UsedSpaceFlag
|
306
288
|
);
|
307
289
|
});
|
308
290
|
}
|
309
291
|
|
310
292
|
if (visibleEntities === VISIBLE_ENTITIES.space) {
|
311
|
-
columns =
|
293
|
+
columns = columns.filter((col) => col.name !== TableColumnsIds.Degraded);
|
312
294
|
|
313
295
|
if (!data.length) {
|
314
296
|
return (
|
@@ -322,7 +304,7 @@ export function StorageGroups({
|
|
322
304
|
}
|
323
305
|
|
324
306
|
if (visibleEntities === VISIBLE_ENTITIES.missing) {
|
325
|
-
columns =
|
307
|
+
columns = columns.filter((col) => col.name !== TableColumnsIds.UsedSpaceFlag);
|
326
308
|
|
327
309
|
if (!data.length) {
|
328
310
|
return (
|
@@ -342,8 +324,9 @@ export function StorageGroups({
|
|
342
324
|
data={data}
|
343
325
|
columns={columns}
|
344
326
|
settings={tableSettings}
|
345
|
-
initialSortOrder={setSortOrder(visibleEntities)}
|
346
327
|
emptyDataMessage={i18n('empty.default')}
|
328
|
+
sortOrder={sort}
|
329
|
+
onSort={handleSort}
|
347
330
|
/>
|
348
331
|
) : null;
|
349
332
|
}
|
@@ -2,11 +2,14 @@ import cn from 'bem-cn-lite';
|
|
2
2
|
|
3
3
|
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
4
4
|
|
5
|
+
import type {ValueOf} from '../../../types/common';
|
5
6
|
import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
|
7
|
+
import type {HandleSort} from '../../../utils/hooks/useTableSort';
|
6
8
|
|
7
9
|
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
8
10
|
import {
|
9
11
|
AdditionalNodesInfo,
|
12
|
+
isSortableNodesProperty,
|
10
13
|
isUnavailableNode,
|
11
14
|
NodesUptimeFilterValues,
|
12
15
|
} from '../../../utils/nodes';
|
@@ -19,18 +22,17 @@ import {PDisk} from '../PDisk';
|
|
19
22
|
import i18n from './i18n';
|
20
23
|
import './StorageNodes.scss';
|
21
24
|
|
22
|
-
|
23
|
-
NodeId
|
24
|
-
|
25
|
-
|
26
|
-
Rack
|
27
|
-
Uptime
|
28
|
-
PDisks
|
29
|
-
Missing
|
30
|
-
}
|
25
|
+
const TableColumnsIds = {
|
26
|
+
NodeId: 'NodeId',
|
27
|
+
Host: 'Host',
|
28
|
+
DC: 'DC',
|
29
|
+
Rack: 'Rack',
|
30
|
+
Uptime: 'Uptime',
|
31
|
+
PDisks: 'PDisks',
|
32
|
+
Missing: 'Missing',
|
33
|
+
} as const;
|
31
34
|
|
32
|
-
type
|
33
|
-
type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
|
35
|
+
type TableColumnId = ValueOf<typeof TableColumnsIds>;
|
34
36
|
|
35
37
|
interface StorageNodesProps {
|
36
38
|
data: PreparedStorageNode[];
|
@@ -39,12 +41,14 @@ interface StorageNodesProps {
|
|
39
41
|
nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
|
40
42
|
onShowAll?: VoidFunction;
|
41
43
|
additionalNodesInfo?: AdditionalNodesInfo;
|
44
|
+
sort?: SortOrder;
|
45
|
+
handleSort?: HandleSort;
|
42
46
|
}
|
43
47
|
|
44
|
-
const tableColumnsNames: Record<
|
48
|
+
const tableColumnsNames: Record<TableColumnId, string> = {
|
45
49
|
NodeId: 'Node ID',
|
46
|
-
|
47
|
-
|
50
|
+
Host: 'Host',
|
51
|
+
DC: 'DC',
|
48
52
|
Rack: 'Rack',
|
49
53
|
Uptime: 'Uptime',
|
50
54
|
PDisks: 'PDisks',
|
@@ -53,26 +57,6 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
|
|
53
57
|
|
54
58
|
const b = cn('global-storage-nodes');
|
55
59
|
|
56
|
-
function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
|
57
|
-
switch (visibleEntities) {
|
58
|
-
case VISIBLE_ENTITIES.all: {
|
59
|
-
return {
|
60
|
-
columnId: TableColumnsIds.NodeId,
|
61
|
-
order: DataTable.ASCENDING,
|
62
|
-
};
|
63
|
-
}
|
64
|
-
case VISIBLE_ENTITIES.missing: {
|
65
|
-
return {
|
66
|
-
columnId: TableColumnsIds.Missing,
|
67
|
-
order: DataTable.DESCENDING,
|
68
|
-
};
|
69
|
-
}
|
70
|
-
default: {
|
71
|
-
return undefined;
|
72
|
-
}
|
73
|
-
}
|
74
|
-
}
|
75
|
-
|
76
60
|
export function StorageNodes({
|
77
61
|
data,
|
78
62
|
tableSettings,
|
@@ -80,10 +64,12 @@ export function StorageNodes({
|
|
80
64
|
onShowAll,
|
81
65
|
nodesUptimeFilter,
|
82
66
|
additionalNodesInfo,
|
67
|
+
sort,
|
68
|
+
handleSort,
|
83
69
|
}: StorageNodesProps) {
|
84
70
|
const getNodeRef = additionalNodesInfo?.getNodeRef;
|
85
71
|
|
86
|
-
const
|
72
|
+
const rawColumns: Column<PreparedStorageNode>[] = [
|
87
73
|
{
|
88
74
|
name: TableColumnsIds.NodeId,
|
89
75
|
header: tableColumnsNames[TableColumnsIds.NodeId],
|
@@ -91,8 +77,8 @@ export function StorageNodes({
|
|
91
77
|
align: DataTable.RIGHT,
|
92
78
|
},
|
93
79
|
{
|
94
|
-
name: TableColumnsIds.
|
95
|
-
header: tableColumnsNames[TableColumnsIds.
|
80
|
+
name: TableColumnsIds.Host,
|
81
|
+
header: tableColumnsNames[TableColumnsIds.Host],
|
96
82
|
width: 350,
|
97
83
|
render: ({row}) => {
|
98
84
|
return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
|
@@ -100,8 +86,8 @@ export function StorageNodes({
|
|
100
86
|
align: DataTable.LEFT,
|
101
87
|
},
|
102
88
|
{
|
103
|
-
name: TableColumnsIds.
|
104
|
-
header: tableColumnsNames[TableColumnsIds.
|
89
|
+
name: TableColumnsIds.DC,
|
90
|
+
header: tableColumnsNames[TableColumnsIds.DC],
|
105
91
|
render: ({row}) => row.DataCenter || '—',
|
106
92
|
align: DataTable.LEFT,
|
107
93
|
},
|
@@ -144,10 +130,13 @@ export function StorageNodes({
|
|
144
130
|
},
|
145
131
|
];
|
146
132
|
|
147
|
-
let columns =
|
133
|
+
let columns = rawColumns.map((column) => ({
|
134
|
+
...column,
|
135
|
+
sortable: isSortableNodesProperty(column.name),
|
136
|
+
}));
|
148
137
|
|
149
|
-
if (visibleEntities
|
150
|
-
columns =
|
138
|
+
if (visibleEntities !== VISIBLE_ENTITIES.missing) {
|
139
|
+
columns = columns.filter((col) => col.name !== TableColumnsIds.Missing);
|
151
140
|
}
|
152
141
|
|
153
142
|
if (!data.length) {
|
@@ -187,9 +176,10 @@ export function StorageNodes({
|
|
187
176
|
...tableSettings,
|
188
177
|
dynamicRenderType: 'variable',
|
189
178
|
}}
|
190
|
-
initialSortOrder={setSortOrder(visibleEntities)}
|
191
179
|
emptyDataMessage={i18n('empty.default')}
|
192
180
|
rowClassName={(row) => b('node', {unavailable: isUnavailableNode(row)})}
|
181
|
+
sortOrder={sort}
|
182
|
+
onSort={handleSort}
|
193
183
|
/>
|
194
184
|
) : null;
|
195
185
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {
|
1
|
+
import type {PreparedStorageGroup} from '../../../store/reducers/storage/types';
|
2
2
|
import {EFlag} from '../../../types/api/enums';
|
3
3
|
|
4
4
|
export * from './constants';
|
@@ -35,12 +35,12 @@ const degradationEvaluators = {
|
|
35
35
|
const canEvaluateErasureSpecies = (value?: string): value is keyof typeof degradationEvaluators =>
|
36
36
|
value !== undefined && value in degradationEvaluators;
|
37
37
|
|
38
|
-
export const getDegradedSeverity = (group:
|
38
|
+
export const getDegradedSeverity = (group: PreparedStorageGroup) => {
|
39
39
|
const evaluate = canEvaluateErasureSpecies(group.ErasureSpecies)
|
40
40
|
? degradationEvaluators[group.ErasureSpecies]
|
41
41
|
: defaultDegradationEvaluator;
|
42
42
|
|
43
|
-
return evaluate(group.
|
43
|
+
return evaluate(group.Degraded);
|
44
44
|
};
|
45
45
|
|
46
46
|
export const getUsageSeverityForStorageGroup = generateEvaluator(80, 85, [
|
@@ -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 (
|