@linzjs/step-ag-grid 28.5.1 → 29.0.1
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/dist/index.css +11 -7
- package/dist/src/components/Grid.d.ts +5 -1
- package/dist/src/contexts/GridContext.d.ts +3 -4
- package/dist/src/contexts/GridPopoverContext.d.ts +1 -0
- package/dist/src/contexts/GridUpdatingContext.d.ts +1 -0
- package/dist/src/lui/reactUtils.d.ts +4 -0
- package/dist/step-ag-grid.cjs +272 -250
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +273 -251
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +21 -22
- package/src/components/Grid.tsx +114 -112
- package/src/components/GridCell.tsx +6 -2
- package/src/components/GridPopoverHook.tsx +25 -20
- package/src/components/gridFilter/useGridFilter.ts +3 -3
- package/src/components/gridForm/GridFormTextInput.tsx +6 -2
- package/src/components/gridHook/useGridContextMenu.tsx +3 -3
- package/src/contexts/GridContext.tsx +11 -14
- package/src/contexts/GridContextProvider.tsx +164 -137
- package/src/contexts/GridPopoverContext.tsx +2 -0
- package/src/contexts/GridPopoverContextProvider.tsx +9 -5
- package/src/contexts/GridUpdatingContext.tsx +5 -0
- package/src/contexts/GridUpdatingContextProvider.tsx +35 -28
- package/src/lui/reactUtils.tsx +24 -0
- package/src/react-menu3/components/MenuList.tsx +3 -0
- package/src/stories/grid/GridFilterButtons.stories.tsx +1 -1
- package/src/stories/grid/GridNonEditableRow.stories.tsx +1 -1
- package/src/stories/grid/GridPinnedRow.stories.tsx +1 -1
- package/src/stories/grid/GridPopoutContextMenu.stories.tsx +3 -3
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +3 -3
- package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +8 -4
- package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +1 -0
- package/src/stories/grid/GridReadOnly.stories.tsx +1 -1
- package/src/stories/grid/GridViewList.stories.tsx +1 -1
- package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +5 -3
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectGridInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormStatic/GridFormDropDown.stories.tsx +2 -2
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +2 -2
|
@@ -25,7 +25,6 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
25
25
|
getColumnIds: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => string[];
|
|
26
26
|
setApis: (gridApi: GridApi | undefined, hasExternallySelectedItems: boolean, dataTestId?: string) => void;
|
|
27
27
|
prePopupOps: () => void;
|
|
28
|
-
postPopupOps: () => void;
|
|
29
28
|
setQuickFilter: (quickFilter: string) => void;
|
|
30
29
|
editingCells: () => boolean;
|
|
31
30
|
getSelectedRows: <T extends GridBaseRow>() => T[];
|
|
@@ -44,9 +43,9 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
44
43
|
getFirstRowId: () => number;
|
|
45
44
|
autoSizeColumns: (props?: AutoSizeColumnsProps) => AutoSizeColumnsResult;
|
|
46
45
|
sizeColumnsToFit: () => void;
|
|
47
|
-
cancelEdit: () => void;
|
|
48
46
|
startCellEditing: ({ rowId, colId }: { rowId: number; colId: string }) => Promise<void>;
|
|
49
|
-
|
|
47
|
+
// Restores the previous focus after cell editing
|
|
48
|
+
resetFocusedCellAfterCellEditing: () => void;
|
|
50
49
|
updatingCells: (
|
|
51
50
|
props: { selectedRows: GridBaseRow[]; field?: string },
|
|
52
51
|
fnUpdate: (selectedRows: any[]) => Promise<boolean>,
|
|
@@ -64,7 +63,8 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
64
63
|
invisibleColumnIds: string[] | undefined;
|
|
65
64
|
setInvisibleColumnIds: (colIds: string[]) => void;
|
|
66
65
|
downloadCsv: (csvExportParams?: CsvExportParams) => void;
|
|
67
|
-
|
|
66
|
+
onBulkEditingComplete: () => void;
|
|
67
|
+
setOnBulkEditingComplete: (callback: (() => void) | undefined) => void;
|
|
68
68
|
showNoRowsOverlay: () => void;
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -90,9 +90,6 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
90
90
|
prePopupOps: () => {
|
|
91
91
|
console.error('no context provider for prePopupOps');
|
|
92
92
|
},
|
|
93
|
-
postPopupOps: () => {
|
|
94
|
-
console.error('no context provider for prePopupOps');
|
|
95
|
-
},
|
|
96
93
|
externallySelectedItemsAreInSync: false,
|
|
97
94
|
setApis: () => {
|
|
98
95
|
console.error('no context provider for setApis');
|
|
@@ -164,15 +161,12 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
164
161
|
console.error('no context provider for editingCells');
|
|
165
162
|
return false;
|
|
166
163
|
},
|
|
167
|
-
cancelEdit: () => {
|
|
168
|
-
console.error('no context provider for cancelEdit');
|
|
169
|
-
},
|
|
170
164
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
171
165
|
startCellEditing: async () => {
|
|
172
166
|
console.error('no context provider for startCellEditing');
|
|
173
167
|
},
|
|
174
|
-
|
|
175
|
-
console.error('no context provider for
|
|
168
|
+
resetFocusedCellAfterCellEditing: () => {
|
|
169
|
+
console.error('no context provider for resetFocusedCellAfterCellEditing');
|
|
176
170
|
},
|
|
177
171
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
178
172
|
updatingCells: async () => {
|
|
@@ -206,8 +200,11 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
206
200
|
downloadCsv: () => {
|
|
207
201
|
console.error('no context provider for downloadCsv');
|
|
208
202
|
},
|
|
209
|
-
|
|
210
|
-
console.error('no context provider for
|
|
203
|
+
onBulkEditingComplete: () => {
|
|
204
|
+
console.error('no context provider for onBulkEditingComplete');
|
|
205
|
+
},
|
|
206
|
+
setOnBulkEditingComplete: () => {
|
|
207
|
+
console.error('no context provider for setOnBulkEditingComplete');
|
|
211
208
|
},
|
|
212
209
|
showNoRowsOverlay: () => {
|
|
213
210
|
console.error('no context provider for showLoadingOverlay');
|
|
@@ -17,7 +17,7 @@ import { GridUpdatingContext } from './GridUpdatingContext';
|
|
|
17
17
|
* Also, make sure the provider is created in a separate component, otherwise it won't be found.
|
|
18
18
|
*/
|
|
19
19
|
export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithChildren): ReactElement => {
|
|
20
|
-
const { modifyUpdating,
|
|
20
|
+
const { modifyUpdating, anyUpdating } = useContext(GridUpdatingContext);
|
|
21
21
|
const [gridApi, setGridApi] = useState<GridApi>();
|
|
22
22
|
const [gridReady, setGridReady] = useState(false);
|
|
23
23
|
const [quickFilter, _setQuickFilter] = useState('');
|
|
@@ -41,8 +41,10 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
41
41
|
/**
|
|
42
42
|
* Make extra sure the GridCellFillerColId never gets added to invisibleColumnIds as it's dynamically determined
|
|
43
43
|
*/
|
|
44
|
-
const setInvisibleColumnIds = (
|
|
45
|
-
_setInvisibleColumnIds(pull(invisibleColumnIds, GridCellFillerColId))
|
|
44
|
+
const setInvisibleColumnIds = useCallback(
|
|
45
|
+
(invisibleColumnIds: string[]) => _setInvisibleColumnIds(pull(invisibleColumnIds, GridCellFillerColId)),
|
|
46
|
+
[],
|
|
47
|
+
);
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Set quick filter directly on grid, based on previously save quickFilter state.
|
|
@@ -149,18 +151,6 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
149
151
|
prePopupFocusedCell.current = gridApi.getFocusedCell() ?? undefined;
|
|
150
152
|
}, [gridApi]);
|
|
151
153
|
|
|
152
|
-
/**
|
|
153
|
-
* After a popup refocus the cell.
|
|
154
|
-
*/
|
|
155
|
-
const postPopupOps = useCallback(() => {
|
|
156
|
-
if (!gridApi || gridApi.isDestroyed()) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (prePopupFocusedCell.current) {
|
|
160
|
-
gridApi.setFocusedCell(prePopupFocusedCell.current.rowIndex, prePopupFocusedCell.current.column);
|
|
161
|
-
}
|
|
162
|
-
}, [gridApi]);
|
|
163
|
-
|
|
164
154
|
/**
|
|
165
155
|
* Get all row id's in grid.
|
|
166
156
|
*/
|
|
@@ -461,13 +451,16 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
461
451
|
}
|
|
462
452
|
}, [gridApi]);
|
|
463
453
|
|
|
464
|
-
|
|
465
|
-
|
|
454
|
+
/**
|
|
455
|
+
*
|
|
456
|
+
*/
|
|
457
|
+
const resetFocusedCellAfterCellEditing = useCallback((): void => {
|
|
458
|
+
if (!gridApi || gridApi.isDestroyed() || startCellEditingInProgressRef.current) {
|
|
466
459
|
return;
|
|
467
460
|
}
|
|
468
|
-
gridApi.stopEditing();
|
|
469
461
|
if (prePopupFocusedCell.current) {
|
|
470
462
|
gridApi.setFocusedCell(prePopupFocusedCell.current.rowIndex, prePopupFocusedCell.current.column);
|
|
463
|
+
prePopupFocusedCell.current = undefined;
|
|
471
464
|
}
|
|
472
465
|
}, [gridApi]);
|
|
473
466
|
|
|
@@ -491,59 +484,65 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
491
484
|
}
|
|
492
485
|
}, []);
|
|
493
486
|
|
|
487
|
+
const startCellEditingInProgressRef = useRef(false);
|
|
494
488
|
const startCellEditing = useCallback(
|
|
495
489
|
async ({ rowId, colId }: { rowId: number; colId: string }) => {
|
|
496
|
-
if (!gridApi)
|
|
497
|
-
|
|
498
|
-
const colDef = gridApi.getColumnDef(colId);
|
|
499
|
-
if (!colDef) {
|
|
490
|
+
if (!gridApi || startCellEditingInProgressRef.current) {
|
|
500
491
|
return;
|
|
501
492
|
}
|
|
493
|
+
startCellEditingInProgressRef.current = true;
|
|
502
494
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
495
|
+
try {
|
|
496
|
+
// Edit in progress so don't edit until finished, timeout waiting after 5s
|
|
497
|
+
if (!(await waitForCondition(() => !anyUpdating(), 5000))) {
|
|
498
|
+
console.error("Could not start edit because previous edit hasn't finished after 5 seconds");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
507
501
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
setExternallySelectedItemsAreInSync(false);
|
|
513
|
-
rowNode.setSelected(true, true);
|
|
514
|
-
await waitForExternallySelectedItemsToBeInSync();
|
|
515
|
-
}
|
|
502
|
+
const colDef = gridApi.getColumnDef(colId);
|
|
503
|
+
if (!colDef) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
516
506
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
507
|
+
const rowNode = gridApi.getRowNode(`${rowId}`);
|
|
508
|
+
if (!rowNode) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
521
511
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
512
|
+
prePopupOps();
|
|
513
|
+
const shouldSelectNode = !rowNode.isSelected();
|
|
514
|
+
if (shouldSelectNode) {
|
|
515
|
+
externallySelectedItemsAreInSyncRef.current = false;
|
|
516
|
+
setExternallySelectedItemsAreInSync(false);
|
|
517
|
+
rowNode.setSelected(true, true);
|
|
518
|
+
await waitForExternallySelectedItemsToBeInSync();
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const rowIndex = rowNode.rowIndex;
|
|
522
|
+
if (rowIndex != null) {
|
|
523
|
+
defer(() => {
|
|
524
|
+
!gridApi.isDestroyed() &&
|
|
525
|
+
gridApi.startEditingCell({
|
|
526
|
+
rowIndex,
|
|
527
|
+
colKey: colId,
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
} finally {
|
|
532
|
+
startCellEditingInProgressRef.current = false;
|
|
531
533
|
}
|
|
532
534
|
},
|
|
533
|
-
[
|
|
535
|
+
[anyUpdating, gridApi, prePopupOps, waitForExternallySelectedItemsToBeInSync],
|
|
534
536
|
);
|
|
535
537
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const cellEditingCompleteCallbackRef = useRef<() => void>();
|
|
545
|
-
const setOnCellEditingComplete = useCallback((cellEditingCompleteCallback: (() => void) | undefined) => {
|
|
546
|
-
cellEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
|
|
538
|
+
const bulkEditingCompleteCallbackRef = useRef<() => void>();
|
|
539
|
+
const onBulkEditingComplete = useCallback(() => {
|
|
540
|
+
resetFocusedCellAfterCellEditing();
|
|
541
|
+
bulkEditingCompleteCallbackRef.current?.();
|
|
542
|
+
}, [resetFocusedCellAfterCellEditing]);
|
|
543
|
+
|
|
544
|
+
const setOnBulkEditingComplete = useCallback((cellEditingCompleteCallback: (() => void) | undefined) => {
|
|
545
|
+
bulkEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
|
|
547
546
|
}, []);
|
|
548
547
|
|
|
549
548
|
/**
|
|
@@ -552,7 +551,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
552
551
|
const selectNextEditableCell = useCallback(
|
|
553
552
|
async (tabDirection: -1 | 1): Promise<boolean> => {
|
|
554
553
|
// Pretend it succeeded to prevent unwanted cellEditingCompleteCallback
|
|
555
|
-
if (!gridApi)
|
|
554
|
+
if (!gridApi) {
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
556
557
|
|
|
557
558
|
const focusedCellIsEditable = () => {
|
|
558
559
|
const focusedCell = gridApi.isDestroyed() ? null : gridApi.getFocusedCell();
|
|
@@ -572,17 +573,17 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
572
573
|
if (gridApi.isDestroyed()) {
|
|
573
574
|
return true;
|
|
574
575
|
}
|
|
576
|
+
// Prevent resetting focus to original editing cell
|
|
577
|
+
prePopupFocusedCell.current = undefined;
|
|
578
|
+
|
|
575
579
|
const preRow = gridApi.getFocusedCell();
|
|
576
580
|
if (tabDirection === 1) {
|
|
581
|
+
gridApi.stopEditing();
|
|
577
582
|
gridApi.tabToNextCell();
|
|
578
583
|
} else {
|
|
579
584
|
gridApi.tabToPreviousCell();
|
|
580
585
|
}
|
|
581
586
|
|
|
582
|
-
// If we don't wait the tab to next element won't work
|
|
583
|
-
// I think this is due to the grid resizing
|
|
584
|
-
await wait(150);
|
|
585
|
-
|
|
586
587
|
if (gridApi.isDestroyed()) {
|
|
587
588
|
return true;
|
|
588
589
|
}
|
|
@@ -596,18 +597,19 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
596
597
|
if (focusedCellIsEditable()) {
|
|
597
598
|
const focusedCell = gridApi.getFocusedCell();
|
|
598
599
|
if (focusedCell) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
600
|
+
const rowNode = gridApi.getDisplayedRowAtIndex(focusedCell.rowIndex);
|
|
601
|
+
const rowId = rowNode?.data?.id;
|
|
602
|
+
if (rowId == null) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
await startCellEditing({ rowId, colId: focusedCell.column.getColId() });
|
|
604
606
|
return true;
|
|
605
607
|
}
|
|
606
608
|
}
|
|
607
609
|
}
|
|
608
610
|
return false;
|
|
609
611
|
},
|
|
610
|
-
[gridApi,
|
|
612
|
+
[gridApi, startCellEditing],
|
|
611
613
|
);
|
|
612
614
|
|
|
613
615
|
const updatingCells = useCallback(
|
|
@@ -617,65 +619,71 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
617
619
|
setSaving?: (saving: boolean) => void,
|
|
618
620
|
tabDirection?: 1 | 0 | -1,
|
|
619
621
|
): Promise<boolean> => {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
// MATT Disabled I don't believe these are needed anymore
|
|
642
|
-
// I've left them here just in case they are
|
|
643
|
-
// async processes need to refresh their own rows
|
|
644
|
-
// gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
|
|
622
|
+
try {
|
|
623
|
+
setSaving?.(true);
|
|
624
|
+
return await gridApiOp(async (gridApi) => {
|
|
625
|
+
const selectedRows = props.selectedRows;
|
|
626
|
+
|
|
627
|
+
let ok = false;
|
|
628
|
+
|
|
629
|
+
await modifyUpdating(
|
|
630
|
+
props.field ?? '',
|
|
631
|
+
selectedRows.map((data) => data.id),
|
|
632
|
+
async () => {
|
|
633
|
+
// MATT Disabled I don't believe these are needed anymore
|
|
634
|
+
// I've left them here just in case they are
|
|
635
|
+
// Need to refresh to get spinners to work on all rows
|
|
636
|
+
// gridApi.refreshCells({ rowNodes: props.selectedRows as RowNode[], force: true });
|
|
637
|
+
ok = await fnUpdate(selectedRows).catch((ex) => {
|
|
638
|
+
console.error('Exception during modifyUpdating', ex);
|
|
639
|
+
return false;
|
|
640
|
+
});
|
|
641
|
+
},
|
|
642
|
+
);
|
|
645
643
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
644
|
+
// MATT Disabled I don't believe these are needed anymore
|
|
645
|
+
// I've left them here just in case they are
|
|
646
|
+
// async processes need to refresh their own rows
|
|
647
|
+
// gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
|
|
649
648
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (cell && gridApi.getFocusedCell() == null) {
|
|
653
|
-
!gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
|
|
649
|
+
if (gridApi.isDestroyed()) {
|
|
650
|
+
return ok;
|
|
654
651
|
}
|
|
655
|
-
// This is needed to trigger postSortRowsHook
|
|
656
|
-
gridApi.refreshClientSideRowModel();
|
|
657
|
-
} else {
|
|
658
|
-
// Don't set saving if ok as the form has already closed
|
|
659
|
-
setSaving?.(false);
|
|
660
|
-
}
|
|
661
652
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
if (!tabDirection || !(await selectNextEditableCell(tabDirection))) {
|
|
671
|
-
cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
|
|
653
|
+
if (ok) {
|
|
654
|
+
const cell = gridApi.getFocusedCell();
|
|
655
|
+
if (cell && gridApi.getFocusedCell() == null) {
|
|
656
|
+
!gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// This is needed to trigger postSortRowsHook
|
|
660
|
+
gridApi.refreshClientSideRowModel();
|
|
672
661
|
}
|
|
673
|
-
}
|
|
674
662
|
|
|
675
|
-
|
|
676
|
-
|
|
663
|
+
void (async () => {
|
|
664
|
+
// Only focus next cell if user hasn't already manually changed focus
|
|
665
|
+
const postPopupFocusedCell = gridApi.getFocusedCell();
|
|
666
|
+
if (
|
|
667
|
+
prePopupFocusedCell.current &&
|
|
668
|
+
postPopupFocusedCell &&
|
|
669
|
+
prePopupFocusedCell.current.rowIndex == postPopupFocusedCell.rowIndex &&
|
|
670
|
+
prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()
|
|
671
|
+
) {
|
|
672
|
+
if (!tabDirection || !(await selectNextEditableCell(tabDirection))) {
|
|
673
|
+
onBulkEditingComplete();
|
|
674
|
+
}
|
|
675
|
+
} else {
|
|
676
|
+
onBulkEditingComplete();
|
|
677
|
+
}
|
|
678
|
+
})();
|
|
679
|
+
|
|
680
|
+
return ok;
|
|
681
|
+
});
|
|
682
|
+
} finally {
|
|
683
|
+
setSaving?.(false);
|
|
684
|
+
}
|
|
677
685
|
},
|
|
678
|
-
[gridApiOp, modifyUpdating, selectNextEditableCell],
|
|
686
|
+
[gridApiOp, modifyUpdating, onBulkEditingComplete, selectNextEditableCell],
|
|
679
687
|
);
|
|
680
688
|
|
|
681
689
|
const redrawRows: any = useMemo(
|
|
@@ -718,20 +726,28 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
718
726
|
[gridApi],
|
|
719
727
|
);
|
|
720
728
|
|
|
721
|
-
const addExternalFilter = (
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
729
|
+
const addExternalFilter = useCallback(
|
|
730
|
+
(filter: GridFilterExternal<TData>) => {
|
|
731
|
+
externalFilters.current.push(filter);
|
|
732
|
+
void onFilterChanged();
|
|
733
|
+
},
|
|
734
|
+
[onFilterChanged],
|
|
735
|
+
);
|
|
725
736
|
|
|
726
|
-
const removeExternalFilter = (
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
737
|
+
const removeExternalFilter = useCallback(
|
|
738
|
+
(filter: GridFilterExternal<TData>) => {
|
|
739
|
+
remove(externalFilters.current, (v) => v === filter);
|
|
740
|
+
void onFilterChanged();
|
|
741
|
+
},
|
|
742
|
+
[onFilterChanged],
|
|
743
|
+
);
|
|
730
744
|
|
|
731
|
-
const isExternalFilterPresent = (): boolean => !isEmpty(externalFilters.current);
|
|
745
|
+
const isExternalFilterPresent = useCallback((): boolean => !isEmpty(externalFilters.current), []);
|
|
732
746
|
|
|
733
|
-
const doesExternalFilterPass = (
|
|
734
|
-
externalFilters.current.every((filter) => filter(node.data, node))
|
|
747
|
+
const doesExternalFilterPass = useCallback(
|
|
748
|
+
(node: IRowNode): boolean => externalFilters.current.every((filter) => filter(node.data, node)),
|
|
749
|
+
[],
|
|
750
|
+
);
|
|
735
751
|
|
|
736
752
|
const getColDef = useCallback(
|
|
737
753
|
(colId?: string): ColDef | undefined => (!!colId && gridApi?.getColumnDef(colId)) || undefined,
|
|
@@ -804,7 +820,6 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
804
820
|
setInvisibleColumnIds,
|
|
805
821
|
gridReady,
|
|
806
822
|
prePopupOps,
|
|
807
|
-
postPopupOps,
|
|
808
823
|
setApis,
|
|
809
824
|
setQuickFilter,
|
|
810
825
|
selectRowsById,
|
|
@@ -825,8 +840,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
825
840
|
sizeColumnsToFit,
|
|
826
841
|
autoSizeColumns,
|
|
827
842
|
startCellEditing,
|
|
828
|
-
|
|
829
|
-
cancelEdit,
|
|
843
|
+
resetFocusedCellAfterCellEditing,
|
|
830
844
|
updatingCells,
|
|
831
845
|
redrawRows,
|
|
832
846
|
externallySelectedItemsAreInSync,
|
|
@@ -837,7 +851,8 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
837
851
|
isExternalFilterPresent,
|
|
838
852
|
doesExternalFilterPass,
|
|
839
853
|
downloadCsv,
|
|
840
|
-
|
|
854
|
+
onBulkEditingComplete,
|
|
855
|
+
setOnBulkEditingComplete,
|
|
841
856
|
showNoRowsOverlay,
|
|
842
857
|
}}
|
|
843
858
|
>
|
|
@@ -894,3 +909,15 @@ export const downloadCsvUseValueFormattersProcessCellCallback = (params: Process
|
|
|
894
909
|
// We add an extra encodeToString here just in case valueFormatter is returning non string values
|
|
895
910
|
return encodeToString(result);
|
|
896
911
|
};
|
|
912
|
+
|
|
913
|
+
const waitForCondition = async (condition: () => boolean, timeoutMs: number): Promise<boolean> => {
|
|
914
|
+
const endTime = Date.now() + timeoutMs;
|
|
915
|
+
while (Date.now() < endTime) {
|
|
916
|
+
if (condition()) {
|
|
917
|
+
return true;
|
|
918
|
+
}
|
|
919
|
+
await wait(100);
|
|
920
|
+
}
|
|
921
|
+
console.warn('waitForCondition failed');
|
|
922
|
+
return false;
|
|
923
|
+
};
|
|
@@ -6,6 +6,7 @@ export interface GridPopoverContextType<TData extends GridBaseRow> {
|
|
|
6
6
|
anchorRef: RefObject<Element>;
|
|
7
7
|
saving: boolean;
|
|
8
8
|
setSaving: (saving: boolean) => void;
|
|
9
|
+
stopEditing: () => void;
|
|
9
10
|
colId: string;
|
|
10
11
|
field: keyof TData;
|
|
11
12
|
value: any;
|
|
@@ -22,6 +23,7 @@ export const GridPopoverContext = createContext<GridPopoverContextType<any>>({
|
|
|
22
23
|
anchorRef: { current: null },
|
|
23
24
|
saving: false,
|
|
24
25
|
setSaving: () => {},
|
|
26
|
+
stopEditing: () => {},
|
|
25
27
|
colId: '',
|
|
26
28
|
field: '',
|
|
27
29
|
value: null,
|
|
@@ -19,7 +19,7 @@ export const GridPopoverContextProvider = (props2: PropsWithChildren<GridPopover
|
|
|
19
19
|
const hasSaved = useRef(false);
|
|
20
20
|
const [saving, setSaving] = useState(false);
|
|
21
21
|
|
|
22
|
-
const { colDef } = props;
|
|
22
|
+
const { colDef, stopEditing, formatValue, data, value } = props;
|
|
23
23
|
const { cellEditorParams } = colDef;
|
|
24
24
|
const multiEdit = cellEditorParams?.multiEdit ?? false;
|
|
25
25
|
// Then item that is clicked on will always be first in the list
|
|
@@ -34,7 +34,10 @@ export const GridPopoverContextProvider = (props2: PropsWithChildren<GridPopover
|
|
|
34
34
|
|
|
35
35
|
const updateValue = useCallback(
|
|
36
36
|
async (saveFn: (selectedRows: any[]) => Promise<boolean>, tabDirection: 1 | 0 | -1): Promise<boolean> => {
|
|
37
|
-
if (hasSaved.current)
|
|
37
|
+
if (hasSaved.current) {
|
|
38
|
+
// already called save so ignore
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
38
41
|
hasSaved.current = true;
|
|
39
42
|
return saving ? false : await updatingCells({ selectedRows, field }, saveFn, setSaving, tabDirection);
|
|
40
43
|
},
|
|
@@ -50,10 +53,11 @@ export const GridPopoverContextProvider = (props2: PropsWithChildren<GridPopover
|
|
|
50
53
|
selectedRows,
|
|
51
54
|
colId,
|
|
52
55
|
field,
|
|
53
|
-
data
|
|
54
|
-
value
|
|
56
|
+
data,
|
|
57
|
+
value,
|
|
55
58
|
updateValue,
|
|
56
|
-
formatValue
|
|
59
|
+
formatValue,
|
|
60
|
+
stopEditing,
|
|
57
61
|
}}
|
|
58
62
|
>
|
|
59
63
|
{children}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
|
|
3
3
|
export type GridUpdatingContextType = {
|
|
4
|
+
anyUpdating: () => boolean;
|
|
4
5
|
checkUpdating: (fields: string | string[], id: number | string) => boolean;
|
|
5
6
|
modifyUpdating: (
|
|
6
7
|
fields: string | string[],
|
|
@@ -12,6 +13,10 @@ export type GridUpdatingContextType = {
|
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export const GridUpdatingContext = createContext<GridUpdatingContextType>({
|
|
16
|
+
anyUpdating: () => {
|
|
17
|
+
console.error('Missing GridUpdatingContext');
|
|
18
|
+
return false;
|
|
19
|
+
},
|
|
15
20
|
checkUpdating: () => {
|
|
16
21
|
console.error('Missing GridUpdatingContext');
|
|
17
22
|
return false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { castArray, flatten, remove } from 'lodash-es';
|
|
2
|
-
import { PropsWithChildren, useRef, useState } from 'react';
|
|
1
|
+
import { castArray, flatten, isEmpty, remove } from 'lodash-es';
|
|
2
|
+
import { PropsWithChildren, useCallback, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
import { GridUpdatingContext } from './GridUpdatingContext';
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ export const GridUpdatingContextProvider = (props: PropsWithChildren) => {
|
|
|
14
14
|
const updating = useRef<GridUpdatingContextStatus>({});
|
|
15
15
|
const [updatedDep, setUpdatedDep] = useState(0);
|
|
16
16
|
|
|
17
|
-
const resetUpdating = () => {
|
|
17
|
+
const resetUpdating = useCallback(() => {
|
|
18
18
|
const mergedUpdatingBlocks: GridUpdatingContextStatus = {};
|
|
19
19
|
for (const key in updatingBlocks.current) {
|
|
20
20
|
const arr = flatten(updatingBlocks.current[key]);
|
|
@@ -24,33 +24,40 @@ export const GridUpdatingContextProvider = (props: PropsWithChildren) => {
|
|
|
24
24
|
}
|
|
25
25
|
updating.current = mergedUpdatingBlocks;
|
|
26
26
|
setUpdatedDep((updatedDep) => updatedDep + 1);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
ids: (number | string)[],
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
resetUpdating
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
const updatingCols = useCallback(() => Object.keys(updating.current), []);
|
|
30
|
+
|
|
31
|
+
const modifyUpdating = useCallback(
|
|
32
|
+
async (fields: string | string[], ids: (number | string)[], fn: () => void | Promise<void>) => {
|
|
33
|
+
const idRef = [...ids];
|
|
34
|
+
castArray(fields).forEach((field) => {
|
|
35
|
+
const fieldUpdatingIds = updatingBlocks.current[field] ?? (updatingBlocks.current[field] = []);
|
|
36
|
+
fieldUpdatingIds.push(idRef);
|
|
37
|
+
});
|
|
38
|
+
resetUpdating();
|
|
39
|
+
await fn();
|
|
40
|
+
castArray(fields).forEach((field) => {
|
|
41
|
+
const fieldUpdatingIds = updatingBlocks.current[field];
|
|
42
|
+
remove(fieldUpdatingIds, (idList) => idList === idRef);
|
|
43
|
+
});
|
|
44
|
+
resetUpdating();
|
|
45
|
+
},
|
|
46
|
+
[resetUpdating],
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const anyUpdating = useCallback((): boolean => {
|
|
50
|
+
return !isEmpty(updating.current);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
const checkUpdating = useCallback(
|
|
54
|
+
(fields: string | string[], id: number | string): boolean =>
|
|
55
|
+
castArray(fields).some((f) => updating.current[f]?.includes(id)),
|
|
56
|
+
[],
|
|
57
|
+
);
|
|
51
58
|
|
|
52
59
|
return (
|
|
53
|
-
<GridUpdatingContext.Provider value={{ modifyUpdating, checkUpdating, updatingCols, updatedDep }}>
|
|
60
|
+
<GridUpdatingContext.Provider value={{ modifyUpdating, anyUpdating, checkUpdating, updatingCols, updatedDep }}>
|
|
54
61
|
{props.children}
|
|
55
62
|
</GridUpdatingContext.Provider>
|
|
56
63
|
);
|