@onehat/ui 0.3.148 → 0.3.149

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.148",
3
+ "version": "0.3.149",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "@gluestack-ui/themed": "^0.1.53",
30
30
  "@hookform/resolvers": "^3.3.1",
31
31
  "@k-renwick/colour-mixer": "^1.2.1",
32
- "@onehat/data": "^1.19.0",
32
+ "@onehat/data": "^1.20.0",
33
33
  "@reduxjs/toolkit": "^1.9.5",
34
34
  "inflector-js": "^1.0.1",
35
35
  "js-cookie": "^3.0.5",
@@ -46,12 +46,15 @@ export function ComboComponent(props) {
46
46
  _input = {},
47
47
  isEditor = false,
48
48
  isDisabled = false,
49
+ isInTag = false,
49
50
  tooltipPlacement = 'bottom',
50
51
  placeholder,
51
52
  onRowPress,
52
53
  icon,
53
54
  Editor, // only used for the eyeButton
54
- onSave, // to hook into when menu saves (ComboEditor only)
55
+ onGridAdd, // to hook into when menu adds (ComboEditor only)
56
+ onGridSave, // to hook into when menu saves (ComboEditor only)
57
+ onGridDelete, // to hook into when menu deletes (ComboEditor only)
55
58
 
56
59
  // withComponent
57
60
  self,
@@ -735,19 +738,21 @@ export function ComboComponent(props) {
735
738
  }
736
739
 
737
740
  }}
