Skip to content

Commit 937c561

Browse files
authored
fix: operations tab (#2435)
1 parent ec81875 commit 937c561

File tree

19 files changed

+875
-135
lines changed

19 files changed

+875
-135
lines changed

config-overrides.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ module.exports = {
5858
// By default jest does not transform anything in node_modules
5959
// So this override excludes node_modules except @gravity-ui
6060
// see https://github.com/timarney/react-app-rewired/issues/241
61-
config.transformIgnorePatterns = ['node_modules/(?!(@gravity-ui|@mjackson)/)'];
61+
config.transformIgnorePatterns = [
62+
'node_modules/(?!(@gravity-ui|@mjackson|@standard-schema)/)',
63+
];
6264

6365
// Add .github directory to roots
6466
config.roots = ['<rootDir>/src', '<rootDir>/.github'];

package-lock.json

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@gravity-ui/websql-autocomplete": "^13.7.0",
3030
"@hookform/resolvers": "^3.10.0",
3131
"@mjackson/multipart-parser": "^0.8.2",
32-
"@reduxjs/toolkit": "^2.5.0",
32+
"@reduxjs/toolkit": "^2.8.2",
3333
"@tanstack/react-table": "^8.20.6",
3434
"@ydb-platform/monaco-ghost": "^0.6.1",
3535
"axios": "^1.8.4",

src/components/TableSkeleton/TableSkeleton.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@
3636

3737
&__col-5 {
3838
width: 20%;
39+
margin-right: 5%;
40+
}
41+
42+
&__col-6,
43+
&__col-7,
44+
&__col-8,
45+
&__col-9 {
46+
width: 8%;
47+
margin-right: 3%;
48+
}
49+
50+
&__col-10 {
51+
width: 8%;
3952
}
4053

4154
&__col-full {

src/components/TableSkeleton/TableSkeleton.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,36 @@ interface TableSkeletonProps {
1111
className?: string;
1212
rows?: number;
1313
delay?: number;
14+
columns?: number;
15+
showHeader?: boolean;
1416
}
1517

16-
export const TableSkeleton = ({rows = 2, delay = 600, className}: TableSkeletonProps) => {
18+
export const TableSkeleton = ({
19+
rows = 2,
20+
delay = 600,
21+
className,
22+
columns = 5,
23+
showHeader = true,
24+
}: TableSkeletonProps) => {
1725
const [show] = useDelayed(delay);
1826

19-
return (
20-
<div className={b('wrapper', {hidden: !show}, className)}>
27+
const renderHeaderRow = () => {
28+
if (!showHeader) {
29+
return null;
30+
}
31+
32+
return (
2133
<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')} />
34+
{[...new Array(columns)].map((_, index) => (
35+
<Skeleton key={`header-col-${index}`} className={b(`col-${index + 1}`)} />
36+
))}
2737
</div>
38+
);
39+
};
40+
41+
return (
42+
<div className={b('wrapper', {hidden: !show}, className)}>
43+
{renderHeaderRow()}
2844
{[...new Array(rows)].map((_, index) => (
2945
<div className={b('row')} key={`skeleton-row-${index}`}>
3046
<Skeleton className={b('col-full')} />

src/containers/Operations/Operations.tsx

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,82 @@ import React from 'react';
33
import {AccessDenied} from '../../components/Errors/403';
44
import {ResponseError} from '../../components/Errors/ResponseError';
55
import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable';
6+
import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
67
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
7-
import {operationsApi} from '../../store/reducers/operations';
8-
import {useAutoRefreshInterval} from '../../utils/hooks';
8+
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
99
import {isAccessError} from '../../utils/response';
1010

1111
import {OperationsControls} from './OperationsControls';
1212
import {getColumns} from './columns';
1313
import {OPERATIONS_SELECTED_COLUMNS_KEY} from './constants';
1414
import i18n from './i18n';
1515
import {b} from './shared';
16+
import {useOperationsInfiniteQuery} from './useOperationsInfiniteQuery';
1617
import {useOperationsQueryParams} from './useOperationsQueryParams';
1718

1819
interface OperationsProps {
1920
database: string;
21+
scrollContainerRef?: React.RefObject<HTMLElement>;
2022
}
2123

22-
export function Operations({database}: OperationsProps) {
23-
const [autoRefreshInterval] = useAutoRefreshInterval();
24-
25-
const {kind, searchValue, pageSize, pageToken, handleKindChange, handleSearchChange} =
24+
export function Operations({database, scrollContainerRef}: OperationsProps) {
25+
const {kind, searchValue, pageSize, handleKindChange, handleSearchChange} =
2626
useOperationsQueryParams();
2727

28-
const {data, isLoading, error, refetch} = operationsApi.useGetOperationListQuery(
29-
{database, kind, page_size: pageSize, page_token: pageToken},
30-
{
31-
pollingInterval: autoRefreshInterval,
32-
},
33-
);
34-
35-
const filteredOperations = React.useMemo(() => {
36-
if (!data?.operations) {
37-
return [];
38-
}
39-
return data.operations.filter((op) =>
40-
op.id?.toLowerCase().includes(searchValue.toLowerCase()),
41-
);
42-
}, [data?.operations, searchValue]);
28+
const {operations, isLoading, isLoadingMore, error, refreshTable, totalCount} =
29+
useOperationsInfiniteQuery({
30+
database,
31+
kind,
32+
pageSize,
33+
searchValue,
34+
scrollContainerRef,
35+
});
4336

4437
if (isAccessError(error)) {
4538
return <AccessDenied position="left" />;
4639
}
4740

41+
const settings = React.useMemo(() => {
42+
return {
43+
...DEFAULT_TABLE_SETTINGS,
44+
sortable: false,
45+
};
46+
}, []);
47+
4848
return (
4949
<TableWithControlsLayout>
5050
<TableWithControlsLayout.Controls>
5151
<OperationsControls
5252
kind={kind}
5353
searchValue={searchValue}
54-
entitiesCountCurrent={filteredOperations.length}
55-
entitiesCountTotal={data?.operations?.length}
54+
entitiesCountCurrent={operations.length}
55+
entitiesCountTotal={totalCount}
5656
entitiesLoading={isLoading}
5757
handleKindChange={handleKindChange}
5858
handleSearchChange={handleSearchChange}
5959
/>
6060
</TableWithControlsLayout.Controls>
6161
{error ? <ResponseError error={error} /> : null}
6262
<TableWithControlsLayout.Table loading={isLoading} className={b('table')}>
63-
{data ? (
63+
{operations.length > 0 || isLoading ? (
6464
<ResizeableDataTable
65-
columns={getColumns({database, refreshTable: refetch})}
65+
columns={getColumns({database, refreshTable, kind})}
6666
columnsWidthLSKey={OPERATIONS_SELECTED_COLUMNS_KEY}
67-
data={filteredOperations}
67+
data={operations}
68+
settings={settings}
6869
emptyDataMessage={i18n('title_empty')}
6970
/>
70-
) : null}
71+
) : (
72+
<div>{i18n('title_empty')}</div>
73+
)}
74+
{isLoadingMore && (
75+
<TableSkeleton
76+
showHeader={false}
77+
rows={3}
78+
delay={0}
79+
className={b('loading-more')}
80+
/>
81+
)}
7182
</TableWithControlsLayout.Table>
7283
</TableWithControlsLayout>
7384
);

0 commit comments

Comments
 (0)