@youp-grid/core 0.1.0
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/README.md +11 -0
- package/dist/aggregation.d.ts +2 -0
- package/dist/aggregation.js +58 -0
- package/dist/clipboard.d.ts +33 -0
- package/dist/clipboard.js +79 -0
- package/dist/column-state.d.ts +7 -0
- package/dist/column-state.js +66 -0
- package/dist/columns.d.ts +3 -0
- package/dist/columns.js +44 -0
- package/dist/csv.d.ts +15 -0
- package/dist/csv.js +30 -0
- package/dist/fill-handle.d.ts +17 -0
- package/dist/fill-handle.js +73 -0
- package/dist/filtering.d.ts +3 -0
- package/dist/filtering.js +68 -0
- package/dist/history.d.ts +28 -0
- package/dist/history.js +54 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +16 -0
- package/dist/infinite-scroll.d.ts +2 -0
- package/dist/infinite-scroll.js +24 -0
- package/dist/pagination.d.ts +5 -0
- package/dist/pagination.js +16 -0
- package/dist/row-grouping.d.ts +3 -0
- package/dist/row-grouping.js +65 -0
- package/dist/row-model.d.ts +2 -0
- package/dist/row-model.js +72 -0
- package/dist/selection.d.ts +5 -0
- package/dist/selection.js +28 -0
- package/dist/sorting.d.ts +2 -0
- package/dist/sorting.js +49 -0
- package/dist/state.d.ts +28 -0
- package/dist/state.js +295 -0
- package/dist/types.d.ts +181 -0
- package/dist/types.js +1 -0
- package/dist/virtualizer.d.ts +2 -0
- package/dist/virtualizer.js +47 -0
- package/package.json +29 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function getInfiniteScrollTrigger(options) {
|
|
2
|
+
const rowCount = Math.max(0, Math.trunc(options.rowCount));
|
|
3
|
+
const lastVisibleRowIndex = normalizeLastVisibleRowIndex(options.lastVisibleRowIndex, rowCount);
|
|
4
|
+
const threshold = Math.max(0, Math.trunc(options.threshold ?? 20));
|
|
5
|
+
const remainingRows = Math.max(0, rowCount - 1 - lastVisibleRowIndex);
|
|
6
|
+
const hasMoreRows = options.hasMoreRows ?? true;
|
|
7
|
+
const loading = options.loading ?? false;
|
|
8
|
+
return {
|
|
9
|
+
shouldLoadMore: rowCount > 0 && hasMoreRows && !loading && remainingRows <= threshold,
|
|
10
|
+
rowCount,
|
|
11
|
+
lastVisibleRowIndex,
|
|
12
|
+
threshold,
|
|
13
|
+
remainingRows,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function normalizeLastVisibleRowIndex(lastVisibleRowIndex, rowCount) {
|
|
17
|
+
if (rowCount === 0) {
|
|
18
|
+
return -1;
|
|
19
|
+
}
|
|
20
|
+
return clamp(Math.trunc(lastVisibleRowIndex), -1, rowCount - 1);
|
|
21
|
+
}
|
|
22
|
+
function clamp(value, min, max) {
|
|
23
|
+
return Math.min(Math.max(value, min), max);
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function applyPagination(rows, pagination) {
|
|
2
|
+
if (!pagination) {
|
|
3
|
+
return { rows: [...rows] };
|
|
4
|
+
}
|
|
5
|
+
const pageSize = Math.max(1, pagination.pageSize);
|
|
6
|
+
const pageCount = Math.max(1, Math.ceil(rows.length / pageSize));
|
|
7
|
+
const pageIndex = clamp(pagination.pageIndex, 0, pageCount - 1);
|
|
8
|
+
const start = pageIndex * pageSize;
|
|
9
|
+
return {
|
|
10
|
+
rows: rows.slice(start, start + pageSize),
|
|
11
|
+
pageCount,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function clamp(value, min, max) {
|
|
15
|
+
return Math.min(Math.max(value, min), max);
|
|
16
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ResolvedColumnDef, RowDisplayNode, RowGroupNode, RowGroupingState, RowNode } from "./types.ts";
|
|
2
|
+
export declare function applyRowGrouping<TRow>(rows: readonly RowNode<TRow>[], columns: readonly ResolvedColumnDef<TRow>[], rowGrouping?: RowGroupingState): RowDisplayNode<TRow>[];
|
|
3
|
+
export declare function isRowGroupNode<TRow>(row: RowDisplayNode<TRow>): row is RowGroupNode;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getColumnById } from "./columns.js";
|
|
2
|
+
export function applyRowGrouping(rows, columns, rowGrouping) {
|
|
3
|
+
const groupColumns = (rowGrouping?.columnIds ?? [])
|
|
4
|
+
.map((columnId) => getColumnById(columns, columnId))
|
|
5
|
+
.filter((column) => Boolean(column));
|
|
6
|
+
if (groupColumns.length === 0) {
|
|
7
|
+
return [...rows];
|
|
8
|
+
}
|
|
9
|
+
const collapsedGroupIds = new Set(rowGrouping?.collapsedGroupIds ?? []);
|
|
10
|
+
const groupedRows = groupRows(rows, groupColumns, collapsedGroupIds, 0, []);
|
|
11
|
+
return groupedRows.map((row, index) => isRowGroupNode(row) ? { ...row, index } : row);
|
|
12
|
+
}
|
|
13
|
+
export function isRowGroupNode(row) {
|
|
14
|
+
return "type" in row && row.type === "group";
|
|
15
|
+
}
|
|
16
|
+
function groupRows(rows, columns, collapsedGroupIds, depth, path) {
|
|
17
|
+
const column = columns[depth];
|
|
18
|
+
if (!column) {
|
|
19
|
+
return [...rows];
|
|
20
|
+
}
|
|
21
|
+
const grouped = new Map();
|
|
22
|
+
for (const row of rows) {
|
|
23
|
+
const value = column.accessor(row.original);
|
|
24
|
+
const key = stringifyGroupValue(value);
|
|
25
|
+
const existing = grouped.get(key);
|
|
26
|
+
if (existing) {
|
|
27
|
+
existing.rows.push(row);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
grouped.set(key, { value, rows: [row] });
|
|
31
|
+
}
|
|
32
|
+
const result = [];
|
|
33
|
+
for (const [key, group] of grouped) {
|
|
34
|
+
const groupId = createGroupId([...path, `${column.id}:${key}`]);
|
|
35
|
+
const expanded = !collapsedGroupIds.has(groupId);
|
|
36
|
+
result.push({
|
|
37
|
+
type: "group",
|
|
38
|
+
id: groupId,
|
|
39
|
+
groupId,
|
|
40
|
+
index: result.length,
|
|
41
|
+
depth,
|
|
42
|
+
columnId: column.id,
|
|
43
|
+
value: group.value,
|
|
44
|
+
label: stringifyGroupLabel(group.value),
|
|
45
|
+
rowCount: group.rows.length,
|
|
46
|
+
expanded,
|
|
47
|
+
});
|
|
48
|
+
if (expanded) {
|
|
49
|
+
result.push(...groupRows(group.rows, columns, collapsedGroupIds, depth + 1, [
|
|
50
|
+
...path,
|
|
51
|
+
`${column.id}:${key}`,
|
|
52
|
+
]));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function createGroupId(path) {
|
|
58
|
+
return `group:${path.join("/")}`;
|
|
59
|
+
}
|
|
60
|
+
function stringifyGroupValue(value) {
|
|
61
|
+
return encodeURIComponent(stringifyGroupLabel(value));
|
|
62
|
+
}
|
|
63
|
+
function stringifyGroupLabel(value) {
|
|
64
|
+
return String(value ?? "(empty)");
|
|
65
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { applyColumnState, getVisibleColumns } from "./column-state.js";
|
|
2
|
+
import { applyAggregation } from "./aggregation.js";
|
|
3
|
+
import { normalizeColumns } from "./columns.js";
|
|
4
|
+
import { applyFilters } from "./filtering.js";
|
|
5
|
+
import { applyPagination } from "./pagination.js";
|
|
6
|
+
import { applyRowGrouping } from "./row-grouping.js";
|
|
7
|
+
import { applySorting } from "./sorting.js";
|
|
8
|
+
export function buildRowModel(options) {
|
|
9
|
+
const columns = applyColumnState(normalizeColumns(options.columns), options.state?.columns);
|
|
10
|
+
const visibleColumns = getVisibleColumns(columns);
|
|
11
|
+
const allRows = createRowNodes(options.rows, options.getRowId);
|
|
12
|
+
if (options.rowModelType === "server") {
|
|
13
|
+
return buildServerRowModel({
|
|
14
|
+
allRows,
|
|
15
|
+
columns,
|
|
16
|
+
visibleColumns,
|
|
17
|
+
state: options.state,
|
|
18
|
+
serverRowCount: options.serverRowCount,
|
|
19
|
+
serverFilteredRowCount: options.serverFilteredRowCount,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const filteredRows = applyFilters(allRows, columns, options.state?.filters);
|
|
23
|
+
const sortedRows = applySorting(filteredRows, columns, options.state?.sort);
|
|
24
|
+
const paginated = applyPagination(sortedRows, options.state?.pagination);
|
|
25
|
+
const aggregation = applyAggregation(filteredRows, columns, options.state?.aggregation);
|
|
26
|
+
const displayRows = applyRowGrouping(paginated.rows, columns, options.state?.rowGrouping);
|
|
27
|
+
return {
|
|
28
|
+
columns,
|
|
29
|
+
visibleColumns,
|
|
30
|
+
allRows,
|
|
31
|
+
filteredRows,
|
|
32
|
+
sortedRows,
|
|
33
|
+
visibleRows: paginated.rows,
|
|
34
|
+
displayRows,
|
|
35
|
+
aggregation,
|
|
36
|
+
totalRowCount: allRows.length,
|
|
37
|
+
filteredRowCount: filteredRows.length,
|
|
38
|
+
visibleRowCount: paginated.rows.length,
|
|
39
|
+
pageCount: paginated.pageCount,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function buildServerRowModel(context) {
|
|
43
|
+
const totalRowCount = context.serverRowCount ?? context.allRows.length;
|
|
44
|
+
const filteredRowCount = context.serverFilteredRowCount ?? totalRowCount;
|
|
45
|
+
return {
|
|
46
|
+
columns: context.columns,
|
|
47
|
+
visibleColumns: context.visibleColumns,
|
|
48
|
+
allRows: context.allRows,
|
|
49
|
+
filteredRows: context.allRows,
|
|
50
|
+
sortedRows: context.allRows,
|
|
51
|
+
visibleRows: context.allRows,
|
|
52
|
+
displayRows: applyRowGrouping(context.allRows, context.columns, context.state?.rowGrouping),
|
|
53
|
+
aggregation: applyAggregation(context.allRows, context.columns, context.state?.aggregation),
|
|
54
|
+
totalRowCount,
|
|
55
|
+
filteredRowCount,
|
|
56
|
+
visibleRowCount: context.allRows.length,
|
|
57
|
+
pageCount: getServerPageCount(filteredRowCount, context.state?.pagination),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function getServerPageCount(rowCount, pagination) {
|
|
61
|
+
if (!pagination) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return Math.ceil(Math.max(0, rowCount) / Math.max(1, pagination.pageSize));
|
|
65
|
+
}
|
|
66
|
+
function createRowNodes(rows, getRowId) {
|
|
67
|
+
return rows.map((row, index) => ({
|
|
68
|
+
id: getRowId ? getRowId(row, index) : index,
|
|
69
|
+
index,
|
|
70
|
+
original: row,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { GridRowId, GridState } from "./types.ts";
|
|
2
|
+
export declare function setRowSelected(state: GridState, rowId: GridRowId, selected: boolean): GridState;
|
|
3
|
+
export declare function toggleRowSelected(state: GridState, rowId: GridRowId): GridState;
|
|
4
|
+
export declare function setSelectedRows(state: GridState, rowIds: readonly GridRowId[]): GridState;
|
|
5
|
+
export declare function clearSelection(state: GridState): GridState;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function setRowSelected(state, rowId, selected) {
|
|
2
|
+
const selectedRowIds = new Set(state.selectedRowIds ?? []);
|
|
3
|
+
if (selected) {
|
|
4
|
+
selectedRowIds.add(rowId);
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
selectedRowIds.delete(rowId);
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
...state,
|
|
11
|
+
selectedRowIds: [...selectedRowIds],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function toggleRowSelected(state, rowId) {
|
|
15
|
+
return setRowSelected(state, rowId, !(state.selectedRowIds ?? []).includes(rowId));
|
|
16
|
+
}
|
|
17
|
+
export function setSelectedRows(state, rowIds) {
|
|
18
|
+
return {
|
|
19
|
+
...state,
|
|
20
|
+
selectedRowIds: [...new Set(rowIds)],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function clearSelection(state) {
|
|
24
|
+
return {
|
|
25
|
+
...state,
|
|
26
|
+
selectedRowIds: [],
|
|
27
|
+
};
|
|
28
|
+
}
|
package/dist/sorting.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getColumnById } from "./columns.js";
|
|
2
|
+
export function applySorting(rows, columns, sortRules = []) {
|
|
3
|
+
const activeRules = sortRules.filter((rule) => rule.direction);
|
|
4
|
+
if (activeRules.length === 0) {
|
|
5
|
+
return [...rows];
|
|
6
|
+
}
|
|
7
|
+
return [...rows].sort((left, right) => {
|
|
8
|
+
for (const rule of activeRules) {
|
|
9
|
+
const column = getColumnById(columns, rule.columnId);
|
|
10
|
+
if (!column) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const result = compareRows(left, right, column);
|
|
14
|
+
if (result !== 0) {
|
|
15
|
+
return rule.direction === "desc" ? -result : result;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return left.index - right.index;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function compareRows(left, right, column) {
|
|
22
|
+
const leftValue = column.accessor(left.original);
|
|
23
|
+
const rightValue = column.accessor(right.original);
|
|
24
|
+
if (column.comparator) {
|
|
25
|
+
return column.comparator(leftValue, rightValue, left.original, right.original);
|
|
26
|
+
}
|
|
27
|
+
return comparePrimitive(leftValue, rightValue);
|
|
28
|
+
}
|
|
29
|
+
function comparePrimitive(left, right) {
|
|
30
|
+
if (left == null && right == null) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
if (left == null) {
|
|
34
|
+
return -1;
|
|
35
|
+
}
|
|
36
|
+
if (right == null) {
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
40
|
+
return left - right;
|
|
41
|
+
}
|
|
42
|
+
if (left instanceof Date && right instanceof Date) {
|
|
43
|
+
return left.getTime() - right.getTime();
|
|
44
|
+
}
|
|
45
|
+
return String(left).localeCompare(String(right), undefined, {
|
|
46
|
+
numeric: true,
|
|
47
|
+
sensitivity: "base",
|
|
48
|
+
});
|
|
49
|
+
}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AggregationRule, CursorPaginationState, FilterRule, GridState, PaginationState, RemoteCacheState, RowGroupingState, SortDirection } from "./types.ts";
|
|
2
|
+
export declare function createGridState(state?: GridState): GridState;
|
|
3
|
+
export declare function toggleSort(state: GridState, columnId: string, options?: {
|
|
4
|
+
multi?: boolean;
|
|
5
|
+
cycle?: readonly (SortDirection | undefined)[];
|
|
6
|
+
}): GridState;
|
|
7
|
+
export declare function setSort(state: GridState, columnId: string, direction: SortDirection, options?: {
|
|
8
|
+
multi?: boolean;
|
|
9
|
+
}): GridState;
|
|
10
|
+
export declare function clearSort(state: GridState, columnId: string): GridState;
|
|
11
|
+
export declare function setFilter(state: GridState, filter: FilterRule): GridState;
|
|
12
|
+
export declare function clearFilter(state: GridState, columnId: string): GridState;
|
|
13
|
+
export declare function setPagination(state: GridState, pagination: PaginationState): GridState;
|
|
14
|
+
export declare function setCursorPagination(state: GridState, cursorPagination: CursorPaginationState): GridState;
|
|
15
|
+
export declare function setCursorPage(state: GridState, cursor: string | undefined): GridState;
|
|
16
|
+
export declare function setCursorPageSize(state: GridState, pageSize: number): GridState;
|
|
17
|
+
export declare function setAggregation(state: GridState, aggregation: readonly AggregationRule[]): GridState;
|
|
18
|
+
export declare function setRowGrouping(state: GridState, rowGrouping: RowGroupingState | undefined): GridState;
|
|
19
|
+
export declare function toggleRowGroupExpanded(state: GridState, groupId: string): GridState;
|
|
20
|
+
export declare function startRemoteRequest(state: GridState, requestId: string): GridState;
|
|
21
|
+
export declare function finishRemoteRequest(state: GridState, requestId: string): GridState;
|
|
22
|
+
export declare function failRemoteRequest(state: GridState, requestId: string, error?: string): GridState;
|
|
23
|
+
export declare function cancelRemoteRequest(state: GridState, requestId?: string | undefined): GridState;
|
|
24
|
+
export declare function isActiveRemoteRequest(state: GridState, requestId: string): boolean;
|
|
25
|
+
export declare function createRemoteCacheKey(state: GridState): string;
|
|
26
|
+
export declare function setRemoteCache(state: GridState, remoteCache: RemoteCacheState): GridState;
|
|
27
|
+
export declare function invalidateRemoteCache(state: GridState, key?: string): GridState;
|
|
28
|
+
export declare function acknowledgeRemoteCache(state: GridState, key?: string): GridState;
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
export function createGridState(state = {}) {
|
|
2
|
+
return {
|
|
3
|
+
columns: state.columns ? [...state.columns] : [],
|
|
4
|
+
sort: state.sort ? [...state.sort] : [],
|
|
5
|
+
filters: state.filters ? [...state.filters] : [],
|
|
6
|
+
aggregation: state.aggregation ? [...state.aggregation] : [],
|
|
7
|
+
rowGrouping: state.rowGrouping
|
|
8
|
+
? {
|
|
9
|
+
columnIds: [...state.rowGrouping.columnIds],
|
|
10
|
+
collapsedGroupIds: state.rowGrouping.collapsedGroupIds
|
|
11
|
+
? [...state.rowGrouping.collapsedGroupIds]
|
|
12
|
+
: undefined,
|
|
13
|
+
}
|
|
14
|
+
: undefined,
|
|
15
|
+
pagination: state.pagination ? { ...state.pagination } : undefined,
|
|
16
|
+
cursorPagination: state.cursorPagination ? { ...state.cursorPagination } : undefined,
|
|
17
|
+
remoteRequest: state.remoteRequest ? { ...state.remoteRequest } : undefined,
|
|
18
|
+
remoteCache: state.remoteCache
|
|
19
|
+
? {
|
|
20
|
+
...state.remoteCache,
|
|
21
|
+
invalidatedKeys: state.remoteCache.invalidatedKeys
|
|
22
|
+
? [...state.remoteCache.invalidatedKeys]
|
|
23
|
+
: undefined,
|
|
24
|
+
}
|
|
25
|
+
: undefined,
|
|
26
|
+
selectedRowIds: state.selectedRowIds ? [...state.selectedRowIds] : [],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function toggleSort(state, columnId, options = {}) {
|
|
30
|
+
const cycle = options.cycle ?? ["asc", "desc", undefined];
|
|
31
|
+
const currentRules = state.sort ?? [];
|
|
32
|
+
const currentRule = currentRules.find((rule) => rule.columnId === columnId);
|
|
33
|
+
const currentIndex = cycle.findIndex((direction) => direction === currentRule?.direction);
|
|
34
|
+
const nextDirection = cycle[(currentIndex + 1) % cycle.length];
|
|
35
|
+
const remainingRules = options.multi
|
|
36
|
+
? currentRules.filter((rule) => rule.columnId !== columnId)
|
|
37
|
+
: [];
|
|
38
|
+
return {
|
|
39
|
+
...state,
|
|
40
|
+
sort: nextDirection
|
|
41
|
+
? [...remainingRules, { columnId, direction: nextDirection }]
|
|
42
|
+
: remainingRules,
|
|
43
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function setSort(state, columnId, direction, options = {}) {
|
|
47
|
+
const currentRules = state.sort ?? [];
|
|
48
|
+
const remainingRules = options.multi
|
|
49
|
+
? currentRules.filter((rule) => rule.columnId !== columnId)
|
|
50
|
+
: [];
|
|
51
|
+
return {
|
|
52
|
+
...state,
|
|
53
|
+
sort: [...remainingRules, { columnId, direction }],
|
|
54
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function clearSort(state, columnId) {
|
|
58
|
+
return {
|
|
59
|
+
...state,
|
|
60
|
+
sort: (state.sort ?? []).filter((rule) => rule.columnId !== columnId),
|
|
61
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function setFilter(state, filter) {
|
|
65
|
+
const filters = (state.filters ?? []).filter((item) => item.columnId !== filter.columnId);
|
|
66
|
+
return {
|
|
67
|
+
...state,
|
|
68
|
+
filters: [...filters, filter],
|
|
69
|
+
pagination: resetPageIndex(state.pagination),
|
|
70
|
+
cursorPagination: resetCursor(state.cursorPagination),
|
|
71
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function clearFilter(state, columnId) {
|
|
75
|
+
return {
|
|
76
|
+
...state,
|
|
77
|
+
filters: (state.filters ?? []).filter((filter) => filter.columnId !== columnId),
|
|
78
|
+
pagination: resetPageIndex(state.pagination),
|
|
79
|
+
cursorPagination: resetCursor(state.cursorPagination),
|
|
80
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function setPagination(state, pagination) {
|
|
84
|
+
return {
|
|
85
|
+
...state,
|
|
86
|
+
pagination: {
|
|
87
|
+
pageIndex: Math.max(0, pagination.pageIndex),
|
|
88
|
+
pageSize: Math.max(1, pagination.pageSize),
|
|
89
|
+
},
|
|
90
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function setCursorPagination(state, cursorPagination) {
|
|
94
|
+
return {
|
|
95
|
+
...state,
|
|
96
|
+
cursorPagination: {
|
|
97
|
+
...cursorPagination,
|
|
98
|
+
pageSize: Math.max(1, cursorPagination.pageSize),
|
|
99
|
+
},
|
|
100
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function setCursorPage(state, cursor) {
|
|
104
|
+
const cursorPagination = state.cursorPagination ?? {
|
|
105
|
+
pageSize: state.pagination?.pageSize ?? 50,
|
|
106
|
+
};
|
|
107
|
+
return setCursorPagination(state, {
|
|
108
|
+
...cursorPagination,
|
|
109
|
+
cursor,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
export function setCursorPageSize(state, pageSize) {
|
|
113
|
+
return setCursorPagination(state, {
|
|
114
|
+
...state.cursorPagination,
|
|
115
|
+
cursor: undefined,
|
|
116
|
+
pageSize,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
export function setAggregation(state, aggregation) {
|
|
120
|
+
return {
|
|
121
|
+
...state,
|
|
122
|
+
aggregation: [...aggregation],
|
|
123
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export function setRowGrouping(state, rowGrouping) {
|
|
127
|
+
return {
|
|
128
|
+
...state,
|
|
129
|
+
rowGrouping: rowGrouping
|
|
130
|
+
? {
|
|
131
|
+
columnIds: [...rowGrouping.columnIds],
|
|
132
|
+
collapsedGroupIds: rowGrouping.collapsedGroupIds
|
|
133
|
+
? [...rowGrouping.collapsedGroupIds]
|
|
134
|
+
: undefined,
|
|
135
|
+
}
|
|
136
|
+
: undefined,
|
|
137
|
+
remoteCache: markRemoteCacheStale(state.remoteCache),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export function toggleRowGroupExpanded(state, groupId) {
|
|
141
|
+
const rowGrouping = state.rowGrouping;
|
|
142
|
+
if (!rowGrouping) {
|
|
143
|
+
return state;
|
|
144
|
+
}
|
|
145
|
+
const collapsedGroupIds = new Set(rowGrouping.collapsedGroupIds ?? []);
|
|
146
|
+
if (collapsedGroupIds.has(groupId)) {
|
|
147
|
+
collapsedGroupIds.delete(groupId);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
collapsedGroupIds.add(groupId);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
...state,
|
|
154
|
+
rowGrouping: {
|
|
155
|
+
...rowGrouping,
|
|
156
|
+
columnIds: [...rowGrouping.columnIds],
|
|
157
|
+
collapsedGroupIds: collapsedGroupIds.size > 0 ? [...collapsedGroupIds] : undefined,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export function startRemoteRequest(state, requestId) {
|
|
162
|
+
return {
|
|
163
|
+
...state,
|
|
164
|
+
remoteRequest: {
|
|
165
|
+
requestId,
|
|
166
|
+
sequence: (state.remoteRequest?.sequence ?? 0) + 1,
|
|
167
|
+
status: "loading",
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
export function finishRemoteRequest(state, requestId) {
|
|
172
|
+
if (!isActiveRemoteRequest(state, requestId)) {
|
|
173
|
+
return state;
|
|
174
|
+
}
|
|
175
|
+
return setRemoteRequestStatus(state, {
|
|
176
|
+
requestId,
|
|
177
|
+
sequence: state.remoteRequest?.sequence ?? 0,
|
|
178
|
+
status: "success",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
export function failRemoteRequest(state, requestId, error) {
|
|
182
|
+
if (!isActiveRemoteRequest(state, requestId)) {
|
|
183
|
+
return state;
|
|
184
|
+
}
|
|
185
|
+
return setRemoteRequestStatus(state, {
|
|
186
|
+
requestId,
|
|
187
|
+
sequence: state.remoteRequest?.sequence ?? 0,
|
|
188
|
+
status: "error",
|
|
189
|
+
error,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
export function cancelRemoteRequest(state, requestId = state.remoteRequest?.requestId) {
|
|
193
|
+
if (!requestId || !isActiveRemoteRequest(state, requestId)) {
|
|
194
|
+
return state;
|
|
195
|
+
}
|
|
196
|
+
return setRemoteRequestStatus(state, {
|
|
197
|
+
requestId,
|
|
198
|
+
sequence: state.remoteRequest?.sequence ?? 0,
|
|
199
|
+
status: "cancelled",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
export function isActiveRemoteRequest(state, requestId) {
|
|
203
|
+
return state.remoteRequest?.requestId === requestId && state.remoteRequest.status === "loading";
|
|
204
|
+
}
|
|
205
|
+
export function createRemoteCacheKey(state) {
|
|
206
|
+
return JSON.stringify({
|
|
207
|
+
sort: state.sort ?? [],
|
|
208
|
+
filters: state.filters ?? [],
|
|
209
|
+
aggregation: state.aggregation ?? [],
|
|
210
|
+
rowGrouping: state.rowGrouping,
|
|
211
|
+
pagination: state.pagination,
|
|
212
|
+
cursorPagination: state.cursorPagination,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
export function setRemoteCache(state, remoteCache) {
|
|
216
|
+
return {
|
|
217
|
+
...state,
|
|
218
|
+
remoteCache: normalizeRemoteCache(remoteCache),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
export function invalidateRemoteCache(state, key = state.remoteCache?.key ?? createRemoteCacheKey(state)) {
|
|
222
|
+
const remoteCache = normalizeRemoteCache(state.remoteCache);
|
|
223
|
+
return {
|
|
224
|
+
...state,
|
|
225
|
+
remoteCache: {
|
|
226
|
+
...remoteCache,
|
|
227
|
+
key,
|
|
228
|
+
version: remoteCache.version + 1,
|
|
229
|
+
stale: true,
|
|
230
|
+
invalidatedKeys: addUniqueKey(remoteCache.invalidatedKeys, key),
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export function acknowledgeRemoteCache(state, key = state.remoteCache?.key ?? createRemoteCacheKey(state)) {
|
|
235
|
+
const remoteCache = normalizeRemoteCache(state.remoteCache);
|
|
236
|
+
const invalidatedKeys = (remoteCache.invalidatedKeys ?? []).filter((item) => item !== key);
|
|
237
|
+
const nextRemoteCache = normalizeRemoteCache({
|
|
238
|
+
...remoteCache,
|
|
239
|
+
key,
|
|
240
|
+
stale: invalidatedKeys.length > 0,
|
|
241
|
+
invalidatedKeys: invalidatedKeys.length > 0 ? invalidatedKeys : undefined,
|
|
242
|
+
});
|
|
243
|
+
return {
|
|
244
|
+
...state,
|
|
245
|
+
remoteCache: nextRemoteCache,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function resetPageIndex(pagination) {
|
|
249
|
+
if (!pagination) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
...pagination,
|
|
254
|
+
pageIndex: 0,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function resetCursor(cursorPagination) {
|
|
258
|
+
if (!cursorPagination) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
...cursorPagination,
|
|
263
|
+
cursor: undefined,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function setRemoteRequestStatus(state, remoteRequest) {
|
|
267
|
+
return {
|
|
268
|
+
...state,
|
|
269
|
+
remoteRequest,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function markRemoteCacheStale(remoteCache) {
|
|
273
|
+
if (!remoteCache) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
...normalizeRemoteCache(remoteCache),
|
|
278
|
+
stale: true,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function normalizeRemoteCache(remoteCache) {
|
|
282
|
+
const { invalidatedKeys: rawInvalidatedKeys, ...rest } = remoteCache ?? {};
|
|
283
|
+
const invalidatedKeys = rawInvalidatedKeys ? [...new Set(rawInvalidatedKeys)] : undefined;
|
|
284
|
+
const nextRemoteCache = {
|
|
285
|
+
...rest,
|
|
286
|
+
version: Math.max(0, Math.trunc(remoteCache?.version ?? 0)),
|
|
287
|
+
};
|
|
288
|
+
if (invalidatedKeys && invalidatedKeys.length > 0) {
|
|
289
|
+
nextRemoteCache.invalidatedKeys = invalidatedKeys;
|
|
290
|
+
}
|
|
291
|
+
return nextRemoteCache;
|
|
292
|
+
}
|
|
293
|
+
function addUniqueKey(keys, key) {
|
|
294
|
+
return [...new Set([...(keys ?? []), key])];
|
|
295
|
+
}
|