@onehat/ui 0.3.57 → 0.3.59
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 +328 -184
- package/src/Components/Form/Field/Tag/Tag.js +99 -64
- package/src/Components/Form/Field/Tag/ValueBox.js +45 -0
- package/src/Components/Form/FieldSet.js +5 -4
- package/src/Components/Form/Form.js +87 -28
- package/src/Components/Hoc/withAlert.js +6 -2
- package/src/Components/Hoc/withEditor.js +32 -4
- package/src/Components/Hoc/withFilters.js +3 -1
- package/src/Components/Hoc/withSelection.js +14 -14
- package/src/Components/Hoc/withValue.js +9 -1
- package/src/Components/Icons/Images.js +14 -0
- package/src/Components/Toolbar/Pagination.js +12 -0
- package/src/Components/Viewer/Viewer.js +1 -0
- package/src/Components/index.js +0 -2
- package/src/Functions/delay.js +3 -0
- package/src/Functions/isVideo.js +18 -0
- package/src/Components/Viewer/TagViewer.js +0 -30
|
@@ -35,6 +35,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
35
35
|
},
|
|
36
36
|
record,
|
|
37
37
|
onChange,
|
|
38
|
+
onSave,
|
|
39
|
+
newEntityDisplayValue,
|
|
38
40
|
|
|
39
41
|
// withComponent
|
|
40
42
|
self,
|
|
@@ -57,6 +59,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
57
59
|
} = props,
|
|
58
60
|
listeners = useRef({}),
|
|
59
61
|
editorStateRef = useRef(),
|
|
62
|
+
newEntityDisplayValueRef = useRef(),
|
|
60
63
|
[currentRecord, setCurrentRecord] = useState(null),
|
|
61
64
|
[isAdding, setIsAdding] = useState(false),
|
|
62
65
|
[isSaving, setIsSaving] = useState(false),
|
|
@@ -81,6 +84,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
81
84
|
listeners.current = obj;
|
|
82
85
|
// forceUpdate(); // we don't want to get into an infinite loop of renders. Simply directly assign the listeners in every child render
|
|
83
86
|
},
|
|
87
|
+
getNewEntityDisplayValue = () => {
|
|
88
|
+
return newEntityDisplayValueRef.current;
|
|
89
|
+
},
|
|
84
90
|
onAdd = async () => {
|
|
85
91
|
const defaultValues = Repository.getSchema().getDefaultValues();
|
|
86
92
|
let addValues = _.clone(defaultValues);
|
|
@@ -89,6 +95,11 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
89
95
|
addValues[selectorId] = selectorSelected.id;
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
if (getNewEntityDisplayValue()) {
|
|
99
|
+
const displayPropertyName = Repository.getSchema().model.displayProperty;
|
|
100
|
+
addValues[displayPropertyName] = getNewEntityDisplayValue();
|
|
101
|
+
}
|
|
102
|
+
|
|
92
103
|
if (getListeners().onBeforeAdd) {
|
|
93
104
|
const listenerResult = await getListeners().onBeforeAdd();
|
|
94
105
|
if (listenerResult === false) {
|
|
@@ -116,6 +127,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
116
127
|
// Unmap the values, so we can input true originalData
|
|
117
128
|
addValues = Repository.unmapData(addValues);
|
|
118
129
|
|
|
130
|
+
|
|
119
131
|
setIsAdding(true);
|
|
120
132
|
setIsSaving(true);
|
|
121
133
|
const entity = await Repository.add(addValues, false, true);
|
|
@@ -260,6 +272,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
260
272
|
entity = selection[0],
|
|
261
273
|
id = entity.id;
|
|
262
274
|
const result = await Repository._send('POST', Model + '/duplicate', { id });
|
|
275
|
+
if (!result) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
263
278
|
const {
|
|
264
279
|
root,
|
|
265
280
|
success,
|
|
@@ -273,15 +288,22 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
273
288
|
|
|
274
289
|
const duplicateId = root.id;
|
|
275
290
|
|
|
291
|
+
// TODO: I don't like this.
|
|
292
|
+
// Currently, we filter the repository by only the new Entity, then select the entity for editing.
|
|
293
|
+
// There is a 2-second delay between filtering and being able to select, and this is unacceptable.
|
|
294
|
+
// Why do we filter for just the new entity? Because it's not guaranteed to show up in the grid based on sorting.
|
|
295
|
+
// Can't we just manually add this record to the repository at the top and then edit it?
|
|
296
|
+
|
|
276
297
|
// Filter the grid with only the duplicate's ID, and open it for editing.
|
|
277
298
|
self.filterById(duplicateId, () => { // because of the way useFilters is made, we have to use a callback, not await a Promise.
|
|
278
299
|
|
|
279
300
|
// Select the only node
|
|
280
301
|
const duplicateEntity = Repository.getById(duplicateId);
|
|
281
|
-
|
|
302
|
+
setTimeout(() => {
|
|
303
|
+
setSelection([duplicateEntity]);
|
|
282
304
|
|
|
283
|
-
|
|
284
|
-
|
|
305
|
+
onEdit();
|
|
306
|
+
}, 2000); // we need this delay!
|
|
285
307
|
|
|
286
308
|
});
|
|
287
309
|
|
|
@@ -326,6 +348,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
326
348
|
if (onChange) {
|
|
327
349
|
onChange();
|
|
328
350
|
}
|
|
351
|
+
if (onSave) {
|
|
352
|
+
onSave(what);
|
|
353
|
+
}
|
|
329
354
|
|
|
330
355
|
return true;
|
|
331
356
|
},
|
|
@@ -339,7 +364,6 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
339
364
|
}
|
|
340
365
|
|
|
341
366
|
setIsAdding(false);
|
|
342
|
-
setEditorMode(EDITOR_MODE__VIEW);
|
|
343
367
|
setIsEditorShown(false);
|
|
344
368
|
}
|
|
345
369
|
const formState = editorStateRef.current;
|
|
@@ -350,6 +374,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
350
374
|
}
|
|
351
375
|
},
|
|
352
376
|
onEditorClose = () => {
|
|
377
|
+
if (isAdding) {
|
|
378
|
+
onEditorCancel();
|
|
379
|
+
}
|
|
353
380
|
setIsEditorShown(false);
|
|
354
381
|
},
|
|
355
382
|
onEditorDelete = async () => {
|
|
@@ -406,6 +433,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
406
433
|
self.deleteChildren = onDeleteChildren;
|
|
407
434
|
self.duplicate = onDuplicate;
|
|
408
435
|
}
|
|
436
|
+
newEntityDisplayValueRef.current = newEntityDisplayValue;
|
|
409
437
|
|
|
410
438
|
if (lastSelection !== selection) {
|
|
411
439
|
// NOTE: If I don't calculate this on the fly for selection changes,
|
|
@@ -536,7 +536,9 @@ export default function withFilters(WrappedComponent) {
|
|
|
536
536
|
},
|
|
537
537
|
]}
|
|
538
538
|
onCancel={(e) => {
|
|
539
|
-
|
|
539
|
+
setIsFilterSelectorShown(false);
|
|
540
|
+
}}
|
|
541
|
+
onClose={(e) => {
|
|
540
542
|
setIsFilterSelectorShown(false);
|
|
541
543
|
}}
|
|
542
544
|
onSave={(data, e) => {
|
|
@@ -228,6 +228,9 @@ export default function withSelection(WrappedComponent) {
|
|
|
228
228
|
conformSelectionToValue = async () => {
|
|
229
229
|
let newSelection = [];
|
|
230
230
|
if (Repository) {
|
|
231
|
+
if (Repository.isLoading) {
|
|
232
|
+
await Repository.waitUntilDoneLoading();
|
|
233
|
+
}
|
|
231
234
|
// Get entity or entities that match value
|
|
232
235
|
if ((_.isArray(value) && !_.isEmpty(value)) || !!value) {
|
|
233
236
|
if (_.isArray(value)) {
|
|
@@ -236,16 +239,16 @@ export default function withSelection(WrappedComponent) {
|
|
|
236
239
|
let found = Repository.getById(value);
|
|
237
240
|
if (found) {
|
|
238
241
|
newSelection.push(found);
|
|
239
|
-
} else if (Repository?.isRemote && Repository?.entities.length) {
|
|
242
|
+
// } else if (Repository?.isRemote && Repository?.entities.length) {
|
|
240
243
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
// // Value cannot be found in Repository, but actually exists on server
|
|
245
|
+
// // Try to get this value from the server directly
|
|
246
|
+
// Repository.filter(Repository.schema.model.idProperty, value);
|
|
247
|
+
// await Repository.load();
|
|
248
|
+
// found = Repository.getById(value);
|
|
249
|
+
// if (found) {
|
|
250
|
+
// newSelection.push(found);
|
|
251
|
+
// }
|
|
249
252
|
|
|
250
253
|
}
|
|
251
254
|
}
|
|
@@ -278,9 +281,6 @@ export default function withSelection(WrappedComponent) {
|
|
|
278
281
|
};
|
|
279
282
|
|
|
280
283
|
useEffect(() => {
|
|
281
|
-
if (isReady) {
|
|
282
|
-
return () => {};
|
|
283
|
-
}
|
|
284
284
|
|
|
285
285
|
(async () => {
|
|
286
286
|
|
|
@@ -291,7 +291,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
291
291
|
await Repository.load();
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
-
if (
|
|
294
|
+
if (!_.isNil(value)) {
|
|
295
295
|
|
|
296
296
|
await conformSelectionToValue();
|
|
297
297
|
|
|
@@ -314,7 +314,7 @@ export default function withSelection(WrappedComponent) {
|
|
|
314
314
|
|
|
315
315
|
})();
|
|
316
316
|
|
|
317
|
-
}, []);
|
|
317
|
+
}, [value]);
|
|
318
318
|
|
|
319
319
|
if (self) {
|
|
320
320
|
self.selection = localSelection;
|
|
@@ -28,6 +28,9 @@ export default function withValue(WrappedComponent) {
|
|
|
28
28
|
isValueAlwaysArray = false,
|
|
29
29
|
isValueAsStringifiedJson = false,
|
|
30
30
|
|
|
31
|
+
// withComponent
|
|
32
|
+
self,
|
|
33
|
+
|
|
31
34
|
// withData
|
|
32
35
|
Repository,
|
|
33
36
|
idIx,
|
|
@@ -109,7 +112,7 @@ export default function withValue(WrappedComponent) {
|
|
|
109
112
|
setLocalValue(value);
|
|
110
113
|
}
|
|
111
114
|
}, [value]);
|
|
112
|
-
|
|
115
|
+
|
|
113
116
|
if (fieldSetRegisterChild) {
|
|
114
117
|
useEffect(() => {
|
|
115
118
|
fieldSetRegisterChild({
|
|
@@ -120,6 +123,11 @@ export default function withValue(WrappedComponent) {
|
|
|
120
123
|
}, []);
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
if (self) {
|
|
127
|
+
self.setValue = setValue;
|
|
128
|
+
self.value = getLocalValue();
|
|
129
|
+
}
|
|
130
|
+
|
|
123
131
|
|
|
124
132
|
// Convert localValue to normal JS primitives for field components
|
|
125
133
|
let convertedValue = getLocalValue();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import Svg, { Path } from "react-native-svg"
|
|
4
|
+
import { Icon } from 'native-base';
|
|
5
|
+
|
|
6
|
+
function SvgComponent(props) {
|
|
7
|
+
return (
|
|
8
|
+
<Icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" {...props}>
|
|
9
|
+
<Path d="M512 32H160c-35.35 0-64 28.65-64 64v224c0 35.35 28.65 64 64 64h352c35.35 0 64-28.65 64-64V96c0-35.35-28.7-64-64-64zm16 288c0 8.822-7.178 16-16 16h-16L386.7 175.1c-3-4.4-8-7.1-13.4-7.1a15.978 15.978 0 00-13.31 7.125l-62.74 94.11L274.9 238.6c-3-4.2-7.8-6.6-12.9-6.6a16.007 16.007 0 00-12.93 6.574L176 336h-16c-8.822 0-16-7.178-16-16V96c0-8.822 7.178-16 16-16h352c8.822 0 16 7.178 16 16v224zM224 112c-17.67 0-32 14.33-32 32s14.33 32 32 32c17.68 0 32-14.33 32-32s-14.3-32-32-32zm232 368H120C53.83 480 0 426.2 0 360V120c0-13.2 10.75-24 24-24s24 10.8 24 24v240c0 39.7 32.3 72 72 72h336c13.25 0 24 10.75 24 24s-10.7 24-24 24z" />
|
|
10
|
+
</Icon>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default SvgComponent
|
|
@@ -69,6 +69,18 @@ export default function Pagination(props) {
|
|
|
69
69
|
isDisabled={isDisabled}
|
|
70
70
|
tooltip="Show More"
|
|
71
71
|
>Show More</Button>);
|
|
72
|
+
if (!Repository.isLocal) {
|
|
73
|
+
items.push(<IconButton
|
|
74
|
+
key="reload"
|
|
75
|
+
parent={self}
|
|
76
|
+
reference="reloadPageBtn"
|
|
77
|
+
{...iconButtonProps}
|
|
78
|
+
icon={<Icon as={Rotate} {...iconProps} color="trueGray.600" />}
|
|
79
|
+
onPress={() => Repository.reload()}
|
|
80
|
+
tooltip="Reload"
|
|
81
|
+
ml={2}
|
|
82
|
+
/>);
|
|
83
|
+
}
|
|
72
84
|
} else {
|
|
73
85
|
isDisabled = page === 1;
|
|
74
86
|
items.push(<IconButton
|
package/src/Components/index.js
CHANGED
|
@@ -41,7 +41,6 @@ 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
43
|
import Tag from './Form/Field/Tag/Tag.js';
|
|
44
|
-
import TagViewer from './Viewer/TagViewer.js';
|
|
45
44
|
import TextArea from './Form/Field/TextArea.js';
|
|
46
45
|
import Text from './Form/Field/Text.js';
|
|
47
46
|
import TimezonesCombo from './Form/Field/Combo/TimezonesCombo.js';
|
|
@@ -94,7 +93,6 @@ const components = {
|
|
|
94
93
|
SquareButton,
|
|
95
94
|
TabPanel,
|
|
96
95
|
Tag,
|
|
97
|
-
TagViewer,
|
|
98
96
|
Text,
|
|
99
97
|
TextArea,
|
|
100
98
|
TimezonesCombo,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default function isVideo(mimetype) {
|
|
2
|
+
switch(mimetype) {
|
|
3
|
+
case 'video/quicktime':
|
|
4
|
+
case 'video/mp4':
|
|
5
|
+
case 'video/mpeg':
|
|
6
|
+
case 'video/ogg':
|
|
7
|
+
case 'video/webm':
|
|
8
|
+
case 'video/mp2t':
|
|
9
|
+
case 'video/3gpp':
|
|
10
|
+
case 'video/3gpp2':
|
|
11
|
+
case 'video/x-msvideo':
|
|
12
|
+
case 'video/x-ms-wmv':
|
|
13
|
+
case 'video/x-flv':
|
|
14
|
+
case 'application/x-mpegURL':
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Text,
|
|
3
|
-
} from 'native-base';
|
|
4
|
-
import UiGlobals from '../../UiGlobals.js';
|
|
5
|
-
import withComponent from '../Hoc/withComponent.js';
|
|
6
|
-
import _ from 'lodash';
|
|
7
|
-
|
|
8
|
-
function TagViewer(props) {
|
|
9
|
-
const {
|
|
10
|
-
value,
|
|
11
|
-
} = props,
|
|
12
|
-
parsedValue = value ? JSON.parse(value) : null,
|
|
13
|
-
values = parsedValue ? _.map(parsedValue, (val) => {
|
|
14
|
-
const ret = val?.text;
|
|
15
|
-
return ret;
|
|
16
|
-
}).join(', ') : [],
|
|
17
|
-
styles = UiGlobals.styles;
|
|
18
|
-
|
|
19
|
-
return <Text
|
|
20
|
-
numberOfLines={1}
|
|
21
|
-
ellipsizeMode="head"
|
|
22
|
-
fontSize={styles.FORM_TEXT_FONTSIZE}
|
|
23
|
-
minHeight='40px'
|
|
24
|
-
px={3}
|
|
25
|
-
py={2}
|
|
26
|
-
{...props}
|
|
27
|
-
>{values}</Text>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default withComponent(TagViewer);
|