ydb-embedded-ui 4.27.1 → 4.28.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 +7 -0
- package/dist/components/EmptyState/EmptyState.scss +5 -2
- package/dist/components/EmptyState/EmptyState.tsx +11 -3
- package/dist/components/Errors/403/AccessDenied.tsx +4 -3
- package/dist/components/ProblemFilter/ProblemFilter.tsx +1 -1
- package/dist/components/UptimeFIlter/UptimeFilter.tsx +1 -1
- package/dist/components/VirtualTable/VirtualTable.scss +1 -1
- package/dist/containers/Cluster/Cluster.tsx +11 -12
- package/dist/containers/Nodes/Nodes.tsx +4 -4
- package/dist/containers/Nodes/NodesWrapper.tsx +21 -0
- package/dist/containers/Nodes/VirtualNodes.tsx +4 -14
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +1 -0
- package/dist/containers/Storage/EmptyFilter/EmptyFilter.tsx +1 -0
- package/dist/containers/Storage/PDisk/PDisk.tsx +5 -7
- package/dist/containers/Storage/Storage.tsx +30 -67
- package/dist/containers/Storage/StorageControls/StorageControls.tsx +104 -0
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +18 -62
- package/dist/containers/Storage/StorageGroups/StorageGroupsEmptyDataMessage.tsx +30 -0
- package/dist/containers/Storage/StorageGroups/VirtualStorageGroups.tsx +94 -0
- package/dist/containers/Storage/StorageGroups/getGroups.ts +21 -0
- package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +73 -50
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -138
- package/dist/containers/Storage/StorageNodes/StorageNodesEmptyDataMessage.tsx +44 -0
- package/dist/containers/Storage/StorageNodes/VirtualStorageNodes.tsx +105 -0
- package/dist/containers/Storage/StorageNodes/getNodes.ts +26 -0
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.tsx +125 -0
- package/dist/containers/Storage/StorageNodes/shared.ts +9 -0
- package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +1 -1
- package/dist/containers/Storage/StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx +1 -1
- package/dist/containers/Storage/StorageWrapper.tsx +23 -0
- package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +3 -4
- package/dist/containers/Storage/VirtualStorage.tsx +112 -0
- package/dist/containers/Storage/i18n/en.json +7 -0
- package/dist/containers/Storage/i18n/index.ts +11 -0
- package/dist/containers/Storage/i18n/ru.json +7 -0
- package/dist/containers/Storage/shared.ts +3 -0
- package/dist/containers/Tenants/Tenants.tsx +2 -2
- package/dist/containers/UserSettings/i18n/en.json +2 -2
- package/dist/containers/UserSettings/i18n/ru.json +2 -2
- package/dist/containers/UserSettings/settings.ts +4 -4
- package/dist/store/reducers/storage/selectors.ts +0 -20
- package/package.json +6 -6
@@ -1,62 +1,30 @@
|
|
1
|
-
import
|
1
|
+
import DataTable, {Settings, SortOrder} from '@gravity-ui/react-data-table';
|
2
2
|
|
3
|
-
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
4
|
-
|
5
|
-
import type {ValueOf} from '../../../types/common';
|
6
3
|
import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
|
7
4
|
import type {HandleSort} from '../../../utils/hooks/useTableSort';
|
8
5
|
import type {AdditionalNodesProps} from '../../../types/additionalProps';
|
9
6
|
|
10
7
|
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
11
|
-
import {
|
12
|
-
isSortableNodesProperty,
|
13
|
-
isUnavailableNode,
|
14
|
-
NodesUptimeFilterValues,
|
15
|
-
} from '../../../utils/nodes';
|
16
|
-
|
17
|
-
import {NodeHostWrapper} from '../../../components/NodeHostWrapper/NodeHostWrapper';
|
8
|
+
import {NodesUptimeFilterValues} from '../../../utils/nodes';
|
18
9
|
|
19
|
-
import {
|
20
|
-
import {PDisk} from '../PDisk';
|
10
|
+
import {getPreparedStorageNodesColumns} from './getStorageNodesColumns';
|
21
11
|
|
12
|
+
import {StorageNodesEmptyDataMessage} from './StorageNodesEmptyDataMessage';
|
13
|
+
import {getRowUnavailableClassName} from './shared';
|
22
14
|
import i18n from './i18n';
|
23
15
|
import './StorageNodes.scss';
|
24
16
|
|
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;
|
34
|
-
|
35
|
-
type TableColumnId = ValueOf<typeof TableColumnsIds>;
|
36
|
-
|
37
17
|
interface StorageNodesProps {
|
38
18
|
data: PreparedStorageNode[];
|
39
19
|
tableSettings: Settings;
|
40
20
|
visibleEntities: VisibleEntities;
|
41
|
-
nodesUptimeFilter:
|
21
|
+
nodesUptimeFilter: NodesUptimeFilterValues;
|
42
22
|
onShowAll?: VoidFunction;
|
43
23
|
additionalNodesProps?: AdditionalNodesProps;
|
44
24
|
sort?: SortOrder;
|
45
25
|
handleSort?: HandleSort;
|
46
26
|
}
|
47
27
|
|
48
|
-
const tableColumnsNames: Record<TableColumnId, string> = {
|
49
|
-
NodeId: 'Node ID',
|
50
|
-
Host: 'Host',
|
51
|
-
DC: 'DC',
|
52
|
-
Rack: 'Rack',
|
53
|
-
Uptime: 'Uptime',
|
54
|
-
PDisks: 'PDisks',
|
55
|
-
Missing: 'Missing',
|
56
|
-
};
|
57
|
-
|
58
|
-
const b = cn('global-storage-nodes');
|
59
|
-
|
60
28
|
export function StorageNodes({
|
61
29
|
data,
|
62
30
|
tableSettings,
|
@@ -67,106 +35,23 @@ export function StorageNodes({
|
|
67
35
|
sort,
|
68
36
|
handleSort,
|
69
37
|
}: StorageNodesProps) {
|
70
|
-
const
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
|
85
|
-
},
|
86
|
-
align: DataTable.LEFT,
|
87
|
-
},
|
88
|
-
{
|
89
|
-
name: TableColumnsIds.DC,
|
90
|
-
header: tableColumnsNames[TableColumnsIds.DC],
|
91
|
-
render: ({row}) => row.DataCenter || '—',
|
92
|
-
align: DataTable.LEFT,
|
93
|
-
},
|
94
|
-
{
|
95
|
-
name: TableColumnsIds.Rack,
|
96
|
-
header: tableColumnsNames[TableColumnsIds.Rack],
|
97
|
-
render: ({row}) => row.Rack || '—',
|
98
|
-
align: DataTable.LEFT,
|
99
|
-
},
|
100
|
-
{
|
101
|
-
name: TableColumnsIds.Uptime,
|
102
|
-
header: tableColumnsNames[TableColumnsIds.Uptime],
|
103
|
-
width: 130,
|
104
|
-
sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
|
105
|
-
align: DataTable.RIGHT,
|
106
|
-
},
|
107
|
-
{
|
108
|
-
name: TableColumnsIds.Missing,
|
109
|
-
header: tableColumnsNames[TableColumnsIds.Missing],
|
110
|
-
width: 100,
|
111
|
-
align: DataTable.CENTER,
|
112
|
-
defaultOrder: DataTable.DESCENDING,
|
113
|
-
},
|
114
|
-
{
|
115
|
-
name: TableColumnsIds.PDisks,
|
116
|
-
className: b('pdisks-column'),
|
117
|
-
header: tableColumnsNames[TableColumnsIds.PDisks],
|
118
|
-
render: ({row}) => (
|
119
|
-
<div className={b('pdisks-wrapper')}>
|
120
|
-
{row.PDisks?.map((pDisk) => (
|
121
|
-
<div className={b('pdisks-item')} key={pDisk.PDiskId}>
|
122
|
-
<PDisk data={pDisk} nodeId={row.NodeId} />
|
123
|
-
</div>
|
124
|
-
))}
|
125
|
-
</div>
|
126
|
-
),
|
127
|
-
align: DataTable.CENTER,
|
128
|
-
sortable: false,
|
129
|
-
width: 900,
|
130
|
-
},
|
131
|
-
];
|
132
|
-
|
133
|
-
let columns = rawColumns.map((column) => ({
|
134
|
-
...column,
|
135
|
-
sortable: isSortableNodesProperty(column.name),
|
136
|
-
}));
|
137
|
-
|
138
|
-
if (visibleEntities !== VISIBLE_ENTITIES.missing) {
|
139
|
-
columns = columns.filter((col) => col.name !== TableColumnsIds.Missing);
|
140
|
-
}
|
141
|
-
|
142
|
-
if (!data.length) {
|
143
|
-
let message;
|
144
|
-
|
145
|
-
if (visibleEntities === VISIBLE_ENTITIES.space) {
|
146
|
-
message = i18n('empty.out_of_space');
|
147
|
-
}
|
148
|
-
|
149
|
-
if (visibleEntities === VISIBLE_ENTITIES.missing) {
|
150
|
-
message = i18n('empty.degraded');
|
151
|
-
}
|
152
|
-
|
153
|
-
if (nodesUptimeFilter === NodesUptimeFilterValues.SmallUptime) {
|
154
|
-
message = i18n('empty.small_uptime');
|
155
|
-
}
|
156
|
-
|
157
|
-
if (
|
158
|
-
visibleEntities !== VISIBLE_ENTITIES.all &&
|
159
|
-
nodesUptimeFilter !== NodesUptimeFilterValues.All
|
160
|
-
) {
|
161
|
-
message = i18n('empty.several_filters');
|
162
|
-
}
|
163
|
-
|
164
|
-
if (message) {
|
165
|
-
return <EmptyFilter title={message} showAll={i18n('show_all')} onShowAll={onShowAll} />;
|
166
|
-
}
|
38
|
+
const columns = getPreparedStorageNodesColumns(additionalNodesProps, visibleEntities);
|
39
|
+
|
40
|
+
if (
|
41
|
+
!data.length &&
|
42
|
+
(visibleEntities !== VISIBLE_ENTITIES.all ||
|
43
|
+
nodesUptimeFilter !== NodesUptimeFilterValues.All)
|
44
|
+
) {
|
45
|
+
return (
|
46
|
+
<StorageNodesEmptyDataMessage
|
47
|
+
visibleEntities={visibleEntities}
|
48
|
+
nodesUptimeFilter={nodesUptimeFilter}
|
49
|
+
onShowAll={onShowAll}
|
50
|
+
/>
|
51
|
+
);
|
167
52
|
}
|
168
53
|
|
169
|
-
return
|
54
|
+
return (
|
170
55
|
<DataTable
|
171
56
|
key={visibleEntities as string}
|
172
57
|
theme="yandex-cloud"
|
@@ -177,9 +62,9 @@ export function StorageNodes({
|
|
177
62
|
dynamicRenderType: 'variable',
|
178
63
|
}}
|
179
64
|
emptyDataMessage={i18n('empty.default')}
|
180
|
-
rowClassName={
|
65
|
+
rowClassName={getRowUnavailableClassName}
|
181
66
|
sortOrder={sort}
|
182
67
|
onSort={handleSort}
|
183
68
|
/>
|
184
|
-
)
|
69
|
+
);
|
185
70
|
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import type {VisibleEntities} from '../../../store/reducers/storage/types';
|
2
|
+
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
3
|
+
import {NodesUptimeFilterValues} from '../../../utils/nodes';
|
4
|
+
import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
|
5
|
+
import i18n from './i18n';
|
6
|
+
|
7
|
+
interface StorageNodesEmptyDataMessageProps {
|
8
|
+
visibleEntities: VisibleEntities;
|
9
|
+
nodesUptimeFilter: NodesUptimeFilterValues;
|
10
|
+
onShowAll?: VoidFunction;
|
11
|
+
}
|
12
|
+
|
13
|
+
export const StorageNodesEmptyDataMessage = ({
|
14
|
+
visibleEntities,
|
15
|
+
nodesUptimeFilter,
|
16
|
+
onShowAll,
|
17
|
+
}: StorageNodesEmptyDataMessageProps) => {
|
18
|
+
let message;
|
19
|
+
|
20
|
+
if (visibleEntities === VISIBLE_ENTITIES.space) {
|
21
|
+
message = i18n('empty.out_of_space');
|
22
|
+
}
|
23
|
+
|
24
|
+
if (visibleEntities === VISIBLE_ENTITIES.missing) {
|
25
|
+
message = i18n('empty.degraded');
|
26
|
+
}
|
27
|
+
|
28
|
+
if (nodesUptimeFilter === NodesUptimeFilterValues.SmallUptime) {
|
29
|
+
message = i18n('empty.small_uptime');
|
30
|
+
}
|
31
|
+
|
32
|
+
if (
|
33
|
+
visibleEntities !== VISIBLE_ENTITIES.all &&
|
34
|
+
nodesUptimeFilter !== NodesUptimeFilterValues.All
|
35
|
+
) {
|
36
|
+
message = i18n('empty.several_filters');
|
37
|
+
}
|
38
|
+
|
39
|
+
if (message) {
|
40
|
+
return <EmptyFilter title={message} showAll={i18n('show_all')} onShowAll={onShowAll} />;
|
41
|
+
}
|
42
|
+
|
43
|
+
return null;
|
44
|
+
};
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import {useCallback, useMemo} from 'react';
|
2
|
+
|
3
|
+
import type {AdditionalNodesProps} from '../../../types/additionalProps';
|
4
|
+
import {
|
5
|
+
getUptimeParamValue,
|
6
|
+
NodesUptimeFilterValues,
|
7
|
+
type NodesSortValue,
|
8
|
+
} from '../../../utils/nodes';
|
9
|
+
import {
|
10
|
+
VirtualTable,
|
11
|
+
type FetchData,
|
12
|
+
type RenderControls,
|
13
|
+
type RenderErrorMessage,
|
14
|
+
} from '../../../components/VirtualTable';
|
15
|
+
import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
|
16
|
+
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
17
|
+
|
18
|
+
import {StorageNodesEmptyDataMessage} from './StorageNodesEmptyDataMessage';
|
19
|
+
import {getPreparedStorageNodesColumns} from './getStorageNodesColumns';
|
20
|
+
import {getStorageNodes} from './getNodes';
|
21
|
+
import {getRowUnavailableClassName} from './shared';
|
22
|
+
import i18n from './i18n';
|
23
|
+
|
24
|
+
interface VirtualStorageNodesProps {
|
25
|
+
searchValue: string;
|
26
|
+
visibleEntities: VisibleEntities;
|
27
|
+
nodesUptimeFilter: NodesUptimeFilterValues;
|
28
|
+
tenant?: string;
|
29
|
+
|
30
|
+
additionalNodesProps?: AdditionalNodesProps;
|
31
|
+
onShowAll: VoidFunction;
|
32
|
+
|
33
|
+
parentContainer?: Element | null;
|
34
|
+
renderControls: RenderControls;
|
35
|
+
renderErrorMessage: RenderErrorMessage;
|
36
|
+
}
|
37
|
+
|
38
|
+
export const VirtualStorageNodes = ({
|
39
|
+
searchValue,
|
40
|
+
visibleEntities,
|
41
|
+
nodesUptimeFilter,
|
42
|
+
tenant,
|
43
|
+
additionalNodesProps,
|
44
|
+
onShowAll,
|
45
|
+
parentContainer,
|
46
|
+
renderControls,
|
47
|
+
renderErrorMessage,
|
48
|
+
}: VirtualStorageNodesProps) => {
|
49
|
+
const filters = useMemo(() => {
|
50
|
+
return [searchValue, visibleEntities, nodesUptimeFilter, tenant];
|
51
|
+
}, [searchValue, visibleEntities, nodesUptimeFilter, tenant]);
|
52
|
+
|
53
|
+
const fetchData = useCallback<FetchData<PreparedStorageNode>>(
|
54
|
+
async (limit, offset, {sortOrder, columnId} = {}) => {
|
55
|
+
return await getStorageNodes({
|
56
|
+
limit,
|
57
|
+
offset,
|
58
|
+
filter: searchValue,
|
59
|
+
uptime: getUptimeParamValue(nodesUptimeFilter),
|
60
|
+
visibleEntities,
|
61
|
+
tenant,
|
62
|
+
|
63
|
+
sortOrder,
|
64
|
+
sortValue: columnId as NodesSortValue,
|
65
|
+
});
|
66
|
+
},
|
67
|
+
[nodesUptimeFilter, searchValue, tenant, visibleEntities],
|
68
|
+
);
|
69
|
+
|
70
|
+
const columns = useMemo(() => {
|
71
|
+
return getPreparedStorageNodesColumns(additionalNodesProps, visibleEntities);
|
72
|
+
}, [additionalNodesProps, visibleEntities]);
|
73
|
+
|
74
|
+
const renderEmptyDataMessage = () => {
|
75
|
+
if (
|
76
|
+
visibleEntities !== VISIBLE_ENTITIES.all ||
|
77
|
+
nodesUptimeFilter !== NodesUptimeFilterValues.All
|
78
|
+
) {
|
79
|
+
return (
|
80
|
+
<StorageNodesEmptyDataMessage
|
81
|
+
onShowAll={onShowAll}
|
82
|
+
nodesUptimeFilter={nodesUptimeFilter}
|
83
|
+
visibleEntities={visibleEntities}
|
84
|
+
/>
|
85
|
+
);
|
86
|
+
}
|
87
|
+
|
88
|
+
return i18n('empty.default');
|
89
|
+
};
|
90
|
+
|
91
|
+
return (
|
92
|
+
<VirtualTable
|
93
|
+
parentContainer={parentContainer}
|
94
|
+
columns={columns}
|
95
|
+
fetchData={fetchData}
|
96
|
+
rowHeight={50}
|
97
|
+
limit={50}
|
98
|
+
renderControls={renderControls}
|
99
|
+
renderErrorMessage={renderErrorMessage}
|
100
|
+
renderEmptyDataMessage={renderEmptyDataMessage}
|
101
|
+
getRowClassName={getRowUnavailableClassName}
|
102
|
+
dependencyArray={filters}
|
103
|
+
/>
|
104
|
+
);
|
105
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import type {NodesApiRequestParams} from '../../../store/reducers/nodes/types';
|
2
|
+
import {prepareStorageNodesResponse} from '../../../store/reducers/storage/utils';
|
3
|
+
|
4
|
+
const getConcurrentId = (limit?: number, offset?: number) => {
|
5
|
+
return `getStorageNodes|offset${offset}|limit${limit}`;
|
6
|
+
};
|
7
|
+
|
8
|
+
export const getStorageNodes = async ({
|
9
|
+
type = 'static',
|
10
|
+
storage = true,
|
11
|
+
limit,
|
12
|
+
offset,
|
13
|
+
...params
|
14
|
+
}: NodesApiRequestParams) => {
|
15
|
+
const response = await window.api.getNodes(
|
16
|
+
{type, storage, limit, offset, ...params},
|
17
|
+
{concurrentId: getConcurrentId(limit, offset)},
|
18
|
+
);
|
19
|
+
const preparedResponse = prepareStorageNodesResponse(response);
|
20
|
+
|
21
|
+
return {
|
22
|
+
data: preparedResponse.nodes || [],
|
23
|
+
found: preparedResponse.found || 0,
|
24
|
+
total: preparedResponse.total || 0,
|
25
|
+
};
|
26
|
+
};
|
@@ -0,0 +1,125 @@
|
|
1
|
+
import DataTable, {type Column as DataTableColumn} from '@gravity-ui/react-data-table';
|
2
|
+
|
3
|
+
import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
|
4
|
+
import type {AdditionalNodesProps} from '../../../types/additionalProps';
|
5
|
+
import type {Column as VirtualTableColumn} from '../../../components/VirtualTable';
|
6
|
+
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
|
7
|
+
import {NodeHostWrapper} from '../../../components/NodeHostWrapper/NodeHostWrapper';
|
8
|
+
import {isSortableNodesProperty} from '../../../utils/nodes';
|
9
|
+
|
10
|
+
import {PDisk} from '../PDisk/PDisk';
|
11
|
+
import {b} from './shared';
|
12
|
+
|
13
|
+
export const STORAGE_NODES_COLUMNS_IDS = {
|
14
|
+
NodeId: 'NodeId',
|
15
|
+
Host: 'Host',
|
16
|
+
DC: 'DC',
|
17
|
+
Rack: 'Rack',
|
18
|
+
Uptime: 'Uptime',
|
19
|
+
PDisks: 'PDisks',
|
20
|
+
Missing: 'Missing',
|
21
|
+
} as const;
|
22
|
+
|
23
|
+
type StorageGroupsColumn = VirtualTableColumn<PreparedStorageNode> &
|
24
|
+
DataTableColumn<PreparedStorageNode>;
|
25
|
+
|
26
|
+
const getStorageNodesColumns = (additionalNodesProps: AdditionalNodesProps | undefined) => {
|
27
|
+
const getNodeRef = additionalNodesProps?.getNodeRef;
|
28
|
+
|
29
|
+
const columns: StorageGroupsColumn[] = [
|
30
|
+
{
|
31
|
+
name: STORAGE_NODES_COLUMNS_IDS.NodeId,
|
32
|
+
header: 'Node ID',
|
33
|
+
width: 100,
|
34
|
+
align: DataTable.RIGHT,
|
35
|
+
render: ({row}) => row.NodeId,
|
36
|
+
},
|
37
|
+
{
|
38
|
+
name: STORAGE_NODES_COLUMNS_IDS.Host,
|
39
|
+
header: 'Host',
|
40
|
+
width: 350,
|
41
|
+
render: ({row}) => {
|
42
|
+
return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
|
43
|
+
},
|
44
|
+
align: DataTable.LEFT,
|
45
|
+
},
|
46
|
+
{
|
47
|
+
name: STORAGE_NODES_COLUMNS_IDS.DC,
|
48
|
+
header: 'DC',
|
49
|
+
width: 100,
|
50
|
+
render: ({row}) => row.DataCenter || '—',
|
51
|
+
align: DataTable.LEFT,
|
52
|
+
},
|
53
|
+
{
|
54
|
+
name: STORAGE_NODES_COLUMNS_IDS.Rack,
|
55
|
+
header: 'Rack',
|
56
|
+
width: 100,
|
57
|
+
render: ({row}) => row.Rack || '—',
|
58
|
+
align: DataTable.LEFT,
|
59
|
+
},
|
60
|
+
{
|
61
|
+
name: STORAGE_NODES_COLUMNS_IDS.Uptime,
|
62
|
+
header: 'Uptime',
|
63
|
+
width: 130,
|
64
|
+
sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
|
65
|
+
align: DataTable.RIGHT,
|
66
|
+
render: ({row}) => row.Uptime,
|
67
|
+
},
|
68
|
+
{
|
69
|
+
name: STORAGE_NODES_COLUMNS_IDS.Missing,
|
70
|
+
header: 'Missing',
|
71
|
+
width: 100,
|
72
|
+
align: DataTable.CENTER,
|
73
|
+
defaultOrder: DataTable.DESCENDING,
|
74
|
+
render: ({row}) => row.Missing,
|
75
|
+
},
|
76
|
+
{
|
77
|
+
name: STORAGE_NODES_COLUMNS_IDS.PDisks,
|
78
|
+
className: b('pdisks-column'),
|
79
|
+
header: 'PDisks',
|
80
|
+
render: ({row}) => {
|
81
|
+
return (
|
82
|
+
<div className={b('pdisks-wrapper')}>
|
83
|
+
{row.PDisks?.map((pDisk) => {
|
84
|
+
const vDisks = row.VDisks?.filter(
|
85
|
+
(vdisk) => vdisk.PDiskId === pDisk.PDiskId,
|
86
|
+
).map((data) => ({
|
87
|
+
...data,
|
88
|
+
NodeId: row.NodeId,
|
89
|
+
}));
|
90
|
+
|
91
|
+
return (
|
92
|
+
<div className={b('pdisks-item')} key={pDisk.PDiskId}>
|
93
|
+
<PDisk data={pDisk} nodeId={row.NodeId} vDisks={vDisks} />
|
94
|
+
</div>
|
95
|
+
);
|
96
|
+
})}
|
97
|
+
</div>
|
98
|
+
);
|
99
|
+
},
|
100
|
+
align: DataTable.CENTER,
|
101
|
+
sortable: false,
|
102
|
+
width: 900,
|
103
|
+
},
|
104
|
+
];
|
105
|
+
|
106
|
+
return columns;
|
107
|
+
};
|
108
|
+
|
109
|
+
export const getPreparedStorageNodesColumns = (
|
110
|
+
additionalNodesProps: AdditionalNodesProps | undefined,
|
111
|
+
visibleEntities: VisibleEntities,
|
112
|
+
) => {
|
113
|
+
const rawColumns = getStorageNodesColumns(additionalNodesProps);
|
114
|
+
|
115
|
+
const sortableColumns = rawColumns.map((column) => ({
|
116
|
+
...column,
|
117
|
+
sortable: isSortableNodesProperty(column.name),
|
118
|
+
}));
|
119
|
+
|
120
|
+
if (visibleEntities !== VISIBLE_ENTITIES.missing) {
|
121
|
+
return sortableColumns.filter((col) => col.name !== STORAGE_NODES_COLUMNS_IDS.Missing);
|
122
|
+
}
|
123
|
+
|
124
|
+
return sortableColumns;
|
125
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import cn from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import type {PreparedStorageNode} from '../../../store/reducers/storage/types';
|
4
|
+
import {isUnavailableNode} from '../../../utils/nodes';
|
5
|
+
|
6
|
+
export const b = cn('global-storage-nodes');
|
7
|
+
|
8
|
+
export const getRowUnavailableClassName = (row: PreparedStorageNode) =>
|
9
|
+
b('node', {unavailable: isUnavailableNode(row)});
|
package/dist/containers/Storage/StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx
CHANGED
@@ -11,7 +11,7 @@ export const VisibleEntitiesTitles = {
|
|
11
11
|
|
12
12
|
interface StorageProblemFilterProps {
|
13
13
|
value: VisibleEntities;
|
14
|
-
onChange: (value:
|
14
|
+
onChange: (value: VisibleEntities) => void;
|
15
15
|
}
|
16
16
|
|
17
17
|
const storageVisibleEntitiesFilterQa = 'storage-visible-entities-filter';
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import type {AdditionalNodesProps} from '../../types/additionalProps';
|
2
|
+
import {USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../../utils/constants';
|
3
|
+
import {useSetting} from '../../utils/hooks';
|
4
|
+
|
5
|
+
import {VirtualStorage} from './VirtualStorage';
|
6
|
+
import {Storage} from './Storage';
|
7
|
+
|
8
|
+
interface StorageWrapperProps {
|
9
|
+
tenant?: string;
|
10
|
+
nodeId?: string;
|
11
|
+
parentContainer?: Element | null;
|
12
|
+
additionalNodesProps?: AdditionalNodesProps;
|
13
|
+
}
|
14
|
+
|
15
|
+
export const StorageWrapper = ({parentContainer, ...props}: StorageWrapperProps) => {
|
16
|
+
const [useVirtualTable] = useSetting<boolean>(USE_BACKEND_PARAMS_FOR_TABLES_KEY);
|
17
|
+
|
18
|
+
if (useVirtualTable) {
|
19
|
+
return <VirtualStorage parentContainer={parentContainer} {...props} />;
|
20
|
+
}
|
21
|
+
|
22
|
+
return <Storage {...props} />;
|
23
|
+
};
|
@@ -10,7 +10,7 @@ import {getUsageSeverityForEntityStatus} from '../utils';
|
|
10
10
|
import i18n from './i18n';
|
11
11
|
import './UsageFilter.scss';
|
12
12
|
|
13
|
-
interface UsageFilterItem {
|
13
|
+
export interface UsageFilterItem {
|
14
14
|
threshold: number;
|
15
15
|
count: number;
|
16
16
|
}
|
@@ -21,13 +21,12 @@ interface UsageFilterProps {
|
|
21
21
|
groups?: UsageFilterItem[];
|
22
22
|
onChange?: (value: string[]) => void;
|
23
23
|
debounce?: number;
|
24
|
-
disabled?: boolean;
|
25
24
|
}
|
26
25
|
|
27
26
|
const b = cn('usage-filter');
|
28
27
|
|
29
28
|
export const UsageFilter = (props: UsageFilterProps) => {
|
30
|
-
const {className, value = [], groups = [], onChange, debounce = 200
|
29
|
+
const {className, value = [], groups = [], onChange, debounce = 200} = props;
|
31
30
|
|
32
31
|
const [filterValue, setFilterValue] = useState(value);
|
33
32
|
const timer = useRef<number>();
|
@@ -94,7 +93,7 @@ export const UsageFilter = (props: UsageFilterProps) => {
|
|
94
93
|
renderOption={renderOption}
|
95
94
|
getOptionHeight={() => 50}
|
96
95
|
popupWidth={280}
|
97
|
-
disabled={
|
96
|
+
disabled={groups.length === 0}
|
98
97
|
/>
|
99
98
|
);
|
100
99
|
};
|