@linzjs/step-ag-grid 29.1.2 → 29.1.4

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.
Files changed (29) hide show
  1. package/dist/src/components/Grid.d.ts +1 -1
  2. package/dist/src/components/GridPopoverHook.d.ts +2 -0
  3. package/dist/src/contexts/GridContext.d.ts +2 -2
  4. package/dist/src/utils/waitForCondition.d.ts +1 -1
  5. package/dist/step-ag-grid.cjs +147 -114
  6. package/dist/step-ag-grid.cjs.map +1 -1
  7. package/dist/step-ag-grid.esm.js +147 -115
  8. package/dist/step-ag-grid.esm.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/components/Grid.tsx +1 -1
  11. package/src/components/GridCell.tsx +34 -14
  12. package/src/components/GridPopoverHook.tsx +10 -15
  13. package/src/components/gridForm/GridFormDropDown.tsx +73 -49
  14. package/src/components/gridForm/GridFormMultiSelect.tsx +12 -4
  15. package/src/components/gridPopoverEdit/GridPopoverMessage.ts +1 -0
  16. package/src/contexts/GridContext.tsx +2 -2
  17. package/src/contexts/GridContextProvider.tsx +31 -23
  18. package/src/stories/grid/GridPopoutEditGeneric.stories.tsx +1 -1
  19. package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +1 -1
  20. package/src/stories/grid/GridPopoverEditMultiSelectGrid.stories.tsx +1 -1
  21. package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +1 -1
  22. package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +2 -1
  23. package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +1 -1
  24. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +2 -1
  25. package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +2 -2
  26. package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +1 -1
  27. package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +1 -1
  28. package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +56 -13
  29. package/src/utils/waitForCondition.tsx +6 -2
@@ -65,7 +65,7 @@ export interface GridProps<TData extends GridBaseRow = GridBaseRow> {
65
65
  * When pressing tab whilst editing the grid will select and edit the next cell if available.
66
66
  * Once the last cell to edit closes this callback is called.
67
67
  */
68
- onBulkEditingComplete?: () => void;
68
+ onBulkEditingComplete?: () => Promise<void> | void;
69
69
  /**
70
70
  * Context menu definition if required.
71
71
  */
@@ -6,7 +6,9 @@ export interface GridPopoverHookProps<TData> {
6
6
  save?: (selectedRows: TData[]) => Promise<boolean>;
7
7
  dontSaveOnExternalClick?: boolean;
8
8
  }
9
+ export declare const CancelPromise: () => Promise<boolean>;
9
10
  export declare const useGridPopoverHook: <TData extends GridBaseRow>({ className, save, invalid, dontSaveOnExternalClick, }: GridPopoverHookProps<TData>) => {
10
11
  popoverWrapper: (children: ReactElement) => import("react/jsx-runtime").JSX.Element;
11
12
  triggerSave: (reason?: string) => Promise<void>;
13
+ gridPopoverOpen: boolean;
12
14
  };
@@ -57,8 +57,8 @@ export interface GridContextType<TData extends GridBaseRow> {
57
57
  invisibleColumnIds: string[] | undefined;
58
58
  setInvisibleColumnIds: (colIds: string[]) => void;
59
59
  downloadCsv: (csvExportParams?: CsvExportParams) => void;
60
- onBulkEditingComplete: () => void;
61
- setOnBulkEditingComplete: (callback: (() => void) | undefined) => void;
60
+ onBulkEditingComplete: () => Promise<void> | void;
61
+ setOnBulkEditingComplete: (callback: (() => Promise<void> | void) | undefined) => void;
62
62
  showNoRowsOverlay: () => void;
63
63
  }
64
64
  export declare const GridContext: import("react").Context<GridContextType<any>>;
@@ -1 +1 @@
1
- export declare const waitForCondition: (condition: () => boolean, timeoutMs: number) => Promise<boolean>;
1
+ export declare const waitForCondition: (error: string, condition: () => boolean, timeoutMs: number) => Promise<boolean>;
@@ -3400,20 +3400,25 @@ const GridCell = (props, custom) => {
3400
3400
  sortable: true,
3401
3401
  resizable: true,
3402
3402
  valueSetter: custom?.editor ? blockValueSetter : undefined,
3403
- editable: props.editable ?? false,
3404
- ...(custom?.editor && {
3405
- cellClassRules: GridCellMultiSelectClassRules,
3406
- editable: props.editable ?? true,
3407
- cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
3408
- }),
3403
+ editable: props.editable ?? !!custom?.editor,
3404
+ ...(custom?.editor
3405
+ ? {
3406
+ cellClassRules: GridCellMultiSelectClassRules,
3407
+ cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
3408
+ }
3409
+ : {
3410
+ cellEditor: CellEditorToBlockEditing,
3411
+ }),
3409
3412
  suppressKeyboardEvent: suppressCellKeyboardEvents,
3410
- ...(custom?.editorParams && {
3411
- cellEditorParams: {
3412
- ...custom.editorParams,
3413
- multiEdit: custom.multiEdit,
3414
- preventAutoEdit: custom.preventAutoEdit ?? false,
3415
- },
3416
- }),
3413
+ ...(custom?.editorParams
3414
+ ? {
3415
+ cellEditorParams: {
3416
+ ...custom.editorParams,
3417
+ multiEdit: custom.multiEdit,
3418
+ preventAutoEdit: custom.preventAutoEdit ?? !custom?.editor,
3419
+ },
3420
+ }
3421
+ : { cellEditorParams: { preventAutoEdit: !custom?.editor } }),
3417
3422
  // If there's a valueFormatter and no filterValueGetter then create a filterValueGetter
3418
3423
  getQuickFilterText: filterValueGetter,
3419
3424
  // Default value formatter, otherwise react freaks out on objects
@@ -3430,6 +3435,19 @@ const GridCell = (props, custom) => {
3430
3435
  },
3431
3436
  };
3432
3437
  };
