Skip to content

Commit 12630dd

Browse files
chore: get rid of old nodes tables (#1678)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent a46ebbe commit 12630dd

File tree

8 files changed

+245
-388
lines changed

8 files changed

+245
-388
lines changed

src/containers/Cluster/Cluster.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import type {
2626
import {cn} from '../../utils/cn';
2727
import {useTypedDispatch, useTypedSelector} from '../../utils/hooks';
2828
import {parseVersionsToVersionToColorMap} from '../../utils/versions';
29-
import {NodesWrapper} from '../Nodes/NodesWrapper';
29+
import {Nodes} from '../Nodes/Nodes';
3030
import {StorageWrapper} from '../Storage/StorageWrapper';
3131
import {TabletsTable} from '../Tablets/TabletsTable';
3232
import {Tenants} from '../Tenants/Tenants';
@@ -192,10 +192,7 @@ export function Cluster({
192192
<Route
193193
path={getLocationObjectFromHref(getClusterPath(clusterTabsIds.nodes)).pathname}
194194
>
195-
<NodesWrapper
196-
parentRef={container}
197-
additionalNodesProps={additionalNodesProps}
198-
/>
195+
<Nodes parentRef={container} additionalNodesProps={additionalNodesProps} />
199196
</Route>
200197
<Route
201198
path={

src/containers/Nodes/Nodes.tsx

Lines changed: 234 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,283 @@
11
import React from 'react';
22

3-
import {ASCENDING} from '@gravity-ui/react-data-table/build/esm/lib/constants';
4-
5-
import {AccessDenied} from '../../components/Errors/403';
6-
import {isAccessError} from '../../components/Errors/PageError/PageError';
73
import {ResponseError} from '../../components/Errors/ResponseError';
8-
import {Illustration} from '../../components/Illustration';
9-
import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable';
4+
import {LoaderWrapper} from '../../components/LoaderWrapper/LoaderWrapper';
5+
import type {Column, RenderControls} from '../../components/PaginatedTable';
106
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
11-
import {NODES_COLUMNS_WIDTH_LS_KEY} from '../../components/nodesColumns/constants';
7+
import {NODES_COLUMNS_TITLES} from '../../components/nodesColumns/constants';
8+
import type {NodesColumnId} from '../../components/nodesColumns/constants';
9+
import {
10+
useCapabilitiesLoaded,
11+
useViewerNodesHandlerHasGrouping,
12+
} from '../../store/reducers/capabilities/hooks';
1213
import {nodesApi} from '../../store/reducers/nodes/nodes';
13-
import {filterNodes} from '../../store/reducers/nodes/selectors';
14-
import type {NodesSortParams} from '../../store/reducers/nodes/types';
14+
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
1515
import {useProblemFilter} from '../../store/reducers/settings/hooks';
1616
import type {AdditionalNodesProps} from '../../types/additionalProps';
17-
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
18-
import {useAutoRefreshInterval, useTableSort} from '../../utils/hooks';
17+
import type {NodesGroupByField} from '../../types/api/nodes';
18+
import {useAutoRefreshInterval} from '../../utils/hooks';
19+
import {useSelectedColumns} from '../../utils/hooks/useSelectedColumns';
1920
import {NodesUptimeFilterValues} from '../../utils/nodes';
21+
import {TableGroup} from '../Storage/TableGroup/TableGroup';
22+
import {useExpandedGroups} from '../Storage/TableGroup/useExpandedTableGroups';
2023

2124
import {NodesControls} from './NodesControls/NodesControls';
22-
import {useNodesSelectedColumns} from './columns/hooks';
25+
import {NodesTable} from './NodesTable';
26+
import {getNodesColumns} from './columns/columns';
27+
import {
28+
ALL_NODES_GROUP_BY_PARAMS,
29+
DEFAULT_NODES_COLUMNS,
30+
NODES_TABLE_SELECTED_COLUMNS_LS_KEY,
31+
REQUIRED_NODES_COLUMNS,
32+
} from './columns/constants';
2333
import i18n from './i18n';
24-
import {getRowClassName} from './shared';
34+
import {b} from './shared';
2535
import {useNodesPageQueryParams} from './useNodesPageQueryParams';
2636

2737
import './Nodes.scss';
2838

29-
interface NodesProps {
39+
export interface NodesProps {
3040
path?: string;
3141
database?: string;
42+
parentRef: React.RefObject<HTMLElement>;
3243
additionalNodesProps?: AdditionalNodesProps;
44+
45+
columns?: Column<NodesPreparedEntity>[];
46+
defaultColumnsIds?: NodesColumnId[];
47+
requiredColumnsIds?: NodesColumnId[];
48+
selectedColumnsKey?: string;
49+
groupByParams?: NodesGroupByField[];
3350
}
3451

35-
export const Nodes = ({path, database, additionalNodesProps = {}}: NodesProps) => {
36-
const {searchValue, uptimeFilter} = useNodesPageQueryParams(undefined);
37-
const {problemFilter} = useProblemFilter();
52+
export function Nodes({
53+
path,
54+
database,
55+
parentRef,
56+
additionalNodesProps,
57+
columns = getNodesColumns({database, getNodeRef: additionalNodesProps?.getNodeRef}),
58+
defaultColumnsIds = DEFAULT_NODES_COLUMNS,
59+
requiredColumnsIds = REQUIRED_NODES_COLUMNS,
60+
selectedColumnsKey = NODES_TABLE_SELECTED_COLUMNS_LS_KEY,
61+
groupByParams = ALL_NODES_GROUP_BY_PARAMS,
62+
}: NodesProps) {
63+
const {uptimeFilter, groupByParam, handleUptimeFilterChange} =
64+
useNodesPageQueryParams(groupByParams);
65+
const {problemFilter, handleProblemFilterChange} = useProblemFilter();
3866

39-
const [autoRefreshInterval] = useAutoRefreshInterval();
67+
const capabilitiesLoaded = useCapabilitiesLoaded();
68+
const viewerNodesHandlerHasGrouping = useViewerNodesHandlerHasGrouping();
4069

41-
const {columnsToShow, columnsToSelect, setColumns} = useNodesSelectedColumns({
42-
getNodeRef: additionalNodesProps.getNodeRef,
43-
database,
44-
});
70+
// Other filters do not fit with grouping
71+
// Reset them if grouping available
72+
React.useEffect(() => {
73+
if (
74+
viewerNodesHandlerHasGrouping &&
75+
(problemFilter !== 'All' || uptimeFilter !== NodesUptimeFilterValues.All)
76+
) {
77+
handleProblemFilterChange('All');
78+
handleUptimeFilterChange(NodesUptimeFilterValues.All);
79+
}
80+
}, [
81+
handleProblemFilterChange,
82+
handleUptimeFilterChange,
83+
problemFilter,
84+
uptimeFilter,
85+
viewerNodesHandlerHasGrouping,
86+
]);
4587

46-
const {
47-
currentData: data,
48-
isLoading,
49-
error,
50-
} = nodesApi.useGetNodesQuery({path, database}, {pollingInterval: autoRefreshInterval});
88+
const renderContent = () => {
89+
if (viewerNodesHandlerHasGrouping && groupByParam) {
90+
return (
91+
<GroupedNodesComponent
92+
path={path}
93+
database={database}
94+
parentRef={parentRef}
95+
columns={columns}
96+
defaultColumnsIds={defaultColumnsIds}
97+
requiredColumnsIds={requiredColumnsIds}
98+
selectedColumnsKey={selectedColumnsKey}
99+
groupByParams={groupByParams}
100+
/>
101+
);
102+
}
51103

52-
const [sortValue, setSortValue] = React.useState<NodesSortParams>({
53-
sortValue: 'NodeId',
54-
sortOrder: ASCENDING,
55-
});
56-
const [sort, handleSort] = useTableSort(sortValue, (sortParams) => {
57-
setSortValue(sortParams as NodesSortParams);
58-
});
104+
return (
105+
<NodesComponent
106+
path={path}
107+
database={database}
108+
parentRef={parentRef}
109+
columns={columns}
110+
defaultColumnsIds={defaultColumnsIds}
111+
requiredColumnsIds={requiredColumnsIds}
112+
selectedColumnsKey={selectedColumnsKey}
113+
groupByParams={groupByParams}
114+
/>
115+
);
116+
};
59117

60-
const nodes = React.useMemo(() => {
61-
return filterNodes(data?.Nodes, {searchValue, uptimeFilter, problemFilter});
62-
}, [data, searchValue, uptimeFilter, problemFilter]);
118+
return <LoaderWrapper loading={!capabilitiesLoaded}>{renderContent()}</LoaderWrapper>;
119+
}
63120

64-
const totalNodes = data?.TotalNodes || 0;
121+
interface NodesComponentProps {
122+
path?: string;
123+
database?: string;
124+
parentRef: React.RefObject<HTMLElement>;
65125

66-
const renderControls = () => {
126+
columns: Column<NodesPreparedEntity>[];
127+
defaultColumnsIds: NodesColumnId[];
128+
requiredColumnsIds: NodesColumnId[];
129+
selectedColumnsKey: string;
130+
groupByParams: NodesGroupByField[];
131+
}
132+
133+
function NodesComponent({
134+
path,
135+
database,
136+
parentRef,
137+
columns,
138+
defaultColumnsIds,
139+
requiredColumnsIds,
140+
selectedColumnsKey,
141+
groupByParams,
142+
}: NodesComponentProps) {
143+
const {searchValue, uptimeFilter} = useNodesPageQueryParams(groupByParams);
144+
const {problemFilter} = useProblemFilter();
145+
const viewerNodesHandlerHasGrouping = useViewerNodesHandlerHasGrouping();
146+
147+
const {columnsToShow, columnsToSelect, setColumns} = useSelectedColumns(
148+
columns,
149+
selectedColumnsKey,
150+
NODES_COLUMNS_TITLES,
151+
defaultColumnsIds,
152+
requiredColumnsIds,
153+
);
154+
155+
const renderControls: RenderControls = ({totalEntities, foundEntities, inited}) => {
67156
return (
68157
<NodesControls
158+
withGroupBySelect={viewerNodesHandlerHasGrouping}
159+
groupByParams={groupByParams}
69160
columnsToSelect={columnsToSelect}
70161
handleSelectedColumnsUpdate={setColumns}
71-
entitiesCountCurrent={nodes.length}
72-
entitiesCountTotal={totalNodes}
73-
entitiesLoading={isLoading}
74-
groupByParams={undefined}
162+
entitiesCountCurrent={foundEntities}
163+
entitiesCountTotal={totalEntities}
164+
entitiesLoading={!inited}
75165
/>
76166
);
77167
};
78168

79-
const renderTable = () => {
80-
if (nodes.length === 0) {
81-
if (problemFilter !== 'All' || uptimeFilter !== NodesUptimeFilterValues.All) {
82-
return <Illustration name="thumbsUp" width="200" />;
83-
}
84-
}
169+
return (
170+
<NodesTable
171+
path={path}
172+
database={database}
173+
searchValue={searchValue}
174+
problemFilter={problemFilter}
175+
uptimeFilter={uptimeFilter}
176+
columns={columnsToShow}
177+
parentRef={parentRef}
178+
renderControls={renderControls}
179+
/>
180+
);
181+
}
182+
183+
function GroupedNodesComponent({
184+
path,
185+
database,
186+
parentRef,
187+
columns,
188+
defaultColumnsIds,
189+
requiredColumnsIds,
190+
selectedColumnsKey,
191+
groupByParams,
192+
}: NodesComponentProps) {
193+
const {searchValue, groupByParam} = useNodesPageQueryParams(groupByParams);
194+
const [autoRefreshInterval] = useAutoRefreshInterval();
195+
196+
const {columnsToShow, columnsToSelect, setColumns} = useSelectedColumns(
197+
columns,
198+
selectedColumnsKey,
199+
NODES_COLUMNS_TITLES,
200+
defaultColumnsIds,
201+
requiredColumnsIds,
202+
);
203+
204+
const {currentData, isFetching, error} = nodesApi.useGetNodesQuery(
205+
{
206+
path,
207+
database,
208+
filter: searchValue,
209+
group: groupByParam,
210+
limit: 0,
211+
},
212+
{
213+
pollingInterval: autoRefreshInterval,
214+
},
215+
);
216+
217+
const isLoading = currentData === undefined && isFetching;
218+
const {
219+
NodeGroups: tableGroups,
220+
FoundNodes: found = 0,
221+
TotalNodes: total = 0,
222+
} = currentData || {};
85223

224+
const {expandedGroups, setIsGroupExpanded} = useExpandedGroups(tableGroups);
225+
226+
const renderControls = () => {
86227
return (
87-
<ResizeableDataTable
88-
columnsWidthLSKey={NODES_COLUMNS_WIDTH_LS_KEY}
89-
data={nodes || []}
90-
columns={columnsToShow}
91-
settings={DEFAULT_TABLE_SETTINGS}
92-
sortOrder={sort}
93-
onSort={handleSort}
94-
emptyDataMessage={i18n('empty.default')}
95-
rowClassName={getRowClassName}
228+
<NodesControls
229+
withGroupBySelect
230+
groupByParams={groupByParams}
231+
columnsToSelect={columnsToSelect}
232+
handleSelectedColumnsUpdate={setColumns}
233+
entitiesCountCurrent={found}
234+
entitiesCountTotal={total}
235+
entitiesLoading={isLoading}
96236
/>
97237
);
98238
};
99239

100-
if (isAccessError(error)) {
101-
return <AccessDenied />;
102-
}
240+
const renderGroups = () => {
241+
if (tableGroups?.length) {
242+
return tableGroups.map(({name, count}) => {
243+
const isExpanded = expandedGroups[name];
244+
245+
return (
246+
<TableGroup
247+
key={name}
248+
title={name}
249+
count={count}
250+
entityName={i18n('nodes')}
251+
expanded={isExpanded}
252+
onIsExpandedChange={setIsGroupExpanded}
253+
>
254+
<NodesTable
255+
path={path}
256+
database={database}
257+
searchValue={searchValue}
258+
problemFilter={'All'}
259+
uptimeFilter={NodesUptimeFilterValues.All}
260+
filterGroup={name}
261+
filterGroupBy={groupByParam}
262+
initialEntitiesCount={count}
263+
columns={columnsToShow}
264+
parentRef={parentRef}
265+
/>
266+
</TableGroup>
267+
);
268+
});
269+
}
270+
271+
return i18n('no-nodes-groups');
272+
};
103273

104274
return (
105275
<TableWithControlsLayout>
106276
<TableWithControlsLayout.Controls>{renderControls()}</TableWithControlsLayout.Controls>
107277
{error ? <ResponseError error={error} /> : null}
108-
<TableWithControlsLayout.Table loading={isLoading}>
109-
{data ? renderTable() : null}
278+
<TableWithControlsLayout.Table loading={isLoading} className={b('groups-wrapper')}>
279+
{renderGroups()}
110280
</TableWithControlsLayout.Table>
111281
</TableWithControlsLayout>
112282
);
113-
};
283+
}

src/containers/Nodes/PaginatedNodesTable.tsx renamed to src/containers/Nodes/NodesTable.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {getNodes} from './getNodes';
1414
import i18n from './i18n';
1515
import {getRowClassName, renderPaginatedTableErrorMessage} from './shared';
1616

17-
interface PaginatedNodesTableProps {
17+
interface NodesTableProps {
1818
path?: string;
1919
database?: string;
2020

@@ -32,7 +32,7 @@ interface PaginatedNodesTableProps {
3232
initialEntitiesCount?: number;
3333
}
3434

35-
export function PaginatedNodesTable({
35+
export function NodesTable({
3636
path,
3737
database,
3838
searchValue,
@@ -44,7 +44,7 @@ export function PaginatedNodesTable({
4444
parentRef,
4545
renderControls,
4646
initialEntitiesCount,
47-
}: PaginatedNodesTableProps) {
47+
}: NodesTableProps) {
4848
const tableFilters = React.useMemo(() => {
4949
return {
5050
path,

0 commit comments

Comments
 (0)