@mui/x-data-grid-premium 8.18.0 → 8.20.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/CHANGELOG.md +175 -0
- package/DataGridPremium/DataGridPremium.d.ts +1 -1
- package/DataGridPremium/DataGridPremium.js +40 -7
- package/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
- package/DataGridPremium/useDataGridPremiumComponent.js +3 -2
- package/components/GridFooterCell.js +1 -1
- package/esm/DataGridPremium/DataGridPremium.d.ts +1 -1
- package/esm/DataGridPremium/DataGridPremium.js +40 -7
- package/esm/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
- package/esm/DataGridPremium/useDataGridPremiumComponent.js +4 -3
- package/esm/components/GridFooterCell.js +1 -1
- package/esm/hooks/features/aggregation/useGridAggregation.js +38 -17
- package/esm/hooks/features/chartsIntegration/useGridChartsIntegration.js +1 -0
- package/esm/hooks/features/rowGrouping/useGridRowGrouping.d.ts +1 -1
- package/esm/hooks/features/rowGrouping/useGridRowGrouping.js +21 -17
- package/esm/hooks/features/rowReorder/operations.d.ts +7 -27
- package/esm/hooks/features/rowReorder/operations.js +133 -274
- package/esm/hooks/features/rowReorder/rowGroupingReorderExecutor.d.ts +2 -0
- package/esm/hooks/features/rowReorder/rowGroupingReorderExecutor.js +3 -0
- package/esm/hooks/features/rowReorder/rowGroupingReorderValidator.d.ts +2 -0
- package/esm/hooks/features/rowReorder/{reorderValidator.js → rowGroupingReorderValidator.js} +2 -22
- package/esm/hooks/features/rows/useGridRowsOverridableMethods.d.ts +3 -3
- package/esm/hooks/features/rows/useGridRowsOverridableMethods.js +61 -7
- package/esm/index.js +1 -1
- package/hooks/features/aggregation/useGridAggregation.js +37 -16
- package/hooks/features/chartsIntegration/useGridChartsIntegration.js +1 -0
- package/hooks/features/rowGrouping/useGridRowGrouping.d.ts +1 -1
- package/hooks/features/rowGrouping/useGridRowGrouping.js +20 -16
- package/hooks/features/rowReorder/operations.d.ts +7 -27
- package/hooks/features/rowReorder/operations.js +136 -279
- package/hooks/features/rowReorder/rowGroupingReorderExecutor.d.ts +2 -0
- package/hooks/features/rowReorder/rowGroupingReorderExecutor.js +9 -0
- package/hooks/features/rowReorder/rowGroupingReorderValidator.d.ts +2 -0
- package/hooks/features/rowReorder/rowGroupingReorderValidator.js +102 -0
- package/hooks/features/rows/useGridRowsOverridableMethods.d.ts +3 -3
- package/hooks/features/rows/useGridRowsOverridableMethods.js +61 -7
- package/index.js +1 -1
- package/package.json +6 -6
- package/esm/hooks/features/rowReorder/reorderExecutor.d.ts +0 -15
- package/esm/hooks/features/rowReorder/reorderExecutor.js +0 -25
- package/esm/hooks/features/rowReorder/reorderValidator.d.ts +0 -16
- package/esm/hooks/features/rowReorder/types.d.ts +0 -42
- package/esm/hooks/features/rowReorder/types.js +0 -1
- package/esm/hooks/features/rowReorder/utils.d.ts +0 -127
- package/esm/hooks/features/rowReorder/utils.js +0 -343
- package/hooks/features/rowReorder/reorderExecutor.d.ts +0 -15
- package/hooks/features/rowReorder/reorderExecutor.js +0 -31
- package/hooks/features/rowReorder/reorderValidator.d.ts +0 -16
- package/hooks/features/rowReorder/reorderValidator.js +0 -122
- package/hooks/features/rowReorder/types.d.ts +0 -42
- package/hooks/features/rowReorder/types.js +0 -5
- package/hooks/features/rowReorder/utils.d.ts +0 -127
- package/hooks/features/rowReorder/utils.js +0 -360
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import type { RefObject } from '@mui/x-internals/types';
|
|
2
|
-
import { type GridRowId, type GridTreeNode, type GridGroupNode, type GridRowTreeConfig, type GridKeyValue, type GridValidRowModel } from '@mui/x-data-grid-pro';
|
|
3
|
-
import type { RowTreeBuilderGroupingCriterion } from '@mui/x-data-grid-pro/internals';
|
|
4
|
-
import type { ReorderValidationContext as Ctx, ReorderOperationType } from "./types.js";
|
|
5
|
-
import type { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
|
|
6
|
-
import { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
|
|
7
|
-
/**
|
|
8
|
-
* Reusable validation conditions for row reordering validation
|
|
9
|
-
*/
|
|
10
|
-
export declare const conditions: {
|
|
11
|
-
isGroupToGroup: (ctx: Ctx) => boolean;
|
|
12
|
-
isLeafToLeaf: (ctx: Ctx) => boolean;
|
|
13
|
-
isLeafToGroup: (ctx: Ctx) => boolean;
|
|
14
|
-
isGroupToLeaf: (ctx: Ctx) => boolean;
|
|
15
|
-
isDropAbove: (ctx: Ctx) => boolean;
|
|
16
|
-
isDropBelow: (ctx: Ctx) => boolean;
|
|
17
|
-
sameDepth: (ctx: Ctx) => boolean;
|
|
18
|
-
sourceDepthGreater: (ctx: Ctx) => boolean;
|
|
19
|
-
targetDepthIsSourceMinusOne: (ctx: Ctx) => boolean;
|
|
20
|
-
sameParent: (ctx: Ctx) => boolean;
|
|
21
|
-
targetGroupExpanded: (ctx: Ctx) => boolean;
|
|
22
|
-
targetGroupCollapsed: (ctx: Ctx) => boolean;
|
|
23
|
-
hasPrevNode: (ctx: Ctx) => boolean;
|
|
24
|
-
hasNextNode: (ctx: Ctx) => boolean;
|
|
25
|
-
prevIsLeaf: (ctx: Ctx) => boolean;
|
|
26
|
-
prevIsGroup: (ctx: Ctx) => boolean;
|
|
27
|
-
nextIsLeaf: (ctx: Ctx) => boolean;
|
|
28
|
-
nextIsGroup: (ctx: Ctx) => boolean;
|
|
29
|
-
prevDepthEquals: (ctx: Ctx, depth: number) => boolean;
|
|
30
|
-
prevDepthEqualsSource: (ctx: Ctx) => boolean;
|
|
31
|
-
prevBelongsToSource: (ctx: Ctx) => boolean;
|
|
32
|
-
isAdjacentPosition: (ctx: Ctx) => boolean;
|
|
33
|
-
targetFirstChildIsGroupWithSourceDepth: (ctx: Ctx) => boolean;
|
|
34
|
-
targetFirstChildDepthEqualsSource: (ctx: Ctx) => boolean;
|
|
35
|
-
};
|
|
36
|
-
export declare function determineOperationType(sourceNode: GridTreeNode, targetNode: GridTreeNode): ReorderOperationType;
|
|
37
|
-
export declare function calculateTargetIndex(sourceNode: GridTreeNode, targetNode: GridTreeNode, isLastChild: boolean, rowTree: Record<GridRowId, GridTreeNode>): number;
|
|
38
|
-
export declare const getNodePathInTree: ({
|
|
39
|
-
id,
|
|
40
|
-
tree
|
|
41
|
-
}: {
|
|
42
|
-
id: GridRowId;
|
|
43
|
-
tree: GridRowTreeConfig;
|
|
44
|
-
}) => RowTreeBuilderGroupingCriterion[];
|
|
45
|
-
export declare const collectAllLeafDescendants: (groupNode: GridGroupNode, tree: GridRowTreeConfig) => GridRowId[];
|
|
46
|
-
/**
|
|
47
|
-
* Adjusts the target node based on specific reorder scenarios and constraints.
|
|
48
|
-
*
|
|
49
|
-
* This function applies scenario-specific logic to find the actual target node
|
|
50
|
-
* for operations, handling cases like:
|
|
51
|
-
* - Moving to collapsed groups
|
|
52
|
-
* - Depth-based adjustments
|
|
53
|
-
* - End-of-list positioning
|
|
54
|
-
*
|
|
55
|
-
* @param sourceNode The node being moved
|
|
56
|
-
* @param targetNode The initial target node
|
|
57
|
-
* @param targetIndex The index of the target node in the visible rows
|
|
58
|
-
* @param placeholderIndex The index where the placeholder appears
|
|
59
|
-
* @param sortedFilteredRowIds Array of visible row IDs in display order
|
|
60
|
-
* @param apiRef Reference to the grid API
|
|
61
|
-
* @returns Object containing the adjusted target node and last child flag
|
|
62
|
-
*/
|
|
63
|
-
export declare function adjustTargetNode(sourceNode: GridTreeNode, targetNode: GridTreeNode, targetIndex: number, placeholderIndex: number, sortedFilteredRowIds: GridRowId[], apiRef: RefObject<GridPrivateApiPremium>): {
|
|
64
|
-
adjustedTargetNode: GridTreeNode;
|
|
65
|
-
isLastChild: boolean;
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Finds an existing group node with the same groupingKey and groupingField under a parent.
|
|
69
|
-
*
|
|
70
|
-
* @param parentNode - The parent group node to search in
|
|
71
|
-
* @param groupingKey - The grouping key to match
|
|
72
|
-
* @param groupingField - The grouping field to match
|
|
73
|
-
* @param tree - The row tree configuration
|
|
74
|
-
* @returns The existing group node if found, null otherwise
|
|
75
|
-
*/
|
|
76
|
-
export declare function findExistingGroupWithSameKey(parentNode: GridGroupNode, groupingKey: GridKeyValue, groupingField: string, tree: GridRowTreeConfig): GridGroupNode | null;
|
|
77
|
-
/**
|
|
78
|
-
* Removes empty ancestor groups from the tree after a row move operation.
|
|
79
|
-
* Walks up the tree from the given group, removing any empty groups encountered.
|
|
80
|
-
*
|
|
81
|
-
* @param groupId - The ID of the group to start checking from
|
|
82
|
-
* @param tree - The row tree configuration
|
|
83
|
-
* @param removedGroups - Set to track which groups have been removed
|
|
84
|
-
* @returns The number of root-level groups that were removed
|
|
85
|
-
*/
|
|
86
|
-
export declare function removeEmptyAncestors(groupId: GridRowId, tree: GridRowTreeConfig, removedGroups: Set<GridRowId>): number;
|
|
87
|
-
export declare function handleProcessRowUpdateError(error: any, onProcessRowUpdateError?: DataGridPremiumProcessedProps['onProcessRowUpdateError']): void;
|
|
88
|
-
/**
|
|
89
|
-
* Handles batch row updates with partial failure tracking.
|
|
90
|
-
*
|
|
91
|
-
* This class is designed for operations that need to update multiple rows
|
|
92
|
-
* atomically (like moving entire groups), while gracefully handling cases
|
|
93
|
-
* where some updates succeed and others fail.
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```tsx
|
|
97
|
-
* const updater = new BatchRowUpdater(processRowUpdate, onError);
|
|
98
|
-
*
|
|
99
|
-
* // Queue multiple updates
|
|
100
|
-
* updater.queueUpdate('row1', originalRow1, newRow1);
|
|
101
|
-
* updater.queueUpdate('row2', originalRow2, newRow2);
|
|
102
|
-
*
|
|
103
|
-
* // Execute all updates
|
|
104
|
-
* const { successful, failed, updates } = await updater.executeAll();
|
|
105
|
-
*
|
|
106
|
-
* // Handle results
|
|
107
|
-
* if (successful.length > 0) {
|
|
108
|
-
* apiRef.current.updateRows(updates);
|
|
109
|
-
* }
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
export declare class BatchRowUpdater {
|
|
113
|
-
private processRowUpdate;
|
|
114
|
-
private onProcessRowUpdateError;
|
|
115
|
-
private rowsToUpdate;
|
|
116
|
-
private originalRows;
|
|
117
|
-
private successfulRowIds;
|
|
118
|
-
private failedRowIds;
|
|
119
|
-
private pendingRowUpdates;
|
|
120
|
-
constructor(processRowUpdate: DataGridPremiumProcessedProps['processRowUpdate'] | undefined, onProcessRowUpdateError: DataGridPremiumProcessedProps['onProcessRowUpdateError'] | undefined);
|
|
121
|
-
queueUpdate(rowId: GridRowId, originalRow: GridValidRowModel, updatedRow: GridValidRowModel): void;
|
|
122
|
-
executeAll(): Promise<{
|
|
123
|
-
successful: GridRowId[];
|
|
124
|
-
failed: GridRowId[];
|
|
125
|
-
updates: GridValidRowModel[];
|
|
126
|
-
}>;
|
|
127
|
-
}
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.BatchRowUpdater = void 0;
|
|
7
|
-
exports.adjustTargetNode = adjustTargetNode;
|
|
8
|
-
exports.calculateTargetIndex = calculateTargetIndex;
|
|
9
|
-
exports.conditions = exports.collectAllLeafDescendants = void 0;
|
|
10
|
-
exports.determineOperationType = determineOperationType;
|
|
11
|
-
exports.findExistingGroupWithSameKey = findExistingGroupWithSameKey;
|
|
12
|
-
exports.getNodePathInTree = void 0;
|
|
13
|
-
exports.handleProcessRowUpdateError = handleProcessRowUpdateError;
|
|
14
|
-
exports.removeEmptyAncestors = removeEmptyAncestors;
|
|
15
|
-
var _xDataGridPro = require("@mui/x-data-grid-pro");
|
|
16
|
-
var _warning = require("@mui/x-internals/warning");
|
|
17
|
-
// TODO: Share these conditions with the executor by making the contexts similar
|
|
18
|
-
/**
|
|
19
|
-
* Reusable validation conditions for row reordering validation
|
|
20
|
-
*/
|
|
21
|
-
const conditions = exports.conditions = {
|
|
22
|
-
// Node type checks
|
|
23
|
-
isGroupToGroup: ctx => ctx.sourceNode.type === 'group' && ctx.targetNode.type === 'group',
|
|
24
|
-
isLeafToLeaf: ctx => ctx.sourceNode.type === 'leaf' && ctx.targetNode.type === 'leaf',
|
|
25
|
-
isLeafToGroup: ctx => ctx.sourceNode.type === 'leaf' && ctx.targetNode.type === 'group',
|
|
26
|
-
isGroupToLeaf: ctx => ctx.sourceNode.type === 'group' && ctx.targetNode.type === 'leaf',
|
|
27
|
-
// Drop position checks
|
|
28
|
-
isDropAbove: ctx => ctx.dropPosition === 'above',
|
|
29
|
-
isDropBelow: ctx => ctx.dropPosition === 'below',
|
|
30
|
-
// Depth checks
|
|
31
|
-
sameDepth: ctx => ctx.sourceNode.depth === ctx.targetNode.depth,
|
|
32
|
-
sourceDepthGreater: ctx => ctx.sourceNode.depth > ctx.targetNode.depth,
|
|
33
|
-
targetDepthIsSourceMinusOne: ctx => ctx.targetNode.depth === ctx.sourceNode.depth - 1,
|
|
34
|
-
// Parent checks
|
|
35
|
-
sameParent: ctx => ctx.sourceNode.parent === ctx.targetNode.parent,
|
|
36
|
-
// Node state checks
|
|
37
|
-
targetGroupExpanded: ctx => (ctx.targetNode.type === 'group' && ctx.targetNode.childrenExpanded) ?? false,
|
|
38
|
-
targetGroupCollapsed: ctx => ctx.targetNode.type === 'group' && !ctx.targetNode.childrenExpanded,
|
|
39
|
-
// Previous/Next node checks
|
|
40
|
-
hasPrevNode: ctx => ctx.prevNode !== null,
|
|
41
|
-
hasNextNode: ctx => ctx.nextNode !== null,
|
|
42
|
-
prevIsLeaf: ctx => ctx.prevNode?.type === 'leaf',
|
|
43
|
-
prevIsGroup: ctx => ctx.prevNode?.type === 'group',
|
|
44
|
-
nextIsLeaf: ctx => ctx.nextNode?.type === 'leaf',
|
|
45
|
-
nextIsGroup: ctx => ctx.nextNode?.type === 'group',
|
|
46
|
-
prevDepthEquals: (ctx, depth) => ctx.prevNode?.depth === depth,
|
|
47
|
-
prevDepthEqualsSource: ctx => ctx.prevNode?.depth === ctx.sourceNode.depth,
|
|
48
|
-
// Complex checks
|
|
49
|
-
prevBelongsToSource: ctx => {
|
|
50
|
-
if (!ctx.prevNode) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
// Check if prevNode.parent OR any of its ancestors === sourceNode.id
|
|
54
|
-
let currentId = ctx.prevNode.parent;
|
|
55
|
-
while (currentId) {
|
|
56
|
-
if (currentId === ctx.sourceNode.id) {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
const node = ctx.rowTree[currentId];
|
|
60
|
-
if (!node) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
currentId = node.parent;
|
|
64
|
-
}
|
|
65
|
-
return false;
|
|
66
|
-
},
|
|
67
|
-
// Position checks
|
|
68
|
-
isAdjacentPosition: ctx => {
|
|
69
|
-
const {
|
|
70
|
-
sourceRowIndex,
|
|
71
|
-
targetRowIndex,
|
|
72
|
-
dropPosition
|
|
73
|
-
} = ctx;
|
|
74
|
-
return dropPosition === 'above' && targetRowIndex === sourceRowIndex + 1 || dropPosition === 'below' && targetRowIndex === sourceRowIndex - 1;
|
|
75
|
-
},
|
|
76
|
-
// First child check
|
|
77
|
-
targetFirstChildIsGroupWithSourceDepth: ctx => {
|
|
78
|
-
if (ctx.targetNode.type !== 'group') {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
const targetGroup = ctx.targetNode;
|
|
82
|
-
const firstChild = targetGroup.children?.[0] ? ctx.rowTree[targetGroup.children[0]] : null;
|
|
83
|
-
return firstChild?.type === 'group' && firstChild.depth === ctx.sourceNode.depth;
|
|
84
|
-
},
|
|
85
|
-
targetFirstChildDepthEqualsSource: ctx => {
|
|
86
|
-
if (ctx.targetNode.type !== 'group') {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
const targetGroup = ctx.targetNode;
|
|
90
|
-
const firstChild = targetGroup.children?.[0] ? ctx.rowTree[targetGroup.children[0]] : null;
|
|
91
|
-
return firstChild ? firstChild.depth === ctx.sourceNode.depth : false;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
function determineOperationType(sourceNode, targetNode) {
|
|
95
|
-
if (sourceNode.parent === targetNode.parent) {
|
|
96
|
-
return 'same-parent-swap';
|
|
97
|
-
}
|
|
98
|
-
if (sourceNode.type === 'leaf') {
|
|
99
|
-
return 'cross-parent-leaf';
|
|
100
|
-
}
|
|
101
|
-
return 'cross-parent-group';
|
|
102
|
-
}
|
|
103
|
-
function calculateTargetIndex(sourceNode, targetNode, isLastChild, rowTree) {
|
|
104
|
-
if (sourceNode.parent === targetNode.parent && !isLastChild) {
|
|
105
|
-
// Same parent: find target's position in parent's children
|
|
106
|
-
const parent = rowTree[sourceNode.parent];
|
|
107
|
-
return parent.children.findIndex(id => id === targetNode.id);
|
|
108
|
-
}
|
|
109
|
-
if (isLastChild) {
|
|
110
|
-
// Append at the end
|
|
111
|
-
const targetParent = rowTree[targetNode.parent];
|
|
112
|
-
return targetParent.children.length;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Find position in target parent
|
|
116
|
-
const targetParent = rowTree[targetNode.parent];
|
|
117
|
-
const targetIndex = targetParent.children.findIndex(id => id === targetNode.id);
|
|
118
|
-
return targetIndex >= 0 ? targetIndex : 0;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Get the path from a node to the root in the tree
|
|
122
|
-
const getNodePathInTree = ({
|
|
123
|
-
id,
|
|
124
|
-
tree
|
|
125
|
-
}) => {
|
|
126
|
-
const path = [];
|
|
127
|
-
let node = tree[id];
|
|
128
|
-
while (node.id !== _xDataGridPro.GRID_ROOT_GROUP_ID) {
|
|
129
|
-
path.push({
|
|
130
|
-
field: node.type === 'leaf' ? null : node.groupingField,
|
|
131
|
-
key: node.groupingKey
|
|
132
|
-
});
|
|
133
|
-
node = tree[node.parent];
|
|
134
|
-
}
|
|
135
|
-
path.reverse();
|
|
136
|
-
return path;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// Recursively collect all leaf node IDs from a group
|
|
140
|
-
exports.getNodePathInTree = getNodePathInTree;
|
|
141
|
-
const collectAllLeafDescendants = (groupNode, tree) => {
|
|
142
|
-
const leafIds = [];
|
|
143
|
-
const collectFromNode = nodeId => {
|
|
144
|
-
const node = tree[nodeId];
|
|
145
|
-
if (node.type === 'leaf') {
|
|
146
|
-
leafIds.push(nodeId);
|
|
147
|
-
} else if (node.type === 'group') {
|
|
148
|
-
node.children.forEach(collectFromNode);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
groupNode.children.forEach(collectFromNode);
|
|
152
|
-
return leafIds;
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Adjusts the target node based on specific reorder scenarios and constraints.
|
|
157
|
-
*
|
|
158
|
-
* This function applies scenario-specific logic to find the actual target node
|
|
159
|
-
* for operations, handling cases like:
|
|
160
|
-
* - Moving to collapsed groups
|
|
161
|
-
* - Depth-based adjustments
|
|
162
|
-
* - End-of-list positioning
|
|
163
|
-
*
|
|
164
|
-
* @param sourceNode The node being moved
|
|
165
|
-
* @param targetNode The initial target node
|
|
166
|
-
* @param targetIndex The index of the target node in the visible rows
|
|
167
|
-
* @param placeholderIndex The index where the placeholder appears
|
|
168
|
-
* @param sortedFilteredRowIds Array of visible row IDs in display order
|
|
169
|
-
* @param apiRef Reference to the grid API
|
|
170
|
-
* @returns Object containing the adjusted target node and last child flag
|
|
171
|
-
*/
|
|
172
|
-
exports.collectAllLeafDescendants = collectAllLeafDescendants;
|
|
173
|
-
function adjustTargetNode(sourceNode, targetNode, targetIndex, placeholderIndex, sortedFilteredRowIds, apiRef) {
|
|
174
|
-
let adjustedTargetNode = targetNode;
|
|
175
|
-
let isLastChild = false;
|
|
176
|
-
|
|
177
|
-
// Handle end-of-list case
|
|
178
|
-
if (placeholderIndex >= sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
179
|
-
isLastChild = true;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Case A and B adjustment: Move to last child of parent where target should be the node above
|
|
183
|
-
if (targetNode.type === 'group' && sourceNode.parent !== targetNode.parent && sourceNode.depth > targetNode.depth) {
|
|
184
|
-
// Find the first node with the same depth as source before target and quit early if a
|
|
185
|
-
// node with depth < source.depth is found
|
|
186
|
-
let i = targetIndex - 1;
|
|
187
|
-
while (i >= 0) {
|
|
188
|
-
const node = apiRef.current.getRowNode(sortedFilteredRowIds[i]);
|
|
189
|
-
if (node && node.depth < sourceNode.depth) {
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
if (node && node.depth === sourceNode.depth) {
|
|
193
|
-
adjustedTargetNode = node;
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
i -= 1;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Case D adjustment: Leaf to group where we need previous leaf
|
|
201
|
-
if (sourceNode.type === 'leaf' && targetNode.type === 'group' && targetNode.depth < sourceNode.depth) {
|
|
202
|
-
isLastChild = true;
|
|
203
|
-
const prevIndex = placeholderIndex - 1;
|
|
204
|
-
if (prevIndex >= 0) {
|
|
205
|
-
const prevRowId = sortedFilteredRowIds[prevIndex];
|
|
206
|
-
const leafTargetNode = (0, _xDataGridPro.gridRowNodeSelector)(apiRef, prevRowId);
|
|
207
|
-
if (leafTargetNode && leafTargetNode.type === 'leaf') {
|
|
208
|
-
adjustedTargetNode = leafTargetNode;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return {
|
|
213
|
-
adjustedTargetNode,
|
|
214
|
-
isLastChild
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Finds an existing group node with the same groupingKey and groupingField under a parent.
|
|
220
|
-
*
|
|
221
|
-
* @param parentNode - The parent group node to search in
|
|
222
|
-
* @param groupingKey - The grouping key to match
|
|
223
|
-
* @param groupingField - The grouping field to match
|
|
224
|
-
* @param tree - The row tree configuration
|
|
225
|
-
* @returns The existing group node if found, null otherwise
|
|
226
|
-
*/
|
|
227
|
-
function findExistingGroupWithSameKey(parentNode, groupingKey, groupingField, tree) {
|
|
228
|
-
for (const childId of parentNode.children) {
|
|
229
|
-
const childNode = tree[childId];
|
|
230
|
-
if (childNode && childNode.type === 'group' && childNode.groupingKey === groupingKey && childNode.groupingField === groupingField) {
|
|
231
|
-
return childNode;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Removes empty ancestor groups from the tree after a row move operation.
|
|
239
|
-
* Walks up the tree from the given group, removing any empty groups encountered.
|
|
240
|
-
*
|
|
241
|
-
* @param groupId - The ID of the group to start checking from
|
|
242
|
-
* @param tree - The row tree configuration
|
|
243
|
-
* @param removedGroups - Set to track which groups have been removed
|
|
244
|
-
* @returns The number of root-level groups that were removed
|
|
245
|
-
*/
|
|
246
|
-
function removeEmptyAncestors(groupId, tree, removedGroups) {
|
|
247
|
-
let rootLevelRemovals = 0;
|
|
248
|
-
let currentGroupId = groupId;
|
|
249
|
-
while (currentGroupId && currentGroupId !== _xDataGridPro.GRID_ROOT_GROUP_ID) {
|
|
250
|
-
const group = tree[currentGroupId];
|
|
251
|
-
if (!group) {
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
const remainingChildren = group.children.filter(childId => !removedGroups.has(childId));
|
|
255
|
-
if (remainingChildren.length > 0) {
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
if (group.depth === 0) {
|
|
259
|
-
rootLevelRemovals += 1;
|
|
260
|
-
}
|
|
261
|
-
removedGroups.add(currentGroupId);
|
|
262
|
-
currentGroupId = group.parent;
|
|
263
|
-
}
|
|
264
|
-
return rootLevelRemovals;
|
|
265
|
-
}
|
|
266
|
-
function handleProcessRowUpdateError(error, onProcessRowUpdateError) {
|
|
267
|
-
if (onProcessRowUpdateError) {
|
|
268
|
-
onProcessRowUpdateError(error);
|
|
269
|
-
} else if (process.env.NODE_ENV !== 'production') {
|
|
270
|
-
(0, _warning.warnOnce)(['MUI X: A call to `processRowUpdate()` threw an error which was not handled because `onProcessRowUpdateError()` is missing.', 'To handle the error pass a callback to the `onProcessRowUpdateError()` prop, for example `<DataGrid onProcessRowUpdateError={(error) => ...} />`.', 'For more detail, see https://mui.com/x/react-data-grid/editing/persistence/.'], 'error');
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Handles batch row updates with partial failure tracking.
|
|
276
|
-
*
|
|
277
|
-
* This class is designed for operations that need to update multiple rows
|
|
278
|
-
* atomically (like moving entire groups), while gracefully handling cases
|
|
279
|
-
* where some updates succeed and others fail.
|
|
280
|
-
*
|
|
281
|
-
* @example
|
|
282
|
-
* ```tsx
|
|
283
|
-
* const updater = new BatchRowUpdater(processRowUpdate, onError);
|
|
284
|
-
*
|
|
285
|
-
* // Queue multiple updates
|
|
286
|
-
* updater.queueUpdate('row1', originalRow1, newRow1);
|
|
287
|
-
* updater.queueUpdate('row2', originalRow2, newRow2);
|
|
288
|
-
*
|
|
289
|
-
* // Execute all updates
|
|
290
|
-
* const { successful, failed, updates } = await updater.executeAll();
|
|
291
|
-
*
|
|
292
|
-
* // Handle results
|
|
293
|
-
* if (successful.length > 0) {
|
|
294
|
-
* apiRef.current.updateRows(updates);
|
|
295
|
-
* }
|
|
296
|
-
* ```
|
|
297
|
-
*/
|
|
298
|
-
class BatchRowUpdater {
|
|
299
|
-
rowsToUpdate = new Map();
|
|
300
|
-
originalRows = new Map();
|
|
301
|
-
successfulRowIds = new Set();
|
|
302
|
-
failedRowIds = new Set();
|
|
303
|
-
pendingRowUpdates = [];
|
|
304
|
-
constructor(processRowUpdate, onProcessRowUpdateError) {
|
|
305
|
-
this.processRowUpdate = processRowUpdate;
|
|
306
|
-
this.onProcessRowUpdateError = onProcessRowUpdateError;
|
|
307
|
-
}
|
|
308
|
-
queueUpdate(rowId, originalRow, updatedRow) {
|
|
309
|
-
this.originalRows.set(rowId, originalRow);
|
|
310
|
-
this.rowsToUpdate.set(rowId, updatedRow);
|
|
311
|
-
}
|
|
312
|
-
async executeAll() {
|
|
313
|
-
const rowIds = Array.from(this.rowsToUpdate.keys());
|
|
314
|
-
if (rowIds.length === 0) {
|
|
315
|
-
return {
|
|
316
|
-
successful: [],
|
|
317
|
-
failed: [],
|
|
318
|
-
updates: []
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Handle each row update, tracking success/failure
|
|
323
|
-
const handleRowUpdate = async rowId => {
|
|
324
|
-
const newRow = this.rowsToUpdate.get(rowId);
|
|
325
|
-
const oldRow = this.originalRows.get(rowId);
|
|
326
|
-
try {
|
|
327
|
-
if (typeof this.processRowUpdate === 'function') {
|
|
328
|
-
const params = {
|
|
329
|
-
rowId,
|
|
330
|
-
previousRow: oldRow,
|
|
331
|
-
updatedRow: newRow
|
|
332
|
-
};
|
|
333
|
-
const finalRow = await this.processRowUpdate(newRow, oldRow, params);
|
|
334
|
-
this.pendingRowUpdates.push(finalRow || newRow);
|
|
335
|
-
this.successfulRowIds.add(rowId);
|
|
336
|
-
} else {
|
|
337
|
-
this.pendingRowUpdates.push(newRow);
|
|
338
|
-
this.successfulRowIds.add(rowId);
|
|
339
|
-
}
|
|
340
|
-
} catch (error) {
|
|
341
|
-
this.failedRowIds.add(rowId);
|
|
342
|
-
handleProcessRowUpdateError(error, this.onProcessRowUpdateError);
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
// Use Promise.all with wrapped promises to avoid Promise.allSettled (browser support)
|
|
347
|
-
const promises = rowIds.map(rowId => {
|
|
348
|
-
return new Promise(resolve => {
|
|
349
|
-
handleRowUpdate(rowId).then(resolve).catch(resolve);
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
await Promise.all(promises);
|
|
353
|
-
return {
|
|
354
|
-
successful: Array.from(this.successfulRowIds),
|
|
355
|
-
failed: Array.from(this.failedRowIds),
|
|
356
|
-
updates: this.pendingRowUpdates
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
exports.BatchRowUpdater = BatchRowUpdater;
|