@onehat/ui 0.4.105 → 0.4.107
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 +2 -1
- package/src/Components/Form/Field/Combo/Combo.js +20 -0
- package/src/Components/Form/Form.js +40 -3
- package/src/Components/Grid/Grid.js +1 -1
- package/src/Components/Grid/GridRow.js +4 -6
- package/src/Components/Hoc/withEditor.js +21 -6
- package/src/Components/Hoc/withPdfButtons.js +61 -48
- package/src/Components/Layout/SetupButton.js +29 -3
- package/src/Components/Pms/Editor/MetersEditor.js +5 -0
- package/src/Components/Viewer/Viewer.js +24 -4
package/package.json
CHANGED
|
@@ -46,10 +46,11 @@ function Editor(props) {
|
|
|
46
46
|
if (canRecordBeEdited && !canRecordBeEdited(selection)) {
|
|
47
47
|
canEdit = false;
|
|
48
48
|
}
|
|
49
|
+
const record = selection[0];
|
|
50
|
+
self.record = record; // make it so we can target the record from within a Viewer or Form
|
|
49
51
|
|
|
50
52
|
// Repository?.isRemotePhantomMode && selection.length === 1 &&
|
|
51
53
|
if (getEditorMode() === EDITOR_MODE__VIEW || isEditorViewOnly || !canEdit) {
|
|
52
|
-
const record = selection[0];
|
|
53
54
|
if (record.isDestroyed) {
|
|
54
55
|
return null;
|
|
55
56
|
}
|
|
@@ -1223,6 +1223,25 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
|
|
1225
1225
|
if (isViewerShown && Editor) {
|
|
1226
|
+
let modalBackdrop = <ModalBackdrop className="Combo-viewer-ModalBackdrop" />;
|
|
1227
|
+
if (CURRENT_MODE === UI_MODE_NATIVE) {
|
|
1228
|
+
// Gluestack's ModalBackdrop was not working on Native,
|
|
1229
|
+
// so workaround is to do it manually for now
|
|
1230
|
+
modalBackdrop = <Pressable
|
|
1231
|
+
onPress={onViewerClose}
|
|
1232
|
+
className={clsx(
|
|
1233
|
+
'Combo-viewer-ModalBackdrop-replacment',
|
|
1234
|
+
'h-full',
|
|
1235
|
+
'w-full',
|
|
1236
|
+
'absolute',
|
|
1237
|
+
'top-0',
|
|
1238
|
+
'left-0',
|
|
1239
|
+
'bg-[#000]',
|
|
1240
|
+
'opacity-50',
|
|
1241
|
+
)}
|
|
1242
|
+
/>;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1226
1245
|
const propsForViewer = _.pick(props, [
|
|
1227
1246
|
'disableCopy',
|
|
1228
1247
|
'disableDuplicate',
|
|
@@ -1246,6 +1265,7 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
1246
1265
|
isOpen={true}
|
|
1247
1266
|
onClose={onViewerClose}
|
|
1248
1267
|
>
|
|
1268
|
+
{modalBackdrop}
|
|
1249
1269
|
<Editor
|
|
1250
1270
|
editorType={EDITOR_TYPE__WINDOWED}
|
|
1251
1271
|
isEditorViewOnly={true}
|
|
@@ -240,6 +240,7 @@ function Form(props) {
|
|
|
240
240
|
resolver: yupResolver(validatorToUse),
|
|
241
241
|
context: { isPhantom },
|
|
242
242
|
}),
|
|
243
|
+
currentEditorMode = getEditorMode(),
|
|
243
244
|
buildFromColumnsConfig = () => {
|
|
244
245
|
// Only used in InlineEditor
|
|
245
246
|
// Build the fields that match the current columnsConfig in the grid
|
|
@@ -969,6 +970,14 @@ function Form(props) {
|
|
|
969
970
|
buildAncillary = () => {
|
|
970
971
|
const
|
|
971
972
|
validAncillaryItems = _.filter(ancillaryItems, (item) => !!item), // filter out any null/undefined items
|
|
973
|
+
parentEditorModeRaw = getEditorMode?.() || props.editorMode || null,
|
|
974
|
+
parentEditorMode = parentEditorModeRaw === EDITOR_MODE__ADD
|
|
975
|
+
? EDITOR_MODE__EDIT
|
|
976
|
+
: parentEditorModeRaw,
|
|
977
|
+
normalizedParentEditorMode =
|
|
978
|
+
parentEditorMode === EDITOR_MODE__EDIT || parentEditorMode === EDITOR_MODE__VIEW
|
|
979
|
+
? parentEditorMode
|
|
980
|
+
: null,
|
|
972
981
|
components = [];
|
|
973
982
|
setAncillaryButtons([]);
|
|
974
983
|
if (validAncillaryItems.length) {
|
|
@@ -1011,6 +1020,8 @@ function Form(props) {
|
|
|
1011
1020
|
}
|
|
1012
1021
|
|
|
1013
1022
|
const
|
|
1023
|
+
ancillaryEditorMode = itemPropsToPass.editorMode ?? normalizedParentEditorMode,
|
|
1024
|
+
ancillaryInitialEditorMode = itemPropsToPass.initialEditorMode ?? ancillaryEditorMode ?? undefined,
|
|
1014
1025
|
Element = getComponentFromType(type),
|
|
1015
1026
|
element = <Element
|
|
1016
1027
|
{...testProps('ancillary-' + type)}
|
|
@@ -1020,6 +1031,8 @@ function Form(props) {
|
|
|
1020
1031
|
uniqueRepository={true}
|
|
1021
1032
|
parent={self}
|
|
1022
1033
|
{...itemPropsToPass}
|
|
1034
|
+
editorMode={ancillaryEditorMode}
|
|
1035
|
+
initialEditorMode={ancillaryInitialEditorMode}
|
|
1023
1036
|
/>;
|
|
1024
1037
|
if (title) {
|
|
1025
1038
|
if (record?.displayValue) {
|
|
@@ -1033,7 +1046,7 @@ function Form(props) {
|
|
|
1033
1046
|
)}
|
|
1034
1047
|
>{title}</Text>;
|
|
1035
1048
|
if (icon) {
|
|
1036
|
-
titleElement = <HStack className="items-center"><Icon as={icon} className="w-[32px] h-[32px] mr-2" />{titleElement}</HStack>
|
|
1049
|
+
titleElement = <HStack className="items-center mb-1"><Icon as={icon} className="w-[32px] h-[32px] mr-2" />{titleElement}</HStack>
|
|
1037
1050
|
}
|
|
1038
1051
|
}
|
|
1039
1052
|
if (description) {
|
|
@@ -1137,6 +1150,29 @@ function Form(props) {
|
|
|
1137
1150
|
}
|
|
1138
1151
|
}, [record]);
|
|
1139
1152
|
|
|
1153
|
+
useEffect(() => {
|
|
1154
|
+
if (skipAll) {
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
if (currentEditorMode !== EDITOR_MODE__ADD) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (!containerWidth) {
|
|
1161
|
+
// Wait until fields are mounted; before this, isValid can be false with empty errors.
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// In some flows the editor mode flips to ADD after the record effect runs.
|
|
1166
|
+
// Validate again so the Add button is enabled immediately when form is valid.
|
|
1167
|
+
const timeoutId = setTimeout(() => {
|
|
1168
|
+
trigger();
|
|
1169
|
+
}, 0);
|
|
1170
|
+
|
|
1171
|
+
return () => {
|
|
1172
|
+
clearTimeout(timeoutId);
|
|
1173
|
+
};
|
|
1174
|
+
}, [record, currentEditorMode, containerWidth, trigger]);
|
|
1175
|
+
|
|
1140
1176
|
useEffect(() => {
|
|
1141
1177
|
if (skipAll) {
|
|
1142
1178
|
return;
|
|
@@ -1237,7 +1273,8 @@ function Form(props) {
|
|
|
1237
1273
|
showCloseBtn = false,
|
|
1238
1274
|
showCancelBtn = false,
|
|
1239
1275
|
showSaveBtn = false,
|
|
1240
|
-
showSubmitBtn = false
|
|
1276
|
+
showSubmitBtn = false,
|
|
1277
|
+
isAddMode = getEditorMode() === EDITOR_MODE__ADD;
|
|
1241
1278
|
if (containerWidth) { // we need to render this component twice in order to get the container width. Skip this on first render
|
|
1242
1279
|
|
|
1243
1280
|
// create editor
|
|
@@ -1320,7 +1357,7 @@ function Form(props) {
|
|
|
1320
1357
|
isSaveDisabled = true;
|
|
1321
1358
|
isSubmitDisabled = true;
|
|
1322
1359
|
}
|
|
1323
|
-
if (_.isEmpty(formState.dirtyFields) && !isPhantom) {
|
|
1360
|
+
if (_.isEmpty(formState.dirtyFields) && !isPhantom && !isAddMode) {
|
|
1324
1361
|
isSaveDisabled = true;
|
|
1325
1362
|
}
|
|
1326
1363
|
if (onDelete && getEditorMode() === EDITOR_MODE__EDIT && isSingle) {
|
|
@@ -430,7 +430,7 @@ function GridComponent(props) {
|
|
|
430
430
|
return processedConfig;
|
|
431
431
|
});
|
|
432
432
|
const items = _.map(processedButtons, (config, ix) => getIconButtonFromConfig(config, ix, self));
|
|
433
|
-
if (canRowsReorder && CURRENT_MODE === UI_MODE_WEB) { // DND is currently web-only TODO: implement for RN
|
|
433
|
+
if (canRowsReorder && CURRENT_MODE === UI_MODE_WEB && onEdit && (!canUser || canUser(EDIT)) && !isEditorViewOnly) { // DND is currently web-only TODO: implement for RN
|
|
434
434
|
items.unshift(<IconButton
|
|
435
435
|
{...testProps('reorderBtn')}
|
|
436
436
|
key="reorderBtn"
|
|
@@ -450,6 +450,8 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
450
450
|
)}
|
|
451
451
|
/>}
|
|
452
452
|
</>;
|
|
453
|
+
const hasCustomBgClass = rowProps?.className && /\bbg-/.test(rowProps.className);
|
|
454
|
+
|
|
453
455
|
if (dropTargetRef) {
|
|
454
456
|
rowContents = <HStack
|
|
455
457
|
ref={dropTargetRef}
|
|
@@ -459,9 +461,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
459
461
|
'flex-1',
|
|
460
462
|
'grow-1',
|
|
461
463
|
)}
|
|
462
|
-
style={{
|
|
463
|
-
backgroundColor: bg,
|
|
464
|
-
}}
|
|
464
|
+
style={hasCustomBgClass ? undefined : { backgroundColor: bg }}
|
|
465
465
|
>{rowContents}</HStack>;
|
|
466
466
|
}
|
|
467
467
|
|
|
@@ -485,9 +485,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
485
485
|
{...rowProps}
|
|
486
486
|
key={hash}
|
|
487
487
|
className={rowClassName}
|
|
488
|
-
style={{
|
|
489
|
-
backgroundColor: bg,
|
|
490
|
-
}}
|
|
488
|
+
style={hasCustomBgClass ? undefined : { backgroundColor: bg }}
|
|
491
489
|
>{rowContents}</HStackNative>;
|
|
492
490
|
if (rowProps.tooltip) {
|
|
493
491
|
row = <Tooltip
|
|
@@ -57,6 +57,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
57
57
|
newEntityDisplayValue,
|
|
58
58
|
newEntityDisplayProperty, // in case the field to set for newEntityDisplayValue is different from model
|
|
59
59
|
defaultValues,
|
|
60
|
+
editorMode: parentEditorModeProp,
|
|
60
61
|
initialEditorMode = EDITOR_MODE__VIEW,
|
|
61
62
|
stayInEditModeOnSelectionChange = false,
|
|
62
63
|
inheritParentEditorMode = true,
|
|
@@ -148,7 +149,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
148
149
|
selection = getSelection();
|
|
149
150
|
if (!_.isEmpty(formState?.dirtyFields) && newSelection !== selection && getEditorMode() === EDITOR_MODE__EDIT) {
|
|
150
151
|
confirm('This record has unsaved changes. Are you sure you want to cancel editing? Changes will be lost.', doIt);
|
|
151
|
-
} else if (selection && selection[0] && !selection[0].isDestroyed &&
|
|
152
|
+
} else if (selection && selection[0] && !selection[0].isDestroyed && selection[0].isPhantom) {
|
|
152
153
|
confirm('This new record is unsaved. Are you sure you want to cancel editing? Changes will be lost.', async () => {
|
|
153
154
|
await selection[0].delete();
|
|
154
155
|
doIt();
|
|
@@ -174,7 +175,21 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
174
175
|
}
|
|
175
176
|
},
|
|
176
177
|
getParentEditorMode = () => {
|
|
177
|
-
|
|
178
|
+
const contextMode = parentEditorModeContext?.effectiveEditorMode || null;
|
|
179
|
+
if (contextMode) {
|
|
180
|
+
return contextMode;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Some modal implementations break React context boundaries. Fall back to
|
|
184
|
+
// an explicitly-passed parent mode so nested ancillary editors still inherit.
|
|
185
|
+
if (parentEditorModeProp === EDITOR_MODE__ADD) {
|
|
186
|
+
return EDITOR_MODE__EDIT;
|
|
187
|
+
}
|
|
188
|
+
if (parentEditorModeProp === EDITOR_MODE__EDIT || parentEditorModeProp === EDITOR_MODE__VIEW) {
|
|
189
|
+
return parentEditorModeProp;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return null;
|
|
178
193
|
},
|
|
179
194
|
getInheritedEditorMode = () => {
|
|
180
195
|
if (!inheritParentEditorMode) {
|
|
@@ -201,7 +216,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
201
216
|
if (!record || record.isDestroyed) {
|
|
202
217
|
return false;
|
|
203
218
|
}
|
|
204
|
-
return !!
|
|
219
|
+
return !!record.isPhantom;
|
|
205
220
|
},
|
|
206
221
|
getIsEditorDisabledByParent = () => {
|
|
207
222
|
return getIsParentSaveLocked();
|
|
@@ -665,8 +680,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
665
680
|
// just update this one entity
|
|
666
681
|
selection[0].setValues(data);
|
|
667
682
|
|
|
668
|
-
//
|
|
669
|
-
if (selection[0].
|
|
683
|
+
// In ADD mode, if record is phantom and nothing is dirty, stage it so save() still submits and solidifies.
|
|
684
|
+
if (getEditorMode() === EDITOR_MODE__ADD && selection[0].isPhantom && !selection[0].isDirty) {
|
|
670
685
|
selection[0].markStaged();
|
|
671
686
|
useStaged = true;
|
|
672
687
|
}
|
|
@@ -819,7 +834,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
819
834
|
if (canRecordBeEdited && canRecordBeEdited(selection) === false) {
|
|
820
835
|
return EDITOR_MODE__VIEW;
|
|
821
836
|
}
|
|
822
|
-
if (selection.length === 1 && !selection[0].isDestroyed &&
|
|
837
|
+
if (selection.length === 1 && !selection[0].isDestroyed && selection[0].isPhantom && !disableAdd) {
|
|
823
838
|
return EDITOR_MODE__ADD;
|
|
824
839
|
}
|
|
825
840
|
return selection.length ? EDITOR_MODE__EDIT : EDITOR_MODE__VIEW;
|
|
@@ -33,7 +33,9 @@ export default function withPdfButtons(WrappedComponent) {
|
|
|
33
33
|
additionalEditButtons = [],
|
|
34
34
|
additionalViewButtons = [],
|
|
35
35
|
items = [],
|
|
36
|
+
pdfItems,
|
|
36
37
|
ancillaryItems = [],
|
|
38
|
+
pdfAncillaryItems,
|
|
37
39
|
columnDefaults = {},
|
|
38
40
|
|
|
39
41
|
// withComponent
|
|
@@ -58,32 +60,15 @@ export default function withPdfButtons(WrappedComponent) {
|
|
|
58
60
|
styles = UiGlobals.styles,
|
|
59
61
|
propertyNames = [],
|
|
60
62
|
buildModalItems = () => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let {
|
|
70
|
-
additionalEditButtons,
|
|
71
|
-
items,
|
|
72
|
-
} = item;
|
|
73
|
-
if (!_.isEmpty(items)) {
|
|
74
|
-
_.each(items, (item) => {
|
|
75
|
-
walkTreeToDeleteAdditionalEditButtons(item);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
if (additionalEditButtons) {
|
|
79
|
-
delete item.additionalEditButtons;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
_.each(modalItems, walkTreeToDeleteAdditionalEditButtons);
|
|
63
|
+
// Build a cloned PDF item tree so we never mutate source items by reference.
|
|
64
|
+
const
|
|
65
|
+
itemsTouse = pdfItems || items,
|
|
66
|
+
ancillaryItemsToUse = pdfAncillaryItems || ancillaryItems,
|
|
67
|
+
modalItems = _.compact(_.map(itemsTouse, (item, ix) => buildNextLayer(item, ix, columnDefaults)));
|
|
83
68
|
|
|
84
|
-
if (!_.isEmpty(
|
|
69
|
+
if (!_.isEmpty(ancillaryItemsToUse)) {
|
|
85
70
|
const
|
|
86
|
-
ancillaryItemsClone = _.cloneDeepWith(
|
|
71
|
+
ancillaryItemsClone = _.cloneDeepWith(ancillaryItemsToUse, (value) => {
|
|
87
72
|
// Exclude the 'parent' property from being cloned, as it would introduce an infinitely recursive loop
|
|
88
73
|
if (value && value.parent) {
|
|
89
74
|
const { parent, ...rest } = value;
|
|
@@ -127,47 +112,75 @@ export default function withPdfButtons(WrappedComponent) {
|
|
|
127
112
|
return modalItems;
|
|
128
113
|
},
|
|
129
114
|
buildNextLayer = (item, ix, defaults) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
115
|
+
if (!item) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const {
|
|
120
|
+
type,
|
|
121
|
+
name,
|
|
122
|
+
title,
|
|
123
|
+
items: childItems,
|
|
124
|
+
isHiddenInViewMode,
|
|
125
|
+
} = item;
|
|
126
|
+
|
|
135
127
|
if (inArray(type, ['Column', 'FieldSet'])) {
|
|
136
|
-
|
|
137
|
-
|
|
128
|
+
const nextDefaults = {
|
|
129
|
+
...(defaults || {}),
|
|
130
|
+
...(item.defaults || {}),
|
|
131
|
+
labelWidth: '90%',
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const nextItem = {
|
|
135
|
+
type,
|
|
136
|
+
defaults: nextDefaults,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
if (title) {
|
|
140
|
+
nextItem.title = title;
|
|
141
|
+
}
|
|
142
|
+
if (item.reference) {
|
|
143
|
+
nextItem.reference = item.reference;
|
|
144
|
+
}
|
|
145
|
+
if (item.flex) {
|
|
146
|
+
nextItem.flex = item.flex;
|
|
138
147
|
}
|
|
139
148
|
if (type === 'FieldSet') {
|
|
140
|
-
|
|
141
|
-
|
|
149
|
+
nextItem.showToggleAllCheckbox = true;
|
|
150
|
+
nextItem.isCollapsible = false;
|
|
142
151
|
}
|
|
143
|
-
|
|
144
|
-
if (!_.isEmpty(
|
|
145
|
-
|
|
146
|
-
item.items = _.map(items, (item, ix) => {
|
|
147
|
-
if (!item){
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
return buildNextLayer(item, ix, defaults);
|
|
151
|
-
});
|
|
152
|
+
|
|
153
|
+
if (!_.isEmpty(childItems)) {
|
|
154
|
+
nextItem.items = _.compact(_.map(childItems, (childItem, childIx) => buildNextLayer(childItem, childIx, nextDefaults)));
|
|
152
155
|
}
|
|
153
|
-
|
|
156
|
+
|
|
157
|
+
return nextItem;
|
|
154
158
|
}
|
|
155
159
|
|
|
156
|
-
if (
|
|
160
|
+
if (isHiddenInViewMode || type === 'Button') {
|
|
157
161
|
return null;
|
|
158
162
|
}
|
|
159
163
|
|
|
160
|
-
|
|
164
|
+
let resolvedTitle = title;
|
|
165
|
+
if (!resolvedTitle) {
|
|
161
166
|
const propertyDef = name && Repository?.getSchema().getPropertyDefinition(name);
|
|
162
167
|
if (propertyDef?.title) {
|
|
163
|
-
|
|
168
|
+
resolvedTitle = propertyDef.title;
|
|
164
169
|
}
|
|
165
170
|
}
|
|
166
171
|
if (name) {
|
|
167
172
|
propertyNames.push(name); // for validator
|
|
168
173
|
}
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
if (!name) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
type: 'Checkbox',
|
|
180
|
+
name,
|
|
181
|
+
title: resolvedTitle,
|
|
182
|
+
isEditable: false, // hack to force all checkboxes to use same render branch in Form
|
|
183
|
+
};
|
|
171
184
|
},
|
|
172
185
|
buildValidator = () => {
|
|
173
186
|
const propertyValidatorDefs = {};
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
selectIsSetupMode,
|
|
4
4
|
toggleSetupMode,
|
|
5
5
|
} from '@src/Models/Slices/AppSlice';
|
|
6
|
+
import clsx from 'clsx';
|
|
6
7
|
import Button from '../Buttons/Button';
|
|
7
8
|
import IconButton from '../Buttons/IconButton';
|
|
8
9
|
import Gear from '../Icons/Gear';
|
|
@@ -13,19 +14,44 @@ export default function SetupButton(props) {
|
|
|
13
14
|
} = props,
|
|
14
15
|
dispatch = useDispatch(),
|
|
15
16
|
isSetupMode = useSelector(selectIsSetupMode),
|
|
16
|
-
onPress = () => dispatch(toggleSetupMode())
|
|
17
|
+
onPress = () => dispatch(toggleSetupMode()),
|
|
18
|
+
buttonClassName = clsx(
|
|
19
|
+
'SetupButton',
|
|
20
|
+
isSetupMode
|
|
21
|
+
? 'bg-red-500 data-[hover=true]:bg-red-600 data-[active=true]:bg-red-700'
|
|
22
|
+
: 'bg-grey-100 data-[hover=true]:bg-grey-900/20 data-[active=true]:bg-grey-900/50',
|
|
23
|
+
),
|
|
24
|
+
textClassName = clsx(
|
|
25
|
+
isSetupMode
|
|
26
|
+
? 'text-white data-[hover=true]:text-white data-[active=true]:text-white'
|
|
27
|
+
: 'text-black data-[hover=true]:text-black data-[active=true]:text-black',
|
|
28
|
+
),
|
|
29
|
+
iconClassName = clsx(
|
|
30
|
+
isSetupMode ? 'fill-white' : 'fill-black',
|
|
31
|
+
isSetupMode ? 'text-white' : 'text-black',
|
|
32
|
+
);
|
|
33
|
+
|
|
17
34
|
return isMinimized ?
|
|
18
35
|
<IconButton
|
|
19
36
|
icon={Gear}
|
|
37
|
+
_icon={{
|
|
38
|
+
className: iconClassName,
|
|
39
|
+
}}
|
|
20
40
|
onPress={onPress}
|
|
21
41
|
tooltip="Toggle Setup Mode"
|
|
22
|
-
className=
|
|
42
|
+
className={buttonClassName}
|
|
23
43
|
/> :
|
|
24
44
|
<Button
|
|
25
45
|
text={isSetupMode ? 'Exit Setup' : 'Setup'}
|
|
26
46
|
icon={Gear}
|
|
47
|
+
_text={{
|
|
48
|
+
className: textClassName,
|
|
49
|
+
}}
|
|
50
|
+
_icon={{
|
|
51
|
+
className: iconClassName,
|
|
52
|
+
}}
|
|
27
53
|
onPress={onPress}
|
|
28
54
|
tooltip="Toggle Setup Mode"
|
|
29
|
-
className=
|
|
55
|
+
className={buttonClassName}
|
|
30
56
|
/>;
|
|
31
57
|
};
|
|
@@ -126,6 +126,11 @@ export default function MetersEditor(props) {
|
|
|
126
126
|
isEditable: false,
|
|
127
127
|
isEditingEnabledInPlainEditor: true,
|
|
128
128
|
},
|
|
129
|
+
{
|
|
130
|
+
name: 'meters__latest_meter_reading_date',
|
|
131
|
+
isEditable: false,
|
|
132
|
+
isEditingEnabledInPlainEditor: true,
|
|
133
|
+
},
|
|
129
134
|
...(includeExtendedCalculatedFields ? [
|
|
130
135
|
{
|
|
131
136
|
name: 'meters__latest_inspection_date',
|
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
EDIT,
|
|
19
19
|
} from '../../Constants/Commands.js';
|
|
20
20
|
import {
|
|
21
|
+
EDITOR_MODE__ADD,
|
|
22
|
+
EDITOR_MODE__EDIT,
|
|
23
|
+
EDITOR_MODE__VIEW,
|
|
21
24
|
EDITOR_TYPE__SIDE,
|
|
22
25
|
EDITOR_TYPE__SMART,
|
|
23
26
|
} from '../../Constants/Editor.js';
|
|
@@ -48,6 +51,7 @@ function Viewer(props) {
|
|
|
48
51
|
const {
|
|
49
52
|
viewerCanDelete = false,
|
|
50
53
|
items = [], // Columns, FieldSets, Fields, etc to define the form
|
|
54
|
+
isItemsCustomLayout = false,
|
|
51
55
|
ancillaryItems = [], // additional items which are not controllable form elements, but should appear in the form
|
|
52
56
|
showAncillaryButtons = false,
|
|
53
57
|
columnDefaults = {}, // defaults for each Column defined in items (above)
|
|
@@ -69,6 +73,8 @@ function Viewer(props) {
|
|
|
69
73
|
|
|
70
74
|
// withEditor
|
|
71
75
|
editorType,
|
|
76
|
+
getEditorMode,
|
|
77
|
+
editorMode,
|
|
72
78
|
onEditMode,
|
|
73
79
|
onClose,
|
|
74
80
|
onDelete,
|
|
@@ -178,7 +184,7 @@ function Viewer(props) {
|
|
|
178
184
|
let children;
|
|
179
185
|
const style = {};
|
|
180
186
|
if (type === 'Column') {
|
|
181
|
-
const isEverythingInOneColumn = containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD;
|
|
187
|
+
const isEverythingInOneColumn = isItemsCustomLayout || containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD;
|
|
182
188
|
if (itemPropsToPass.hasOwnProperty('flex')) {
|
|
183
189
|
if (!isEverythingInOneColumn) {
|
|
184
190
|
style.flex = itemPropsToPass.flex;
|
|
@@ -353,6 +359,14 @@ function Viewer(props) {
|
|
|
353
359
|
buildAncillary = () => {
|
|
354
360
|
const
|
|
355
361
|
validAncillaryItems = _.filter(ancillaryItems, (item) => !!item), // filter out any null/undefined items
|
|
362
|
+
parentEditorModeRaw = (getEditorMode && getEditorMode()) || editorMode || null,
|
|
363
|
+
parentEditorMode = parentEditorModeRaw === EDITOR_MODE__ADD
|
|
364
|
+
? EDITOR_MODE__EDIT
|
|
365
|
+
: parentEditorModeRaw,
|
|
366
|
+
normalizedParentEditorMode =
|
|
367
|
+
parentEditorMode === EDITOR_MODE__EDIT || parentEditorMode === EDITOR_MODE__VIEW
|
|
368
|
+
? parentEditorMode
|
|
369
|
+
: null,
|
|
356
370
|
components = [];
|
|
357
371
|
setAncillaryButtons([]);
|
|
358
372
|
if (validAncillaryItems.length) {
|
|
@@ -396,6 +410,8 @@ function Viewer(props) {
|
|
|
396
410
|
}
|
|
397
411
|
|
|
398
412
|
const
|
|
413
|
+
ancillaryEditorMode = itemPropsToPass.editorMode ?? normalizedParentEditorMode,
|
|
414
|
+
ancillaryInitialEditorMode = itemPropsToPass.initialEditorMode ?? ancillaryEditorMode ?? undefined,
|
|
399
415
|
Element = getComponentFromType(type),
|
|
400
416
|
element = <Element
|
|
401
417
|
{...testProps('ancillary-' + type)}
|
|
@@ -407,6 +423,8 @@ function Viewer(props) {
|
|
|
407
423
|
uniqueRepository={true}
|
|
408
424
|
parent={self}
|
|
409
425
|
{...itemPropsToPass}
|
|
426
|
+
editorMode={ancillaryEditorMode}
|
|
427
|
+
initialEditorMode={ancillaryInitialEditorMode}
|
|
410
428
|
className={className}
|
|
411
429
|
canRowsReorder={false}
|
|
412
430
|
/>;
|
|
@@ -472,7 +490,9 @@ function Viewer(props) {
|
|
|
472
490
|
const
|
|
473
491
|
showDeleteBtn = onDelete && viewerCanDelete,
|
|
474
492
|
showCloseBtn = !isSideEditor && !isSmartEditor && onClose,
|
|
475
|
-
showFooter = (showDeleteBtn || showCloseBtn)
|
|
493
|
+
showFooter = (showDeleteBtn || showCloseBtn),
|
|
494
|
+
hasTopLevelColumns = _.some(items, (item) => item?.type === 'Column'),
|
|
495
|
+
shouldUseHorizontalViewerLayout = !isItemsCustomLayout && hasTopLevelColumns && containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD;
|
|
476
496
|
let additionalButtons = null,
|
|
477
497
|
viewerComponents = null,
|
|
478
498
|
ancillaryComponents = null,
|
|
@@ -594,8 +614,8 @@ function Viewer(props) {
|
|
|
594
614
|
{buildAdditionalButtons(_.omitBy(getAncillaryButtons(), (btnConfig) => btnConfig.reference === 'scrollToTop'))}
|
|
595
615
|
</Toolbar>}
|
|
596
616
|
|
|
597
|
-
{
|
|
598
|
-
{
|
|
617
|
+
{shouldUseHorizontalViewerLayout ? <HStack className="Viewer-formComponents-HStack p-4 gap-4 justify-center">{viewerComponents}</HStack> : null}
|
|
618
|
+
{!shouldUseHorizontalViewerLayout ? <VStack className="Viewer-formComponents-VStack p-4">{viewerComponents}</VStack> : null}
|
|
599
619
|
<VStack className="Viewer-AncillaryComponents m-2 pt-4 px-2">{ancillaryComponents}</VStack>
|
|
600
620
|
</ScrollView>
|
|
601
621
|
|