3438
+ /**
3439
+ * Ag-grid will start its own editor if editable is true and there is no cell editor
3440
+ * like in the case of a cell that is editable because it triggers a modal.
3441
+ * This will block that editor.
3442
+ */
3443
+ const CellEditorToBlockEditing = ({ stopEditing }) => {
3444
+ React.useEffect(() => {
3445
+ lodashEs.defer(() => {
3446
+ stopEditing();
3447
+ });
3448
+ }, [stopEditing]);
3449
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {});
3450
+ };
3433
3451
  const GenericCellEditorComponentWrapper = (editor) => {
3434
3452
  const obj = { editor };
3435
3453
  return React.forwardRef(function GenericCellEditorComponentFr(cellEditorParams, _) {
@@ -3783,6 +3801,19 @@ const FormError = (props) => {
3783
3801
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.error && (jsxRuntime.jsxs("div", { className: "FormError", children: [jsxRuntime.jsx(lui.LuiIcon, { alt: "error", name: "ic_error", className: "FormError-text-icon", size: "sm", status: "error" }), jsxRuntime.jsx("span", { className: "FormError-error", children: props.error })] })), props.helpText && !props.error && jsxRuntime.jsx("span", { className: 'FormError-helpText', children: props.helpText })] }));
3784
3802
  };
3785
3803
 
3804
+ /**
3805
+ * Track previous values of states.
3806
+ *
3807
+ * @param value Value to track.
3808
+ */
3809
+ const usePrevious = (value) => {
3810
+ const ref = React.useRef();
3811
+ React.useEffect(() => {
3812
+ ref.current = value;
3813
+ }, [value]);
3814
+ return ref.current;
3815
+ };
3816
+
3786
3817
  function escapeStringRegexp(string) {
3787
3818
  if (typeof string !== 'string') {
3788
3819
  throw new TypeError('Expected a string');
@@ -3938,8 +3969,8 @@ const textMatch = (text, filter) => {
3938
3969
  negativeFilters.every((superFilter) => values.every((value) => isMatch(value, superFilter)))));
3939
3970
  };
3940
3971
 
3972
+ const CancelPromise = () => Promise.resolve(true);
3941
3973
  const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick, }) => {
3942
- const { onBulkEditingComplete, redrawRows } = useGridContext();
3943
3974
  const { anchorRef, saving, updateValue, stopEditing } = useGridPopoverContext();
3944
3975
  const saveButtonRef = React.useRef(null);
3945
3976
  const [isOpen, setOpen] = React.useState(false);
@@ -3948,27 +3979,18 @@ const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick,
3948
3979
  }, []);
