@onehat/ui 0.4.81 → 0.4.83
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 +7 -6
- package/src/Components/Container/Container.js +4 -4
- package/src/Components/Form/Field/Combo/Combo.js +88 -16
- package/src/Components/Form/Field/Combo/MeterTypesCombo.js +1 -0
- package/src/Components/Form/Field/Date.js +1 -1
- package/src/Components/Form/Field/Json.js +2 -1
- package/src/Components/Form/Field/Select/PageSizeSelect.js +6 -1
- package/src/Components/Form/Field/Select/Select.js +14 -38
- package/src/Components/Form/Field/Tag/Tag.js +234 -14
- package/src/Components/Form/Field/Tag/ValueBox.js +20 -1
- package/src/Components/Form/Form.js +26 -13
- package/src/Components/Grid/Grid.js +316 -106
- package/src/Components/Grid/GridHeaderRow.js +42 -22
- package/src/Components/Grid/GridRow.js +16 -6
- package/src/Components/Grid/RowHandle.js +16 -4
- package/src/Components/Hoc/Secondary/withSecondaryEditor.js +137 -43
- package/src/Components/Hoc/Secondary/withSecondarySideEditor.js +1 -1
- package/src/Components/Hoc/withData.js +7 -0
- package/src/Components/Hoc/withEditor.js +19 -4
- package/src/Components/Hoc/withPresetButtons.js +1 -1
- package/src/Components/Hoc/withSideEditor.js +1 -1
- package/src/Components/Icons/Join.js +10 -0
- package/src/Components/Layout/AsyncOperation.js +61 -14
- package/src/Components/Layout/CenterBox.js +1 -1
- package/src/Components/Screens/Manager.js +1 -1
- package/src/Components/Toolbar/Pagination.js +108 -106
- package/src/Components/Toolbar/PaginationToolbar.js +3 -1
- package/src/Components/Toolbar/Toolbar.js +10 -6
- package/src/Components/Tree/TreeNode.js +39 -9
- package/src/Components/Viewer/Viewer.js +7 -2
- package/src/Constants/Progress.js +2 -1
|
@@ -105,12 +105,19 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
105
105
|
columnHeaders = _.filter(columnHeader.parentElement.children, (childNode) => {
|
|
106
106
|
return childNode.getBoundingClientRect().width !== 0; // Skip zero-width children
|
|
107
107
|
}),
|
|
108
|
-
currentX = proxyRect.left
|
|
108
|
+
currentX = proxyRect.left, // left position of pointer
|
|
109
|
+
rowHandleOffset = showRowHandle ? 1 : 0; // Account for RowHandleSpacer
|
|
109
110
|
|
|
110
111
|
// Figure out which index the user wants
|
|
111
112
|
let newIx = 0;
|
|
112
113
|
_.each(columnHeaders, (child, ix, all) => {
|
|
114
|
+
// Skip the row handle spacer if present
|
|
115
|
+
if (showRowHandle && ix === 0) {
|
|
116
|
+
return true; // continue to next iteration
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
const
|
|
120
|
+
adjustedIx = ix - rowHandleOffset, // Adjust index for row handle offset
|
|
114
121
|
rect = child.getBoundingClientRect(), // rect of the columnHeader of this iteration
|
|
115
122
|
{
|
|
116
123
|
left,
|
|
@@ -119,8 +126,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
119
126
|
} = rect,
|
|
120
127
|
halfWidth = width /2;
|
|
121
128
|
|
|
122
|
-
if (
|
|
123
|
-
// first column
|
|
129
|
+
if (adjustedIx === 0) {
|
|
130
|
+
// first actual data column
|
|
124
131
|
if (currentX < left + halfWidth) {
|
|
125
132
|
newIx = 0;
|
|
126
133
|
return false;
|
|
@@ -128,22 +135,22 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
128
135
|
newIx = 1;
|
|
129
136
|
return false;
|
|
130
137
|
}
|
|
131
|
-
} else if (
|
|
132
|
-
// last column
|
|
138
|
+
} else if (adjustedIx === all.length - 1 - rowHandleOffset) {
|
|
139
|
+
// last actual data column (account for nav column and row handle)
|
|
133
140
|
if (currentX < left + halfWidth) {
|
|
134
|
-
newIx =
|
|
141
|
+
newIx = adjustedIx;
|
|
135
142
|
return false;
|
|
136
143
|
}
|
|
137
|
-
newIx =
|
|
144
|
+
newIx = adjustedIx + 1;
|
|
138
145
|
return false;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
// all other columns
|
|
142
149
|
if (left <= currentX && currentX < left + halfWidth) {
|
|
143
|
-
newIx =
|
|
150
|
+
newIx = adjustedIx;
|
|
144
151
|
return false;
|
|
145
152
|
} else if (currentX < right) {
|
|
146
|
-
newIx =
|
|
153
|
+
newIx = adjustedIx + 1;
|
|
147
154
|
return false;
|
|
148
155
|
}
|
|
149
156
|
});
|
|
@@ -155,7 +162,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
155
162
|
|
|
156
163
|
// Render marker showing destination location (can't use regular render cycle because this div is absolutely positioned on page)
|
|
157
164
|
const
|
|
158
|
-
|
|
165
|
+
targetColumnIndex = newIx + rowHandleOffset, // Add back offset for visual positioning
|
|
166
|
+
columnHeaderRect = columnHeaders[targetColumnIndex].getBoundingClientRect(),
|
|
159
167
|
left = columnHeaderRect.left,
|
|
160
168
|
gridRowsContainer = gridRef.current._listRef._scrollRef.childNodes[0],
|
|
161
169
|
gridRowsContainerRect = gridRowsContainer.getBoundingClientRect(),
|
|
@@ -180,12 +188,19 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
180
188
|
columnHeaders = _.filter(columnHeader.parentElement.children, (childNode) => {
|
|
181
189
|
return childNode.getBoundingClientRect().width !== 0; // Skip zero-width children
|
|
182
190
|
}),
|
|
183
|
-
currentX = proxyRect.left
|
|
191
|
+
currentX = proxyRect.left, // left position of pointer
|
|
192
|
+
rowHandleOffset = showRowHandle ? 1 : 0; // Account for RowHandleSpacer
|
|
184
193
|
|
|
185
194
|
// Figure out which index the user wants
|
|
186
195
|
let newIx = 0;
|
|
187
196
|
_.each(columnHeaders, (child, ix, all) => {
|
|
197
|
+
// Skip the row handle spacer if present
|
|
198
|
+
if (showRowHandle && ix === 0) {
|
|
199
|
+
return true; // continue to next iteration
|
|
200
|
+
}
|
|
201
|
+
|
|
188
202
|
const
|
|
203
|
+
adjustedIx = ix - rowHandleOffset, // Adjust index for row handle offset
|
|
189
204
|
rect = child.getBoundingClientRect(), // rect of the columnHeader of this iteration
|
|
190
205
|
{
|
|
191
206
|
left,
|
|
@@ -194,8 +209,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
194
209
|
} = rect,
|
|
195
210
|
halfWidth = width /2;
|
|
196
211
|
|
|
197
|
-
if (
|
|
198
|
-
// first column
|
|
212
|
+
if (adjustedIx === 0) {
|
|
213
|
+
// first actual data column
|
|
199
214
|
if (currentX < left + halfWidth) {
|
|
200
215
|
newIx = 0;
|
|
201
216
|
return false;
|
|
@@ -203,22 +218,22 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
203
218
|
newIx = 1;
|
|
204
219
|
return false;
|
|
205
220
|
}
|
|
206
|
-
} else if (
|
|
207
|
-
// last column
|
|
221
|
+
} else if (adjustedIx === all.length - 1 - rowHandleOffset) {
|
|
222
|
+
// last actual data column (account for nav column and row handle)
|
|
208
223
|
if (currentX < left + halfWidth) {
|
|
209
|
-
newIx =
|
|
224
|
+
newIx = adjustedIx;
|
|
210
225
|
return false;
|
|
211
226
|
}
|
|
212
|
-
newIx =
|
|
227
|
+
newIx = adjustedIx + 1;
|
|
213
228
|
return false;
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
// all other columns
|
|
217
232
|
if (left <= currentX && currentX < left + halfWidth) {
|
|
218
|
-
newIx =
|
|
233
|
+
newIx = adjustedIx;
|
|
219
234
|
return false;
|
|
220
235
|
} else if (currentX < right) {
|
|
221
|
-
newIx =
|
|
236
|
+
newIx = adjustedIx + 1;
|
|
222
237
|
return false;
|
|
223
238
|
}
|
|
224
239
|
});
|
|
@@ -230,7 +245,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
230
245
|
|
|
231
246
|
// Render marker showing destination location (can't use regular render cycle because this div is absolutely positioned on page)
|
|
232
247
|
const
|
|
233
|
-
|
|
248
|
+
targetColumnIndex = newIx + rowHandleOffset, // Add back offset for visual positioning
|
|
249
|
+
columnHeaderRect = columnHeaders[targetColumnIndex].getBoundingClientRect(),
|
|
234
250
|
left = columnHeaderRect.left;
|
|
235
251
|
let marker = dragColumnSlot && dragColumnSlot.marker;
|
|
236
252
|
if (marker) {
|
|
@@ -468,7 +484,12 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
468
484
|
if (showRowHandle) {
|
|
469
485
|
headerColumns.unshift(<Box
|
|
470
486
|
key="RowHandleSpacer"
|
|
471
|
-
className=
|
|
487
|
+
className={clsx(
|
|
488
|
+
'Spacer-RowHandle',
|
|
489
|
+
'w-[40px]',
|
|
490
|
+
'flex-none',
|
|
491
|
+
styles.ROW_HANDLE_CLASSNAME,
|
|
492
|
+
)}
|
|
472
493
|
/>);
|
|
473
494
|
}
|
|
474
495
|
if (!hideNavColumn) {
|
|
@@ -510,4 +531,3 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
510
531
|
showRowHandle,
|
|
511
532
|
]);
|
|
512
533
|
});
|
|
513
|
-
|
|
@@ -29,7 +29,7 @@ let getEmptyImage = null;
|
|
|
29
29
|
|
|
30
30
|
// This was broken out from Grid simply so we can memoize it
|
|
31
31
|
|
|
32
|
-
const GridRow = forwardRef(
|
|
32
|
+
const GridRow = forwardRef((props, ref) => {
|
|
33
33
|
const {
|
|
34
34
|
columnsConfig,
|
|
35
35
|
columnProps,
|
|
@@ -37,6 +37,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
37
37
|
rowProps,
|
|
38
38
|
hideNavColumn,
|
|
39
39
|
showRowHandle,
|
|
40
|
+
areCellsScrollable,
|
|
40
41
|
rowCanSelect,
|
|
41
42
|
rowCanDrag,
|
|
42
43
|
isRowHoverable,
|
|
@@ -141,7 +142,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
141
142
|
'justify-center',
|
|
142
143
|
'border-r-black-100',
|
|
143
144
|
'block',
|
|
144
|
-
'overflow-auto',
|
|
145
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
145
146
|
whichCursor,
|
|
146
147
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
147
148
|
);
|
|
@@ -207,7 +208,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
207
208
|
let textClassName = clsx(
|
|
208
209
|
'GridRow-TextNative',
|
|
209
210
|
'self-center',
|
|
210
|
-
'overflow-hidden',
|
|
211
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
211
212
|
colClassName,
|
|
212
213
|
styles.GRID_CELL_CLASSNAME,
|
|
213
214
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
@@ -216,7 +217,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
216
217
|
textClassName += ' ' + config.className;
|
|
217
218
|
}
|
|
218
219
|
const rendererProps = {
|
|
219
|
-
...testProps('rendererCol-' + config.fieldName),
|
|
220
|
+
...testProps('rendererCol-' + (config.fieldName || config.id || key)),
|
|
220
221
|
className: textClassName,
|
|
221
222
|
...propsToPass,
|
|
222
223
|
...extraProps,
|
|
@@ -283,7 +284,10 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
283
284
|
'px-2',
|
|
284
285
|
'py-3',
|
|
285
286
|
'block',
|
|
286
|
-
'overflow-
|
|
287
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
288
|
+
'[&::-webkit-scrollbar]:h-2',
|
|
289
|
+
'[&::-webkit-scrollbar-thumb]:bg-gray-400',
|
|
290
|
+
'[&::-webkit-scrollbar-thumb]:rounded-full',
|
|
287
291
|
colClassName,
|
|
288
292
|
styles.GRID_CELL_CLASSNAME,
|
|
289
293
|
styles.GRID_ROW_MAX_HEIGHT_NORMAL,
|
|
@@ -291,6 +295,9 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
291
295
|
if (config.className) {
|
|
292
296
|
elementClassName += ' ' + config.className;
|
|
293
297
|
}
|
|
298
|
+
if (rowProps?._cell?.className) {
|
|
299
|
+
elementClassName += ' ' + rowProps._cell.className;
|
|
300
|
+
}
|
|
294
301
|
if (cellProps.className) {
|
|
295
302
|
elementClassName += ' ' + cellProps.className;
|
|
296
303
|
}
|
|
@@ -346,11 +353,14 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
346
353
|
let textClassName = clsx(
|
|
347
354
|
'GridRow-TextNative',
|
|
348
355
|
'self-center',
|
|
349
|
-
'overflow-hidden',
|
|
356
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
350
357
|
colClassName,
|
|
351
358
|
styles.GRID_CELL_CLASSNAME,
|
|
352
359
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
353
360
|
);
|
|
361
|
+
if (rowProps?._cell?.className) {
|
|
362
|
+
textClassName += ' ' + rowProps._cell.className;
|
|
363
|
+
}
|
|
354
364
|
if (config.className) {
|
|
355
365
|
textClassName += ' ' + config.className;
|
|
356
366
|
}
|
|
@@ -3,15 +3,17 @@ import {
|
|
|
3
3
|
Icon,
|
|
4
4
|
VStack,
|
|
5
5
|
} from '@project-components/Gluestack';
|
|
6
|
-
import withTooltip from '
|
|
6
|
+
import withTooltip from '../Hoc/withTooltip';
|
|
7
7
|
import clsx from 'clsx';
|
|
8
|
+
import UiGlobals from '../../UiGlobals.js';
|
|
8
9
|
import Arcs from '../Icons/Arcs.js';
|
|
9
10
|
|
|
10
11
|
const RowHandle = forwardRef((props, ref) => {
|
|
11
12
|
const {
|
|
12
13
|
isDragSource,
|
|
13
14
|
isDraggable
|
|
14
|
-
} = props
|
|
15
|
+
} = props,
|
|
16
|
+
styles = UiGlobals.styles;
|
|
15
17
|
let className = clsx(
|
|
16
18
|
'RowHandle',
|
|
17
19
|
'h-full',
|
|
@@ -20,13 +22,23 @@ const RowHandle = forwardRef((props, ref) => {
|
|
|
20
22
|
'items-center',
|
|
21
23
|
'justify-center',
|
|
22
24
|
'select-none',
|
|
23
|
-
'cursor-pointer'
|
|
25
|
+
'cursor-pointer',
|
|
26
|
+
styles.ROW_HANDLE_CLASSNAME,
|
|
24
27
|
);
|
|
25
28
|
return <VStack
|
|
26
29
|
ref={isDragSource || isDraggable ? ref : undefined}
|
|
27
30
|
className={className}
|
|
28
31
|
>
|
|
29
|
-
<Icon
|
|
32
|
+
<Icon
|
|
33
|
+
as={Arcs}
|
|
34
|
+
size="xs"
|
|
35
|
+
className={clsx(
|
|
36
|
+
'w-full',
|
|
37
|
+
'h-full',
|
|
38
|
+
'text-[#ddd]',
|
|
39
|
+
styles.ROW_HANDLE_ICON_CLASSNAME,
|
|
40
|
+
)}
|
|
41
|
+
/>
|
|
30
42
|
</VStack>;
|
|
31
43
|
});
|
|
32
44
|
|
|
@@ -32,6 +32,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
32
32
|
secondaryUserCanEdit = true, // not permissions, but capability
|
|
33
33
|
secondaryUserCanView = true,
|
|
34
34
|
secondaryCanEditorViewOnly = false, // whether the editor can *ever* change state out of 'View' mode
|
|
35
|
+
secondaryCanProceedWithCrud, // fn returns bool on if the CRUD operation can proceed
|
|
35
36
|
secondaryDisableAdd = false,
|
|
36
37
|
secondaryDisableEdit = false,
|
|
37
38
|
secondaryDisableDelete = false,
|
|
@@ -47,12 +48,14 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
47
48
|
secondaryEditorType,
|
|
48
49
|
secondaryOnAdd,
|
|
49
50
|
secondaryOnChange, // any kind of crud change
|
|
51
|
+
secondaryOnBeforeDelete,
|
|
50
52
|
secondaryOnDelete,
|
|
51
53
|
secondaryOnSave, // this could also be called 'onEdit'
|
|
52
54
|
secondaryOnEditorClose,
|
|
53
55
|
secondaryNewEntityDisplayValue,
|
|
54
56
|
secondaryNewEntityDisplayProperty, // in case the field to set for newEntityDisplayValue is different from model
|
|
55
57
|
secondaryDefaultValues,
|
|
58
|
+
secondaryInitialEditorMode = EDITOR_MODE__VIEW,
|
|
56
59
|
secondaryStayInEditModeOnSelectionChange = false,
|
|
57
60
|
|
|
58
61
|
// withComponent
|
|
@@ -86,11 +89,11 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
86
89
|
secondaryNewEntityDisplayValueRef = useRef(),
|
|
87
90
|
secondaryEditorModeRef = useRef(EDITOR_MODE__VIEW),
|
|
88
91
|
secondaryIsIgnoreNextSelectionChangeRef = useRef(false),
|
|
92
|
+
secondaryIsEditorShownRef = useRef(false),
|
|
89
93
|
secondaryModel = SecondaryRepository?.schema?.name,
|
|
90
94
|
[secondaryCurrentRecord, secondarySetCurrentRecord] = useState(null),
|
|
91
95
|
[secondaryIsAdding, setIsAdding] = useState(false),
|
|
92
96
|
[secondaryIsSaving, setIsSaving] = useState(false),
|
|
93
|
-
[secondaryIsEditorShown, secondarySetIsEditorShownRaw] = useState(false),
|
|
94
97
|
[secondaryIsEditorViewOnly, setIsEditorViewOnly] = useState(secondaryCanEditorViewOnly), // current state of whether editor is in view-only mode
|
|
95
98
|
[secondaryLastSelection, setLastSelection] = useState(),
|
|
96
99
|
secondarySetIsIgnoreNextSelectionChange = (bool) => {
|
|
@@ -100,11 +103,24 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
100
103
|
return secondaryIsIgnoreNextSelectionChangeRef.current;
|
|
101
104
|
},
|
|
102
105
|
secondarySetIsEditorShown = (bool) => {
|
|
103
|
-
|
|
106
|
+
secondaryIsEditorShownRef.current = bool;
|
|
107
|
+
forceUpdate();
|
|
104
108
|
if (!bool && secondaryOnEditorClose) {
|
|
105
109
|
secondaryOnEditorClose();
|
|
106
110
|
}
|
|
107
111
|
},
|
|
112
|
+
secondaryGetIsEditorShown = () => {
|
|
113
|
+
return secondaryIsEditorShownRef.current;
|
|
114
|
+
},
|
|
115
|
+
secondarySetIsWaitModalShown = (bool) => {
|
|
116
|
+
const
|
|
117
|
+
dispatch = UiGlobals.redux?.dispatch,
|
|
118
|
+
setIsWaitModalShownAction = UiGlobals.systemReducer?.setIsWaitModalShownAction;
|
|
119
|
+
if (setIsWaitModalShownAction) {
|
|
120
|
+
console.log('withSecondaryEditor:setIsWaitModalShownAction', bool);
|
|
121
|
+
dispatch(setIsWaitModalShownAction(bool));
|
|
122
|
+
}
|
|
123
|
+
},
|
|
108
124
|
secondarySetSelectionDecorated = (newSelection) => {
|
|
109
125
|
function doIt() {
|
|
110
126
|
secondarySetSelection(newSelection);
|
|
@@ -139,7 +155,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
139
155
|
forceUpdate();
|
|
140
156
|
}
|
|
141
157
|
},
|
|
142
|
-
|
|
158
|
+
secondaryGetNewEntityDisplayValue = () => {
|
|
143
159
|
return secondaryNewEntityDisplayValueRef.current;
|
|
144
160
|
},
|
|
145
161
|
secondaryDoAdd = async (e, values) => {
|
|
@@ -147,6 +163,9 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
147
163
|
showPermissionsError(ADD, secondaryModel);
|
|
148
164
|
return;
|
|
149
165
|
}
|
|
166
|
+
if (secondaryCanProceedWithCrud && !secondaryCanProceedWithCrud()) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
150
169
|
|
|
151
170
|
const secondarySelection = secondaryGetSelection();
|
|
152
171
|
let addValues = values;
|
|
@@ -165,20 +184,20 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
165
184
|
// 1. directlty submit 'values' to use in secondaryDoAdd(), or
|
|
166
185
|
// 2. Use the repository's default values (defined on each property as 'defaultValue'), or
|
|
167
186
|
// 3. Individually override the repository's default values with submitted 'defaultValues' (given as a prop to this HOC)
|
|
168
|
-
let
|
|
187
|
+
let secondaryDefaultValuesToUse = SecondaryRepository.getSchema().getDefaultValues();
|
|
169
188
|
if (secondaryDefaultValues) {
|
|
170
|
-
_.merge(
|
|
189
|
+
_.merge(secondaryDefaultValuesToUse, secondaryDefaultValues);
|
|
171
190
|
}
|
|
172
|
-
addValues = {...
|
|
191
|
+
addValues = {...secondaryDefaultValuesToUse};
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
if (secondarySelectorId && !_.isEmpty(secondarySelectorSelected)) {
|
|
176
195
|
addValues[secondarySelectorId] = secondarySelectorSelected[secondarySelectorSelectedField];
|
|
177
196
|
}
|
|
178
197
|
|
|
179
|
-
if (
|
|
198
|
+
if (secondaryGetNewEntityDisplayValue()) {
|
|
180
199
|
const displayPropertyName = secondaryNewEntityDisplayProperty || SecondaryRepository.getSchema().model.displayProperty;
|
|
181
|
-
addValues[displayPropertyName] =
|
|
200
|
+
addValues[displayPropertyName] = secondaryGetNewEntityDisplayValue();
|
|
182
201
|
}
|
|
183
202
|
|
|
184
203
|
if (getListeners().onBeforeAdd) {
|
|
@@ -246,6 +265,9 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
246
265
|
showPermissionsError(EDIT, secondaryModel);
|
|
247
266
|
return;
|
|
248
267
|
}
|
|
268
|
+
if (secondaryCanProceedWithCrud && !secondaryCanProceedWithCrud()) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
249
271
|
const secondarySelection = secondaryGetSelection();
|
|
250
272
|
if (_.isEmpty(secondarySelection) || (_.isArray(secondarySelection) && (secondarySelection.length > 1 || secondarySelection[0]?.isDestroyed))) {
|
|
251
273
|
return;
|
|
@@ -265,6 +287,9 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
265
287
|
showPermissionsError(DELETE, secondaryModel);
|
|
266
288
|
return;
|
|
267
289
|
}
|
|
290
|
+
if (secondaryCanProceedWithCrud && !secondaryCanProceedWithCrud()) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
268
293
|
let cb = null;
|
|
269
294
|
if (_.isFunction(args)) {
|
|
270
295
|
cb = args;
|
|
@@ -273,7 +298,15 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
273
298
|
if (_.isEmpty(secondarySelection) || (_.isArray(secondarySelection) && (secondarySelection.length > 1 || secondarySelection[0]?.isDestroyed))) {
|
|
274
299
|
return;
|
|
275
300
|
}
|
|
301
|
+
if (secondaryOnBeforeDelete) {
|
|
302
|
+
// This listener is set by parent components using a prop
|
|
303
|
+
const listenerResult = await secondaryOnBeforeDelete(secondarySelection);
|
|
304
|
+
if (listenerResult === false) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
276
308
|
if (getListeners().onBeforeDelete) {
|
|
309
|
+
// This listener is set by child components using setWithEditListeners()
|
|
277
310
|
const listenerResult = await getListeners().onBeforeDelete();
|
|
278
311
|
if (listenerResult === false) {
|
|
279
312
|
return;
|
|
@@ -309,26 +342,33 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
309
342
|
});
|
|
310
343
|
} else
|
|
311
344
|
if (isSingle && isPhantom) {
|
|
312
|
-
|
|
345
|
+
secondaryDeleteRecord(cb);
|
|
313
346
|
} else {
|
|
314
347
|
const identifier = secondaryGetRecordIdentifier(secondarySelection);
|
|
315
|
-
confirm('Are you sure you want to delete the ' + identifier, () =>
|
|
348
|
+
confirm('Are you sure you want to delete the ' + identifier, () => secondaryDeleteRecord(null, cb));
|
|
316
349
|
}
|
|
317
350
|
},
|
|
318
351
|
secondaryDoMoveChildren = (cb) => {
|
|
319
352
|
hideAlert();
|
|
320
|
-
|
|
353
|
+
secondaryDeleteRecord(true, cb);
|
|
321
354
|
},
|
|
322
355
|
secondaryDoDeleteChildren = (cb) => {
|
|
323
356
|
hideAlert();
|
|
324
|
-
|
|
357
|
+
secondaryDeleteRecord(false, cb);
|
|
325
358
|
},
|
|
326
|
-
|
|
359
|
+
secondaryDeleteRecord = async (moveSubtreeUp, cb) => {
|
|
327
360
|
if (canUser && !canUser(DELETE, secondaryModel)) {
|
|
328
361
|
showPermissionsError(DELETE, secondaryModel);
|
|
329
362
|
return;
|
|
330
363
|
}
|
|
331
364
|
const secondarySelection = secondaryGetSelection();
|
|
365
|
+
if (secondaryOnBeforeDelete) {
|
|
366
|
+
// This listener is set by parent components using a prop
|
|
367
|
+
const listenerResult = await secondaryOnBeforeDelete(secondarySelection);
|
|
368
|
+
if (listenerResult === false) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
332
372
|
if (getListeners().onBeforeDelete) {
|
|
333
373
|
const listenerResult = await getListeners().onBeforeDelete(secondarySelection);
|
|
334
374
|
if (listenerResult === false) {
|
|
@@ -362,6 +402,9 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
362
402
|
showPermissionsError(VIEW, secondaryModel);
|
|
363
403
|
return;
|
|
364
404
|
}
|
|
405
|
+
if (secondaryCanProceedWithCrud && !secondaryCanProceedWithCrud()) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
365
408
|
if (secondaryEditorType === EDITOR_TYPE__INLINE) {
|
|
366
409
|
alert('Cannot view in inline editor.');
|
|
367
410
|
return; // inline editor doesn't have a view mode
|
|
@@ -389,37 +432,70 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
389
432
|
showPermissionsError(DUPLICATE, secondaryModel);
|
|
390
433
|
return;
|
|
391
434
|
}
|
|
392
|
-
|
|
393
|
-
|
|
435
|
+
if (secondaryCanProceedWithCrud && !secondaryCanProceedWithCrud()) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
394
438
|
|
|
395
439
|
const secondarySelection = secondaryGetSelection();
|
|
396
440
|
if (secondarySelection.length !== 1) {
|
|
397
441
|
return;
|
|
398
442
|
}
|
|
443
|
+
|
|
399
444
|
if (secondaryUseRemoteDuplicate) {
|
|
400
|
-
|
|
401
|
-
|
|
445
|
+
return await secondaryOnRemoteDuplicate();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
let isSuccess = false,
|
|
449
|
+
duplicateEntity;
|
|
450
|
+
try {
|
|
451
|
+
const
|
|
452
|
+
entity = secondarySelection[0],
|
|
453
|
+
idProperty = SecondaryRepository.getSchema().model.idProperty,
|
|
454
|
+
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
455
|
+
rawValues.id = null; // unset the id of the duplicate
|
|
456
|
+
|
|
457
|
+
setIsWaitModalShown(true);
|
|
458
|
+
|
|
459
|
+
duplicateEntity = await SecondaryRepository.add(rawValues, false, true);
|
|
460
|
+
isSuccess = true;
|
|
461
|
+
|
|
462
|
+
} catch(err) {
|
|
463
|
+
// do nothing
|
|
464
|
+
} finally {
|
|
465
|
+
setIsWaitModalShown(false);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (isSuccess) {
|
|
469
|
+
secondarySetIsIgnoreNextSelectionChange(true);
|
|
470
|
+
secondarySetSelection([duplicateEntity]);
|
|
471
|
+
secondarySetEditorMode(EDITOR_MODE__EDIT);
|
|
472
|
+
secondarySetIsEditorShown(true);
|
|
402
473
|
}
|
|
403
|
-
const
|
|
404
|
-
entity = secondarySelection[0],
|
|
405
|
-
idProperty = SecondaryRepository.getSchema().model.idProperty,
|
|
406
|
-
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
407
|
-
rawValues.id = null; // unset the id of the duplicate
|
|
408
|
-
const duplicate = await SecondaryRepository.add(rawValues, false, true);
|
|
409
|
-
secondarySetIsIgnoreNextSelectionChange(true);
|
|
410
|
-
secondarySetSelection([duplicate]);
|
|
411
|
-
secondarySetEditorMode(EDITOR_MODE__EDIT);
|
|
412
|
-
secondarySetIsEditorShown(true);
|
|
413
474
|
},
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
475
|
+
secondaryOnRemoteDuplicate = async () => {
|
|
476
|
+
let isSuccess = false,
|
|
477
|
+
duplicateEntity;
|
|
478
|
+
try {
|
|
479
|
+
const
|
|
480
|
+
secondarySelection = secondaryGetSelection(),
|
|
481
|
+
entity = secondarySelection[0];
|
|
482
|
+
|
|
483
|
+
setIsWaitModalShown(true);
|
|
419
484
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
485
|
+
duplicateEntity = await SecondaryRepository.remoteDuplicate(entity);
|
|
486
|
+
isSuccess = true;
|
|
487
|
+
|
|
488
|
+
} catch(err) {
|
|
489
|
+
// do nothing
|
|
490
|
+
} finally {
|
|
491
|
+
setIsWaitModalShown(false);
|
|
492
|
+
}
|
|
493
|
+
if (isSuccess) {
|
|
494
|
+
secondarySetIsIgnoreNextSelectionChange(true);
|
|
495
|
+
secondarySetSelection([duplicateEntity]);
|
|
496
|
+
secondaryDoEdit();
|
|
497
|
+
return duplicateEntity;
|
|
498
|
+
}
|
|
423
499
|
},
|
|
424
500
|
secondaryDoEditorSave = async (data, e) => {
|
|
425
501
|
let mode = secondaryGetEditorMode() === EDITOR_MODE__ADD ? ADD : EDIT;
|
|
@@ -516,7 +592,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
516
592
|
isSingle = secondarySelection.length === 1,
|
|
517
593
|
isPhantom = secondarySelection[0] && !secondarySelection[0]?.isDestroyed && secondarySelection[0].isPhantom;
|
|
518
594
|
if (isSingle && isPhantom) {
|
|
519
|
-
await
|
|
595
|
+
await secondaryDeleteRecord();
|
|
520
596
|
}
|
|
521
597
|
|
|
522
598
|
setIsAdding(false);
|
|
@@ -551,7 +627,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
551
627
|
secondarySetIsEditorShown(false);
|
|
552
628
|
});
|
|
553
629
|
},
|
|
554
|
-
|
|
630
|
+
secondaryCalculateEditorMode = () => {
|
|
555
631
|
|
|
556
632
|
let secondaryIsIgnoreNextSelectionChange = secondaryGetIsIgnoreNextSelectionChange(),
|
|
557
633
|
doStayInEditModeOnSelectionChange = secondaryStayInEditModeOnSelectionChange;
|
|
@@ -563,7 +639,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
563
639
|
secondaryIsIgnoreNextSelectionChange = true;
|
|
564
640
|
}
|
|
565
641
|
|
|
566
|
-
//
|
|
642
|
+
// secondaryCalculateEditorMode gets called only on selection changes
|
|
567
643
|
const secondarySelection = secondaryGetSelection();
|
|
568
644
|
let mode;
|
|
569
645
|
if (secondaryEditorType === EDITOR_TYPE__SIDE && !_.isNil(UiGlobals.isSideEditorAlwaysEditMode) && UiGlobals.isSideEditorAlwaysEditMode) {
|
|
@@ -617,10 +693,26 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
617
693
|
};
|
|
618
694
|
|
|
619
695
|
useEffect(() => {
|
|
620
|
-
secondarySetEditorMode(calculateEditorMode());
|
|
621
696
|
|
|
622
|
-
|
|
697
|
+
if (secondaryEditorType === EDITOR_TYPE__SIDE) {
|
|
698
|
+
if (secondarySelection?.length) { // || isAdding
|
|
699
|
+
// there is a selection, so show the editor
|
|
700
|
+
secondarySetIsEditorShown(true);
|
|
701
|
+
} else {
|
|
702
|
+
// no selection, so close the editor
|
|
703
|
+
secondarySetIsEditorShown(false);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
secondarySetEditorMode(secondaryCalculateEditorMode());
|
|
623
708
|
setLastSelection(secondarySelection);
|
|
709
|
+
|
|
710
|
+
// Push isIgnoreNextSelectionChange until after a microtask to ensure all
|
|
711
|
+
// synchronous operations (including listener callbacks) are complete
|
|
712
|
+
// (this is to prevent the editor from immediately switching modes on doAdd in Tree)
|
|
713
|
+
Promise.resolve().then(() => {
|
|
714
|
+
secondarySetIsIgnoreNextSelectionChange(false);
|
|
715
|
+
});
|
|
624
716
|
}, [secondarySelection]);
|
|
625
717
|
|
|
626
718
|
if (self) {
|
|
@@ -638,21 +730,23 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
|
|
|
638
730
|
// NOTE: If I don't calculate this on the fly for selection changes,
|
|
639
731
|
// we see a flash of the previous state, since useEffect hasn't yet run.
|
|
640
732
|
// (basically redo what's in the useEffect, above)
|
|
641
|
-
secondarySetEditorMode(
|
|
733
|
+
secondarySetEditorMode(secondaryCalculateEditorMode());
|
|
642
734
|
}
|
|
643
735
|
|
|
644
736
|
return <WrappedComponent
|
|
645
737
|
{...props}
|
|
738
|
+
ref={ref}
|
|
646
739
|
secondaryDisableWithEditor={false}
|
|
647
740
|
secondaryAlreadyHasWithEditor={true}
|
|
648
|
-
ref={ref}
|
|
649
741
|
secondaryCurrentRecord={secondaryCurrentRecord}
|
|
650
742
|
secondarySetCurrentRecord={secondarySetCurrentRecord}
|
|
651
|
-
secondaryIsEditorShown={
|
|
743
|
+
secondaryIsEditorShown={secondaryGetIsEditorShown()}
|
|
744
|
+
secondaryGetIsEditorShown={secondaryGetIsEditorShown}
|
|
652
745
|
secondaryIsEditorViewOnly={secondaryIsEditorViewOnly}
|
|
653
746
|
secondaryIsAdding={secondaryIsAdding}
|
|
654
747
|
secondaryIsSaving={secondaryIsSaving}
|
|
655
748
|
secondaryEditorMode={secondaryGetEditorMode()}
|
|
749
|
+
secondaryGetEditorMode={secondaryGetEditorMode}
|
|
656
750
|
secondaryOnEditMode={secondarySetEditMode}
|
|
657
751
|
secondaryOnViewMode={secondarySetViewMode}
|
|
658
752
|
secondaryEditorStateRef={secondaryEditorStateRef}
|
|
@@ -68,7 +68,7 @@ export default function withSecondarySideEditor(WrappedComponent, isTree = false
|
|
|
68
68
|
isSideEditor={true}
|
|
69
69
|
{...props}
|
|
70
70
|
/>}
|
|
71
|
-
east={<Editor
|
|
71
|
+
east={props.secondaryIsEditorShown && <Editor
|
|
72
72
|
{...propsToPass}
|
|
73
73
|
editorType={EDITOR_TYPE__SIDE}
|
|
74
74
|
{...secondaryEditorProps}
|
|
@@ -130,6 +130,13 @@ export default function withData(WrappedComponent) {
|
|
|
130
130
|
displayField={displayField}
|
|
131
131
|
idIx={localIdIx}
|
|
132
132
|
displayIx={localDisplayIx}
|
|
133
|
+
setBaseParams={(baseParams) => {
|
|
134
|
+
// This allows components down the hierarchy to dynamically set the baseParams
|
|
135
|
+
LocalRepository.setBaseParams(baseParams);
|
|
136
|
+
if (LocalRepository.isRemote) {
|
|
137
|
+
LocalRepository.load();
|
|
138
|
+
}
|
|
139
|
+
}}
|
|
133
140
|
/>;
|
|
134
141
|
});
|
|
135
142
|
}
|