@onehat/ui 0.3.50 → 0.3.53
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/Form/Field/Combo/Combo.js +50 -31
- package/src/Components/Form/Field/Tag/Tag.js +128 -0
- package/src/Components/Form/Form.js +1 -1
- package/src/Components/Grid/Grid.js +18 -4
- package/src/Components/Grid/GridHeaderRow.js +3 -1
- package/src/Components/Hoc/withAlert.js +6 -0
- package/src/Components/Hoc/withData.js +6 -0
- package/src/Components/Hoc/withEditor.js +5 -0
- package/src/Components/Hoc/withPresetButtons.js +1 -0
- package/src/Components/Hoc/withSelection.js +5 -0
- package/src/Components/Hoc/withValue.js +12 -41
- package/src/Components/index.js +1 -1
- package/src/PlatformImports/Web/Attachments.js +57 -6
- package/src/Components/Form/Field/Combo/Tag.js +0 -23
package/package.json
CHANGED
|
@@ -51,6 +51,7 @@ export function ComboComponent(props) {
|
|
|
51
51
|
displayIx,
|
|
52
52
|
|
|
53
53
|
// withSelection
|
|
54
|
+
disableWithSelection,
|
|
54
55
|
selection,
|
|
55
56
|
setSelection,
|
|
56
57
|
selectionMode,
|
|
@@ -186,7 +187,9 @@ export function ComboComponent(props) {
|
|
|
186
187
|
|
|
187
188
|
// If user focused on the trigger and text is blank, clear the selection and close the menu
|
|
188
189
|
if ((triggerRef.current === relatedTarget || triggerRef.current.contains(relatedTarget)) && (_.isEmpty(textValue) || _.isNil(textValue))) {
|
|
189
|
-
|
|
190
|
+
if (!disableWithSelection) {
|
|
191
|
+
setSelection([]); // delete current selection
|
|
192
|
+
}
|
|
190
193
|
hideMenu();
|
|
191
194
|
return;
|
|
192
195
|
}
|
|
@@ -209,18 +212,28 @@ export function ComboComponent(props) {
|
|
|
209
212
|
hideMenu();
|
|
210
213
|
}
|
|
211
214
|
if (_.isEmpty(textValue) || _.isNil(textValue)) {
|
|
212
|
-
|
|
215
|
+
|
|
216
|
+
if (!disableWithSelection) {
|
|
217
|
+
setSelection([]); // delete current selection
|
|
218
|
+
}
|
|
213
219
|
|
|
214
220
|
} else if (getIsManuallyEnteringText()) {
|
|
215
221
|
if (forceSelection) {
|
|
216
|
-
|
|
222
|
+
if (!disableWithSelection) {
|
|
223
|
+
setSelection([]); // delete current selection
|
|
224
|
+
} else {
|
|
225
|
+
setValue(textValue);
|
|
226
|
+
}
|
|
217
227
|
hideMenu();
|
|
218
228
|
} else {
|
|
219
229
|
setValue(textValue);
|
|
220
230
|
}
|
|
221
231
|
}
|
|
222
|
-
|
|
223
|
-
|
|
232
|
+
|
|
233
|
+
if (!disableWithSelection) {
|
|
234
|
+
if (_.isEmpty(selection)) {
|
|
235
|
+
setTextValue('');
|
|
236
|
+
}
|
|
224
237
|
}
|
|
225
238
|
},
|
|
226
239
|
onInputClick = (e) => {
|
|
@@ -245,8 +258,10 @@ export function ComboComponent(props) {
|
|
|
245
258
|
relatedTarget
|
|
246
259
|
} = e;
|
|
247
260
|
|
|
248
|
-
if (
|
|
249
|
-
|
|
261
|
+
if (!disableWithSelection) {
|
|
262
|
+
if (_.isEmpty(textValue) || _.isNil(textValue)) {
|
|
263
|
+
setSelection([]); // delete current selection
|
|
264
|
+
}
|
|
250
265
|
}
|
|
251
266
|
|
|
252
267
|
if (!isMenuShown) {
|
|
@@ -301,13 +316,15 @@ export function ComboComponent(props) {
|
|
|
301
316
|
}
|
|
302
317
|
|
|
303
318
|
setSavedSearch(value);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
319
|
+
if (!disableWithSelection) {
|
|
320
|
+
const numResults = Repository.entities.length;
|
|
321
|
+
if (!numResults) {
|
|
322
|
+
setSelection([]);
|
|
323
|
+
} else if (numResults === 1) {
|
|
324
|
+
const selection = Repository.entities[0];
|
|
325
|
+
setSelection([selection]);
|
|
326
|
+
setSavedSearch(null);
|
|
327
|
+
}
|
|
311
328
|
}
|
|
312
329
|
|
|
313
330
|
} else {
|
|
@@ -324,19 +341,19 @@ export function ComboComponent(props) {
|
|
|
324
341
|
newTextValue = getDisplayValuesFromSelection(newSelection);
|
|
325
342
|
|
|
326
343
|
setTextValue(newTextValue);
|
|
327
|
-
|
|
344
|
+
if (!disableWithSelection) {
|
|
345
|
+
setSelection(newSelection);
|
|
346
|
+
}
|
|
328
347
|
} else {
|
|
329
348
|
if (value === '') { // Text field was cleared, so clear selection
|
|
330
|
-
|
|
349
|
+
if (!disableWithSelection) {
|
|
350
|
+
setSelection([]);
|
|
351
|
+
}
|
|
331
352
|
}
|
|
332
353
|
}
|
|
333
354
|
}
|
|
334
355
|
};
|
|
335
356
|
|
|
336
|
-
if (_.isUndefined(selection)) {
|
|
337
|
-
throw new Error('Combo must be used with withSelection hook!');
|
|
338
|
-
}
|
|
339
|
-
|
|
340
357
|
useEffect(() => {
|
|
341
358
|
// on render, focus the input
|
|
342
359
|
if (!isRendered) {
|
|
@@ -348,18 +365,20 @@ export function ComboComponent(props) {
|
|
|
348
365
|
|
|
349
366
|
}, [isRendered]);
|
|
350
367
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
368
|
+
if (!disableWithSelection) {
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
if (getIsManuallyEnteringText() && getSavedSearch()) {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
355
373
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
374
|
+
// Adjust text input to match selection
|
|
375
|
+
let localTextValue = getDisplayValuesFromSelection(selection);
|
|
376
|
+
if (!_.isEqual(localTextValue, textValue)) {
|
|
377
|
+
setTextValue(localTextValue);
|
|
378
|
+
}
|
|
379
|
+
setIsManuallyEnteringText(false);
|
|
380
|
+
}, [selection]);
|
|
381
|
+
}
|
|
363
382
|
|
|
364
383
|
|
|
365
384
|
const refProps = {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Column,
|
|
3
|
+
Pressable,
|
|
4
|
+
Row,
|
|
5
|
+
Text,
|
|
6
|
+
} from 'native-base';
|
|
7
|
+
import withComponent from '../../../Hoc/withComponent.js';
|
|
8
|
+
import withData from '../../../Hoc/withData.js';
|
|
9
|
+
import withValue from '../../../Hoc/withValue.js';
|
|
10
|
+
import IconButton from '../../../Buttons/IconButton.js';
|
|
11
|
+
import Xmark from '../../../Icons/Xmark.js';
|
|
12
|
+
import Combo, { ComboEditor } from '../Combo/Combo.js';
|
|
13
|
+
import _ from 'lodash';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function ValueBox(props) {
|
|
17
|
+
const {
|
|
18
|
+
text,
|
|
19
|
+
onDelete,
|
|
20
|
+
} = props;
|
|
21
|
+
|
|
22
|
+
return <Row
|
|
23
|
+
borderWidth={1}
|
|
24
|
+
borderColor="trueGray.400"
|
|
25
|
+
borderRadius="md"
|
|
26
|
+
pl={2}
|
|
27
|
+
mr={1}
|
|
28
|
+
bg="trueGray.200"
|
|
29
|
+
alignItems="center"
|
|
30
|
+
>
|
|
31
|
+
<Text color="trueGray.600">{text}</Text>
|
|
32
|
+
<IconButton
|
|
33
|
+
_icon={{
|
|
34
|
+
as: Xmark,
|
|
35
|
+
color: 'trueGray.600',
|
|
36
|
+
size: 'sm',
|
|
37
|
+
}}
|
|
38
|
+
onPress={onDelete}
|
|
39
|
+
h="100%"
|
|
40
|
+
/>
|
|
41
|
+
</Row>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function TagComponent(props) {
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
// withValue
|
|
48
|
+
value = [],
|
|
49
|
+
setValue,
|
|
50
|
+
} = props,
|
|
51
|
+
onAdd = (item, e) => {
|
|
52
|
+
// make sure value doesn't already exist
|
|
53
|
+
let exists = false;
|
|
54
|
+
_.each(value, (val) => {
|
|
55
|
+
if (val.id === item.getId()) {
|
|
56
|
+
exists = true;
|
|
57
|
+
return false; // break
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!exists) {
|
|
62
|
+
// add new value
|
|
63
|
+
const newValue = _.clone(value); // so we trigger a re-render
|
|
64
|
+
newValue.push({
|
|
65
|
+
id: item.getId(),
|
|
66
|
+
text: item.getDisplayValue(),
|
|
67
|
+
})
|
|
68
|
+
setValue(newValue);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
onDelete = (val) => {
|
|
72
|
+
// Remove from value array
|
|
73
|
+
const newValue = _.filter(value, (val1) => {
|
|
74
|
+
return val1.id !== val.id;
|
|
75
|
+
});
|
|
76
|
+
setValue(newValue);
|
|
77
|
+
},
|
|
78
|
+
valueBoxes = _.map(value, (val, ix) => {
|
|
79
|
+
return <ValueBox key={ix} text={val.text} onDelete={() => onDelete(val)} />;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return <Column w="100%" flex={1}>
|
|
83
|
+
{!_.isEmpty(valueBoxes) &&
|
|
84
|
+
<Row
|
|
85
|
+
w="100%"
|
|
86
|
+
borderWidth={1}
|
|
87
|
+
borderColor="trueGray.300"
|
|
88
|
+
borderRadius="md"
|
|
89
|
+
bg="trueGray.100"
|
|
90
|
+
p={1}
|
|
91
|
+
mb={1}
|
|
92
|
+
flexWrap="wrap"
|
|
93
|
+
>{valueBoxes}</Row>}
|
|
94
|
+
<Combo
|
|
95
|
+
{...props}
|
|
96
|
+
disableWithValue={true}
|
|
97
|
+
disableWithSelection={true}
|
|
98
|
+
disableWithEditor={true}
|
|
99
|
+
onRowPress={onAdd}
|
|
100
|
+
/>
|
|
101
|
+
</Column>;
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function withAdditionalProps(WrappedComponent) {
|
|
106
|
+
return (props) => {
|
|
107
|
+
return <WrappedComponent
|
|
108
|
+
isValueAlwaysArray={true}
|
|
109
|
+
isValueAsStringifiedJson={true}
|
|
110
|
+
{...props}
|
|
111
|
+
/>;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const Tag = withAdditionalProps(
|
|
116
|
+
withComponent(
|
|
117
|
+
withData(
|
|
118
|
+
withValue(
|
|
119
|
+
TagComponent
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
export const TagEditor = Tag;
|
|
126
|
+
// export const TagEditor = withAdditionalProps(ComboEditor);
|
|
127
|
+
|
|
128
|
+
export default Tag;
|
|
@@ -482,7 +482,7 @@ function Form(props) {
|
|
|
482
482
|
labelProps.w = defaults.labelWidth;
|
|
483
483
|
}
|
|
484
484
|
let requiredIndicator = null;
|
|
485
|
-
if (propertyDef
|
|
485
|
+
if (propertyDef?.validator?.spec && !propertyDef.validator.spec.optional) {
|
|
486
486
|
requiredIndicator = <Text color="#f00" pr={1}>*</Text>;
|
|
487
487
|
}
|
|
488
488
|
element = <Row w="100%" py={1}>
|
|
@@ -72,6 +72,7 @@ function GridComponent(props) {
|
|
|
72
72
|
};
|
|
73
73
|
},
|
|
74
74
|
flatListProps = {},
|
|
75
|
+
onRowPress,
|
|
75
76
|
// enableEditors = false,
|
|
76
77
|
loadOnRender = true,
|
|
77
78
|
pullToRefresh = true,
|
|
@@ -124,6 +125,7 @@ function GridComponent(props) {
|
|
|
124
125
|
onChangeColumnsConfig,
|
|
125
126
|
|
|
126
127
|
// withSelection
|
|
128
|
+
disableWithSelection,
|
|
127
129
|
selection,
|
|
128
130
|
setSelection,
|
|
129
131
|
selectionMode,
|
|
@@ -167,6 +169,12 @@ function GridComponent(props) {
|
|
|
167
169
|
if (isInlineEditorShown) {
|
|
168
170
|
return;
|
|
169
171
|
}
|
|
172
|
+
if (onRowPress) {
|
|
173
|
+
onRowPress(item, e);
|
|
174
|
+
}
|
|
175
|
+
if (disableWithSelection) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
170
178
|
const
|
|
171
179
|
{
|
|
172
180
|
shiftKey,
|
|
@@ -258,7 +266,7 @@ function GridComponent(props) {
|
|
|
258
266
|
} = row,
|
|
259
267
|
isHeaderRow = row.item.id === 'headerRow',
|
|
260
268
|
rowProps = getRowProps && !isHeaderRow ? getRowProps(item) : {},
|
|
261
|
-
isSelected = !isHeaderRow && isInSelection(item);
|
|
269
|
+
isSelected = !isHeaderRow && !disableWithSelection && isInSelection(item);
|
|
262
270
|
|
|
263
271
|
return <Pressable
|
|
264
272
|
// {...testProps(Repository ? Repository.schema.name + '-' + item.id : item.id)}
|
|
@@ -299,7 +307,9 @@ function GridComponent(props) {
|
|
|
299
307
|
|
|
300
308
|
// context menu
|
|
301
309
|
const selection = [item];
|
|
302
|
-
|
|
310
|
+
if (!disableWithSelection) {
|
|
311
|
+
setSelection(selection);
|
|
312
|
+
}
|
|
303
313
|
if (onEditorRowClick) { // e.g. inline editor
|
|
304
314
|
onEditorRowClick(item, index, e);
|
|
305
315
|
}
|
|
@@ -762,7 +772,9 @@ function GridComponent(props) {
|
|
|
762
772
|
|
|
763
773
|
Repository.on('beforeLoad', setTrue);
|
|
764
774
|
Repository.on('load', setFalse);
|
|
765
|
-
|
|
775
|
+
if (!disableWithSelection) {
|
|
776
|
+
Repository.ons(['changePage', 'changePageSize',], deselectAll);
|
|
777
|
+
}
|
|
766
778
|
Repository.ons(['changeData', 'change'], forceUpdate);
|
|
767
779
|
Repository.on('changeFilters', onChangeFilters);
|
|
768
780
|
Repository.on('changeSorters', onChangeSorters);
|
|
@@ -771,7 +783,9 @@ function GridComponent(props) {
|
|
|
771
783
|
return () => {
|
|
772
784
|
Repository.off('beforeLoad', setTrue);
|
|
773
785
|
Repository.off('load', setFalse);
|
|
774
|
-
|
|
786
|
+
if (!disableWithSelection) {
|
|
787
|
+
Repository.offs(['changePage', 'changePageSize',], deselectAll);
|
|
788
|
+
}
|
|
775
789
|
Repository.offs(['changeData', 'change'], forceUpdate);
|
|
776
790
|
Repository.off('changeFilters', onChangeFilters);
|
|
777
791
|
Repository.off('changeSorters', onChangeSorters);
|
|
@@ -71,7 +71,9 @@ export default function GridHeaderRow(props) {
|
|
|
71
71
|
Repository.sort(currentSortField, isCurrentSortDirectionAsc ? SORT_ASCENDING : SORT_DESCENDING, sortFn);
|
|
72
72
|
|
|
73
73
|
// clear the selection
|
|
74
|
-
setSelection
|
|
74
|
+
if (setSelection) {
|
|
75
|
+
setSelection([]);
|
|
76
|
+
}
|
|
75
77
|
},
|
|
76
78
|
onHeaderMouseEnter = (e, ix) => {
|
|
77
79
|
if (isDragging) {
|
|
@@ -20,6 +20,11 @@ import _ from 'lodash';
|
|
|
20
20
|
|
|
21
21
|
export default function withAlert(WrappedComponent) {
|
|
22
22
|
return (props) => {
|
|
23
|
+
|
|
24
|
+
if (props.disableWithAlert) {
|
|
25
|
+
return <WrappedComponent {...props} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
const
|
|
24
29
|
[isAlertShown, setIsAlertShown] = useState(false),
|
|
25
30
|
[title, setTitle] = useState(''),
|
|
@@ -146,6 +151,7 @@ export default function withAlert(WrappedComponent) {
|
|
|
146
151
|
return <>
|
|
147
152
|
<WrappedComponent
|
|
148
153
|
{...props}
|
|
154
|
+
disableWithAlert={false}
|
|
149
155
|
alert={onAlert}
|
|
150
156
|
confirm={onConfirm}
|
|
151
157
|
hideAlert={hideAlert}
|
|
@@ -11,6 +11,11 @@ import _ from 'lodash';
|
|
|
11
11
|
|
|
12
12
|
export default function withData(WrappedComponent) {
|
|
13
13
|
return (props) => {
|
|
14
|
+
|
|
15
|
+
if (props.disableWithData) {
|
|
16
|
+
return <WrappedComponent {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
const
|
|
15
20
|
{
|
|
16
21
|
// For @onehat/data repositories
|
|
@@ -102,6 +107,7 @@ export default function withData(WrappedComponent) {
|
|
|
102
107
|
|
|
103
108
|
return <WrappedComponent
|
|
104
109
|
{...propsToPass}
|
|
110
|
+
disableWithData={false}
|
|
105
111
|
Repository={LocalRepository}
|
|
106
112
|
model={model}
|
|
107
113
|
data={data}
|
|
@@ -12,6 +12,10 @@ import _ from 'lodash';
|
|
|
12
12
|
export default function withEditor(WrappedComponent, isTree = false) {
|
|
13
13
|
return (props) => {
|
|
14
14
|
|
|
15
|
+
if (props.disableWithEditor) {
|
|
16
|
+
return <WrappedComponent {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
let [editorMode, setEditorMode] = useState(EDITOR_MODE__VIEW); // Can change below, so use 'let'
|
|
16
20
|
const {
|
|
17
21
|
userCanEdit = true,
|
|
@@ -411,6 +415,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
411
415
|
|
|
412
416
|
return <WrappedComponent
|
|
413
417
|
{...props}
|
|
418
|
+
disableWithEditor={false}
|
|
414
419
|
currentRecord={currentRecord}
|
|
415
420
|
setCurrentRecord={setCurrentRecord}
|
|
416
421
|
isEditorShown={isEditorShown}
|
|
@@ -308,6 +308,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
308
308
|
|
|
309
309
|
return <WrappedComponent
|
|
310
310
|
{...propsToPass}
|
|
311
|
+
disablePresetButtons={false}
|
|
311
312
|
contextMenuItems={contextMenuItemsToPass}
|
|
312
313
|
additionalToolbarButtons={additionalToolbarButtonsToPass}
|
|
313
314
|
onChangeColumnsConfig={onChangeColumnsConfigDecorator}
|
|
@@ -11,6 +11,10 @@ import _ from 'lodash';
|
|
|
11
11
|
export default function withSelection(WrappedComponent) {
|
|
12
12
|
return (props) => {
|
|
13
13
|
|
|
14
|
+
if (props.disableWithSelection) {
|
|
15
|
+
return <WrappedComponent {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
if (props.setSelection) {
|
|
15
19
|
// bypass everything, since we're already using withSelection() in hierarchy.
|
|
16
20
|
// For example, Combo has withSelection(), and intenally it uses Grid which also has withSelection(),
|
|
@@ -352,6 +356,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
352
356
|
|
|
353
357
|
return <WrappedComponent
|
|
354
358
|
{...props}
|
|
359
|
+
disableWithSelection={false}
|
|
355
360
|
selection={localSelection}
|
|
356
361
|
setSelection={setSelection}
|
|
357
362
|
selectionMode={selectionMode}
|
|
@@ -9,6 +9,10 @@ import _ from 'lodash';
|
|
|
9
9
|
export default function withValue(WrappedComponent) {
|
|
10
10
|
return (props) => {
|
|
11
11
|
|
|
12
|
+
if (props.disableWithValue) {
|
|
13
|
+
return <WrappedComponent {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
if (props.setValue) {
|
|
13
17
|
// bypass everything, since we're already using withValue() in hierarchy.
|
|
14
18
|
// For example, Combo has withValue(), and intenally it uses Input which also has withValue(),
|
|
@@ -21,9 +25,8 @@ export default function withValue(WrappedComponent) {
|
|
|
21
25
|
onChangeValue,
|
|
22
26
|
value,
|
|
23
27
|
startingValue = null,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
valueAsStringifiedJson = false,
|
|
28
|
+
isValueAlwaysArray = false,
|
|
29
|
+
isValueAsStringifiedJson = false,
|
|
27
30
|
|
|
28
31
|
// withData
|
|
29
32
|
Repository,
|
|
@@ -46,36 +49,14 @@ export default function withValue(WrappedComponent) {
|
|
|
46
49
|
},
|
|
47
50
|
setValueRef = useRef((newValue) => {
|
|
48
51
|
// NOTE: We useRef so that this function stays current after renders
|
|
49
|
-
if (
|
|
52
|
+
if (isValueAlwaysArray && !_.isArray(newValue)) {
|
|
50
53
|
newValue = _.isNil(newValue) ? [] : [newValue];
|
|
51
54
|
}
|
|
52
55
|
if (_.isArray(newValue)) {
|
|
53
56
|
// TODO: sort by the sortProperty, whatever that is, instead of just value
|
|
54
57
|
newValue.sort(natsort()); // Only sort if we're using id/text arrangement. Otherwise, keep sort order as specified in Repository.
|
|
55
58
|
}
|
|
56
|
-
if (
|
|
57
|
-
if (_.isArray(newValue)) {
|
|
58
|
-
newValue = _.map(newValue, (id) => {
|
|
59
|
-
if (_.isNil(id)) {
|
|
60
|
-
return id;
|
|
61
|
-
}
|
|
62
|
-
const record = Repository.getById(id);
|
|
63
|
-
return {
|
|
64
|
-
id: record.getId(),
|
|
65
|
-
text: record.getDisplayValue(),
|
|
66
|
-
};
|
|
67
|
-
})
|
|
68
|
-
} else {
|
|
69
|
-
if (!_.isNil(id)) {
|
|
70
|
-
const record = Repository.getById(newValue);
|
|
71
|
-
newValue = {
|
|
72
|
-
id: record.getId(),
|
|
73
|
-
text: record.getDisplayValue(),
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (valueAsStringifiedJson) {
|
|
59
|
+
if (isValueAsStringifiedJson) {
|
|
79
60
|
newValue = JSON.stringify(newValue);
|
|
80
61
|
}
|
|
81
62
|
|
|
@@ -142,28 +123,18 @@ export default function withValue(WrappedComponent) {
|
|
|
142
123
|
|
|
143
124
|
// Convert localValue to normal JS primitives for field components
|
|
144
125
|
let convertedValue = getLocalValue();
|
|
145
|
-
if (_.isString(convertedValue) &&
|
|
126
|
+
if (_.isString(convertedValue) && isValueAsStringifiedJson && !_.isNil(convertedValue)) {
|
|
146
127
|
convertedValue = JSON.parse(convertedValue);
|
|
147
128
|
}
|
|
148
|
-
if (
|
|
129
|
+
if (isValueAlwaysArray) {
|
|
149
130
|
if (_.isEmpty(convertedValue) || _.isNil(convertedValue)) {
|
|
150
|
-
convertedValue =
|
|
151
|
-
} else if (convertedValue.length === 1) {
|
|
152
|
-
convertedValue = convertedValue[0];
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (valueAsIdAndText && !_.isNil(convertedValue)) {
|
|
156
|
-
if (_.isArray(convertedValue)) {
|
|
157
|
-
convertedValue = _.map(convertedValue, (value) => {
|
|
158
|
-
return value?.id;
|
|
159
|
-
});
|
|
160
|
-
} else {
|
|
161
|
-
convertedValue = convertedValue?.id;
|
|
131
|
+
convertedValue = [];
|
|
162
132
|
}
|
|
163
133
|
}
|
|
164
134
|
|
|
165
135
|
return <WrappedComponent
|
|
166
136
|
{...props}
|
|
137
|
+
disableWithValue={false}
|
|
167
138
|
value={convertedValue}
|
|
168
139
|
setValue={setValue}
|
|
169
140
|
onChangeSelection={onChangeSelection}
|
package/src/Components/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import PlusMinusButton from './Buttons/PlusMinusButton.js';
|
|
|
40
40
|
import RadioGroup from './Form/Field/RadioGroup/RadioGroup.js';
|
|
41
41
|
import SquareButton from './Buttons/SquareButton.js';
|
|
42
42
|
import TabPanel from './Panel/TabPanel.js';
|
|
43
|
-
import Tag from './Form/Field/
|
|
43
|
+
import Tag from './Form/Field/Tag/Tag.js';
|
|
44
44
|
import TagViewer from './Viewer/TagViewer.js';
|
|
45
45
|
import TextArea from './Form/Field/TextArea.js';
|
|
46
46
|
import Text from './Form/Field/Text.js';
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
Box,
|
|
4
4
|
Button,
|
|
5
5
|
Column,
|
|
6
|
+
Pressable,
|
|
6
7
|
Row,
|
|
8
|
+
Text,
|
|
7
9
|
} from 'native-base';
|
|
8
10
|
import {
|
|
9
11
|
CURRENT_MODE,
|
|
@@ -16,6 +18,8 @@ import {
|
|
|
16
18
|
FILE_MODE_FILE,
|
|
17
19
|
} from '../../Constants/File.js';
|
|
18
20
|
import { Avatar, Dropzone, FileMosaic, FileCard, FileInputButton, } from "@files-ui/react";
|
|
21
|
+
import IconButton from '@onehat/ui/src/Components/Buttons/IconButton.js';
|
|
22
|
+
import Xmark from '@onehat/ui/src/Components/Icons/Xmark.js'
|
|
19
23
|
import withAlert from '../../Components/Hoc/withAlert.js';
|
|
20
24
|
import withData from '../../Components/Hoc/withData.js';
|
|
21
25
|
import _ from 'lodash';
|
|
@@ -24,6 +28,46 @@ const
|
|
|
24
28
|
EXPANDED_MAX = 100,
|
|
25
29
|
COLLAPSED_MAX = 2;
|
|
26
30
|
|
|
31
|
+
const downloadWithFetch = (url, options = {}) => {
|
|
32
|
+
fetch(url, options)
|
|
33
|
+
.then( res => res.blob() )
|
|
34
|
+
.then( blob => {
|
|
35
|
+
const
|
|
36
|
+
winName = 'ReportWindow',
|
|
37
|
+
opts = 'resizable=yes,height=600,width=800,location=0,menubar=0,scrollbars=1',
|
|
38
|
+
externalWindow = window.open('', winName, opts),
|
|
39
|
+
file = externalWindow.URL.createObjectURL(blob);
|
|
40
|
+
externalWindow.location.assign(file);
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function FileCardCustom(props) {
|
|
45
|
+
const
|
|
46
|
+
{
|
|
47
|
+
id,
|
|
48
|
+
name: filename,
|
|
49
|
+
type: mimetype,
|
|
50
|
+
onDelete,
|
|
51
|
+
downloadUrl,
|
|
52
|
+
} = props;
|
|
53
|
+
return <Pressable
|
|
54
|
+
px={3}
|
|
55
|
+
py={1}
|
|
56
|
+
alignItems="center"
|
|
57
|
+
flexDirection="row"
|
|
58
|
+
borderRadius={5}
|
|
59
|
+
borderWidth={1}
|
|
60
|
+
borderColor="primary.700"
|
|
61
|
+
onPress={() => {
|
|
62
|
+
downloadWithFetch(downloadUrl);
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<Text>{filename}</Text>
|
|
66
|
+
<IconButton icon={Xmark} onPress={() => onDelete(id)} />
|
|
67
|
+
</Pressable>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
27
71
|
// Note this component uploads only one file per server request---
|
|
28
72
|
// it doesn't upload multiple files simultaneously.
|
|
29
73
|
|
|
@@ -37,6 +81,7 @@ function AttachmentsElement(props) {
|
|
|
37
81
|
canCrud = true,
|
|
38
82
|
_dropZone = {},
|
|
39
83
|
_fileMosaic = {},
|
|
84
|
+
useFileMosaic = true,
|
|
40
85
|
accept, // 'image/*'
|
|
41
86
|
maxFiles = null,
|
|
42
87
|
disabled = false,
|
|
@@ -200,7 +245,6 @@ function AttachmentsElement(props) {
|
|
|
200
245
|
}
|
|
201
246
|
let content = <Column
|
|
202
247
|
w="100%"
|
|
203
|
-
// minHeight={50}
|
|
204
248
|
p={2}
|
|
205
249
|
background={styles.ATTACHMENTS_BG}
|
|
206
250
|
>
|
|
@@ -210,11 +254,18 @@ function AttachmentsElement(props) {
|
|
|
210
254
|
key={file.id}
|
|
211
255
|
marginRight={4}
|
|
212
256
|
>
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
257
|
+
{useFileMosaic &&
|
|
258
|
+
<FileMosaic
|
|
259
|
+
{...file}
|
|
260
|
+
backgroundBlurImage={false}
|
|
261
|
+
{..._fileMosaic}
|
|
262
|
+
/>}
|
|
263
|
+
{!useFileMosaic &&
|
|
264
|
+
<FileCardCustom
|
|
265
|
+
{...file}
|
|
266
|
+
backgroundBlurImage={false}
|
|
267
|
+
{..._fileMosaic}
|
|
268
|
+
/>}
|
|
218
269
|
</Box>;
|
|
219
270
|
})}
|
|
220
271
|
</Row>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SELECTION_MODE_MULTI,
|
|
3
|
-
} from '../../../../Constants/Selection.js';
|
|
4
|
-
import Combo, { ComboEditor } from './Combo.js';
|
|
5
|
-
|
|
6
|
-
function withAdditionalProps(WrappedComponent) {
|
|
7
|
-
return (props) => {
|
|
8
|
-
return <WrappedComponent
|
|
9
|
-
selectionMode={SELECTION_MODE_MULTI}
|
|
10
|
-
valueIsAlwaysArray={true}
|
|
11
|
-
valueAsIdAndText={true}
|
|
12
|
-
valueAsStringifiedJson={true}
|
|
13
|
-
disableDirectEntry={true}
|
|
14
|
-
pageSize={500}
|
|
15
|
-
{...props}
|
|
16
|
-
/>;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const Tag = withAdditionalProps(Combo);
|
|
21
|
-
export const TagEditor = withAdditionalProps(ComboEditor);
|
|
22
|
-
|
|
23
|
-
export default Tag;
|