ydb-embedded-ui 4.27.1 → 4.28.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/EmptyState/EmptyState.scss +5 -2
  3. package/dist/components/EmptyState/EmptyState.tsx +11 -3
  4. package/dist/components/Errors/403/AccessDenied.tsx +4 -3
  5. package/dist/components/ProblemFilter/ProblemFilter.tsx +1 -1
  6. package/dist/components/UptimeFIlter/UptimeFilter.tsx +1 -1
  7. package/dist/components/VirtualTable/VirtualTable.scss +1 -1
  8. package/dist/containers/Cluster/Cluster.tsx +11 -12
  9. package/dist/containers/Nodes/Nodes.tsx +4 -4
  10. package/dist/containers/Nodes/NodesWrapper.tsx +21 -0
  11. package/dist/containers/Nodes/VirtualNodes.tsx +4 -14
  12. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +1 -0
  13. package/dist/containers/Storage/EmptyFilter/EmptyFilter.tsx +1 -0
  14. package/dist/containers/Storage/PDisk/PDisk.tsx +5 -7
  15. package/dist/containers/Storage/Storage.tsx +30 -67
  16. package/dist/containers/Storage/StorageControls/StorageControls.tsx +104 -0
  17. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +18 -62
  18. package/dist/containers/Storage/StorageGroups/StorageGroupsEmptyDataMessage.tsx +30 -0
  19. package/dist/containers/Storage/StorageGroups/VirtualStorageGroups.tsx +94 -0
  20. package/dist/containers/Storage/StorageGroups/getGroups.ts +21 -0
  21. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +73 -50
  22. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -138
  23. package/dist/containers/Storage/StorageNodes/StorageNodesEmptyDataMessage.tsx +44 -0
  24. package/dist/containers/Storage/StorageNodes/VirtualStorageNodes.tsx +105 -0
  25. package/dist/containers/Storage/StorageNodes/getNodes.ts +26 -0
  26. package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.tsx +125 -0
  27. package/dist/containers/Storage/StorageNodes/shared.ts +9 -0
  28. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +1 -1
  29. package/dist/containers/Storage/StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx +1 -1
  30. package/dist/containers/Storage/StorageWrapper.tsx +23 -0
  31. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +3 -4
  32. package/dist/containers/Storage/VirtualStorage.tsx +112 -0
  33. package/dist/containers/Storage/i18n/en.json +7 -0
  34. package/dist/containers/Storage/i18n/index.ts +11 -0
  35. package/dist/containers/Storage/i18n/ru.json +7 -0
  36. package/dist/containers/Storage/shared.ts +3 -0
  37. package/dist/containers/Tenants/Tenants.tsx +2 -2
  38. package/dist/containers/UserSettings/i18n/en.json +2 -2
  39. package/dist/containers/UserSettings/i18n/ru.json +2 -2
  40. package/dist/containers/UserSettings/settings.ts +4 -4
  41. package/dist/store/reducers/storage/selectors.ts +0 -20
  42. package/package.json +6 -6
@@ -1,62 +1,30 @@
1
- import cn from 'bem-cn-lite';
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 {EmptyFilter} from '../EmptyFilter/EmptyFilter';
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: keyof typeof NodesUptimeFilterValues;
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 getNodeRef = additionalNodesProps?.getNodeRef;
71
-
72
- const rawColumns: Column<PreparedStorageNode>[] = [
73
- {
74
- name: TableColumnsIds.NodeId,
75
- header: tableColumnsNames[TableColumnsIds.NodeId],
76
- width: 100,
77
- align: DataTable.RIGHT,
78
- },
79
- {
80
- name: TableColumnsIds.Host,
81
- header: tableColumnsNames[TableColumnsIds.Host],
82
- width: 350,
83
- render: ({row}) => {
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 data ? (
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={(row) => b('node', {unavailable: isUnavailableNode(row)})}
65
+ rowClassName={getRowUnavailableClassName}
181
66
  sortOrder={sort}
182
67
  onSort={handleSort}
183
68
  />
184
- ) : null;
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)});
@@ -10,7 +10,7 @@ const StorageTypesTitles = {
10
10
 
11
11
  interface StorageTypeFilterProps {
12
12
  value: StorageType;
13
- onChange: (value: string) => void;
13
+ onChange: (value: StorageType) => void;
14
14
  }
15
15
 
16
16
  const storageTypeFilterQa = 'storage-type-filter';
@@ -11,7 +11,7 @@ export const VisibleEntitiesTitles = {
11
11
 
12
12
  interface StorageProblemFilterProps {
13
13
  value: VisibleEntities;
14
- onChange: (value: string) => void;
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, disabled} = props;
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={disabled}
96
+ disabled={groups.length === 0}
98
97
  />
99
98
  );
100
99
  };