es-grid-template 1.9.90 → 1.9.91
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/es/grid-component/GridRefreshButton.css +9 -0
- package/es/grid-component/GridRefreshButton.d.ts +8 -0
- package/es/grid-component/GridRefreshButton.js +47 -0
- package/es/grid-component/TempTable.d.ts +1 -1
- package/es/grid-component/type.d.ts +26 -0
- package/es/group-component/TableContainer.js +8 -2
- package/es/group-component/TableContainerEdit.js +8 -2
- package/es/group-component/hook/utils.d.ts +3 -3
- package/es/table-component/TableContainer.js +8 -2
- package/es/table-virtuoso/InternalTable.js +13 -3
- package/es/table-virtuoso/table/TableContainer.js +8 -2
- package/es/table-virtuoso/table/TableWrapper.d.ts +2 -1
- package/es/table-virtuoso/table/TableWrapper.js +17 -3
- package/lib/grid-component/GridRefreshButton.css +9 -0
- package/lib/grid-component/GridRefreshButton.d.ts +8 -0
- package/lib/grid-component/GridRefreshButton.js +54 -0
- package/lib/grid-component/TempTable.d.ts +1 -1
- package/lib/grid-component/type.d.ts +26 -0
- package/lib/group-component/TableContainer.js +8 -2
- package/lib/group-component/TableContainerEdit.js +8 -2
- package/lib/group-component/hook/utils.d.ts +9 -9
- package/lib/table-component/TableContainer.js +8 -2
- package/lib/table-virtuoso/InternalTable.js +13 -3
- package/lib/table-virtuoso/table/TableContainer.js +8 -2
- package/lib/table-virtuoso/table/TableWrapper.d.ts +2 -1
- package/lib/table-virtuoso/table/TableWrapper.js +17 -3
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import './GridRefreshButton.css';
|
|
3
|
+
import type { TableProps } from './type';
|
|
4
|
+
type Props = Pick<TableProps<object>, 'onRefresh' | 't'> & {
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
declare const GridRefreshButton: ({ id, onRefresh, t }: Props) => JSX.Element;
|
|
8
|
+
export default GridRefreshButton;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { RefreshCw } from 'becoxy-icons';
|
|
4
|
+
import "./GridRefreshButton.css";
|
|
5
|
+
const GridRefreshButton = ({
|
|
6
|
+
id,
|
|
7
|
+
onRefresh,
|
|
8
|
+
t
|
|
9
|
+
}) => {
|
|
10
|
+
const [isRefreshing, setIsRefreshing] = React.useState(false);
|
|
11
|
+
const refreshPendingRef = React.useRef(false);
|
|
12
|
+
if (!onRefresh) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const handleRefresh = async () => {
|
|
16
|
+
if (refreshPendingRef.current) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
refreshPendingRef.current = true;
|
|
20
|
+
setIsRefreshing(true);
|
|
21
|
+
try {
|
|
22
|
+
await onRefresh();
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('Grid refresh failed:', error);
|
|
25
|
+
} finally {
|
|
26
|
+
refreshPendingRef.current = false;
|
|
27
|
+
setIsRefreshing(false);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const label = String(t?.('RefreshData') ?? 'Refresh');
|
|
31
|
+
return /*#__PURE__*/React.createElement(RefreshCw, {
|
|
32
|
+
className: cn('toolbar-icon', {
|
|
33
|
+
'ui-rc-grid-refresh-spin': isRefreshing
|
|
34
|
+
}),
|
|
35
|
+
"data-tooltip-id": `${id}-tooltip-content`,
|
|
36
|
+
"data-tooltip-content": label,
|
|
37
|
+
color: isRefreshing ? '#9B9B9B' : '#555555',
|
|
38
|
+
fontSize: 21,
|
|
39
|
+
style: {
|
|
40
|
+
cursor: isRefreshing ? 'default' : 'pointer'
|
|
41
|
+
},
|
|
42
|
+
onClick: () => {
|
|
43
|
+
void handleRefresh();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export default GridRefreshButton;
|
|
@@ -380,6 +380,18 @@ export type TableProps<RecordType = AnyObject> = {
|
|
|
380
380
|
infiniteScroll?: boolean;
|
|
381
381
|
/** Hàm gọi khi cuộn đến cuối */
|
|
382
382
|
next?: () => void;
|
|
383
|
+
/**
|
|
384
|
+
* Thông báo khi phạm vi dòng đang render thay đổi (cuộn, mở/đóng cây hoặc cập nhật dữ liệu).
|
|
385
|
+
* - `rowIds`: ID dòng TanStack sau khi expand/collapse, gồm cả vùng đệm (overscan).
|
|
386
|
+
* - `startIndex` / `endIndex`: vị trí đầu/cuối trong danh sách dòng đang hiển thị (bao gồm hai đầu).
|
|
387
|
+
* Dùng để xác định dòng cần tải dữ liệu; callback không tự gọi API.
|
|
388
|
+
* Chỉ hỗ trợ khi `groupAble=true` và `editAble=false`. Không truyền thì giữ hành vi cũ.
|
|
389
|
+
*/
|
|
390
|
+
onVisibleRowsChange?: (range: {
|
|
391
|
+
rowIds: string[];
|
|
392
|
+
startIndex: number;
|
|
393
|
+
endIndex: number;
|
|
394
|
+
}) => void;
|
|
383
395
|
/** Ngưỡng trigger load thêm dữ liệu */
|
|
384
396
|
onEndReachedThreshold?: number;
|
|
385
397
|
/** Cho phép group dữ liệu */
|
|
@@ -388,6 +400,12 @@ export type TableProps<RecordType = AnyObject> = {
|
|
|
388
400
|
groupColumns?: string[];
|
|
389
401
|
/** Cấu hình group */
|
|
390
402
|
groupSetting?: IGroupSetting;
|
|
403
|
+
/**
|
|
404
|
+
* Hiện nút làm mới trên toolbar khi truyền callback.
|
|
405
|
+
* Grid không tự gọi API: consumer quyết định dữ liệu cần tải lại.
|
|
406
|
+
* Hỗ trợ Promise (ví dụ refetch() của TanStack Query) để tự khóa nút khi đang tải.
|
|
407
|
+
*/
|
|
408
|
+
onRefresh?: () => void | Promise<unknown>;
|
|
391
409
|
/** Hiển thị toolbar */
|
|
392
410
|
showToolbar?: boolean;
|
|
393
411
|
/** Các action trên toolbar
|
|
@@ -550,6 +568,14 @@ export type ExpandableConfig<RecordType> = {
|
|
|
550
568
|
onExpand?: (expanded: boolean, rowData: RecordType) => void;
|
|
551
569
|
onExpandedRowsChange?: (expandedKeys: readonly Key[]) => void;
|
|
552
570
|
defaultExpandAllRows?: boolean;
|
|
571
|
+
/**
|
|
572
|
+
* Giữ trạng thái mở/đóng cây do người dùng thao tác khi `dataSource` cập nhật.
|
|
573
|
+
* Khi `true`, chỉ áp dụng `defaultExpandAllRows` / `defaultExpandedRowKeys` một lần
|
|
574
|
+
* sau khi có dữ liệu; không tự mở lại những nhánh đã đóng khi tải thêm dòng.
|
|
575
|
+
* Mặc định `false`: dữ liệu thay đổi vẫn áp dụng lại trạng thái mở rộng mặc định như trước.
|
|
576
|
+
* Chỉ hỗ trợ Grid nhóm không chỉnh sửa (`groupAble=true`, `editAble=false`).
|
|
577
|
+
*/
|
|
578
|
+
preserveExpandedOnDataChange?: boolean;
|
|
553
579
|
expandIconColumnIndex?: number;
|
|
554
580
|
showExpandAll?: boolean;
|
|
555
581
|
showExpandColumn?: boolean;
|
|
@@ -5,6 +5,7 @@ import { TableContext } from "./useContext";
|
|
|
5
5
|
import Pagination from 'rc-master-ui/es/pagination';
|
|
6
6
|
import { Toolbar } from 'rc-master-ui';
|
|
7
7
|
import { Collapse2, Expand2, Maximize, Minimize } from 'becoxy-icons';
|
|
8
|
+
import GridRefreshButton from "../grid-component/GridRefreshButton";
|
|
8
9
|
// import { ColumnsChoose } from './ColumnsChoose'
|
|
9
10
|
import { numericFormatter } from 'react-numeric-component';
|
|
10
11
|
import TableWrapper from "./table/TableWrapper";
|
|
@@ -42,6 +43,7 @@ const TableContainer = props => {
|
|
|
42
43
|
showToolbar,
|
|
43
44
|
toolbarItems,
|
|
44
45
|
actionTemplate,
|
|
46
|
+
onRefresh,
|
|
45
47
|
pagination,
|
|
46
48
|
fullScreen,
|
|
47
49
|
showColumnChoose,
|
|
@@ -232,7 +234,7 @@ const TableContainer = props => {
|
|
|
232
234
|
return /*#__PURE__*/React.createElement("div", {
|
|
233
235
|
ref: containerRef,
|
|
234
236
|
id: id
|
|
235
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/React.createElement("div", {
|
|
237
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/React.createElement("div", {
|
|
236
238
|
ref: topToolbarRef,
|
|
237
239
|
className: classNames(`${prefix}-grid-top-toolbar`, {})
|
|
238
240
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -269,7 +271,11 @@ const TableContainer = props => {
|
|
|
269
271
|
showTotal: (totalItems, range) =>
|
|
270
272
|
// @ts-ignore
|
|
271
273
|
`${range[0]}-${range[1]} / ${totalItems} ${t ? t(pagination?.locale?.items ?? 'items') : 'items'}`
|
|
272
|
-
}, pagination)), typeof actionTemplate === 'function' ? actionTemplate() : actionTemplate,
|
|
274
|
+
}, pagination)), typeof actionTemplate === 'function' ? actionTemplate() : actionTemplate, /*#__PURE__*/React.createElement(GridRefreshButton, {
|
|
275
|
+
id: id,
|
|
276
|
+
onRefresh: onRefresh,
|
|
277
|
+
t: t
|
|
278
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/React.createElement(Minimize, {
|
|
273
279
|
fontSize: 16,
|
|
274
280
|
onClick: () => {
|
|
275
281
|
setIsFullScreen(!isFullScreen);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import React, { Fragment } from "react";
|
|
3
|
+
import GridRefreshButton from "../grid-component/GridRefreshButton";
|
|
3
4
|
import { useCopyToClipboard } from 'usehooks-ts';
|
|
4
5
|
import { checkDecimalSeparator, checkThousandSeparator, detectSeparators, findItemByKey, flattenArray, flattenData, getAllRowKey, getColIdsBetween, getDefaultValue, getFormat, getRowIdsBetween, getSelectedCellMatrix, getTableHeight, isEditable, isFormattedNumber, newGuid, sumSize,
|
|
5
6
|
// sumSize,
|
|
@@ -102,6 +103,7 @@ const TableContainerEdit = props => {
|
|
|
102
103
|
pagination,
|
|
103
104
|
showToolbar,
|
|
104
105
|
actionTemplate,
|
|
106
|
+
onRefresh,
|
|
105
107
|
showColumnChoose,
|
|
106
108
|
height,
|
|
107
109
|
minHeight,
|
|
@@ -2112,7 +2114,7 @@ const TableContainerEdit = props => {
|
|
|
2112
2114
|
return /*#__PURE__*/React.createElement("div", {
|
|
2113
2115
|
ref: containerRef,
|
|
2114
2116
|
id: id
|
|
2115
|
-
}, (showToolbar !== false || fullScreen !== false || showColumnChoose || title) && /*#__PURE__*/React.createElement("div", {
|
|
2117
|
+
}, (showToolbar !== false || fullScreen !== false || showColumnChoose || title || onRefresh) && /*#__PURE__*/React.createElement("div", {
|
|
2116
2118
|
ref: topToolbarRef,
|
|
2117
2119
|
className: classNames(`${prefix}-grid-top-toolbar`, {})
|
|
2118
2120
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -2157,7 +2159,11 @@ const TableContainerEdit = props => {
|
|
|
2157
2159
|
}, /*#__PURE__*/React.createElement(Toolbar, {
|
|
2158
2160
|
items: toolbarItemTopRight,
|
|
2159
2161
|
mode: 'responsive'
|
|
2160
|
-
})),
|
|
2162
|
+
})), /*#__PURE__*/React.createElement(GridRefreshButton, {
|
|
2163
|
+
id: id,
|
|
2164
|
+
onRefresh: onRefresh,
|
|
2165
|
+
t: t
|
|
2166
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/React.createElement(Minimize, {
|
|
2161
2167
|
fontSize: 16,
|
|
2162
2168
|
onClick: () => {
|
|
2163
2169
|
setIsFullScreen(!isFullScreen);
|
|
@@ -196,10 +196,10 @@ export declare const fixColumnsLeft: <RecordType>(columns: ColumnTable<RecordTyp
|
|
|
196
196
|
value: any;
|
|
197
197
|
rowData: RecordType;
|
|
198
198
|
}) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
199
|
-
onCellStyles?: Omit<CSSProperties, "
|
|
200
|
-
onCellHeaderStyles?: Omit<CSSProperties, "
|
|
199
|
+
onCellStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cellValue: any, cell: import("@tanstack/react-table").Cell<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
200
|
+
onCellHeaderStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cell: import("@tanstack/react-table").Header<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
201
201
|
onCell?: (rowData: RecordType, index: number) => import("react").TdHTMLAttributes<HTMLTableCellElement>;
|
|
202
|
-
onCellFooterStyles?: Omit<CSSProperties, "
|
|
202
|
+
onCellFooterStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cellValue: any, cell: import("@tanstack/react-table").Header<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
203
203
|
getValue?: (row: any, rowIndex: number) => any;
|
|
204
204
|
getCellProps?: (value: any, row: any, rowIndex: number) => import("./../../grid-component/type").CellProps;
|
|
205
205
|
headerCellProps?: import("./../../grid-component/type").CellProps;
|
|
@@ -5,6 +5,7 @@ import { TableContext } from "./useContext";
|
|
|
5
5
|
import Pagination from 'rc-master-ui/es/pagination';
|
|
6
6
|
import { Toolbar } from 'rc-master-ui';
|
|
7
7
|
import { Maximize, Minimize } from 'becoxy-icons';
|
|
8
|
+
import GridRefreshButton from "../grid-component/GridRefreshButton";
|
|
8
9
|
import { numericFormatter } from 'react-numeric-component';
|
|
9
10
|
import TableWrapper from "./table/TableWrapper";
|
|
10
11
|
import { getTableHeight, sumSize, updateColumnWidthsRecursive } from "./hook/utils";
|
|
@@ -43,6 +44,7 @@ const TableContainer = props => {
|
|
|
43
44
|
toolbarItems,
|
|
44
45
|
toolbarMode,
|
|
45
46
|
actionTemplate,
|
|
47
|
+
onRefresh,
|
|
46
48
|
pagination,
|
|
47
49
|
fullScreen,
|
|
48
50
|
showColumnChoose,
|
|
@@ -232,7 +234,7 @@ const TableContainer = props => {
|
|
|
232
234
|
return /*#__PURE__*/React.createElement("div", {
|
|
233
235
|
ref: containerRef,
|
|
234
236
|
id: id
|
|
235
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/React.createElement("div", {
|
|
237
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/React.createElement("div", {
|
|
236
238
|
ref: topToolbarRef,
|
|
237
239
|
className: classNames(`${prefix}-grid-top-toolbar`, {})
|
|
238
240
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -275,7 +277,11 @@ const TableContainer = props => {
|
|
|
275
277
|
}, /*#__PURE__*/React.createElement(Toolbar, {
|
|
276
278
|
items: toolbarItemTopRight,
|
|
277
279
|
mode: toolbarMode
|
|
278
|
-
})),
|
|
280
|
+
})), /*#__PURE__*/React.createElement(GridRefreshButton, {
|
|
281
|
+
id: id,
|
|
282
|
+
onRefresh: onRefresh,
|
|
283
|
+
t: t
|
|
284
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/React.createElement(Minimize, {
|
|
279
285
|
fontSize: 16,
|
|
280
286
|
onClick: () => {
|
|
281
287
|
setIsFullScreen(!isFullScreen);
|
|
@@ -105,6 +105,8 @@ const InternalTable = props => {
|
|
|
105
105
|
const [columns, setColumns] = React.useState([]);
|
|
106
106
|
const [tableData, setTableData] = React.useState([]);
|
|
107
107
|
const [expanded, setExpanded] = React.useState({});
|
|
108
|
+
// Đánh dấu đã áp dụng expansion mặc định, tránh mở lại nhánh người dùng đóng khi task cập nhật.
|
|
109
|
+
const initializedExpansionRef = React.useRef(false);
|
|
108
110
|
|
|
109
111
|
// const [visible, setVisible] = React.useState({visible: false, column: ''})
|
|
110
112
|
|
|
@@ -209,7 +211,7 @@ const InternalTable = props => {
|
|
|
209
211
|
expanded,
|
|
210
212
|
columnPinning,
|
|
211
213
|
columnVisibility: columnsHiddenKeys ? convertToObj(columnsHiddenKeys) : columnVisibility,
|
|
212
|
-
pagination:
|
|
214
|
+
pagination: paginationState,
|
|
213
215
|
// grouping,
|
|
214
216
|
columnSizing,
|
|
215
217
|
// columnOrder,
|
|
@@ -266,7 +268,8 @@ const InternalTable = props => {
|
|
|
266
268
|
getGroupedRowModel: getGroupedRowModel(),
|
|
267
269
|
// onExpandedChange: setExpanded,
|
|
268
270
|
getExpandedRowModel: getExpandedRowModel(),
|
|
269
|
-
|
|
271
|
+
// Khi không bật phân trang client, giữ nguyên toàn bộ dữ liệu BE/viewport và tránh row model phân trang cũ được dùng lại.
|
|
272
|
+
manualPagination: !shouldUseClientPagination,
|
|
270
273
|
// Chỉ để TanStack tự phân trang khi có pagination, không dùng infinite scroll và đang ở chế độ client.
|
|
271
274
|
// Với server pagination, dữ liệu đã được BE phân trang nên không chạy getPaginationRowModel() để tránh phân trang lần 2.
|
|
272
275
|
getPaginationRowModel: shouldUseClientPagination ? getPaginationRowModel() : undefined,
|
|
@@ -277,6 +280,13 @@ const InternalTable = props => {
|
|
|
277
280
|
// debugTable: true
|
|
278
281
|
});
|
|
279
282
|
React.useEffect(() => {
|
|
283
|
+
if (expandable?.preserveExpandedOnDataChange) {
|
|
284
|
+
// Chờ cây có dữ liệu mới khởi tạo; những lần thay đổi tableData sau đó không reset expanded.
|
|
285
|
+
if (initializedExpansionRef.current || tableData.length === 0) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
initializedExpansionRef.current = true;
|
|
289
|
+
}
|
|
280
290
|
if (defaultExpandAllRows) {
|
|
281
291
|
const allKeys = findAllChildrenKeys2(tableData, rowKey, 'children');
|
|
282
292
|
setExpanded(convertToObjTrue(allKeys));
|
|
@@ -285,7 +295,7 @@ const InternalTable = props => {
|
|
|
285
295
|
setExpanded(convertToObjTrue(defaultExpandedRowKeys ?? []));
|
|
286
296
|
}
|
|
287
297
|
}
|
|
288
|
-
}, [defaultExpandAllRows, defaultExpandedRowKeys, tableData]);
|
|
298
|
+
}, [defaultExpandAllRows, defaultExpandedRowKeys, tableData, expandable?.preserveExpandedOnDataChange]);
|
|
289
299
|
const triggerGroupColumns = groupedColumns => {
|
|
290
300
|
// const abc = updateColumnsByGroup(columns, groupedColumns)
|
|
291
301
|
|
|
@@ -4,6 +4,7 @@ import classNames from 'classnames';
|
|
|
4
4
|
import Pagination from 'rc-master-ui/es/pagination';
|
|
5
5
|
import { Toolbar } from 'rc-master-ui';
|
|
6
6
|
import { Collapse2, Expand2, Maximize, Minimize } from 'becoxy-icons';
|
|
7
|
+
import GridRefreshButton from "../../grid-component/GridRefreshButton";
|
|
7
8
|
import { numericFormatter } from 'react-numeric-component';
|
|
8
9
|
import TableWrapper from "./TableWrapper";
|
|
9
10
|
import { ColumnsChoose } from "../../table-component/ColumnsChoose";
|
|
@@ -42,6 +43,7 @@ const TableContainer = props => {
|
|
|
42
43
|
showToolbar,
|
|
43
44
|
toolbarItems,
|
|
44
45
|
actionTemplate,
|
|
46
|
+
onRefresh,
|
|
45
47
|
pagination,
|
|
46
48
|
fullScreen,
|
|
47
49
|
showColumnChoose,
|
|
@@ -184,7 +186,7 @@ const TableContainer = props => {
|
|
|
184
186
|
return /*#__PURE__*/React.createElement("div", {
|
|
185
187
|
ref: containerRef,
|
|
186
188
|
id: id
|
|
187
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/React.createElement("div", {
|
|
189
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/React.createElement("div", {
|
|
188
190
|
ref: topToolbarRef,
|
|
189
191
|
className: classNames(`${prefix}-grid-top-toolbar`, {})
|
|
190
192
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -228,7 +230,11 @@ const TableContainer = props => {
|
|
|
228
230
|
}, /*#__PURE__*/React.createElement(Toolbar, {
|
|
229
231
|
items: toolbarItemTopRight,
|
|
230
232
|
mode: toolbarMode
|
|
231
|
-
})),
|
|
233
|
+
})), /*#__PURE__*/React.createElement(GridRefreshButton, {
|
|
234
|
+
id: id,
|
|
235
|
+
onRefresh: onRefresh,
|
|
236
|
+
t: t
|
|
237
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/React.createElement(Minimize, {
|
|
232
238
|
fontSize: 16,
|
|
233
239
|
onClick: () => {
|
|
234
240
|
setIsFullScreen(!isFullScreen);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ColumnDef, Table } from "@tanstack/react-table";
|
|
3
|
-
import type { CommandClick, ContextInfo, ContextMenuItem, PaginationConfig } from '../../grid-component/type';
|
|
3
|
+
import type { CommandClick, ContextInfo, ContextMenuItem, PaginationConfig, TableProps } from '../../grid-component/type';
|
|
4
4
|
type Props<T> = {
|
|
5
5
|
tableContainerRef: React.RefObject<HTMLDivElement>;
|
|
6
6
|
table: Table<T>;
|
|
@@ -22,6 +22,7 @@ type Props<T> = {
|
|
|
22
22
|
next?: () => void;
|
|
23
23
|
pagination?: false | PaginationConfig;
|
|
24
24
|
infiniteScroll?: boolean;
|
|
25
|
+
onVisibleRowsChange?: TableProps<T>['onVisibleRowsChange'];
|
|
25
26
|
};
|
|
26
27
|
declare const TableWrapper: <RecordType extends object>(props: Props<RecordType>) => JSX.Element;
|
|
27
28
|
export default TableWrapper;
|
|
@@ -21,6 +21,7 @@ const TableWrapper = props => {
|
|
|
21
21
|
contextMenuHidden,
|
|
22
22
|
contextMenuClick,
|
|
23
23
|
contextMenuOpen,
|
|
24
|
+
onVisibleRowsChange,
|
|
24
25
|
summary
|
|
25
26
|
} = props;
|
|
26
27
|
const menuRef = React.useRef(null);
|
|
@@ -124,11 +125,24 @@ const TableWrapper = props => {
|
|
|
124
125
|
height,
|
|
125
126
|
position: "relative"
|
|
126
127
|
}
|
|
127
|
-
}, /*#__PURE__*/React.createElement(TableVirtuoso, {
|
|
128
|
+
}, /*#__PURE__*/React.createElement(TableVirtuoso, _extends({
|
|
128
129
|
data: table.getRowModel().rows,
|
|
129
130
|
totalCount: rows.length
|
|
131
|
+
}, onVisibleRowsChange ? {
|
|
132
|
+
computeItemKey: (_index, row) => row.id,
|
|
133
|
+
rangeChanged: ({
|
|
134
|
+
startIndex,
|
|
135
|
+
endIndex
|
|
136
|
+
}) => {
|
|
137
|
+
// Dùng row ID sau expand/collapse của TanStack; index không phải vị trí trong cây dữ liệu gốc.
|
|
138
|
+
onVisibleRowsChange({
|
|
139
|
+
rowIds: rows.slice(startIndex, endIndex + 1).map(row => row.id),
|
|
140
|
+
startIndex,
|
|
141
|
+
endIndex
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} : {}, {
|
|
130
145
|
// isScrolling={}
|
|
131
|
-
,
|
|
132
146
|
components: {
|
|
133
147
|
Table: ({
|
|
134
148
|
style,
|
|
@@ -242,7 +256,7 @@ const TableWrapper = props => {
|
|
|
242
256
|
});
|
|
243
257
|
}));
|
|
244
258
|
} : undefined
|
|
245
|
-
})), /*#__PURE__*/React.createElement(Tooltip, {
|
|
259
|
+
}))), /*#__PURE__*/React.createElement(Tooltip, {
|
|
246
260
|
id: `${id}-tooltip-content`,
|
|
247
261
|
style: {
|
|
248
262
|
zIndex: 1999,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import './GridRefreshButton.css';
|
|
3
|
+
import type { TableProps } from './type';
|
|
4
|
+
type Props = Pick<TableProps<object>, 'onRefresh' | 't'> & {
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
declare const GridRefreshButton: ({ id, onRefresh, t }: Props) => JSX.Element;
|
|
8
|
+
export default GridRefreshButton;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _classnames = _interopRequireDefault(require("classnames"));
|
|
10
|
+
var _becoxyIcons = require("becoxy-icons");
|
|
11
|
+
require("./GridRefreshButton.css");
|
|
12
|
+
const GridRefreshButton = ({
|
|
13
|
+
id,
|
|
14
|
+
onRefresh,
|
|
15
|
+
t
|
|
16
|
+
}) => {
|
|
17
|
+
const [isRefreshing, setIsRefreshing] = _react.default.useState(false);
|
|
18
|
+
const refreshPendingRef = _react.default.useRef(false);
|
|
19
|
+
if (!onRefresh) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const handleRefresh = async () => {
|
|
23
|
+
if (refreshPendingRef.current) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
refreshPendingRef.current = true;
|
|
27
|
+
setIsRefreshing(true);
|
|
28
|
+
try {
|
|
29
|
+
await onRefresh();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Grid refresh failed:', error);
|
|
32
|
+
} finally {
|
|
33
|
+
refreshPendingRef.current = false;
|
|
34
|
+
setIsRefreshing(false);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const label = String(t?.('RefreshData') ?? 'Refresh');
|
|
38
|
+
return /*#__PURE__*/_react.default.createElement(_becoxyIcons.RefreshCw, {
|
|
39
|
+
className: (0, _classnames.default)('toolbar-icon', {
|
|
40
|
+
'ui-rc-grid-refresh-spin': isRefreshing
|
|
41
|
+
}),
|
|
42
|
+
"data-tooltip-id": `${id}-tooltip-content`,
|
|
43
|
+
"data-tooltip-content": label,
|
|
44
|
+
color: isRefreshing ? '#9B9B9B' : '#555555',
|
|
45
|
+
fontSize: 21,
|
|
46
|
+
style: {
|
|
47
|
+
cursor: isRefreshing ? 'default' : 'pointer'
|
|
48
|
+
},
|
|
49
|
+
onClick: () => {
|
|
50
|
+
void handleRefresh();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
var _default = exports.default = GridRefreshButton;
|
|
@@ -380,6 +380,18 @@ export type TableProps<RecordType = AnyObject> = {
|
|
|
380
380
|
infiniteScroll?: boolean;
|
|
381
381
|
/** Hàm gọi khi cuộn đến cuối */
|
|
382
382
|
next?: () => void;
|
|
383
|
+
/**
|
|
384
|
+
* Thông báo khi phạm vi dòng đang render thay đổi (cuộn, mở/đóng cây hoặc cập nhật dữ liệu).
|
|
385
|
+
* - `rowIds`: ID dòng TanStack sau khi expand/collapse, gồm cả vùng đệm (overscan).
|
|
386
|
+
* - `startIndex` / `endIndex`: vị trí đầu/cuối trong danh sách dòng đang hiển thị (bao gồm hai đầu).
|
|
387
|
+
* Dùng để xác định dòng cần tải dữ liệu; callback không tự gọi API.
|
|
388
|
+
* Chỉ hỗ trợ khi `groupAble=true` và `editAble=false`. Không truyền thì giữ hành vi cũ.
|
|
389
|
+
*/
|
|
390
|
+
onVisibleRowsChange?: (range: {
|
|
391
|
+
rowIds: string[];
|
|
392
|
+
startIndex: number;
|
|
393
|
+
endIndex: number;
|
|
394
|
+
}) => void;
|
|
383
395
|
/** Ngưỡng trigger load thêm dữ liệu */
|
|
384
396
|
onEndReachedThreshold?: number;
|
|
385
397
|
/** Cho phép group dữ liệu */
|
|
@@ -388,6 +400,12 @@ export type TableProps<RecordType = AnyObject> = {
|
|
|
388
400
|
groupColumns?: string[];
|
|
389
401
|
/** Cấu hình group */
|
|
390
402
|
groupSetting?: IGroupSetting;
|
|
403
|
+
/**
|
|
404
|
+
* Hiện nút làm mới trên toolbar khi truyền callback.
|
|
405
|
+
* Grid không tự gọi API: consumer quyết định dữ liệu cần tải lại.
|
|
406
|
+
* Hỗ trợ Promise (ví dụ refetch() của TanStack Query) để tự khóa nút khi đang tải.
|
|
407
|
+
*/
|
|
408
|
+
onRefresh?: () => void | Promise<unknown>;
|
|
391
409
|
/** Hiển thị toolbar */
|
|
392
410
|
showToolbar?: boolean;
|
|
393
411
|
/** Các action trên toolbar
|
|
@@ -550,6 +568,14 @@ export type ExpandableConfig<RecordType> = {
|
|
|
550
568
|
onExpand?: (expanded: boolean, rowData: RecordType) => void;
|
|
551
569
|
onExpandedRowsChange?: (expandedKeys: readonly Key[]) => void;
|
|
552
570
|
defaultExpandAllRows?: boolean;
|
|
571
|
+
/**
|
|
572
|
+
* Giữ trạng thái mở/đóng cây do người dùng thao tác khi `dataSource` cập nhật.
|
|
573
|
+
* Khi `true`, chỉ áp dụng `defaultExpandAllRows` / `defaultExpandedRowKeys` một lần
|
|
574
|
+
* sau khi có dữ liệu; không tự mở lại những nhánh đã đóng khi tải thêm dòng.
|
|
575
|
+
* Mặc định `false`: dữ liệu thay đổi vẫn áp dụng lại trạng thái mở rộng mặc định như trước.
|
|
576
|
+
* Chỉ hỗ trợ Grid nhóm không chỉnh sửa (`groupAble=true`, `editAble=false`).
|
|
577
|
+
*/
|
|
578
|
+
preserveExpandedOnDataChange?: boolean;
|
|
553
579
|
expandIconColumnIndex?: number;
|
|
554
580
|
showExpandAll?: boolean;
|
|
555
581
|
showExpandColumn?: boolean;
|
|
@@ -12,6 +12,7 @@ var _useContext = require("./useContext");
|
|
|
12
12
|
var _pagination = _interopRequireDefault(require("rc-master-ui/es/pagination"));
|
|
13
13
|
var _rcMasterUi = require("rc-master-ui");
|
|
14
14
|
var _becoxyIcons = require("becoxy-icons");
|
|
15
|
+
var _GridRefreshButton = _interopRequireDefault(require("../grid-component/GridRefreshButton"));
|
|
15
16
|
var _reactNumericComponent = require("react-numeric-component");
|
|
16
17
|
var _TableWrapper = _interopRequireDefault(require("./table/TableWrapper"));
|
|
17
18
|
var _utils = require("./hook/utils");
|
|
@@ -50,6 +51,7 @@ const TableContainer = props => {
|
|
|
50
51
|
showToolbar,
|
|
51
52
|
toolbarItems,
|
|
52
53
|
actionTemplate,
|
|
54
|
+
onRefresh,
|
|
53
55
|
pagination,
|
|
54
56
|
fullScreen,
|
|
55
57
|
showColumnChoose,
|
|
@@ -240,7 +242,7 @@ const TableContainer = props => {
|
|
|
240
242
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
241
243
|
ref: containerRef,
|
|
242
244
|
id: id
|
|
243
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/_react.default.createElement("div", {
|
|
245
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/_react.default.createElement("div", {
|
|
244
246
|
ref: topToolbarRef,
|
|
245
247
|
className: (0, _classnames.default)(`${prefix}-grid-top-toolbar`, {})
|
|
246
248
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -277,7 +279,11 @@ const TableContainer = props => {
|
|
|
277
279
|
showTotal: (totalItems, range) =>
|
|
278
280
|
// @ts-ignore
|
|
279
281
|
`${range[0]}-${range[1]} / ${totalItems} ${t ? t(pagination?.locale?.items ?? 'items') : 'items'}`
|
|
280
|
-
}, pagination)), typeof actionTemplate === 'function' ? actionTemplate() : actionTemplate,
|
|
282
|
+
}, pagination)), typeof actionTemplate === 'function' ? actionTemplate() : actionTemplate, /*#__PURE__*/_react.default.createElement(_GridRefreshButton.default, {
|
|
283
|
+
id: id,
|
|
284
|
+
onRefresh: onRefresh,
|
|
285
|
+
t: t
|
|
286
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/_react.default.createElement(_becoxyIcons.Minimize, {
|
|
281
287
|
fontSize: 16,
|
|
282
288
|
onClick: () => {
|
|
283
289
|
setIsFullScreen(!isFullScreen);
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.default = void 0;
|
|
8
8
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
9
|
var _react = _interopRequireWildcard(require("react"));
|
|
10
|
+
var _GridRefreshButton = _interopRequireDefault(require("../grid-component/GridRefreshButton"));
|
|
10
11
|
var _usehooksTs = require("usehooks-ts");
|
|
11
12
|
var _utils = require("./hook/utils");
|
|
12
13
|
var _reactVirtual = require("@tanstack/react-virtual");
|
|
@@ -110,6 +111,7 @@ const TableContainerEdit = props => {
|
|
|
110
111
|
pagination,
|
|
111
112
|
showToolbar,
|
|
112
113
|
actionTemplate,
|
|
114
|
+
onRefresh,
|
|
113
115
|
showColumnChoose,
|
|
114
116
|
height,
|
|
115
117
|
minHeight,
|
|
@@ -2120,7 +2122,7 @@ const TableContainerEdit = props => {
|
|
|
2120
2122
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
2121
2123
|
ref: containerRef,
|
|
2122
2124
|
id: id
|
|
2123
|
-
}, (showToolbar !== false || fullScreen !== false || showColumnChoose || title) && /*#__PURE__*/_react.default.createElement("div", {
|
|
2125
|
+
}, (showToolbar !== false || fullScreen !== false || showColumnChoose || title || onRefresh) && /*#__PURE__*/_react.default.createElement("div", {
|
|
2124
2126
|
ref: topToolbarRef,
|
|
2125
2127
|
className: (0, _classnames.default)(`${prefix}-grid-top-toolbar`, {})
|
|
2126
2128
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -2165,7 +2167,11 @@ const TableContainerEdit = props => {
|
|
|
2165
2167
|
}, /*#__PURE__*/_react.default.createElement(_rcMasterUi.Toolbar, {
|
|
2166
2168
|
items: toolbarItemTopRight,
|
|
2167
2169
|
mode: 'responsive'
|
|
2168
|
-
})),
|
|
2170
|
+
})), /*#__PURE__*/_react.default.createElement(_GridRefreshButton.default, {
|
|
2171
|
+
id: id,
|
|
2172
|
+
onRefresh: onRefresh,
|
|
2173
|
+
t: t
|
|
2174
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/_react.default.createElement(_becoxyIcons.Minimize, {
|
|
2169
2175
|
fontSize: 16,
|
|
2170
2176
|
onClick: () => {
|
|
2171
2177
|
setIsFullScreen(!isFullScreen);
|
|
@@ -167,7 +167,7 @@ export declare const fixColumnsLeft: <RecordType>(columns: ColumnTable<RecordTyp
|
|
|
167
167
|
haveSum?: boolean;
|
|
168
168
|
isSummary?: boolean;
|
|
169
169
|
sumGroup?: boolean;
|
|
170
|
-
summaryTemplate?: (data: number, key: string) => import("react").
|
|
170
|
+
summaryTemplate?: (data: number, key: string) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode;
|
|
171
171
|
sorter?: boolean;
|
|
172
172
|
allowFiltering?: boolean;
|
|
173
173
|
allowSortering?: boolean;
|
|
@@ -179,27 +179,27 @@ export declare const fixColumnsLeft: <RecordType>(columns: ColumnTable<RecordTyp
|
|
|
179
179
|
showFilterSearch?: boolean;
|
|
180
180
|
hidden?: boolean;
|
|
181
181
|
visible?: boolean;
|
|
182
|
-
headerTooltip?: string | boolean | (() => import("react").
|
|
182
|
+
headerTooltip?: string | boolean | (() => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
183
183
|
columnGroupText?: string;
|
|
184
184
|
headerTextAlign?: import("./../../grid-component/type").ITextAlign;
|
|
185
|
-
headerTemplate?: import("react").
|
|
185
|
+
headerTemplate?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode | ((column: ColumnTable<RecordType>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
186
186
|
fixedType?: import("./../../grid-component/type").FixedType;
|
|
187
187
|
headerTextWrap?: boolean;
|
|
188
188
|
ellipsis?: boolean;
|
|
189
189
|
allowResizing?: boolean;
|
|
190
190
|
align?: import("./../../grid-component/type").ITextAlign;
|
|
191
191
|
textAlign?: import("./../../grid-component/type").ITextAlign;
|
|
192
|
-
template?: import("react").
|
|
193
|
-
linkTemplate?: import("react").
|
|
192
|
+
template?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode | ((args: import("./../../grid-component/type").ColumnTemplate<RecordType>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
193
|
+
linkTemplate?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode | ((args: import("./../../grid-component/type").ColumnTemplate<RecordType>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
194
194
|
showTooltip?: boolean;
|
|
195
195
|
tooltipDescription?: string | ((args: {
|
|
196
196
|
value: any;
|
|
197
197
|
rowData: RecordType;
|
|
198
|
-
}) => import("react").
|
|
199
|
-
onCellStyles?: Omit<CSSProperties, "
|
|
200
|
-
onCellHeaderStyles?: Omit<CSSProperties, "
|
|
198
|
+
}) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | import("react").ReactNode);
|
|
199
|
+
onCellStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cellValue: any, cell: import("@tanstack/react-table").Cell<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
200
|
+
onCellHeaderStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cell: import("@tanstack/react-table").Header<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
201
201
|
onCell?: (rowData: RecordType, index: number) => import("react").TdHTMLAttributes<HTMLTableCellElement>;
|
|
202
|
-
onCellFooterStyles?: Omit<CSSProperties, "
|
|
202
|
+
onCellFooterStyles?: Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display"> | ((cellValue: any, cell: import("@tanstack/react-table").Header<RecordType, unknown>) => Omit<CSSProperties, "width" | "minWidth" | "left" | "right" | "position" | "display">);
|
|
203
203
|
getValue?: (row: any, rowIndex: number) => any;
|
|
204
204
|
getCellProps?: (value: any, row: any, rowIndex: number) => import("./../../grid-component/type").CellProps;
|
|
205
205
|
headerCellProps?: import("./../../grid-component/type").CellProps;
|
|
@@ -12,6 +12,7 @@ var _useContext = require("./useContext");
|
|
|
12
12
|
var _pagination = _interopRequireDefault(require("rc-master-ui/es/pagination"));
|
|
13
13
|
var _rcMasterUi = require("rc-master-ui");
|
|
14
14
|
var _becoxyIcons = require("becoxy-icons");
|
|
15
|
+
var _GridRefreshButton = _interopRequireDefault(require("../grid-component/GridRefreshButton"));
|
|
15
16
|
var _reactNumericComponent = require("react-numeric-component");
|
|
16
17
|
var _TableWrapper = _interopRequireDefault(require("./table/TableWrapper"));
|
|
17
18
|
var _utils = require("./hook/utils");
|
|
@@ -50,6 +51,7 @@ const TableContainer = props => {
|
|
|
50
51
|
toolbarItems,
|
|
51
52
|
toolbarMode,
|
|
52
53
|
actionTemplate,
|
|
54
|
+
onRefresh,
|
|
53
55
|
pagination,
|
|
54
56
|
fullScreen,
|
|
55
57
|
showColumnChoose,
|
|
@@ -239,7 +241,7 @@ const TableContainer = props => {
|
|
|
239
241
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
240
242
|
ref: containerRef,
|
|
241
243
|
id: id
|
|
242
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/_react.default.createElement("div", {
|
|
244
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/_react.default.createElement("div", {
|
|
243
245
|
ref: topToolbarRef,
|
|
244
246
|
className: (0, _classnames.default)(`${prefix}-grid-top-toolbar`, {})
|
|
245
247
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -282,7 +284,11 @@ const TableContainer = props => {
|
|
|
282
284
|
}, /*#__PURE__*/_react.default.createElement(_rcMasterUi.Toolbar, {
|
|
283
285
|
items: toolbarItemTopRight,
|
|
284
286
|
mode: toolbarMode
|
|
285
|
-
})),
|
|
287
|
+
})), /*#__PURE__*/_react.default.createElement(_GridRefreshButton.default, {
|
|
288
|
+
id: id,
|
|
289
|
+
onRefresh: onRefresh,
|
|
290
|
+
t: t
|
|
291
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/_react.default.createElement(_becoxyIcons.Minimize, {
|
|
286
292
|
fontSize: 16,
|
|
287
293
|
onClick: () => {
|
|
288
294
|
setIsFullScreen(!isFullScreen);
|
|
@@ -115,6 +115,8 @@ const InternalTable = props => {
|
|
|
115
115
|
const [columns, setColumns] = _react.default.useState([]);
|
|
116
116
|
const [tableData, setTableData] = _react.default.useState([]);
|
|
117
117
|
const [expanded, setExpanded] = _react.default.useState({});
|
|
118
|
+
// Đánh dấu đã áp dụng expansion mặc định, tránh mở lại nhánh người dùng đóng khi task cập nhật.
|
|
119
|
+
const initializedExpansionRef = _react.default.useRef(false);
|
|
118
120
|
|
|
119
121
|
// const [visible, setVisible] = React.useState({visible: false, column: ''})
|
|
120
122
|
|
|
@@ -219,7 +221,7 @@ const InternalTable = props => {
|
|
|
219
221
|
expanded,
|
|
220
222
|
columnPinning,
|
|
221
223
|
columnVisibility: columnsHiddenKeys ? (0, _utils.convertToObj)(columnsHiddenKeys) : columnVisibility,
|
|
222
|
-
pagination:
|
|
224
|
+
pagination: paginationState,
|
|
223
225
|
// grouping,
|
|
224
226
|
columnSizing,
|
|
225
227
|
// columnOrder,
|
|
@@ -276,7 +278,8 @@ const InternalTable = props => {
|
|
|
276
278
|
getGroupedRowModel: (0, _reactTable.getGroupedRowModel)(),
|
|
277
279
|
// onExpandedChange: setExpanded,
|
|
278
280
|
getExpandedRowModel: (0, _reactTable.getExpandedRowModel)(),
|
|
279
|
-
|
|
281
|
+
// Khi không bật phân trang client, giữ nguyên toàn bộ dữ liệu BE/viewport và tránh row model phân trang cũ được dùng lại.
|
|
282
|
+
manualPagination: !shouldUseClientPagination,
|
|
280
283
|
// Chỉ để TanStack tự phân trang khi có pagination, không dùng infinite scroll và đang ở chế độ client.
|
|
281
284
|
// Với server pagination, dữ liệu đã được BE phân trang nên không chạy getPaginationRowModel() để tránh phân trang lần 2.
|
|
282
285
|
getPaginationRowModel: shouldUseClientPagination ? (0, _reactTable.getPaginationRowModel)() : undefined,
|
|
@@ -287,6 +290,13 @@ const InternalTable = props => {
|
|
|
287
290
|
// debugTable: true
|
|
288
291
|
});
|
|
289
292
|
_react.default.useEffect(() => {
|
|
293
|
+
if (expandable?.preserveExpandedOnDataChange) {
|
|
294
|
+
// Chờ cây có dữ liệu mới khởi tạo; những lần thay đổi tableData sau đó không reset expanded.
|
|
295
|
+
if (initializedExpansionRef.current || tableData.length === 0) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
initializedExpansionRef.current = true;
|
|
299
|
+
}
|
|
290
300
|
if (defaultExpandAllRows) {
|
|
291
301
|
const allKeys = (0, _utils.findAllChildrenKeys2)(tableData, rowKey, 'children');
|
|
292
302
|
setExpanded((0, _utils.convertToObjTrue)(allKeys));
|
|
@@ -295,7 +305,7 @@ const InternalTable = props => {
|
|
|
295
305
|
setExpanded((0, _utils.convertToObjTrue)(defaultExpandedRowKeys ?? []));
|
|
296
306
|
}
|
|
297
307
|
}
|
|
298
|
-
}, [defaultExpandAllRows, defaultExpandedRowKeys, tableData]);
|
|
308
|
+
}, [defaultExpandAllRows, defaultExpandedRowKeys, tableData, expandable?.preserveExpandedOnDataChange]);
|
|
299
309
|
const triggerGroupColumns = groupedColumns => {
|
|
300
310
|
// const abc = updateColumnsByGroup(columns, groupedColumns)
|
|
301
311
|
|
|
@@ -11,6 +11,7 @@ var _classnames = _interopRequireDefault(require("classnames"));
|
|
|
11
11
|
var _pagination = _interopRequireDefault(require("rc-master-ui/es/pagination"));
|
|
12
12
|
var _rcMasterUi = require("rc-master-ui");
|
|
13
13
|
var _becoxyIcons = require("becoxy-icons");
|
|
14
|
+
var _GridRefreshButton = _interopRequireDefault(require("../../grid-component/GridRefreshButton"));
|
|
14
15
|
var _reactNumericComponent = require("react-numeric-component");
|
|
15
16
|
var _TableWrapper = _interopRequireDefault(require("./TableWrapper"));
|
|
16
17
|
var _ColumnsChoose = require("../../table-component/ColumnsChoose");
|
|
@@ -50,6 +51,7 @@ const TableContainer = props => {
|
|
|
50
51
|
showToolbar,
|
|
51
52
|
toolbarItems,
|
|
52
53
|
actionTemplate,
|
|
54
|
+
onRefresh,
|
|
53
55
|
pagination,
|
|
54
56
|
fullScreen,
|
|
55
57
|
showColumnChoose,
|
|
@@ -192,7 +194,7 @@ const TableContainer = props => {
|
|
|
192
194
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
193
195
|
ref: containerRef,
|
|
194
196
|
id: id
|
|
195
|
-
}, (showToolbar !== false || fullScreen !== false || title) && /*#__PURE__*/_react.default.createElement("div", {
|
|
197
|
+
}, (showToolbar !== false || fullScreen !== false || title || onRefresh) && /*#__PURE__*/_react.default.createElement("div", {
|
|
196
198
|
ref: topToolbarRef,
|
|
197
199
|
className: (0, _classnames.default)(`${prefix}-grid-top-toolbar`, {})
|
|
198
200
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -236,7 +238,11 @@ const TableContainer = props => {
|
|
|
236
238
|
}, /*#__PURE__*/_react.default.createElement(_rcMasterUi.Toolbar, {
|
|
237
239
|
items: toolbarItemTopRight,
|
|
238
240
|
mode: toolbarMode
|
|
239
|
-
})),
|
|
241
|
+
})), /*#__PURE__*/_react.default.createElement(_GridRefreshButton.default, {
|
|
242
|
+
id: id,
|
|
243
|
+
onRefresh: onRefresh,
|
|
244
|
+
t: t
|
|
245
|
+
}), fullScreen !== false && (isFullScreen ? /*#__PURE__*/_react.default.createElement(_becoxyIcons.Minimize, {
|
|
240
246
|
fontSize: 16,
|
|
241
247
|
onClick: () => {
|
|
242
248
|
setIsFullScreen(!isFullScreen);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ColumnDef, Table } from "@tanstack/react-table";
|
|
3
|
-
import type { CommandClick, ContextInfo, ContextMenuItem, PaginationConfig } from '../../grid-component/type';
|
|
3
|
+
import type { CommandClick, ContextInfo, ContextMenuItem, PaginationConfig, TableProps } from '../../grid-component/type';
|
|
4
4
|
type Props<T> = {
|
|
5
5
|
tableContainerRef: React.RefObject<HTMLDivElement>;
|
|
6
6
|
table: Table<T>;
|
|
@@ -22,6 +22,7 @@ type Props<T> = {
|
|
|
22
22
|
next?: () => void;
|
|
23
23
|
pagination?: false | PaginationConfig;
|
|
24
24
|
infiniteScroll?: boolean;
|
|
25
|
+
onVisibleRowsChange?: TableProps<T>['onVisibleRowsChange'];
|
|
25
26
|
};
|
|
26
27
|
declare const TableWrapper: <RecordType extends object>(props: Props<RecordType>) => JSX.Element;
|
|
27
28
|
export default TableWrapper;
|
|
@@ -32,6 +32,7 @@ const TableWrapper = props => {
|
|
|
32
32
|
contextMenuHidden,
|
|
33
33
|
contextMenuClick,
|
|
34
34
|
contextMenuOpen,
|
|
35
|
+
onVisibleRowsChange,
|
|
35
36
|
summary
|
|
36
37
|
} = props;
|
|
37
38
|
const menuRef = _react.default.useRef(null);
|
|
@@ -135,11 +136,24 @@ const TableWrapper = props => {
|
|
|
135
136
|
height,
|
|
136
137
|
position: "relative"
|
|
137
138
|
}
|
|
138
|
-
}, /*#__PURE__*/_react.default.createElement(_reactVirtuoso.TableVirtuoso, {
|
|
139
|
+
}, /*#__PURE__*/_react.default.createElement(_reactVirtuoso.TableVirtuoso, (0, _extends2.default)({
|
|
139
140
|
data: table.getRowModel().rows,
|
|
140
141
|
totalCount: rows.length
|
|
142
|
+
}, onVisibleRowsChange ? {
|
|
143
|
+
computeItemKey: (_index, row) => row.id,
|
|
144
|
+
rangeChanged: ({
|
|
145
|
+
startIndex,
|
|
146
|
+
endIndex
|
|
147
|
+
}) => {
|
|
148
|
+
// Dùng row ID sau expand/collapse của TanStack; index không phải vị trí trong cây dữ liệu gốc.
|
|
149
|
+
onVisibleRowsChange({
|
|
150
|
+
rowIds: rows.slice(startIndex, endIndex + 1).map(row => row.id),
|
|
151
|
+
startIndex,
|
|
152
|
+
endIndex
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
} : {}, {
|
|
141
156
|
// isScrolling={}
|
|
142
|
-
,
|
|
143
157
|
components: {
|
|
144
158
|
Table: ({
|
|
145
159
|
style,
|
|
@@ -253,7 +267,7 @@ const TableWrapper = props => {
|
|
|
253
267
|
});
|
|
254
268
|
}));
|
|
255
269
|
} : undefined
|
|
256
|
-
})), /*#__PURE__*/_react.default.createElement(_reactTooltip.Tooltip, {
|
|
270
|
+
}))), /*#__PURE__*/_react.default.createElement(_reactTooltip.Tooltip, {
|
|
257
271
|
id: `${id}-tooltip-content`,
|
|
258
272
|
style: {
|
|
259
273
|
zIndex: 1999,
|