741
+ onAdd={onGridAdd}
738
742
  onSave={(selection) => {
739
743
  const entity = selection[0];
740
- if (entity?.id !== value) {
744
+ if (entity?.id !== value && !isInTag) { // Tag doesn't use value, so don't do this comparison in the Tag
741
745
  // Either a phantom record was just solidified into a real record, or a new (non-phantom) record was added.
742
746
  // Select it and set the value of the combo.
743
747
  setGridSelection([entity]);
744
748
  const id = entity.id;
745
749
  setValue(id);
746
750
  }
747
- if (onSave) {
748
- onSave(selection);
751
+ if (onGridSave) {
752
+ onGridSave(selection);
749
753
  }
750
754
  }}
755
+ onDelete={onGridDelete}
751
756
  onRowPress={(item, e) => {
752
757
  if (onRowPress) {
753
758
  onRowPress(item, e);
@@ -138,6 +138,66 @@ function TagComponent(props) {
138
138
  });
139
139
  setValue(newValue);
140
140
  },
141
+ onGridAdd = (entity) => {
142
+ // underlying GridEditor added a record.
143
+ // add it to this Tag's value
144
+ const
145
+ id = entity.id,
146
+ newValue = _.clone(value);
147
+ newValue.push({
148
+ id,
149
+ text: entity.displayValue,
150
+ });
151
+ setValue(newValue);
152
+ },
153
+ onGridSave = (selection) => {
154
+ // underlying GridEditor has changed a record.
155
+ // Check if that value exists, and if so, update its displayValue
156
+ if (_.isEmpty(value)) {
157
+ return;
158
+ }
159
+
160
+ const
161
+ entity = selection[0],
162
+ id = entity.id,
163
+ ix = _.findIndex(value, (item) => {
164
+ return item.id === id;
165
+ }),
166
+ isFound = ix !== -1;
167
+ if (!isFound) {
168
+ return;
169
+ }
170
+
171
+ const newValue = _.clone(value);
172
+ newValue[ix] = {
173
+ id,
174
+ text: entity.displayValue,
175
+ };
176
+ setValue(newValue);
177
+ },
178
+ onGridDelete = (selection) => {
179
+ // underlying GridEditor has deleted a value.
180
+ // Check if that value exists, and if so delete it
181
+ if (_.isEmpty(value)) {
182
+ return;
183
+ }
184
+
185
+ const
186
+ entity = selection[0],
187
+ id = entity.id,
188
+ ix = _.findIndex(value, (item) => {
189
+ return item.id === id;
190
+ }),
191
+ isFound = ix !== -1;
192
+ if (!isFound) {
193
+ return;
194
+ }
195
+
196
+ const newValue = _.filter(value, (item) => {
197
+ return item.id !== id;
198
+ });
199
+ setValue(newValue);
200
+ },
141
201
  valueBoxes = _.map(value, (val, ix) => {
142
202
  return <ValueBox
143
203
  key={ix}
@@ -193,6 +253,10 @@ function TagComponent(props) {
193
253
  onChangeValue={onChangeComboValue}
194
254
  parent={self}
195
255
  reference="combo"
256
+ isInTag={true}
257
+ onGridAdd={onGridAdd}
258
+ onGridSave={onGridSave}
259
+ onGridDelete={onGridDelete}
196
260
  {..._combo}
197
261
  />}
198
262
  </Column>
@@ -287,6 +287,7 @@ function GridComponent(props) {
287
287
  reference="reorderBtn"
288
288
  onPress={() => setIsDragMode(!isDragMode)}
289
289
  icon={<Icon as={isDragMode ? NoReorderRows : ReorderRows} color={styles.GRID_TOOLBAR_ITEMS_COLOR} />}
290
+ tooltip="Reorder Rows"
290
291
  />);
291
292
  }
292
293
  return items;
@@ -618,7 +619,7 @@ function GridComponent(props) {
618
619
  }
619
620
 
620
621
  setDragRowSlot({ ix: newIx, marker, useBottom, });
621
- // console.log('onRowReorderDrag', newIx);
622
+ // console.log('onRowReorderDrag slot', newIx);
622
623
 
623
624
  },
624
625
  onRowReorderDragStop = (delta, e, config) => {
@@ -887,7 +888,7 @@ function GridComponent(props) {
887
888
 
888
889
  isAddingRef.current = isAdding;
889
890
 
890
- const footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [additionalToolbarButtons, isDragMode]);
891
+ const footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, isDragMode]);
891
892
 
892
893
  if (!isInited) {
893
894
  // first time through, render a placeholder so we can get container dimensions
@@ -7,7 +7,6 @@ import {
7
7
  EDITOR_MODE__ADD,
8
8
  EDITOR_MODE__EDIT,
9
9
  } from '../../../Constants/Editor.js';
10
- import UiGlobals from '../../../UiGlobals.js';
11
10
  import _ from 'lodash';
12
11
 
13
12
  // NOTE: This is a modified version of @onehat/ui/src/Hoc/withEditor
@@ -38,8 +37,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
38
37
  return 'record' + (secondarySelection[0].displayValue ? ' "' + secondarySelection[0].displayValue + '"' : '') + '?';
39
38
  },
40
39
  secondaryRecord,
41
- secondaryOnChange,
42
- secondaryOnSave,
40
+ secondaryOnAdd,
41
+ secondaryOnChange, // any kind of crud change
42
+ secondaryOnDelete,
43
+ secondaryOnSave, // this could also be called 'onEdit'
43
44
  secondaryNewEntityDisplayValue,
44
45
  secondaryDefaultValues,
45
46
 
@@ -93,12 +94,12 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
93
94
  getNewEntityDisplayValue = () => {
94
95
  return secondaryNewEntityDisplayValueRef.current;
95
96
  },
96
- secondaryOnAdd = async (e, values) => {
97
+ secondaryDoAdd = async (e, values) => {
97
98
  let addValues = values;
98
99
 
99
100
  if (!values) {
100
101
  // you can either:
101
- // 1. directlty submit 'values' to use in onAdd(), or
102
+ // 1. directlty submit 'values' to use in secondaryDoAdd(), or
102
103
  // 2. Use the repository's default values (defined on each property as 'defaultValue'), or
103
104
  // 3. Individually override the repository's default values with submitted 'defaultValues' (given as a prop to this HOC)
104
105
  let defaultValuesToUse = Repository.getSchema().getDefaultValues();
@@ -151,18 +152,20 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
151
152
  setIsSaving(false);
152
153
  setSecondaryIsIgnoreNextSelectionChange(true);
153
154
  secondarySetSelection([entity]);
155
+ if (SecondaryRepository.isAutoSave) {
156
+ // for isAutoSave Repositories, submit the handers right away
157
+ if (getListeners().onAfterAdd) {
158
+ await getListeners().onAfterAdd(entity);
159
+ }
160
+ if (onAdd) {
161
+ await secondaryOnAdd(entity);
162
+ }
163
+ }
154
164
  setIsEditorViewOnly(false);
155
- secondarySetEditorMode(EDITOR_MODE__ADD);
165
+ setEditorMode(SecondaryRepository.isAutoSave ? EDITOR_MODE__EDIT : EDITOR_MODE__ADD);
156
166
  secondarySetIsEditorShown(true);
157
-
158
- if (getListeners().onAfterAdd) {
159
- await getListeners().onAfterAdd(entity);
160
- }
161
- if (secondaryOnChange) {
162
- secondaryOnChange();
163
- }
164
167
  },
165
- secondaryOnEdit = async () => {
168
+ secondaryDoEdit = async () => {
166
169
  if (_.isEmpty(secondarySelection) || (_.isArray(secondarySelection) && (secondarySelection.length > 1 || secondarySelection[0]?.isDestroyed))) {
167
170
  return;
168
171
  }
@@ -176,7 +179,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
176
179
  secondarySetEditorMode(EDITOR_MODE__EDIT);
177
180
  secondarySetIsEditorShown(true);
178
181
  },
179
- secondaryOnDelete = async (args) => {
182
+ secondaryDoDelete = async (args) => {
180
183
  let cb = null;
181
184
  if (_.isFunction(args)) {
182
185
  cb = args;
@@ -203,10 +206,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
203
206
  message: 'The node you have selected for deletion has children. ' +
204
207
  'Should these children be moved up to this node\'s parent, or be deleted?',
205
208
  buttons: [
206
- <Button colorScheme="danger" onPress={() => secondaryOnMoveChildren(cb)} key="moveBtn">
209
+ <Button colorScheme="danger" onPress={() => secondaryDoMoveChildren(cb)} key="moveBtn">
207
210
  Move Children
208
211
  </Button>,
209
- <Button colorScheme="danger" onPress={() => secondaryOnDeleteChildren(cb)} key="deleteBtn">
212
+ <Button colorScheme="danger" onPress={() => secondaryDoDeleteChildren(cb)} key="deleteBtn">
210
213
  Delete Children
211
214
  </Button>
212
215
  ],
@@ -220,17 +223,20 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
220
223
  confirm('Are you sure you want to delete the ' + identifier, () => deleteRecord(null, cb));
221
224
  }
222
225
  },
223
- secondaryOnMoveChildren = (cb) => {
226
+ secondaryDoMoveChildren = (cb) => {
224
227
  hideAlert();
225
228
  deleteRecord(true, cb);
226
229
  },
227
- secondaryOnDeleteChildren = (cb) => {
230
+ secondaryDoDeleteChildren = (cb) => {
228
231
  hideAlert();
229
232
  deleteRecord(false, cb);
230
233
  },
231
234
  deleteRecord = async (moveSubtreeUp, cb) => {
232
- if (getListeners().onBeforeDeleteSave) {
233
- await getListeners().onBeforeDeleteSave(secondarySelection);
235
+ if (getListeners().onBeforeDelete) {
236
+ const listenerResult = await getListeners().onBeforeDelete(secondarySelection);
237
+ if (listenerResult === false) {
238
+ return;
239
+ }
234
240
  }
235
241
 
236
242
  await SecondaryRepository.delete(secondarySelection, moveSubtreeUp);
@@ -242,13 +248,16 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
242
248
  }
243
249
  secondarySetSelection([]);
244
250
  if (cb) {
245
- cb();
251
+ cb(secondarySelection);
246
252
  }
247
253
  if (secondaryOnChange) {
248
- secondaryOnChange();
254
+ secondaryOnChange(secondarySelection);
255
+ }
256
+ if (secondaryOnDelete) {
257
+ secondaryOnDelete(secondarySelection);
249
258
  }
250
259
  },
251
- secondaryOnView = async () => {
260
+ secondaryDoView = async () => {
252
261
  if (!secondaryUserCanView) {
253
262
  return;
254
263
  }
@@ -263,7 +272,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
263
272
  await getListeners().onAfterView();
264
273
  }
265
274
  },
266
- secondaryOnDuplicate = async () => {
275
+ secondaryDoDuplicate = async () => {
267
276
  if (!secondaryUserCanEdit || secondaryDisableDuplicate) {
268
277
  return;
269
278
  }
@@ -290,9 +299,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
290
299
 
291
300
  setSecondaryIsIgnoreNextSelectionChange(true);
292
301
  secondarySetSelection([duplicateEntity]);
293
- secondaryOnEdit();
302
+ secondaryDoEdit();
294
303
  },
295
- secondaryOnEditorSave = async (data, e) => {
304
+ secondaryDoEditorSave = async (data, e) => {
305
+ // NOTE: The Form submits onSave for both adds (when not isAutoSsave) and edits.
296
306
  const
297
307
  what = secondaryRecord || secondarySelection,
298
308
  isSingle = what.length === 1;
@@ -314,8 +324,11 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
314
324
  });
315
325
  }
316
326
 
317
- if (getListeners().onBeforeEditSave) {
318
- await getListeners().onBeforeEditSave(what);
327
+ if (getListeners().onBeforeSave) {
328
+ const listenerResult = await getListeners().onBeforeSave(what);
329
+ if (listenerResult === false) {
330
+ return;
331
+ }
319
332
  }
320
333
 
321
334
  setIsSaving(true);
@@ -330,25 +343,32 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
330
343
  setIsSaving(false);
331
344
 
332
345
  if (success) {
333
- setIsAdding(false);
334
-
335
- secondarySetEditorMode(EDITOR_MODE__EDIT);
336
- // secondarySetIsEditorShown(false);
337
-
338
- if (getListeners().onAfterEdit) {
339
- await getListeners().onAfterEdit(what);
340
- }
341
346
  if (secondaryOnChange) {
342
- secondaryOnChange();
347
+ secondaryOnChange(what);
343
348
  }
344
- if (secondaryOnSave) {
345
- secondaryOnSave(what);
349
+ if (editorMode === EDITOR_MODE__ADD) {
350
+ if (onAdd) {
351
+ await onAdd(what);
352
+ }
353
+ if (getListeners().onAfterAdd) {
354
+ await getListeners().onAfterAdd(what);
355
+ }
356
+ setIsAdding(false);
357
+ setEditorMode(EDITOR_MODE__EDIT);
358
+ } else if (editorMode === EDITOR_MODE__EDIT) {
359
+ if (getListeners().onAfterEdit) {
360
+ await getListeners().onAfterEdit(what);
361
+ }
362
+ if (secondaryOnSave) {
363
+ secondaryOnSave(what);
364
+ }
346
365
  }
366
+ // secondarySetIsEditorShown(false);
347
367
  }
348
368
 
349
369
  return success;
350
370
  },
351
- secondaryOnEditorCancel = () => {
371
+ secondaryDoEditorCancel = () => {
352
372
  async function doIt() {
353
373
  const
354
374
  isSingle = secondarySelection.length === 1,
@@ -367,14 +387,14 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
367
387
  doIt();
368
388
  }
369
389
  },
370
- secondaryOnEditorClose = () => {
390
+ secondaryDoEditorClose = () => {
371
391
  if (secondaryIsAdding) {
372
- secondaryOnEditorCancel();
392
+ secondaryDoEditorCancel();
373
393
  }
374
394
  secondarySetIsEditorShown(false);
375
395
  },
376
- secondaryOnEditorDelete = async () => {
377
- secondaryOnDelete(() => {
396
+ secondaryDoEditorDelete = async () => {
397
+ secondaryDoDelete(() => {
378
398
  secondarySetEditorMode(EDITOR_MODE__VIEW);
379
399
  secondarySetIsEditorShown(false);
380
400
  });
@@ -396,10 +416,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
396
416
  }
397
417
  return mode;
398
418
  },
399
- secondaryOnEditMode = () => {
419
+ secondarySetEditMode = () => {
400
420
  secondarySetEditorMode(EDITOR_MODE__EDIT);
401
421
  },
402
- secondaryOnViewMode = () => {
422
+ secondarySetViewMode = () => {
403
423
  function doIt() {
404
424
  secondarySetEditorMode(EDITOR_MODE__VIEW);
405
425
  }
@@ -428,12 +448,12 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
428
448
  }, [secondarySelection]);
429
449
 
430
450
  if (self) {
431
- self.secondaryAdd = secondaryOnAdd;
432
- self.secondaryEdit = secondaryOnEdit;
433
- self.secondaryDelete = secondaryOnDelete;
434
- self.secondarnMoveChildren = secondaryOnMoveChildren;
435
- self.secondaryDeleteChildren = secondaryOnDeleteChildren;
436
- self.secondaryDuplicate = secondaryOnDuplicate;
451
+ self.secondaryAdd = secondaryDoAdd;
452
+ self.secondaryEdit = secondaryDoEdit;
453
+ self.secondaryDelete = secondaryDoDelete;
454
+ self.secondarnMoveChildren = secondaryDoMoveChildren;
455
+ self.secondaryDeleteChildren = secondaryDoDeleteChildren;
456
+ self.secondaryDuplicate = secondaryDoDuplicate;
437
457
  }
438
458
  secondaryNewEntityDisplayValueRef.current = secondaryNewEntityDisplayValue;
439
459
 
@@ -458,19 +478,19 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
458
478
  secondaryIsAdding={secondaryIsAdding}
459
479
  secondaryIsSaving={secondaryIsSaving}
460
480
  secondaryEditorMode={secondaryEditorMode}
461
- secondaryOnEditMode={secondaryOnEditMode}
462
- secondaryOnViewMode={secondaryOnViewMode}
481
+ secondaryOnEditMode={secondarySetEditMode}
482
+ secondaryOnViewMode={secondarySetViewMode}
463
483
  secondaryEditorStateRef={secondaryEditorStateRef}
464
484
  secondarySetIsEditorShown={secondarySetIsEditorShown}
465
- secondaryOnAdd={(!secondaryUserCanEdit || secondaryDisableAdd) ? null : secondaryOnAdd}
466
- secondaryOnEdit={(!secondaryUserCanEdit || secondaryDisableEdit) ? null : secondaryOnEdit}
467
- secondaryOnDelete={(!secondaryUserCanEdit || secondaryDisableDelete) ? null : secondaryOnDelete}
468
- secondaryOnView={secondaryOnView}
469
- secondaryOnDuplicate={secondaryOnDuplicate}
470
- secondaryOnEditorSave={secondaryOnEditorSave}
471
- secondaryOnEditorCancel={secondaryOnEditorCancel}
472
- secondaryOnEditorDelete={(!secondaryUserCanEdit || secondaryDisableDelete) ? null : secondaryOnEditorDelete}
473
- secondaryOnEditorClose={secondaryOnEditorClose}
485
+ secondaryOnAdd={(!secondaryUserCanEdit || secondaryDisableAdd) ? null : secondaryDoAdd}
486
+ secondaryOnEdit={(!secondaryUserCanEdit || secondaryDisableEdit) ? null : secondaryDoEdit}
487
+ secondaryOnDelete={(!secondaryUserCanEdit || secondaryDisableDelete) ? null : secondaryDoDelete}
488
+ secondaryOnView={secondaryDoView}
489
+ secondaryOnDuplicate={secondaryDoDuplicate}
490
+ secondaryOnEditorSave={secondaryDoEditorSave}
491
+ secondaryOnEditorCancel={secondaryDoEditorCancel}
492
+ secondaryOnEditorDelete={(!secondaryUserCanEdit || secondaryDisableDelete) ? null : secondaryDoEditorDelete}
493
+ secondaryOnEditorClose={secondaryDoEditorClose}
474
494
  secondarySetWithEditListeners={setListeners}
475
495
  secondaryIsEditor={true}
476
496
  secondaryUserCanEdit={secondaryUserCanEdit}
@@ -7,7 +7,6 @@ import {
7
7
  EDITOR_MODE__ADD,
8
8
  EDITOR_MODE__EDIT,
9
9
  } from '../../Constants/Editor.js';
10
- import UiGlobals from '../../UiGlobals.js';
11
10
  import _ from 'lodash';
12
11
 
13
12
  export default function withEditor(WrappedComponent, isTree = false) {
@@ -35,8 +34,10 @@ export default function withEditor(WrappedComponent, isTree = false) {
35
34
  return 'record' + (selection[0].displayValue ? ' "' + selection[0].displayValue + '"' : '') + '?';
36
35
  },
37
36
  record,
38
- onChange,
39
- onSave,
37
+ onAdd,
38
+ onChange, // any kind of crud change
39
+ onDelete,
40
+ onSave, // this could also be called 'onEdit'
40
41
  newEntityDisplayValue,
41
42
  defaultValues,
42
43
 
@@ -95,12 +96,12 @@ export default function withEditor(WrappedComponent, isTree = false) {
95
96
  getNewEntityDisplayValue = () => {
96
97
  return newEntityDisplayValueRef.current;
97
98
  },
98
- onAdd = async (e, values) => {
99
+ doAdd = async (e, values) => {
99
100
  let addValues = values;
100
101
 
101
102
  if (!values) {
102
103
  // you can either:
103
- // 1. directlty submit 'values' to use in onAdd(), or
104
+ // 1. directlty submit 'values' to use in doAdd(), or
104
105
  // 2. Use the repository's default values (defined on each property as 'defaultValue'), or
105
106
  // 3. Individually override the repository's default values with submitted 'defaultValues' (given as a prop to this HOC)
106
107
  let defaultValuesToUse = Repository.getSchema().getDefaultValues();
@@ -153,18 +154,20 @@ export default function withEditor(WrappedComponent, isTree = false) {
153
154
  setIsSaving(false);
154
155
  setIsIgnoreNextSelectionChange(true);
155
156
  setSelection([entity]);
157
+ if (Repository.isAutoSave) {
158
+ // for isAutoSave Repositories, submit the handers right away
159
+ if (getListeners().onAfterAdd) {
160
+ await getListeners().onAfterAdd(entity);
161
+ }
162
+ if (onAdd) {
163
+ await onAdd(entity);
164
+ }
165
+ }
156
166
  setIsEditorViewOnly(false);
157
- setEditorMode(EDITOR_MODE__ADD);
167
+ setEditorMode(Repository.isAutoSave ? EDITOR_MODE__EDIT : EDITOR_MODE__ADD);
158
168
  setIsEditorShown(true);
159
-
160
- if (getListeners().onAfterAdd) {
161
- await getListeners().onAfterAdd(entity);
162
- }
163
- if (onChange) {
164
- onChange();
165
- }
166
169
  },
167
- onEdit = async () => {
170
+ doEdit = async () => {
168
171
  if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
169
172
  return;
170
173
  }
@@ -178,7 +181,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
178
181
  setEditorMode(EDITOR_MODE__EDIT);
179
182
  setIsEditorShown(true);
180
183
  },
181
- onDelete = async (args) => {
184
+ doDelete = async (args) => {
182
185
  let cb = null;
183
186
  if (_.isFunction(args)) {
184
187
  cb = args;
@@ -205,10 +208,10 @@ export default function withEditor(WrappedComponent, isTree = false) {
205
208
  message: 'The node you have selected for deletion has children. ' +
206
209
  'Should these children be moved up to this node\'s parent, or be deleted?',
207
210
  buttons: [
208
- <Button colorScheme="danger" onPress={() => onMoveChildren(cb)} key="moveBtn">
211
+ <Button colorScheme="danger" onPress={() => doMoveChildren(cb)} key="moveBtn">
209
212
  Move Children
210
213
  </Button>,
211
- <Button colorScheme="danger" onPress={() => onDeleteChildren(cb)} key="deleteBtn">
214
+ <Button colorScheme="danger" onPress={() => doDeleteChildren(cb)} key="deleteBtn">
212
215
  Delete Children
213
216
  </Button>
214
217
  ],
@@ -222,17 +225,20 @@ export default function withEditor(WrappedComponent, isTree = false) {
222
225
  confirm('Are you sure you want to delete the ' + identifier, () => deleteRecord(null, cb));
223
226
  }
224
227
  },
225
- onMoveChildren = (cb) => {
228
+ doMoveChildren = (cb) => {
226
229
  hideAlert();
227
230
  deleteRecord(true, cb);
228
231
  },
229
- onDeleteChildren = (cb) => {
232
+ doDeleteChildren = (cb) => {
230
233
  hideAlert();
231
234
  deleteRecord(false, cb);
232
235
  },
233
236
  deleteRecord = async (moveSubtreeUp, cb) => {
234
- if (getListeners().onBeforeDeleteSave) {
235
- await getListeners().onBeforeDeleteSave(selection);
237
+ if (getListeners().onBeforeDelete) {
238
+ const listenerResult = await getListeners().onBeforeDelete(selection);
239
+ if (listenerResult === false) {
240
+ return;
241
+ }
236
242
  }
237
243
 
238
244
  await Repository.delete(selection, moveSubtreeUp);
@@ -244,13 +250,16 @@ export default function withEditor(WrappedComponent, isTree = false) {
244
250
  }
245
251
  setSelection([]);
246
252
  if (cb) {
247
- cb();
253
+ cb(selection);
248
254
  }
249
255
  if (onChange) {
250
- onChange();
256
+ onChange(selection);
257
+ }
258
+ if (onDelete) {
259
+ onDelete(selection);
251
260
  }
252
261
  },
253
- onView = async () => {
262
+ doView = async () => {
254
263
  if (!userCanView) {
255
264
  return;
256
265
  }
@@ -265,7 +274,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
265
274
  await getListeners().onAfterView();
266
275
  }
267
276
  },
268
- onDuplicate = async () => {
277
+ doDuplicate = async () => {
269
278
  if (!userCanEdit || disableDuplicate) {
270
279
  return;
271
280
  }
@@ -292,9 +301,10 @@ export default function withEditor(WrappedComponent, isTree = false) {
292
301
 
293
302
  setIsIgnoreNextSelectionChange(true);
294
303
  setSelection([duplicateEntity]);
295
- onEdit();
304
+ doEdit();
296
305
  },
297
- onEditorSave = async (data, e) => {
306
+ doEditorSave = async (data, e) => {
307
+ // NOTE: The Form submits onSave for both adds (when not isAutoSsave) and edits.
298
308
  const
299
309
  what = record || selection,
300
310
  isSingle = what.length === 1;
@@ -316,8 +326,11 @@ export default function withEditor(WrappedComponent, isTree = false) {
316
326
  });
317
327
  }
318
328
 
319
- if (getListeners().onBeforeEditSave) {
320
- await getListeners().onBeforeEditSave(what);
329
+ if (getListeners().onBeforeSave) {
330
+ const listenerResult = await getListeners().onBeforeSave(what);
331
+ if (listenerResult === false) {
332
+ return;
333
+ }
321
334
  }
322
335
 
323
336
  setIsSaving(true);
@@ -332,25 +345,32 @@ export default function withEditor(WrappedComponent, isTree = false) {
332
345
  setIsSaving(false);
333
346
 
334
347
  if (success) {
335
- setIsAdding(false);
336
-
337
- setEditorMode(EDITOR_MODE__EDIT);
338
- // setIsEditorShown(false);
339
-
340
- if (getListeners().onAfterEdit) {
341
- await getListeners().onAfterEdit(what);
342
- }
343
348
  if (onChange) {
344
- onChange();
349
+ onChange(what);
345
350
  }
346
- if (onSave) {
347
- onSave(what);
351
+ if (editorMode === EDITOR_MODE__ADD) {
352
+ if (onAdd) {
353
+ await onAdd(what);
354
+ }
355
+ if (getListeners().onAfterAdd) {
356
+ await getListeners().onAfterAdd(what);
357
+ }
358
+ setIsAdding(false);
359
+ setEditorMode(EDITOR_MODE__EDIT);
360
+ } else if (editorMode === EDITOR_MODE__EDIT) {
361
+ if (getListeners().onAfterEdit) {
362
+ await getListeners().onAfterEdit(what);
363
+ }
364
+ if (onSave) {
365
+ onSave(what);
366
+ }
348
367
  }
368
+ // setIsEditorShown(false);
349
369
  }
350
370
 
351
371
  return success;
352
372
  },
353
- onEditorCancel = () => {
373
+ doEditorCancel = () => {
354
374
  async function doIt() {
355
375
  const
356
376
  isSingle = selection.length === 1,
@@ -369,14 +389,14 @@ export default function withEditor(WrappedComponent, isTree = false) {
369
389
  doIt();
370
390
  }
371
391
  },
372
- onEditorClose = () => {
392
+ doEditorClose = () => {
373
393
  if (isAdding) {
374
- onEditorCancel();
394
+ doEditorCancel();
375
395
  }
376
396
  setIsEditorShown(false);
377
397
  },
378
- onEditorDelete = async () => {
379
- onDelete(() => {
398
+ doEditorDelete = async () => {
399
+ doDelete(() => {
380
400
  setEditorMode(EDITOR_MODE__VIEW);
381
401
  setIsEditorShown(false);
382
402
  });
@@ -398,10 +418,10 @@ export default function withEditor(WrappedComponent, isTree = false) {
398
418
  }
399
419
  return mode;
400
420
  },
401
- onEditMode = () => {
421
+ setEditMode = () => {
402
422
  setEditorMode(EDITOR_MODE__EDIT);
403
423
  },
404
- onViewMode = () => {
424
+ setViewMode = () => {
405
425
  function doIt() {
406
426
  setEditorMode(EDITOR_MODE__VIEW);
407
427
  }
@@ -417,7 +437,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
417
437
  // When selection changes, set the mode appropriately
418
438
  let mode;
419
439
  if (isIgnoreNextSelectionChange) {
420
- // on selection change from onAdd/onDuplicate/etc, calculate whether to put Editor in "add" or "edit" mode
440
+ // on selection change from doAdd/doDuplicate/etc, calculate whether to put Editor in "add" or "edit" mode
421
441
  mode = calculateEditorMode();
422
442
  } else {
423
443
  // Most of the time, if selection changed, put the Editor in "view" mode
@@ -430,12 +450,12 @@ export default function withEditor(WrappedComponent, isTree = false) {
430
450
  }, [selection]);
431
451
 
432
452
  if (self) {
433
- self.add = onAdd;
434
- self.edit = onEdit;
435
- self.delete = onDelete;
436
- self.moveChildren = onMoveChildren;
437
- self.deleteChildren = onDeleteChildren;
438
- self.duplicate = onDuplicate;
453
+ self.add = doAdd;
454
+ self.edit = doEdit;
455
+ self.delete = doDelete;
456
+ self.moveChildren = doMoveChildren;
457
+ self.deleteChildren = doDeleteChildren;
458
+ self.duplicate = doDuplicate;
439
459
  }
440
460
  newEntityDisplayValueRef.current = newEntityDisplayValue;
441
461
 
@@ -460,19 +480,19 @@ export default function withEditor(WrappedComponent, isTree = false) {
460
480
  isAdding={isAdding}
461
481
  isSaving={isSaving}
462
482
  editorMode={editorMode}
463
- onEditMode={onEditMode}
464
- onViewMode={onViewMode}
483
+ onEditMode={setEditMode}
484
+ onViewMode={setViewMode}
465
485
  editorStateRef={editorStateRef}
466
486
  setIsEditorShown={setIsEditorShown}
467
- onAdd={(!userCanEdit || disableAdd) ? null : onAdd}
468
- onEdit={(!userCanEdit || disableEdit) ? null : onEdit}
469
- onDelete={(!userCanEdit || disableDelete) ? null : onDelete}
470
- onView={onView}
471
- onDuplicate={onDuplicate}
472
- onEditorSave={onEditorSave}
473
- onEditorCancel={onEditorCancel}
474
- onEditorDelete={(!userCanEdit || disableDelete) ? null : onEditorDelete}
475
- onEditorClose={onEditorClose}
487
+ onAdd={(!userCanEdit || disableAdd) ? null : doAdd}
488
+ onEdit={(!userCanEdit || disableEdit) ? null : doEdit}
489
+ onDelete={(!userCanEdit || disableDelete) ? null : doDelete}
490
+ onView={doView}
491
+ onDuplicate={doDuplicate}
492
+ onEditorSave={doEditorSave}
493
+ onEditorCancel={doEditorCancel}
494
+ onEditorDelete={(!userCanEdit || disableDelete) ? null : doEditorDelete}
495
+ onEditorClose={doEditorClose}
476
496
  setWithEditListeners={setListeners}
477
497
  isEditor={true}
478
498
  userCanEdit={userCanEdit}
@@ -186,7 +186,7 @@ export default function Pagination(props) {
186
186
  {items}
187
187
  </Row>;
188
188
  }, [
189
- // Repository,
189
+ Repository?.hash,
190
190
  showPagination,
191
191
  page,
192
192
  pageSize,
@@ -1079,8 +1079,8 @@ function TreeComponent(props) {
1079
1079
  });
1080
1080
 
1081
1081
  const
1082
- headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), [treeSearchValue, isDragMode, getTreeNodeData()]),
1083
- footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [additionalToolbarButtons, isDragMode, getTreeNodeData()]);
1082
+ headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), [Repository?.hash, treeSearchValue, isDragMode, getTreeNodeData()]),
1083
+ footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, isDragMode, getTreeNodeData()]);
1084
1084
 
1085
1085
  if (!isReady) {
1086
1086
  return null;