@onehat/ui 0.4.34 → 0.4.37
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 +1 -1
- package/src/Components/Editor/Editor.js +3 -1
- package/src/Components/Form/Field/Combo/Combo.js +5 -1
- package/src/Components/Form/Field/Tag/Tag.js +1 -0
- package/src/Components/Form/Form.js +37 -32
- package/src/Components/Grid/Grid.js +3 -2
- package/src/Components/Grid/GridRow.js +1 -1
- package/src/Components/Hoc/Secondary/withSecondaryEditor.js +51 -19
- package/src/Components/Hoc/Secondary/withSecondarySelection.js +29 -23
- package/src/Components/Hoc/withEditor.js +6 -1
- package/src/Components/Hoc/withModal.js +5 -5
- package/src/Components/Hoc/withPdfButtons.js +0 -1
- package/src/Components/Hoc/withSelection.js +4 -3
- package/src/Components/Report/Report.js +2 -3
- package/src/Components/Viewer/Viewer.js +6 -1
- package/src/Functions/Cypress/dom_functions.js +20 -2
- package/src/Functions/Cypress/form_functions.js +178 -172
- package/src/Functions/Cypress/grid_functions.js +18 -9
- package/src/Functions/buildAdditionalButtons.js +0 -1
- package/src/PlatformImports/Web/Attachments.js +22 -15
package/package.json
CHANGED
|
@@ -56,6 +56,7 @@ export function ComboComponent(props) {
|
|
|
56
56
|
isDisabled = false,
|
|
57
57
|
isInTag = false,
|
|
58
58
|
minimizeForRow = false,
|
|
59
|
+
reloadOnTrigger = false,
|
|
59
60
|
menuHeight,
|
|
60
61
|
tooltipPlacement = 'bottom',
|
|
61
62
|
placeholder,
|
|
@@ -308,11 +309,14 @@ export function ComboComponent(props) {
|
|
|
308
309
|
resetTextInputValue();
|
|
309
310
|
hideMenu();
|
|
310
311
|
},
|
|
311
|
-
onTriggerPress = (e) => {
|
|
312
|
+
onTriggerPress = async (e) => {
|
|
312
313
|
if (!isRendered) {
|
|
313
314
|
return;
|
|
314
315
|
}
|
|
315
316
|
clearGridFilters();
|
|
317
|
+
if (reloadOnTrigger && Repository) {
|
|
318
|
+
await Repository.reload();
|
|
319
|
+
}
|
|
316
320
|
if (isMenuShown) {
|
|
317
321
|
hideMenu();
|
|
318
322
|
} else {
|
|
@@ -65,8 +65,7 @@ import _ from 'lodash';
|
|
|
65
65
|
// Form is embedded on screen in some other way. Mainly use startingValues, items, validator
|
|
66
66
|
|
|
67
67
|
function Form(props) {
|
|
68
|
-
const
|
|
69
|
-
{
|
|
68
|
+
const {
|
|
70
69
|
editorType = EDITOR_TYPE__WINDOWED, // EDITOR_TYPE__INLINE | EDITOR_TYPE__WINDOWED | EDITOR_TYPE__SIDE | EDITOR_TYPE__SMART | EDITOR_TYPE__PLAIN
|
|
71
70
|
startingValues = {},
|
|
72
71
|
items = [], // Columns, FieldSets, Fields, etc to define the form
|
|
@@ -81,6 +80,7 @@ function Form(props) {
|
|
|
81
80
|
checkIsEditingDisabled = true,
|
|
82
81
|
disableLabels = false,
|
|
83
82
|
disableDirtyIcon = false,
|
|
83
|
+
alwaysShowCancelButton = false,
|
|
84
84
|
onBack,
|
|
85
85
|
onReset,
|
|
86
86
|
onInit,
|
|
@@ -114,7 +114,7 @@ function Form(props) {
|
|
|
114
114
|
// withEditor
|
|
115
115
|
isEditorViewOnly = false,
|
|
116
116
|
isSaving = false,
|
|
117
|
-
getEditorMode,
|
|
117
|
+
getEditorMode = () => {},
|
|
118
118
|
onCancel,
|
|
119
119
|
onSave,
|
|
120
120
|
onClose,
|
|
@@ -247,16 +247,14 @@ function Form(props) {
|
|
|
247
247
|
} else {
|
|
248
248
|
// editor is not defined, fall back to property definition
|
|
249
249
|
if (isEditable) {
|
|
250
|
-
const
|
|
251
|
-
{
|
|
250
|
+
const {
|
|
252
251
|
type: t,
|
|
253
252
|
...p
|
|
254
253
|
} = propertyDef?.editorType;
|
|
255
254
|
type = t;
|
|
256
255
|
editorTypeProps = p;
|
|
257
256
|
} else if (propertyDef?.viewerType) {
|
|
258
|
-
const
|
|
259
|
-
{
|
|
257
|
+
const {
|
|
260
258
|
type: t,
|
|
261
259
|
...p
|
|
262
260
|
} = propertyDef?.viewerType;
|
|
@@ -504,16 +502,14 @@ function Form(props) {
|
|
|
504
502
|
}
|
|
505
503
|
if (!type) {
|
|
506
504
|
if (isEditable) {
|
|
507
|
-
const
|
|
508
|
-
{
|
|
505
|
+
const {
|
|
509
506
|
type: t,
|
|
510
507
|
...p
|
|
511
508
|
} = propertyDef?.editorType;
|
|
512
509
|
type = t;
|
|
513
510
|
editorTypeProps = p;
|
|
514
511
|
} else if (propertyDef?.viewerType) {
|
|
515
|
-
const
|
|
516
|
-
{
|
|
512
|
+
const {
|
|
517
513
|
type: t,
|
|
518
514
|
...p
|
|
519
515
|
} = propertyDef?.viewerType;
|
|
@@ -572,7 +568,7 @@ function Form(props) {
|
|
|
572
568
|
return buildFromItem(item, ix, {...defaults, ...itemDefaults});
|
|
573
569
|
});
|
|
574
570
|
|
|
575
|
-
let elementClassName = 'Form-ElementFromItem';
|
|
571
|
+
let elementClassName = 'Form-ElementFromItem gap-2';
|
|
576
572
|
const defaultsClassName = defaults.className;
|
|
577
573
|
if (defaultsClassName) {
|
|
578
574
|
elementClassName += ' ' + defaultsClassName;
|
|
@@ -790,7 +786,7 @@ function Form(props) {
|
|
|
790
786
|
if (item.additionalEditButtons) {
|
|
791
787
|
const buttons = buildAdditionalButtons(item.additionalEditButtons, self, { fieldState, formSetValue, formGetValues, formState });
|
|
792
788
|
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
793
|
-
element = <HStack className="Form-HStack5 flex-1 flex-wrap items-center">
|
|
789
|
+
element = <HStack className="Form-HStack5 flex-1 flex-wrap items-center gap-2">
|
|
794
790
|
{element}
|
|
795
791
|
{buttons}
|
|
796
792
|
</HStack>;
|
|
@@ -1152,7 +1148,7 @@ function Form(props) {
|
|
|
1152
1148
|
</Toolbar>;
|
|
1153
1149
|
}
|
|
1154
1150
|
if (getEditorMode() === EDITOR_MODE__EDIT && !_.isEmpty(additionalButtons)) {
|
|
1155
|
-
formButtons.push(<Toolbar key="additionalButtonsToolbar" className="justify-end flex-wrap">
|
|
1151
|
+
formButtons.push(<Toolbar key="additionalButtonsToolbar" className="justify-end flex-wrap gap-2">
|
|
1156
1152
|
{additionalButtons}
|
|
1157
1153
|
</Toolbar>)
|
|
1158
1154
|
}
|
|
@@ -1175,27 +1171,31 @@ function Form(props) {
|
|
|
1175
1171
|
showResetBtn = true;
|
|
1176
1172
|
}
|
|
1177
1173
|
// determine whether we should show the close or cancel button
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
// }
|
|
1185
|
-
if (formState.isDirty || isPhantom) {
|
|
1186
|
-
if (isSingle && onCancel) {
|
|
1187
|
-
showCancelBtn = true;
|
|
1188
|
-
}
|
|
1174
|
+
if (alwaysShowCancelButton) {
|
|
1175
|
+
showCancelBtn = true;
|
|
1176
|
+
} else {
|
|
1177
|
+
if (editorType !== EDITOR_TYPE__SIDE) {
|
|
1178
|
+
if (isEditorViewOnly) {
|
|
1179
|
+
showCloseBtn = true;
|
|
1189
1180
|
} else {
|
|
1190
|
-
if (
|
|
1191
|
-
|
|
1181
|
+
// if (editorType === EDITOR_TYPE__WINDOWED && onCancel) {
|
|
1182
|
+
// showCancelBtn = true;
|
|
1183
|
+
// }
|
|
1184
|
+
if (formState.isDirty || isPhantom) {
|
|
1185
|
+
if (isSingle && onCancel) {
|
|
1186
|
+
showCancelBtn = true;
|
|
1187
|
+
}
|
|
1188
|
+
} else {
|
|
1189
|
+
if (onClose) {
|
|
1190
|
+
showCloseBtn = true;
|
|
1191
|
+
}
|
|
1192
1192
|
}
|
|
1193
1193
|
}
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1194
|
+
} else {
|
|
1195
|
+
// side editor only
|
|
1196
|
+
if (isPhantom && isSingle && onCancel) {
|
|
1197
|
+
showCancelBtn = true;
|
|
1198
|
+
}
|
|
1199
1199
|
}
|
|
1200
1200
|
}
|
|
1201
1201
|
if (!isEditorViewOnly && onSave) {
|
|
@@ -1272,11 +1272,16 @@ function Form(props) {
|
|
|
1272
1272
|
/>}
|
|
1273
1273
|
|
|
1274
1274
|
{additionalFooterButtons && _.map(additionalFooterButtons, (props) => {
|
|
1275
|
+
let isDisabled = false;
|
|
1276
|
+
if (props.disableOnInvalid) {
|
|
1277
|
+
isDisabled = !formState.isValid;
|
|
1278
|
+
}
|
|
1275
1279
|
return <Button
|
|
1276
1280
|
{...testProps('additionalFooterBtn-' + props.key)}
|
|
1277
1281
|
{...props}
|
|
1278
1282
|
onPress={(e) => handleSubmit(props.onPress, onSubmitError)(e)}
|
|
1279
1283
|
text={props.text}
|
|
1284
|
+
isDisabled={isDisabled}
|
|
1280
1285
|
/>;
|
|
1281
1286
|
})}
|
|
1282
1287
|
</>;
|
|
@@ -391,6 +391,7 @@ function GridComponent(props) {
|
|
|
391
391
|
|
|
392
392
|
let rowComponent =
|
|
393
393
|
<Pressable
|
|
394
|
+
dataSet={{ ix: index }}
|
|
394
395
|
{...testProps(getRowTestId ? getRowTestId(row) : ((Repository ? Repository.schema.name : 'GridRow') + '-' + item?.id))}
|
|
395
396
|
onPress={(e) => {
|
|
396
397
|
if (e.preventDefault && e.cancelable) {
|
|
@@ -467,7 +468,7 @@ function GridComponent(props) {
|
|
|
467
468
|
onContextMenu(item, e, selection);
|
|
468
469
|
}
|
|
469
470
|
}}
|
|
470
|
-
className="flex-row grow">
|
|
471
|
+
className="Pressable Row flex-row grow">
|
|
471
472
|
{({
|
|
472
473
|
hovered,
|
|
473
474
|
focused,
|
|
@@ -1182,7 +1183,7 @@ function GridComponent(props) {
|
|
|
1182
1183
|
initialNumToRender={initialNumToRender}
|
|
1183
1184
|
initialScrollIndex={0}
|
|
1184
1185
|
renderItem={renderRow}
|
|
1185
|
-
className="
|
|
1186
|
+
className="bg-grey-100"
|
|
1186
1187
|
{...flatListProps}
|
|
1187
1188
|
/>;
|
|
1188
1189
|
|
|
@@ -319,7 +319,7 @@ function GridRow(props) {
|
|
|
319
319
|
rowClassName += ' border-4 border-[#0ff]';
|
|
320
320
|
}
|
|
321
321
|
return <HStackNative
|
|
322
|
-
{...testProps('
|
|
322
|
+
{...testProps('Row ' + (isSelected ? 'row-selected' : ''))}
|
|
323
323
|
{...rowProps}
|
|
324
324
|
key={hash}
|
|
325
325
|
className={rowClassName}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
EDITOR_TYPE__SIDE,
|
|
14
14
|
EDITOR_TYPE__INLINE,
|
|
15
15
|
} from '../../../Constants/Editor.js';
|
|
16
|
+
import useForceUpdate from '../../../Hooks/useForceUpdate.js'
|
|
16
17
|
import Button from '../../Buttons/Button.js';
|
|
17
18
|
import UiGlobals from '../../../UiGlobals.js';
|
|
18
19
|
import _ from 'lodash';
|
|
@@ -27,7 +28,6 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
27
28
|
return <WrappedComponent {...props} ref={ref} isTree={isTree} />;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
let [secondaryEditorMode, secondarySetEditorMode] = useState(EDITOR_MODE__VIEW); // Can change below, so use 'let'
|
|
31
31
|
const {
|
|
32
32
|
secondaryUserCanEdit = true, // not permissions, but capability
|
|
33
33
|
secondaryUserCanView = true,
|
|
@@ -72,6 +72,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
72
72
|
|
|
73
73
|
// withSecondarySelection
|
|
74
74
|
secondarySelection,
|
|
75
|
+
secondaryGetSelection,
|
|
75
76
|
secondarySetSelection,
|
|
76
77
|
|
|
77
78
|
// withAlert
|
|
@@ -79,17 +80,25 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
79
80
|
confirm,
|
|
80
81
|
hideAlert,
|
|
81
82
|
} = props,
|
|
83
|
+
forceUpdate = useForceUpdate(),
|
|
82
84
|
secondaryListeners = useRef({}),
|
|
83
85
|
secondaryEditorStateRef = useRef(),
|
|
84
86
|
secondaryNewEntityDisplayValueRef = useRef(),
|
|
87
|
+
secondaryEditorModeRef = useRef(EDITOR_MODE__VIEW),
|
|
88
|
+
secondaryIsIgnoreNextSelectionChangeRef = useRef(false),
|
|
85
89
|
secondaryModel = SecondaryRepository?.schema?.name,
|
|
86
90
|
[secondaryCurrentRecord, secondarySetCurrentRecord] = useState(null),
|
|
87
91
|
[secondaryIsAdding, setIsAdding] = useState(false),
|
|
88
92
|
[secondaryIsSaving, setIsSaving] = useState(false),
|
|
89
93
|
[secondaryIsEditorShown, secondarySetIsEditorShownRaw] = useState(false),
|
|
90
94
|
[secondaryIsEditorViewOnly, setIsEditorViewOnly] = useState(secondaryCanEditorViewOnly), // current state of whether editor is in view-only mode
|
|
91
|
-
[secondaryIsIgnoreNextSelectionChange, setSecondaryIsIgnoreNextSelectionChange] = useState(false),
|
|
92
95
|
[secondaryLastSelection, setLastSelection] = useState(),
|
|
96
|
+
secondarySetIsIgnoreNextSelectionChange = (bool) => {
|
|
97
|
+
secondaryIsIgnoreNextSelectionChangeRef.current = bool;
|
|
98
|
+
},
|
|
99
|
+
secondaryGetIsIgnoreNextSelectionChange = () => {
|
|
100
|
+
return secondaryIsIgnoreNextSelectionChangeRef.current;
|
|
101
|
+
},
|
|
93
102
|
secondarySetIsEditorShown = (bool) => {
|
|
94
103
|
secondarySetIsEditorShownRaw(bool);
|
|
95
104
|
if (!bool && secondaryOnEditorClose) {
|
|
@@ -100,8 +109,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
100
109
|
function doIt() {
|
|
101
110
|
secondarySetSelection(newSelection);
|
|
102
111
|
}
|
|
103
|
-
const
|
|
104
|
-
|
|
112
|
+
const
|
|
113
|
+
formState = secondaryEditorStateRef.current,
|
|
114
|
+
secondarySelection = secondaryGetSelection();
|
|
115
|
+
if (!_.isEmpty(formState?.dirtyFields) && newSelection !== secondarySelection && secondaryGetEditorMode() === EDITOR_MODE__EDIT) {
|
|
105
116
|
confirm('This record has unsaved changes. Are you sure you want to cancel editing? Changes will be lost.', doIt);
|
|
106
117
|
} else if (secondarySelection && secondarySelection[0] && !secondarySelection[0].isDestroyed && (secondarySelection[0]?.isPhantom || secondarySelection[0]?.isRemotePhantom)) {
|
|
107
118
|
confirm('This new record is unsaved. Are you sure you want to cancel editing? Changes will be lost.', async () => {
|
|
@@ -119,6 +130,15 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
119
130
|
secondaryListeners.current = obj;
|
|
120
131
|
// forceUpdate(); // we don't want to get into an infinite loop of renders. Simply directly assign the secondaryListeners in every child render
|
|
121
132
|
},
|
|
133
|
+
secondaryGetEditorMode = () => {
|
|
134
|
+
return secondaryEditorModeRef.current;
|
|
135
|
+
},
|
|
136
|
+
secondarySetEditorMode = (mode) => {
|
|
137
|
+
if (secondaryEditorModeRef.current !== mode) {
|
|
138
|
+
secondaryEditorModeRef.current = mode;
|
|
139
|
+
forceUpdate();
|
|
140
|
+
}
|
|
141
|
+
},
|
|
122
142
|
getNewEntityDisplayValue = () => {
|
|
123
143
|
return secondaryNewEntityDisplayValueRef.current;
|
|
124
144
|
},
|
|
@@ -128,6 +148,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
128
148
|
return;
|
|
129
149
|
}
|
|
130
150
|
|
|
151
|
+
const secondarySelection = secondaryGetSelection();
|
|
131
152
|
let addValues = values;
|
|
132
153
|
|
|
133
154
|
if (SecondaryRepository?.isLoading) {
|
|
@@ -202,7 +223,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
202
223
|
setIsSaving(true);
|
|
203
224
|
const entity = await SecondaryRepository.add(addValues, false, true);
|
|
204
225
|
setIsSaving(false);
|
|
205
|
-
|
|
226
|
+
secondarySetIsIgnoreNextSelectionChange(true);
|
|
206
227
|
secondarySetSelection([entity]);
|
|
207
228
|
if (getListeners().onAfterAdd) {
|
|
208
229
|
await getListeners().onAfterAdd(entity);
|
|
@@ -225,6 +246,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
225
246
|
showPermissionsError(EDIT, secondaryModel);
|
|
226
247
|
return;
|
|
227
248
|
}
|
|
249
|
+
const secondarySelection = secondaryGetSelection();
|
|
228
250
|
if (_.isEmpty(secondarySelection) || (_.isArray(secondarySelection) && (secondarySelection.length > 1 || secondarySelection[0]?.isDestroyed))) {
|
|
229
251
|
return;
|
|
230
252
|
}
|
|
@@ -247,6 +269,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
247
269
|
if (_.isFunction(args)) {
|
|
248
270
|
cb = args;
|
|
249
271
|
}
|
|
272
|
+
const secondarySelection = secondaryGetSelection();
|
|
250
273
|
if (_.isEmpty(secondarySelection) || (_.isArray(secondarySelection) && (secondarySelection.length > 1 || secondarySelection[0]?.isDestroyed))) {
|
|
251
274
|
return;
|
|
252
275
|
}
|
|
@@ -305,6 +328,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
305
328
|
showPermissionsError(DELETE, secondaryModel);
|
|
306
329
|
return;
|
|
307
330
|
}
|
|
331
|
+
const secondarySelection = secondaryGetSelection();
|
|
308
332
|
if (getListeners().onBeforeDelete) {
|
|
309
333
|
const listenerResult = await getListeners().onBeforeDelete(secondarySelection);
|
|
310
334
|
if (listenerResult === false) {
|
|
@@ -345,6 +369,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
345
369
|
|
|
346
370
|
// check permissions for view
|
|
347
371
|
|
|
372
|
+
const secondarySelection = secondaryGetSelection();
|
|
348
373
|
if (secondarySelection.length !== 1) {
|
|
349
374
|
return;
|
|
350
375
|
}
|
|
@@ -367,7 +392,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
367
392
|
|
|
368
393
|
// check permissions for duplicate
|
|
369
394
|
|
|
370
|
-
|
|
395
|
+
const secondarySelection = secondaryGetSelection();
|
|
371
396
|
if (secondarySelection.length !== 1) {
|
|
372
397
|
return;
|
|
373
398
|
}
|
|
@@ -381,29 +406,32 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
381
406
|
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
382
407
|
rawValues.id = null; // unset the id of the duplicate
|
|
383
408
|
const duplicate = await SecondaryRepository.add(rawValues, false, true);
|
|
384
|
-
|
|
409
|
+
secondarySetIsIgnoreNextSelectionChange(true);
|
|
385
410
|
secondarySetSelection([duplicate]);
|
|
386
411
|
secondarySetEditorMode(EDITOR_MODE__EDIT);
|
|
387
412
|
secondarySetIsEditorShown(true);
|
|
388
413
|
},
|
|
389
414
|
onRemoteDuplicate = async () => {
|
|
390
415
|
const
|
|
416
|
+
secondarySelection = secondaryGetSelection(),
|
|
391
417
|
entity = secondarySelection[0],
|
|
392
418
|
duplicateEntity = await SecondaryRepository.remoteDuplicate(entity);
|
|
393
419
|
|
|
394
|
-
|
|
420
|
+
secondarySetIsIgnoreNextSelectionChange(true);
|
|
395
421
|
secondarySetSelection([duplicateEntity]);
|
|
396
422
|
secondaryDoEdit();
|
|
397
423
|
},
|
|
398
424
|
secondaryDoEditorSave = async (data, e) => {
|
|
399
|
-
let mode =
|
|
425
|
+
let mode = secondaryGetEditorMode() === EDITOR_MODE__ADD ? ADD : EDIT;
|
|
400
426
|
if (canUser && !canUser(mode, secondaryModel)) {
|
|
401
427
|
showPermissionsError(mode, secondaryModel);
|
|
402
428
|
return;
|
|
403
429
|
}
|
|
404
430
|
|
|
405
431
|
// NOTE: The Form submits onSave for both adds (when not isAutoSsave) and edits.
|
|
406
|
-
const
|
|
432
|
+
const
|
|
433
|
+
secondarySelection = secondaryGetSelection(),
|
|
434
|
+
isSingle = secondarySelection.length === 1;
|
|
407
435
|
let useStaged = false;
|
|
408
436
|
if (isSingle) {
|
|
409
437
|
// just update this one entity
|
|
@@ -450,7 +478,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
450
478
|
if (secondaryOnChange) {
|
|
451
479
|
secondaryOnChange(secondarySelection);
|
|
452
480
|
}
|
|
453
|
-
if (
|
|
481
|
+
if (secondaryGetEditorMode() === EDITOR_MODE__ADD) {
|
|
454
482
|
if (secondaryOnAdd) {
|
|
455
483
|
await secondaryOnAdd(secondarySelection);
|
|
456
484
|
}
|
|
@@ -463,7 +491,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
463
491
|
} else {
|
|
464
492
|
secondarySetEditorMode(EDITOR_MODE__VIEW);
|
|
465
493
|
}
|
|
466
|
-
} else if (
|
|
494
|
+
} else if (secondaryGetEditorMode() === EDITOR_MODE__EDIT) {
|
|
467
495
|
if (getListeners().onAfterEdit) {
|
|
468
496
|
await getListeners().onAfterEdit(secondarySelection);
|
|
469
497
|
}
|
|
@@ -479,6 +507,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
479
507
|
secondaryDoEditorCancel = () => {
|
|
480
508
|
async function doIt() {
|
|
481
509
|
const
|
|
510
|
+
secondarySelection = secondaryGetSelection(),
|
|
482
511
|
isSingle = secondarySelection.length === 1,
|
|
483
512
|
isPhantom = secondarySelection[0] && !secondarySelection[0]?.isDestroyed && secondarySelection[0].isPhantom;
|
|
484
513
|
if (isSingle && isPhantom) {
|
|
@@ -517,9 +546,10 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
517
546
|
secondarySetIsEditorShown(false);
|
|
518
547
|
});
|
|
519
548
|
},
|
|
520
|
-
calculateEditorMode = (
|
|
549
|
+
calculateEditorMode = () => {
|
|
521
550
|
|
|
522
|
-
let
|
|
551
|
+
let secondaryIsIgnoreNextSelectionChange = secondaryGetIsIgnoreNextSelectionChange(),
|
|
552
|
+
doStayInEditModeOnSelectionChange = secondaryStayInEditModeOnSelectionChange;
|
|
523
553
|
if (!_.isNil(UiGlobals.stayInEditModeOnSelectionChange)) {
|
|
524
554
|
// allow global override to for this property
|
|
525
555
|
doStayInEditModeOnSelectionChange = UiGlobals.stayInEditModeOnSelectionChange;
|
|
@@ -529,13 +559,14 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
529
559
|
}
|
|
530
560
|
|
|
531
561
|
// calculateEditorMode gets called only on selection changes
|
|
562
|
+
const secondarySelection = secondaryGetSelection();
|
|
532
563
|
let mode;
|
|
533
564
|
if (secondaryEditorType === EDITOR_TYPE__SIDE && !_.isNil(UiGlobals.isSideEditorAlwaysEditMode) && UiGlobals.isSideEditorAlwaysEditMode) {
|
|
534
565
|
// special case: side editor is always edit mode
|
|
535
566
|
mode = EDITOR_MODE__EDIT;
|
|
536
567
|
} else {
|
|
537
568
|
if (secondaryIsIgnoreNextSelectionChange) {
|
|
538
|
-
mode =
|
|
569
|
+
mode = secondaryGetEditorMode();
|
|
539
570
|
if (!secondaryCanEditorViewOnly && secondaryUserCanEdit) {
|
|
540
571
|
if (secondarySelection.length > 1) {
|
|
541
572
|
if (!secondaryDisableEdit) {
|
|
@@ -581,9 +612,9 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
581
612
|
};
|
|
582
613
|
|
|
583
614
|
useEffect(() => {
|
|
584
|
-
secondarySetEditorMode(calculateEditorMode(
|
|
615
|
+
secondarySetEditorMode(calculateEditorMode());
|
|
585
616
|
|
|
586
|
-
|
|
617
|
+
secondarySetIsIgnoreNextSelectionChange(false);
|
|
587
618
|
setLastSelection(secondarySelection);
|
|
588
619
|
}, [secondarySelection]);
|
|
589
620
|
|
|
@@ -602,7 +633,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
602
633
|
// NOTE: If I don't calculate this on the fly for selection changes,
|
|
603
634
|
// we see a flash of the previous state, since useEffect hasn't yet run.
|
|
604
635
|
// (basically redo what's in the useEffect, above)
|
|
605
|
-
|
|
636
|
+
secondarySetEditorMode(calculateEditorMode());
|
|
606
637
|
}
|
|
607
638
|
|
|
608
639
|
return <WrappedComponent
|
|
@@ -615,11 +646,12 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
615
646
|
secondaryIsEditorViewOnly={secondaryIsEditorViewOnly}
|
|
616
647
|
secondaryIsAdding={secondaryIsAdding}
|
|
617
648
|
secondaryIsSaving={secondaryIsSaving}
|
|
618
|
-
secondaryEditorMode={
|
|
649
|
+
secondaryEditorMode={secondaryGetEditorMode()}
|
|
619
650
|
secondaryOnEditMode={secondarySetEditMode}
|
|
620
651
|
secondaryOnViewMode={secondarySetViewMode}
|
|
621
652
|
secondaryEditorStateRef={secondaryEditorStateRef}
|
|
622
653
|
secondarySetIsEditorShown={secondarySetIsEditorShown}
|
|
654
|
+
secondarySetIsIgnoreNextSelectionChange={secondarySetIsIgnoreNextSelectionChange}
|
|
623
655
|
secondaryOnAdd={(!secondaryUserCanEdit || secondaryDisableAdd) ? null : secondaryDoAdd}
|
|
624
656
|
secondaryOnEdit={(!secondaryUserCanEdit || secondaryDisableEdit) ? null : secondaryDoEdit}
|
|
625
657
|
secondaryOnDelete={(!secondaryUserCanEdit || secondaryDisableDelete) ? null : secondaryDoDelete}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { useState, useEffect, } from 'react';
|
|
1
|
+
import { forwardRef, useState, useEffect, useRef, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
SELECTION_MODE_SINGLE,
|
|
4
4
|
SELECTION_MODE_MULTI,
|
|
5
5
|
SELECT_UP,
|
|
6
6
|
SELECT_DOWN,
|
|
7
7
|
} from '../../../Constants/Selection.js';
|
|
8
|
+
import useForceUpdate from '../../../Hooks/useForceUpdate.js';
|
|
8
9
|
import inArray from '../../../Functions/inArray.js';
|
|
9
10
|
import _ from 'lodash';
|
|
10
11
|
|
|
11
12
|
// NOTE: This is a modified version of @onehat/ui/src/Hoc/withSelection
|
|
12
|
-
// This HOC will eventually get out of sync with that one, and may need to be updated.
|
|
13
13
|
|
|
14
14
|
export default function withSelection(WrappedComponent) {
|
|
15
|
-
return (props) => {
|
|
15
|
+
return forwardRef((props, ref) => {
|
|
16
16
|
|
|
17
17
|
if (props.secondaryDisableWithSelection) {
|
|
18
18
|
return <WrappedComponent {...props} />;
|
|
@@ -25,8 +25,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
25
25
|
return <WrappedComponent {...props} />;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
{
|
|
28
|
+
const {
|
|
30
29
|
secondarySelection,
|
|
31
30
|
secondaryDefaultSelection,
|
|
32
31
|
secondaryOnChangeSelection,
|
|
@@ -49,20 +48,25 @@ export default function withSelection(WrappedComponent) {
|
|
|
49
48
|
} = props,
|
|
50
49
|
usesWithValue = !!secondarySetValue,
|
|
51
50
|
initialSelection = secondarySelection || secondaryDefaultSelection || [],
|
|
52
|
-
|
|
51
|
+
forceUpdate = useForceUpdate(),
|
|
52
|
+
secondarySelectionRef = useRef(initialSelection),
|
|
53
53
|
[isReady, setIsReady] = useState(secondarySelection || false), // if secondarySelection is already defined, or secondaryValue is not null and we don't need to load repository, it's ready
|
|
54
54
|
secondarySetSelection = (secondarySelection) => {
|
|
55
|
-
if (_.isEqual(secondarySelection,
|
|
55
|
+
if (_.isEqual(secondarySelection, secondaryGetSelection())) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
secondarySelectionRef.current = secondarySelection;
|
|
60
60
|
if (secondaryOnChangeSelection) {
|
|
61
61
|
secondaryOnChangeSelection(secondarySelection);
|
|
62
62
|
}
|
|
63
63
|
if (fireEvent) {
|
|
64
64
|
fireEvent('secondaryChangeSelection', secondarySelection);
|
|
65
65
|
}
|
|
66
|
+
forceUpdate();
|
|
67
|
+
},
|
|
68
|
+
secondaryGetSelection = () => {
|
|
69
|
+
return secondarySelectionRef.current;
|
|
66
70
|
},
|
|
67
71
|
secondarySelectPrev = () => {
|
|
68
72
|
secondarySelectDirection(SELECT_UP);
|
|
@@ -103,21 +107,21 @@ export default function withSelection(WrappedComponent) {
|
|
|
103
107
|
}
|
|
104
108
|
},
|
|
105
109
|
secondaryAddToSelection = (item) => {
|
|
106
|
-
const newSelection = _.clone(
|
|
110
|
+
const newSelection = _.clone(secondaryGetSelection()); // so we get a new object, so descendants rerender
|
|
107
111
|
newSelection.push(item);
|
|
108
112
|
secondarySetSelection(newSelection);
|
|
109
113
|
},
|
|
110
114
|
secondaryRemoveFromSelection = (item) => {
|
|
111
115
|
let newSelection = [];
|
|
112
116
|
if (SecondaryRepository) {
|
|
113
|
-
newSelection = _.remove(
|
|
117
|
+
newSelection = _.remove(secondaryGetSelection(), (sel) => sel !== item);
|
|
114
118
|
} else {
|
|
115
|
-
newSelection = _.remove(
|
|
119
|
+
newSelection = _.remove(secondaryGetSelection(), (sel) => sel[secondaryIdIx] !== item[secondaryIdIx]);
|
|
116
120
|
}
|
|
117
121
|
secondarySetSelection(newSelection);
|
|
118
122
|
},
|
|
119
123
|
secondaryDeselectAll = () => {
|
|
120
|
-
if (!_.isEmpty(
|
|
124
|
+
if (!_.isEmpty(secondaryGetSelection())) {
|
|
121
125
|
secondarySetSelection([]);
|
|
122
126
|
}
|
|
123
127
|
},
|
|
@@ -128,7 +132,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
128
132
|
// That way, after a load event, we'll keep the same selection, if possible.
|
|
129
133
|
const
|
|
130
134
|
newSelection = [],
|
|
131
|
-
ids = _.map(
|
|
135
|
+
ids = _.map(secondaryGetSelection(), (item) => item.id);
|
|
132
136
|
_.each(ids, (id) => {
|
|
133
137
|
const found = SecondaryRepository.getById(id);
|
|
134
138
|
if (found) {
|
|
@@ -162,9 +166,9 @@ export default function withSelection(WrappedComponent) {
|
|
|
162
166
|
secondarySelectRangeTo = (item) => {
|
|
163
167
|
// Select above max or below min to this one
|
|
164
168
|
const
|
|
165
|
-
currentSelectionLength =
|
|
169
|
+
currentSelectionLength = secondaryGetSelection().length,
|
|
166
170
|
index = getIndexOfSelectedItem(item);
|
|
167
|
-
let newSelection = _.clone(
|
|
171
|
+
let newSelection = _.clone(secondaryGetSelection()); // so we get a new object, so descendants rerender
|
|
168
172
|
|
|
169
173
|
if (currentSelectionLength) {
|
|
170
174
|
const { items, max, min, } = getMaxMinSelectionIndices();
|
|
@@ -191,10 +195,10 @@ export default function withSelection(WrappedComponent) {
|
|
|
191
195
|
},
|
|
192
196
|
secondaryIsInSelection = (item) => {
|
|
193
197
|
if (SecondaryRepository) {
|
|
194
|
-
return inArray(item,
|
|
198
|
+
return inArray(item, secondaryGetSelection());
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
const found = _.find(
|
|
201
|
+
const found = _.find(secondaryGetSelection(), (selectedItem) => {
|
|
198
202
|
return selectedItem[secondaryIdIx] === item[secondaryIdIx];
|
|
199
203
|
});
|
|
200
204
|
return !!found;
|
|
@@ -216,10 +220,10 @@ export default function withSelection(WrappedComponent) {
|
|
|
216
220
|
return found;
|
|
217
221
|
},
|
|
218
222
|
secondaryGetIdsFromLocalSelection = () => {
|
|
219
|
-
if (!
|
|
223
|
+
if (!secondaryGetSelection()[0]) {
|
|
220
224
|
return null;
|
|
221
225
|
}
|
|
222
|
-
const secondaryValues = _.map(
|
|
226
|
+
const secondaryValues = _.map(secondaryGetSelection(), (item) => {
|
|
223
227
|
if (SecondaryRepository) {
|
|
224
228
|
return item.id;
|
|
225
229
|
}
|
|
@@ -303,7 +307,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
303
307
|
}
|
|
304
308
|
}
|
|
305
309
|
|
|
306
|
-
if (!_.isEqual(newSelection,
|
|
310
|
+
if (!_.isEqual(newSelection, secondaryGetSelection())) {
|
|
307
311
|
secondarySetSelection(newSelection);
|
|
308
312
|
}
|
|
309
313
|
};
|
|
@@ -354,7 +358,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
354
358
|
}, [secondaryValue]);
|
|
355
359
|
|
|
356
360
|
if (self) {
|
|
357
|
-
self.secondarySelection =
|
|
361
|
+
self.secondarySelection = secondaryGetSelection();
|
|
358
362
|
self.secondarySetSelection = secondarySetSelection;
|
|
359
363
|
self.secondarySelectPrev = secondarySelectPrev;
|
|
360
364
|
self.secondarySelectNext = secondarySelectNext;
|
|
@@ -395,8 +399,10 @@ export default function withSelection(WrappedComponent) {
|
|
|
395
399
|
|
|
396
400
|
return <WrappedComponent
|
|
397
401
|
{...props}
|
|
402
|
+
ref={ref}
|
|
398
403
|
secondaryDisableWithSelection={false}
|
|
399
|
-
secondarySelection={
|
|
404
|
+
secondarySelection={secondaryGetSelection()}
|
|
405
|
+
secondaryGetSelection={secondaryGetSelection}
|
|
400
406
|
secondarySetSelection={secondarySetSelection}
|
|
401
407
|
secondarySelectionMode={secondarySelectionMode}
|
|
402
408
|
secondarySelectPrev={secondarySelectPrev}
|
|
@@ -411,5 +417,5 @@ export default function withSelection(WrappedComponent) {
|
|
|
411
417
|
secondaryGetIdsFromSelection={secondaryGetIdsFromLocalSelection}
|
|
412
418
|
secondaryGetDisplayValuesFromSelection={secondaryGetDisplayValuesFromLocalSelection}
|
|
413
419
|
/>;
|
|
414
|
-
};
|
|
420
|
+
});
|
|
415
421
|
}
|