Skip to content

Commit a16b0be

Browse files
feat(PaginatedStorage): add grouping
1 parent 960e97f commit a16b0be

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+977
-664
lines changed

src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import './PaginatedTable.scss';
2525

2626
export interface PaginatedTableProps<T, F> {
2727
limit: number;
28+
initialEntitiesCount?: number;
2829
fetchData: FetchData<T, F>;
2930
filters?: F;
3031
tableName: string;
@@ -42,6 +43,7 @@ export interface PaginatedTableProps<T, F> {
4243

4344
export const PaginatedTable = <T, F>({
4445
limit,
46+
initialEntitiesCount,
4547
fetchData,
4648
filters,
4749
tableName,
@@ -56,9 +58,12 @@ export const PaginatedTable = <T, F>({
5658
renderEmptyDataMessage,
5759
containerClassName,
5860
}: PaginatedTableProps<T, F>) => {
61+
const initialTotal = initialEntitiesCount || limit;
62+
const initialFound = initialEntitiesCount || 0;
63+
5964
const [sortParams, setSortParams] = React.useState<SortParams | undefined>(initialSortParams);
60-
const [totalEntities, setTotalEntities] = React.useState(limit);
61-
const [foundEntities, setFoundEntities] = React.useState(0);
65+
const [totalEntities, setTotalEntities] = React.useState(initialTotal);
66+
const [foundEntities, setFoundEntities] = React.useState(initialFound);
6267
const [activeChunks, setActiveChunks] = React.useState<number[]>([]);
6368
const [isInitialLoad, setIsInitialLoad] = React.useState(true);
6469

@@ -82,8 +87,8 @@ export const PaginatedTable = <T, F>({
8287

8388
// reset table on filters change
8489
React.useLayoutEffect(() => {
85-
setTotalEntities(limit);
86-
setFoundEntities(0);
90+
setTotalEntities(initialTotal);
91+
setFoundEntities(initialFound);
8792
setIsInitialLoad(true);
8893
if (parentContainer) {
8994
parentContainer.scrollTo(0, 0);
@@ -92,7 +97,7 @@ export const PaginatedTable = <T, F>({
9297
}
9398

9499
setActiveChunks([0]);
95-
}, [filters, limit, parentContainer]);
100+
}, [filters, initialFound, initialTotal, limit, parentContainer]);
96101

97102
const renderChunks = () => {
98103
if (!observer) {
@@ -117,6 +122,7 @@ export const PaginatedTable = <T, F>({
117122
key={value}
118123
id={value}
119124
limit={limit}
125+
totalLength={totalLength}
120126
rowHeight={rowHeight}
121127
columns={columns}
122128
fetchData={fetchData}

src/components/PaginatedTable/TableChunk.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const typedMemo: <T>(Component: T) => T = React.memo;
1717
interface TableChunkProps<T, F> {
1818
id: number;
1919
limit: number;
20+
totalLength: number;
2021
rowHeight: number;
2122
columns: Column<T>[];
2223
filters?: F;
@@ -35,6 +36,7 @@ interface TableChunkProps<T, F> {
3536
export const TableChunk = typedMemo(function TableChunk<T, F>({
3637
id,
3738
limit,
39+
totalLength,
3840
rowHeight,
3941
columns,
4042
fetchData,
@@ -101,7 +103,11 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
101103
}
102104
}, [currentData, isActive, onDataFetched]);
103105

104-
const dataLength = currentData?.data?.length || limit;
106+
const chunkOffset = id * limit;
107+
const remainingLenght = totalLength - chunkOffset;
108+
const calculatedChunkLength = remainingLenght < limit ? remainingLenght : limit;
109+
110+
const dataLength = currentData?.data?.length || calculatedChunkLength;
105111

106112
const renderContent = () => {
107113
if (!isActive) {

src/components/TableSkeleton/TableSkeleton.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
.table-skeleton {
2-
width: 100%;
2+
&__wrapper {
3+
width: 100%;
4+
5+
&_hidden {
6+
visibility: hidden;
7+
}
8+
}
39

410
&__row {
511
display: flex;
Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Skeleton} from '@gravity-ui/uikit';
22

33
import {cn} from '../../utils/cn';
4+
import {useDelayed} from '../../utils/hooks/useDelayed';
45

56
import './TableSkeleton.scss';
67

@@ -9,21 +10,26 @@ const b = cn('table-skeleton');
910
interface TableSkeletonProps {
1011
className?: string;
1112
rows?: number;
13+
delay?: number;
1214
}
1315

14-
export const TableSkeleton = ({rows = 2, className}: TableSkeletonProps) => (
15-
<div className={b(null, className)}>
16-
<div className={b('row')}>
17-
<Skeleton className={b('col-1')} />
18-
<Skeleton className={b('col-2')} />
19-
<Skeleton className={b('col-3')} />
20-
<Skeleton className={b('col-4')} />
21-
<Skeleton className={b('col-5')} />
22-
</div>
23-
{[...new Array(rows)].map((_, index) => (
24-
<div className={b('row')} key={`skeleton-row-${index}`}>
25-
<Skeleton className={b('col-full')} />
16+
export const TableSkeleton = ({rows = 2, delay = 600, className}: TableSkeletonProps) => {
17+
const [show] = useDelayed(delay);
18+
19+
return (
20+
<div className={b('wrapper', {hidden: !show}, className)}>
21+
<div className={b('row')}>
22+
<Skeleton className={b('col-1')} />
23+
<Skeleton className={b('col-2')} />
24+
<Skeleton className={b('col-3')} />
25+
<Skeleton className={b('col-4')} />
26+
<Skeleton className={b('col-5')} />
2627
</div>
27-
))}
28-
</div>
29-
);
28+
{[...new Array(rows)].map((_, index) => (
29+
<div className={b('row')} key={`skeleton-row-${index}`}>
30+
<Skeleton className={b('col-full')} />
31+
</div>
32+
))}
33+
</div>
34+
);
35+
};

src/containers/Cluster/Cluster.scss

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
@import '../../styles/mixins.scss';
22

33
.cluster {
4+
position: relative;
5+
46
overflow: auto;
5-
flex-grow: 1;
67

78
height: 100%;
89
padding: 0 20px;
910

10-
@include flex-container();
11-
1211
&__header {
1312
position: sticky;
1413
left: 0;

src/containers/Storage/PDisk/PDisk.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
}
2222

2323
&__vdisks-item {
24-
flex-basis: 5px;
24+
flex-basis: 3px;
2525
flex-shrink: 0;
2626

2727
.stack__layer {
Lines changed: 8 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,22 @@
1-
import {StringParam, useQueryParams} from 'use-query-params';
1+
import {PaginatedStorageGroups} from './PaginatedStorageGroups';
2+
import {PaginatedStorageNodes} from './PaginatedStorageNodes';
3+
import {useStorageQueryParams} from './useStorageQueryParams';
24

3-
import {AccessDenied} from '../../components/Errors/403/AccessDenied';
4-
import {ResponseError} from '../../components/Errors/ResponseError/ResponseError';
5-
import type {RenderControls, RenderErrorMessage} from '../../components/PaginatedTable';
6-
import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster';
7-
import {VISIBLE_ENTITIES} from '../../store/reducers/storage/constants';
8-
import {storageTypeSchema, visibleEntitiesSchema} from '../../store/reducers/storage/types';
9-
import type {StorageType, VisibleEntities} from '../../store/reducers/storage/types';
10-
import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../utils/nodes';
11-
import {useAdditionalNodeProps} from '../AppWithClusters/useClusterData';
12-
13-
import {StorageControls} from './StorageControls/StorageControls';
14-
import {PaginatedStorageGroups} from './StorageGroups/PaginatedStorageGroups';
15-
import {useStorageGroupsSelectedColumns} from './StorageGroups/columns/hooks';
16-
import {PaginatedStorageNodes} from './StorageNodes/PaginatedStorageNodes';
17-
import {useStorageNodesSelectedColumns} from './StorageNodes/columns/hooks';
18-
19-
interface PaginatedStorageProps {
5+
export interface PaginatedStorageProps {
206
database?: string;
217
nodeId?: string;
228
groupId?: string;
239
parentContainer?: Element | null;
2410
}
2511

26-
export const PaginatedStorage = ({
27-
database,
28-
nodeId,
29-
groupId,
30-
parentContainer,
31-
}: PaginatedStorageProps) => {
32-
const {balancer} = useClusterBaseInfo();
33-
const {additionalNodesProps} = useAdditionalNodeProps({balancer});
12+
export const PaginatedStorage = (props: PaginatedStorageProps) => {
13+
const {storageType} = useStorageQueryParams();
3414

35-
const [queryParams, setQueryParams] = useQueryParams({
36-
type: StringParam,
37-
visible: StringParam,
38-
search: StringParam,
39-
uptimeFilter: StringParam,
40-
});
41-
const storageType = storageTypeSchema.parse(queryParams.type);
42-
const isGroups = storageType === 'groups';
4315
const isNodes = storageType === 'nodes';
4416

45-
const visibleEntities = visibleEntitiesSchema.parse(queryParams.visible);
46-
const searchValue = queryParams.search ?? '';
47-
const nodesUptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
48-
49-
const {
50-
columnsToShow: storageNodesColumnsToShow,
51-
columnsToSelect: storageNodesColumnsToSelect,
52-
setColumns: setStorageNodesSelectedColumns,
53-
} = useStorageNodesSelectedColumns({
54-
additionalNodesProps,
55-
visibleEntities,
56-
database,
57-
groupId,
58-
});
59-
60-
const {
61-
columnsToShow: storageGroupsColumnsToShow,
62-
columnsToSelect: storageGroupsColumnsToSelect,
63-
setColumns: setStorageGroupsSelectedColumns,
64-
} = useStorageGroupsSelectedColumns(visibleEntities);
65-
66-
const handleTextFilterChange = (value: string) => {
67-
setQueryParams({search: value || undefined}, 'replaceIn');
68-
};
69-
70-
const handleGroupVisibilityChange = (value: VisibleEntities) => {
71-
setQueryParams({visible: value}, 'replaceIn');
72-
};
73-
74-
const handleStorageTypeChange = (value: StorageType) => {
75-
setQueryParams({type: value}, 'replaceIn');
76-
};
77-
78-
const handleUptimeFilterChange = (value: NodesUptimeFilterValues) => {
79-
setQueryParams({uptimeFilter: value}, 'replaceIn');
80-
};
81-
82-
const handleShowAllGroups = () => {
83-
handleGroupVisibilityChange(VISIBLE_ENTITIES.all);
84-
};
85-
86-
const handleShowAllNodes = () => {
87-
setQueryParams(
88-
{
89-
visible: VISIBLE_ENTITIES.all,
90-
uptimeFilter: NodesUptimeFilterValues.All,
91-
},
92-
'replaceIn',
93-
);
94-
};
95-
96-
const renderControls: RenderControls = ({totalEntities, foundEntities, inited}) => {
97-
const columnsToSelect = isGroups
98-
? storageGroupsColumnsToSelect
99-
: storageNodesColumnsToSelect;
100-
101-
const handleSelectedColumnsUpdate = isGroups
102-
? setStorageGroupsSelectedColumns
103-
: setStorageNodesSelectedColumns;
104-
105-
return (
106-
<StorageControls
107-
searchValue={searchValue}
108-
handleSearchValueChange={handleTextFilterChange}
109-
withTypeSelector
110-
storageType={storageType}
111-
handleStorageTypeChange={handleStorageTypeChange}
112-
visibleEntities={visibleEntities}
113-
handleVisibleEntitiesChange={handleGroupVisibilityChange}
114-
nodesUptimeFilter={nodesUptimeFilter}
115-
handleNodesUptimeFilterChange={handleUptimeFilterChange}
116-
withGroupsUsageFilter={false}
117-
entitiesCountCurrent={foundEntities}
118-
entitiesCountTotal={totalEntities}
119-
entitiesLoading={!inited}
120-
columnsToSelect={columnsToSelect}
121-
handleSelectedColumnsUpdate={handleSelectedColumnsUpdate}
122-
/>
123-
);
124-
};
125-
126-
const renderErrorMessage: RenderErrorMessage = (error) => {
127-
if (error.status === 403) {
128-
return <AccessDenied position="left" />;
129-
}
130-
131-
return <ResponseError error={error} />;
132-
};
133-
13417
if (isNodes) {
135-
return (
136-
<PaginatedStorageNodes
137-
searchValue={searchValue}
138-
visibleEntities={visibleEntities}
139-
nodesUptimeFilter={nodesUptimeFilter}
140-
database={database}
141-
onShowAll={handleShowAllNodes}
142-
parentContainer={parentContainer}
143-
renderControls={renderControls}
144-
renderErrorMessage={renderErrorMessage}
145-
columns={storageNodesColumnsToShow}
146-
/>
147-
);
18+
return <PaginatedStorageNodes {...props} />;
14819
}
14920

150-
return (
151-
<PaginatedStorageGroups
152-
searchValue={searchValue}
153-
visibleEntities={visibleEntities}
154-
database={database}
155-
nodeId={nodeId}
156-
onShowAll={handleShowAllGroups}
157-
parentContainer={parentContainer}
158-
renderControls={renderControls}
159-
renderErrorMessage={renderErrorMessage}
160-
columns={storageGroupsColumnsToShow}
161-
/>
162-
);
21+
return <PaginatedStorageGroups {...props} />;
16322
};

0 commit comments

Comments
 (0)