3949
3980
  const triggerSave = React.useCallback(async (reason) => {
3950
3981
  if (reason == CloseReason.CANCEL) {
3982
+ await updateValue(CancelPromise, 0);
3951
3983
  stopEditing();
3952
- onBulkEditingComplete();
3953
- redrawRows();
3954
3984
  return;
3955
3985
  }
3956
3986
  if (invalid?.()) {
3957
3987
  // Don't close, don't do anything it's invalid
3958
3988
  return;
3959
3989
  }
3960
- if (!save) {
3961
- // No save method so just close
3990
+ if (await updateValue(save ?? (() => Promise.resolve(true)), reason === CloseReason.TAB_FORWARD ? 1 : reason === CloseReason.TAB_BACKWARD ? -1 : 0)) {
3962
3991
  stopEditing();
3963
- onBulkEditingComplete();
3964
- redrawRows();
3965
- return;
3966
3992
  }
3967
- if (await updateValue(save, reason === CloseReason.TAB_FORWARD ? 1 : reason === CloseReason.TAB_BACKWARD ? -1 : 0)) {
3968
- stopEditing();
3969
- redrawRows();
3970
- }
3971
- }, [invalid, onBulkEditingComplete, redrawRows, save, stopEditing, updateValue]);
3993
+ }, [invalid, save, stopEditing, updateValue]);
3972
3994
  const popoverWrapper = React.useCallback((children) => {
3973
3995
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: anchorRef.current && (jsxRuntime.jsxs(ControlledMenu, { state: isOpen ? 'open' : 'closed', portal: true, unmountOnClose: true, anchorRef: anchorRef, saveButtonRef: saveButtonRef, menuClassName: 'step-ag-grid-react-menu', onClose: (event) => {
3974
3996
  // Prevent menu from closing when modals are invoked
@@ -3988,13 +4010,14 @@ const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick,
3988
4010
  return {
3989
4011
  popoverWrapper,
3990
4012
  triggerSave,
4013
+ gridPopoverOpen: isOpen,
3991
4014
  };
3992
4015
  };
3993
4016
 
3994
4017
  const primitiveToSelectOption = (value) => {
3995
4018
  return {
3996
4019
  value: value,
3997
- label: value ? String(value) : '',
4020
+ label: value ? String(value) : '-',
3998
4021
  };
3999
4022
  };
4000
4023
  const MenuSeparatorString = '_____MENU_SEPARATOR_____';
@@ -4008,6 +4031,7 @@ const fieldToString = (field) => {
4008
4031
  };
4009
4032
  const GridFormDropDown = (props) => {
4010
4033
  const { selectedRows, field, data } = useGridPopoverContext();
4034
+ const { onSelectFilter, options: propOptions, onSelectedItem } = props;
4011
4035
  // Save triggers during async action processing which triggers another selectItem(), this ref blocks that
4012
4036
  const [filter, setFilter] = React.useState(props.filterDefaultValue ?? '');
4013
4037
  const [filteredValues, setFilteredValues] = React.useState();
@@ -4021,8 +4045,8 @@ const GridFormDropDown = (props) => {
4021
4045
  const hasChanged = selectedRows.some((row) => row[field] !== value) ||
4022
4046
  (subComponentValue !== undefined && subComponentInitialValue.current !== JSON.stringify(subComponentValue));
4023
4047
  if (hasChanged) {
4024
- if (props.onSelectedItem) {
4025
- await props.onSelectedItem({
4048
+ if (onSelectedItem) {
4049
+ await onSelectedItem({
4026
4050
  selectedRows,
4027
4051
  selectedRowIds: selectedRows.map((row) => row.id),
4028
4052
  value,
@@ -4034,21 +4058,72 @@ const GridFormDropDown = (props) => {
4034
4058
  }
4035
4059
  }
4036
4060
  return true;
4037
- }, [field, props, selectedRows]);
4038
- // Load up options list if it's async function
4039
- React.useEffect(() => {
4040
- if (options)
4041
- return;
4042
- let optionsConf = props.options;
4043
- void (async () => {
4044
- if (typeof optionsConf === 'function') {
4045
- optionsConf = await optionsConf(selectedRows, filter);
4061
+ }, [field, onSelectedItem, selectedRows]);
4062
+ /**
4063
+ * Saves are wrapped in updateValue and triggered by blur events
4064
+ */
4065
+ const save = React.useCallback(async () => {
4066
+ if (!options) {
4067
+ return true;
4068
+ }
4069
+ // Filter saved
4070
+ if (selectedItem === null) {
4071
+ if (onSelectFilter) {
4072
+ if (!lodashEs.isEmpty(filter)) {
4073
+ await onSelectFilter({
4074
+ selectedRows,
4075
+ selectedRowIds: selectedRows.map((row) => row.id),
4076
+ value: filter,
4077
+ });
4078
+ }
4079
+ return true;
4046
4080
  }
4047
- if (optionsConf !== undefined) {
4048
- setOptions(optionsConf);
4081
+ else {
4082
+ if (filteredValues && filteredValues.length === 1) {
4083
+ if (filteredValues[0].subComponent)
4084
+ return false;
4085
+ return await selectItemHandler(filteredValues[0].value, null);
4086
+ }
4049
4087
  }
4050
- })();
4051
- }, [filter, options, props, selectedRows]);
4088
+ return false;
4089
+ }
4090
+ if (selectedItem.subComponent && !subComponentIsValid.current) {
4091
+ return false;
4092
+ }
4093
+ await selectItemHandler(selectedItem.value, subSelectedValue);
4094
+ return true;
4095
+ }, [
4096
+ filter,
4097
+ filteredValues,
4098
+ onSelectFilter,
4099
+ options,
4100
+ selectItemHandler,
4101
+ selectedItem,
4102
+ selectedRows,
4103
+ subSelectedValue,
4104
+ ]);
4105
+ const { popoverWrapper, gridPopoverOpen } = useGridPopoverHook({
4106
+ className: props.className,
4107
+ invalid: () => !options || !!(selectedItem && !subComponentIsValid.current),
4108
+ save,
4109
+ dontSaveOnExternalClick: true,
4110
+ });
4111
+ // Load up options list if it's async function
4112
+ const prevIsOpen = usePrevious(gridPopoverOpen);
4113
+ const prevFilter = usePrevious(filter);
4114
+ React.useEffect(() => {
4115
+ if ((gridPopoverOpen !== prevIsOpen || filter !== prevFilter) && gridPopoverOpen) {
4116
+ let optionsConf = propOptions;
4117
+ void (async () => {
4118
+ if (typeof optionsConf === 'function') {
4119
+ optionsConf = await optionsConf(selectedRows, filter);
4120
+ }
4121
+ if (optionsConf !== undefined) {
4122
+ setOptions(optionsConf);
4123
+ }
4124
+ })();
4125
+ }
4126
+ }, [filter, gridPopoverOpen, options, prevFilter, prevIsOpen, propOptions, selectedRows]);
4052
4127
  // Local filtering.
4053
4128
  React.useEffect(() => {
4054
4129
  if (props.filtered == 'local') {
@@ -4076,39 +4151,6 @@ const GridFormDropDown = (props) => {
4076
4151
  void reSearchOnFilterChange();
4077
4152
  }
4078
4153
  }, [filter, props, reSearchOnFilterChange]);
4079
- /**
4080
- * Saves are wrapped in updateValue and triggered by blur events
4081
- */
4082
- const save = React.useCallback(async () => {
4083
- if (!options)
4084
- return true;
4085
- // Filter saved
4086
- if (selectedItem === null) {
4087
- if (props.onSelectFilter) {
4088
- const { onSelectFilter } = props;
4089
- await onSelectFilter({ selectedRows, selectedRowIds: selectedRows.map((row) => row.id), value: filter });
4090
- return true;
4091
- }
4092
- else {
4093
- if (filteredValues && filteredValues.length === 1) {
4094
- if (filteredValues[0].subComponent)
4095
- return false;
4096
- return await selectItemHandler(filteredValues[0].value, null);
4097
- }
4098
- }
4099
- return false;
4100
- }
4101
- if (selectedItem.subComponent && !subComponentIsValid.current)
4102
- return false;
4103
- await selectItemHandler(selectedItem.value, subSelectedValue);
4104
- return true;
4105
- }, [filter, filteredValues, options, props, selectItemHandler, selectedItem, selectedRows, subSelectedValue]);
4106
- const { popoverWrapper } = useGridPopoverHook({
4107
- className: props.className,
4108
- invalid: () => !options || !!(selectedItem && !subComponentIsValid.current),
4109
- save,
4110
- dontSaveOnExternalClick: true,
4111
- });
4112
4154
  let lastHeader = null;
4113
4155
  let showHeader = null;
4114
4156
  return popoverWrapper(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.filtered && (jsxRuntime.jsxs("div", { className: 'GridFormDropDown-filter', children: [jsxRuntime.jsx(FocusableItem, { className: 'filter-item', onFocus: () => {
@@ -4116,7 +4158,7 @@ const GridFormDropDown = (props) => {
4116
4158
  setSubSelectedValue(null);
4117
4159
  subComponentIsValid.current = true;
4118
4160
  }, children: ({ ref }) => (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', width: '100%' }, children: [jsxRuntime.jsx("input", { className: 'LuiTextInput-input', ref: ref, type: "text", placeholder: props.filterPlaceholder ?? 'Filter...', "data-testid": 'filteredMenu-free-text-input', defaultValue: filter, "data-allowtabtosave": true, "data-disableenterautosave": !props.onSelectFilter &&
4119
- !(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value) }), props.filterHelpText && isNotEmpty(filter) && (jsxRuntime.jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsxRuntime.jsx(MenuDivider, {}, `$$divider_filter`)] })), jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormDropDown-options', children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [options && (lodashEs.isEmpty(options) || (filteredValues && lodashEs.isEmpty(filteredValues))) && (jsxRuntime.jsx(MenuItem, { className: 'GridPopoverEditDropDown-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, `${fieldToString(field)}-empty`)), options?.map((item, index) => {
4161
+ !(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value.trim()) }), props.filterHelpText && isNotEmpty(filter) && (jsxRuntime.jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsxRuntime.jsx(MenuDivider, {}, `$$divider_filter`)] })), jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormDropDown-options', children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [options && (lodashEs.isEmpty(options) || (filteredValues && lodashEs.isEmpty(filteredValues))) && (jsxRuntime.jsx(MenuItem, { className: 'GridPopoverEditDropDown-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, `${fieldToString(field)}-empty`)), options?.map((item, index) => {
4120
4162
  showHeader = null;
4121
4163
  if (item.value === MenuSeparatorString) {
4122
4164
  return jsxRuntime.jsx(MenuDivider, {}, `$$divider_${index}`);
@@ -4346,11 +4388,13 @@ const GridFormMultiSelect = (props) => {
4346
4388
  props.invalid(selectedRows, options.filter((o) => o.checked)));
4347
4389
  }, [options, props, selectedRows]);
4348
4390
  const save = React.useCallback(async (selectedRows) => {
4349
- if (!options || !props.onSave)
4391
+ if (!options || !props.onSave) {
4350
4392
  return true;
4393
+ }
4351
4394
  // Any changes to save?
4352
- if (initialValues === JSON.stringify(options))
4395
+ if (initialValues === JSON.stringify(options)) {
4353
4396
  return true;
4397
+ }
4354
4398
  return props.onSave({
4355
4399
  selectedRows,
4356
4400
  selectedOptions: options.filter((o) => o.checked),
@@ -4443,8 +4487,9 @@ const FilterInput = (props) => {
4443
4487
  setOptions([...options]);
4444
4488
  }, [filter, headerGroups, options, setOptions]);
4445
4489
  const addCustomFilterValue = React.useCallback(() => {
4446
- if (!options || !onSelectFilter)
4490
+ if (!options || !onSelectFilter) {
4447
4491
  return;
4492
+ }
4448
4493
  const filterTrimmed = filter.trim();
4449
4494
  if (lodashEs.isEmpty(filterTrimmed)) {
4450
4495
  void triggerSave();
@@ -4453,8 +4498,9 @@ const FilterInput = (props) => {
4453
4498
  const preFilterOptions = JSON.stringify(options);
4454
4499
  onSelectFilter({ filter: filterTrimmed, options });
4455
4500
  // Detect if options list changed and update
4456
- if (preFilterOptions === JSON.stringify(options))
4501
+ if (preFilterOptions === JSON.stringify(options)) {
4457
4502
  return;
4503
+ }
4458
4504
  setOptions([...options]);
4459
4505
  setFilter('');
4460
4506
  }, [filter, onSelectFilter, options, setFilter, setOptions, triggerSave]);
@@ -5049,6 +5095,7 @@ const GridPopoverMessage = (colDef, props) => GridCell({
5049
5095
  singleClickEdit: true,
5050
5096
  }, {
5051
5097
  editor: GridFormMessage,
5098
+ preventAutoEdit: true,
5052
5099
  ...props,
5053
5100
  });
5054
5101
 
@@ -5064,7 +5111,7 @@ const GridWrapper = ({ children, maxHeight }) => (jsxRuntime.jsx("div", { classN
5064
5111
  const getColId = (colDef) => colDef.colId ?? '';
5065
5112
  const isFlexColumn = (colDef) => !!colDef.flex && !isGridCellFiller(colDef);
5066
5113
 
5067
- const waitForCondition = async (condition, timeoutMs) => {
5114
+ const waitForCondition = async (error, condition, timeoutMs) => {
5068
5115
  const endTime = Date.now() + timeoutMs;
5069
5116
  while (Date.now() < endTime) {
5070
5117
  if (condition()) {
@@ -5072,7 +5119,7 @@ const waitForCondition = async (condition, timeoutMs) => {
5072
5119
  }
5073
5120
  await wait(100);
5074
5121
  }
5075
- console.warn('waitForCondition failed');
5122
+ console.warn(error);
5076
5123
  return false;
5077
5124
  };
5078
5125
 
@@ -5421,8 +5468,7 @@ const GridContextProvider = (props) => {
5421
5468
  startCellEditingInProgressRef.current = true;
5422
5469
  try {
5423
5470
  // Edit in progress so don't edit until finished, timeout waiting after 5s
5424
- if (!(await waitForCondition(() => !anyUpdating(), 5000))) {
5425
- console.error("Could not start edit because previous edit hasn't finished after 5 seconds");
5471
+ if (!(await waitForCondition('startCellEditing failed as update still in progress, waited for 15 seconds', () => !anyUpdating(), 15000))) {
5426
5472
  return;
5427
5473
  }
5428
5474
  const colDef = gridApi.getColumnDef(colId);
@@ -5444,11 +5490,12 @@ const GridContextProvider = (props) => {
5444
5490
  const rowIndex = rowNode.rowIndex;
5445
5491
  if (rowIndex != null) {
5446
5492
  lodashEs.defer(() => {
5447
- !gridApi.isDestroyed() &&
5493
+ if (!gridApi.isDestroyed()) {
5448
5494
  gridApi.startEditingCell({
5449
5495
  rowIndex,
5450
5496
  colKey: colId,
5451
5497
  });
5498
+ }
5452
5499
  });
5453
5500
  }
5454
5501
  }
@@ -5457,9 +5504,9 @@ const GridContextProvider = (props) => {
5457
5504
  }
5458
5505
  }, [anyUpdating, gridApi, prePopupOps, waitForExternallySelectedItemsToBeInSync]);
5459
5506
  const bulkEditingCompleteCallbackRef = React.useRef();
5460
- const onBulkEditingComplete = React.useCallback(() => {
5507
+ const onBulkEditingComplete = React.useCallback(async () => {
5461
5508
  resetFocusedCellAfterCellEditing();
5462
- bulkEditingCompleteCallbackRef.current?.();
5509
+ await bulkEditingCompleteCallbackRef.current?.();
5463
5510
  }, [resetFocusedCellAfterCellEditing]);
5464
5511
  const setOnBulkEditingComplete = React.useCallback((cellEditingCompleteCallback) => {
5465
5512
  bulkEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
@@ -5490,8 +5537,10 @@ const GridContextProvider = (props) => {
5490
5537
  // Prevent resetting focus to original editing cell
5491
5538
  prePopupFocusedCell.current = undefined;
5492
5539
  const preRow = gridApi.getFocusedCell();
5540
+ // If we don't do this ag-grid will do its own continuation of an edit on tab, we don't want that as
5541
+ // we are managing it ourselves
5542
+ gridApi.stopEditing();
5493
5543
  if (tabDirection === 1) {
5494
- gridApi.stopEditing();
5495
5544
  gridApi.tabToNextCell();
5496
5545
  }
5497
5546
  else {
@@ -5528,29 +5577,25 @@ const GridContextProvider = (props) => {
5528
5577
  const selectedRows = props.selectedRows;
5529
5578
  let ok = false;
5530
5579
  await modifyUpdating(props.field ?? '', selectedRows.map((data) => data.id), async () => {
5531
- // MATT Disabled I don't believe these are needed anymore
5532
- // I've left them here just in case they are
5533
5580
  // Need to refresh to get spinners to work on all rows
5534
- // gridApi.refreshCells({ rowNodes: props.selectedRows as RowNode[], force: true });
5581
+ gridApi.refreshCells({ rowNodes: props.selectedRows, force: true });
5535
5582
  ok = await fnUpdate(selectedRows).catch((ex) => {
5536
5583
  console.error('Exception during modifyUpdating', ex);
5537
5584
  return false;
5538
5585
  });
5539
5586
  });
5540
- // MATT Disabled I don't believe these are needed anymore
5541
- // I've left them here just in case they are
5542
5587
  // async processes need to refresh their own rows
5543
- // gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
5588
+ gridApi.refreshCells({ rowNodes: selectedRows, force: true });
5544
5589
  if (gridApi.isDestroyed()) {
5545
5590
  return ok;
5546
5591
  }
5547
5592
  if (ok) {
5548
- const cell = gridApi.getFocusedCell();
5549
- if (cell && gridApi.getFocusedCell() == null) {
5550
- !gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
5551
- }
5593
+ //const cell = gridApi.getFocusedCell();
5594
+ //if (cell && gridApi.getFocusedCell() == null) {
5595
+ // !gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
5596
+ // }
5552
5597
  // This is needed to trigger postSortRowsHook
5553
- gridApi.refreshClientSideRowModel();
5598
+ !gridApi.isDestroyed && gridApi.refreshClientSideRowModel();
5554
5599
  }
5555
5600
  void (async () => {
5556
5601
  // Only focus next cell if user hasn't already manually changed focus
@@ -5560,11 +5605,11 @@ const GridContextProvider = (props) => {
5560
5605
  prePopupFocusedCell.current.rowIndex == postPopupFocusedCell.rowIndex &&
5561
5606
  prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()) {
5562
5607
  if (!tabDirection || !(await selectNextEditableCell(tabDirection))) {
5563
- onBulkEditingComplete();
5608
+ await onBulkEditingComplete();
5564
5609
  }
5565
5610
  }
5566
5611
  else {
5567
- onBulkEditingComplete();
5612
+ await onBulkEditingComplete();
5568
5613
  }
5569
5614
  })();
5570
5615
  return ok;
@@ -5789,19 +5834,6 @@ const GridUpdatingContextProvider = (props) => {
5789
5834
  var css_248z = ".ActionButton{align-items:center;display:flex}.ActionButton-inProgress .LuiIcon{visibility:hidden}.ActionButton-minimal.lui-button-lg.lui-button-icon-right{padding-right:38px}.ActionButton.lui-button-lg.lui-button-icon-right:not(.ActionButton-tight) .LuiIcon{margin:0 4px}.ActionButton.ActionButton-tight.lui-button-lg.lui-button-icon-right .LuiIcon{margin:0}.ActionButton-iconOnly.lui-button-lg.lui-button-icon-right:not(.ActionButton-tight){padding:8px 5px}.ActionButton-iconOnly.lui-button-lg.lui-button-icon-right.ActionButton-tight{padding:0}.ActionButton-minimalArea{position:relative}.ActionButton-minimalAreaDisplay{position:absolute}.ActionButton-minimalAreaExpand{visibility:hidden}.ActionButton-inProgress.lui-button-lg.lui-button-icon-right{background-color:#e2f3f7;color:#007198;cursor:progress}.ActionButton-fill{justify-content:center;width:100%}";
5790
5835
  styleInject(css_248z);
5791
5836
 
5792
- /**
5793
- * Track previous values of states.
5794
- *
5795
- * @param value Value to track.
5796
- */
5797
- const usePrevious = (value) => {
5798
- const ref = React.useRef();
5799
- React.useEffect(() => {
5800
- ref.current = value;
5801
- }, [value]);
5802
- return ref.current;
5803
- };
5804
-
5805
5837
  // Kept this less than one second, so I don't have issues with waitFor as it defaults to 1s
5806
5838
  const minimumInProgressTimeMs = 950;
5807
5839
  const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style, className, title, onClick, size = 'sm', iconPosition = 'left', level = 'tertiary', 'aria-label': ariaLabel, }) => {
@@ -5876,6 +5908,7 @@ const useDeferredPromise = () => {
5876
5908
  };
5877
5909
 
5878
5910
  exports.ActionButton = ActionButton;
5911
+ exports.CancelPromise = CancelPromise;
5879
5912
  exports.ComponentLoadingWrapper = ComponentLoadingWrapper;
5880
5913
  exports.ControlledMenu = ControlledMenu;
5881
5914
  exports.Editor = Editor;