@onehat/ui 0.4.41 → 0.4.42
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/Buttons/ReloadButton.js +0 -1
- package/src/Components/Form/Field/Checkbox/CheckboxGroup.js +11 -9
- package/src/Components/Form/Field/Combo/Combo.js +91 -63
- package/src/Components/Form/Field/Number.js +1 -0
- package/src/Components/Form/Field/RadioGroup/RadioGroup.js +11 -9
- package/src/Components/Form/Field/Select/PageSizeSelect.js +1 -1
- package/src/Components/Form/Field/Tag/Tag.js +12 -10
- package/src/Components/Form/Form.js +3 -3
- package/src/Components/Grid/Grid.js +15 -19
- package/src/Components/Grid/GridRow.js +11 -12
- package/src/Components/Hoc/withEditor.js +60 -21
- package/src/Components/Hoc/withFilters.js +1 -1
- package/src/Components/Hoc/withPdfButtons.js +3 -0
- package/src/Components/Hoc/withSelection.js +40 -27
- package/src/Components/Toolbar/Pagination.js +56 -57
- package/src/Components/Toolbar/PaginationToolbar.js +18 -15
- package/src/Components/Toolbar/Toolbar.js +4 -7
- package/src/Components/Tree/Tree.js +14 -10
- package/src/Constants/Styles.js +2 -0
package/package.json
CHANGED
|
@@ -28,15 +28,17 @@ const
|
|
|
28
28
|
const checkboxProps = {
|
|
29
29
|
};
|
|
30
30
|
if (Repository) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
if (!Repository.isDestroyed) {
|
|
32
|
+
const entities = Repository.getEntitiesOnPage();
|
|
33
|
+
checkboxes = _.map(entities, (entity, ix) => {
|
|
34
|
+
return <Checkbox
|
|
35
|
+
{...testProps('checkbox-' + entity.id)}
|
|
36
|
+
key={ix}
|
|
37
|
+
value={entity.id}
|
|
38
|
+
{...checkboxProps}
|
|
39
|
+
>{entity.displayValue}</Checkbox>;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
40
42
|
} else {
|
|
41
43
|
checkboxes = _.map(data, (datum, ix) => {
|
|
42
44
|
return <Checkbox
|
|
@@ -36,6 +36,21 @@ import _ from 'lodash';
|
|
|
36
36
|
|
|
37
37
|
const FILTER_NAME = 'q';
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* isEmptyValue
|
|
41
|
+
* _.isEmpty returns true for all integers, so we need this instead
|
|
42
|
+
* @param {*} value
|
|
43
|
+
* @returns boolean
|
|
44
|
+
*/
|
|
45
|
+
function isEmptyValue(value) {
|
|
46
|
+
//
|
|
47
|
+
return value === null ||
|
|
48
|
+
value === undefined ||
|
|
49
|
+
value === '' ||
|
|
50
|
+
value === 0 ||
|
|
51
|
+
(_.isObject(value) && _.isEmpty(value));
|
|
52
|
+
};
|
|
53
|
+
|
|
39
54
|
export const ComboComponent = forwardRef((props, ref) => {
|
|
40
55
|
|
|
41
56
|
const {
|
|
@@ -170,19 +185,20 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
170
185
|
} else if (_.isArray(value)) {
|
|
171
186
|
displayValue = [];
|
|
172
187
|
if (Repository) {
|
|
173
|
-
if (!Repository.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
if (Repository.isLoading) {
|
|
178
|
-
await Repository.waitUntilDoneLoading();
|
|
179
|
-
}
|
|
180
|
-
displayValue = _.each(value, (id) => {
|
|
181
|
-
const entity = Repository.getById(id);
|
|
182
|
-
if (entity) {
|
|
183
|
-
displayValue.push(entity.displayValue);
|
|
188
|
+
if (!Repository.isDestroyed) {
|
|
189
|
+
if (!Repository.isLoaded) {
|
|
190
|
+
throw Error('Not yet implemented'); // Would a Combo ever have multiple remote selections? Shouldn't that be a Tag field??
|
|
184
191
|
}
|
|
185
|
-
|
|
192
|
+
if (Repository.isLoading) {
|
|
193
|
+
await Repository.waitUntilDoneLoading();
|
|
194
|
+
}
|
|
195
|
+
displayValue = _.each(value, (id) => {
|
|
196
|
+
const entity = Repository.getById(id);
|
|
197
|
+
if (entity) {
|
|
198
|
+
displayValue.push(entity.displayValue);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
186
202
|
} else {
|
|
187
203
|
displayValue = _.each(value, (id) => {
|
|
188
204
|
const item = _.find(data, (datum) => datum[idIx] === id);
|
|
@@ -194,25 +210,33 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
194
210
|
displayValue = displayValue.join(', ');
|
|
195
211
|
} else {
|
|
196
212
|
if (Repository) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
if (!Repository.isDestroyed) {
|
|
214
|
+
let entity;
|
|
215
|
+
if (!isEmptyValue(value)) {
|
|
216
|
+
if (!Repository.isLoaded) {
|
|
217
|
+
entity = await Repository.getSingleEntityFromServer(value);
|
|
218
|
+
} else {
|
|
219
|
+
if (Repository.isLoading) {
|
|
220
|
+
await Repository.waitUntilDoneLoading();
|
|
221
|
+
}
|
|
222
|
+
entity = Repository.getById(value);
|
|
223
|
+
if (!entity) {
|
|
224
|
+
entity = await Repository.getSingleEntityFromServer(value);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
207
227
|
}
|
|
228
|
+
displayValue = entity?.displayValue || '';
|
|
208
229
|
}
|
|
209
|
-
displayValue = entity?.displayValue || '';
|
|
210
230
|
} else {
|
|
211
231
|
const item = _.find(data, (datum) => datum[idIx] === value);
|
|
212
232
|
displayValue = (item && item[displayIx]) || '';
|
|
213
233
|
}
|
|
214
234
|
}
|
|
215
235
|
|
|
236
|
+
if (isInTag) {
|
|
237
|
+
displayValue = '';
|
|
238
|
+
}
|
|
239
|
+
|
|
216
240
|
displayValueRef.current = displayValue;
|
|
217
241
|
resetTextInputValue();
|
|
218
242
|
},
|
|
@@ -399,14 +423,16 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
399
423
|
},
|
|
400
424
|
clearGridFilters = async () => {
|
|
401
425
|
if (Repository) {
|
|
402
|
-
if (Repository.
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
Repository.
|
|
408
|
-
|
|
409
|
-
|
|
426
|
+
if (!Repository.isDestroyed) {
|
|
427
|
+
if (Repository.isLoading) {
|
|
428
|
+
await Repository.waitUntilDoneLoading();
|
|
429
|
+
}
|
|
430
|
+
const filterName = getFilterName();
|
|
431
|
+
if (Repository.hasFilter(filterName)) {
|
|
432
|
+
Repository.clearFilters(filterName);
|
|
433
|
+
if (Repository.isRemote && !Repository.isAutoLoad) {
|
|
434
|
+
await Repository.reload();
|
|
435
|
+
}
|
|
410
436
|
}
|
|
411
437
|
}
|
|
412
438
|
} else {
|
|
@@ -421,42 +447,44 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
421
447
|
searchForMatches = async (value) => {
|
|
422
448
|
let found;
|
|
423
449
|
if (Repository) {
|
|
424
|
-
if (Repository.
|
|
425
|
-
|
|
426
|
-
|
|
450
|
+
if (!Repository.isDestroyed) {
|
|
451
|
+
if (Repository.isLoading) {
|
|
452
|
+
await Repository.waitUntilDoneLoading();
|
|
453
|
+
}
|
|
427
454
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
455
|
+
if (_.isEmpty(value)) {
|
|
456
|
+
clearGridFilters();
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
432
459
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
460
|
+
// Set filter
|
|
461
|
+
const
|
|
462
|
+
idRegex = /^id:(.*)$/,
|
|
463
|
+
isId = _.isString(value) && !!value.match(idRegex),
|
|
464
|
+
filterName = getFilterName(isId);
|
|
465
|
+
if (Repository.isRemote) {
|
|
466
|
+
// remote
|
|
467
|
+
const filterValue = _.isEmpty(value) ? null : (isId ? value.match(idRegex)[1] : value + '%');
|
|
468
|
+
await Repository.filter(filterName, filterValue);
|
|
469
|
+
if (!Repository.isAutoLoad) {
|
|
470
|
+
await Repository.reload();
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
// local
|
|
474
|
+
Repository.filter({
|
|
475
|
+
name: filterName,
|
|
476
|
+
fn: (entity) => {
|
|
477
|
+
const
|
|
478
|
+
displayValue = entity.displayValue,
|
|
479
|
+
regex = new RegExp('^' + value, 'i'); // case-insensitive
|
|
480
|
+
return displayValue.match(regex);
|
|
481
|
+
},
|
|
482
|
+
});
|
|
444
483
|
}
|
|
445
|
-
} else {
|
|
446
|
-
// local
|
|
447
|
-
Repository.filter({
|
|
448
|
-
name: filterName,
|
|
449
|
-
fn: (entity) => {
|
|
450
|
-
const
|
|
451
|
-
displayValue = entity.displayValue,
|
|
452
|
-
regex = new RegExp('^' + value, 'i'); // case-insensitive
|
|
453
|
-
return displayValue.match(regex);
|
|
454
|
-
},
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
484
|
|
|
458
|
-
|
|
459
|
-
|
|
485
|
+
if (!isId) {
|
|
486
|
+
setNewEntityDisplayValue(value); // capture the search query so we can tell Grid what to use for a new entity's displayValue
|
|
487
|
+
}
|
|
460
488
|
}
|
|
461
489
|
} else {
|
|
462
490
|
// Search through data
|
|
@@ -30,15 +30,17 @@ const
|
|
|
30
30
|
my: '2px',
|
|
31
31
|
};
|
|
32
32
|
if (Repository) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
if (!Repository.isDestroyed) {
|
|
34
|
+
const entities = Repository.getEntitiesOnPage();
|
|
35
|
+
radios = _.map(entities, (entity, ix) => {
|
|
36
|
+
return <Radio
|
|
37
|
+
{...testProps('radio-' + entity.id)}
|
|
38
|
+
key={ix}
|
|
39
|
+
value={entity.id}
|
|
40
|
+
{...radioProps}
|
|
41
|
+
>{entity.displayValue}</Radio>;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
42
44
|
} else {
|
|
43
45
|
radios = _.map(data, (datum, ix) => {
|
|
44
46
|
return <Radio
|
|
@@ -11,7 +11,7 @@ export default function PageSizeSelect(props) {
|
|
|
11
11
|
} = props;
|
|
12
12
|
|
|
13
13
|
return useMemo(() => {
|
|
14
|
-
return <HStack className="PageSizeSelect-HStack w-[70px]
|
|
14
|
+
return <HStack className="PageSizeSelect-HStack w-[70px]">
|
|
15
15
|
<Select
|
|
16
16
|
data={[
|
|
17
17
|
// [ 1, '1', ],
|
|
@@ -124,11 +124,13 @@ function TagComponent(props) {
|
|
|
124
124
|
if (!id) {
|
|
125
125
|
displayValue = '';
|
|
126
126
|
} else if (Repository) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
if (!Repository.isDestroyed) {
|
|
128
|
+
item = Repository.getById(id);
|
|
129
|
+
if (!item) {
|
|
130
|
+
throw Error('item not found');
|
|
131
|
+
}
|
|
132
|
+
displayValue = item.displayValue;
|
|
130
133
|
}
|
|
131
|
-
displayValue = item.displayValue;
|
|
132
134
|
} else {
|
|
133
135
|
item = _.find(data, (datum) => datum[idIx] === id);
|
|
134
136
|
if (!item) {
|
|
@@ -248,19 +250,19 @@ function TagComponent(props) {
|
|
|
248
250
|
className += ' ' + props.className;
|
|
249
251
|
}
|
|
250
252
|
const style = {};
|
|
251
|
-
if (
|
|
253
|
+
if (props.style) {
|
|
254
|
+
_.assign(style, props.style); // needed for grid; otherwise valuebox width can be too wide
|
|
255
|
+
}
|
|
256
|
+
if (!props.flex && !props.w && !style.width) {
|
|
252
257
|
style.flex = 1;
|
|
253
258
|
} else {
|
|
254
|
-
if (props.w) {
|
|
259
|
+
if (props.w && !style.width) {
|
|
255
260
|
style.width = props.w;
|
|
256
261
|
}
|
|
257
|
-
if (props.flex) {
|
|
262
|
+
if (props.flex && !style.width) {
|
|
258
263
|
style.flex = props.flex;
|
|
259
264
|
}
|
|
260
265
|
}
|
|
261
|
-
if (props.style) {
|
|
262
|
-
_.assign(style, props.style); // needed for grid; otherwise valuebox width can be too wide
|
|
263
|
-
}
|
|
264
266
|
let valueBoxesClassName = `
|
|
265
267
|
Tag-valueBoxes-container
|
|
266
268
|
w-full
|
|
@@ -966,7 +966,7 @@ function Form(props) {
|
|
|
966
966
|
doReset = (values) => {
|
|
967
967
|
reset(values);
|
|
968
968
|
if (onReset) {
|
|
969
|
-
onReset(values, formSetValue, formGetValues);
|
|
969
|
+
onReset(values, formSetValue, formGetValues, trigger);
|
|
970
970
|
}
|
|
971
971
|
},
|
|
972
972
|
onSaveDecorated = async (data, e) => {
|
|
@@ -998,14 +998,14 @@ function Form(props) {
|
|
|
998
998
|
}
|
|
999
999
|
if (record === previousRecord) {
|
|
1000
1000
|
if (onInit) {
|
|
1001
|
-
onInit(initialValues, formSetValue, formGetValues);
|
|
1001
|
+
onInit(initialValues, formSetValue, formGetValues, trigger);
|
|
1002
1002
|
}
|
|
1003
1003
|
} else {
|
|
1004
1004
|
setPreviousRecord(record);
|
|
1005
1005
|
doReset(defaultValues);
|
|
1006
1006
|
}
|
|
1007
1007
|
if (formSetup) {
|
|
1008
|
-
formSetup(formSetValue, formGetValues, formState);
|
|
1008
|
+
formSetup(formSetValue, formGetValues, formState, trigger);
|
|
1009
1009
|
}
|
|
1010
1010
|
}, [record]);
|
|
1011
1011
|
|
|
@@ -146,6 +146,7 @@ function GridComponent(props) {
|
|
|
146
146
|
disableBottomToolbar = false,
|
|
147
147
|
disablePagination = false,
|
|
148
148
|
bottomToolbar = 'pagination',
|
|
149
|
+
_paginationToolbarProps = {},
|
|
149
150
|
topToolbar = null,
|
|
150
151
|
additionalToolbarButtons = [],
|
|
151
152
|
bg = '#fff',
|
|
@@ -744,10 +745,12 @@ function GridComponent(props) {
|
|
|
744
745
|
let dragRecord,
|
|
745
746
|
dropRecord;
|
|
746
747
|
if (Repository) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
748
|
+
if (!Repository.isDestroyed) {
|
|
749
|
+
dragRecord = Repository.getByIx(dragIx);
|
|
750
|
+
dropRecord = Repository.getByIx(dropIx);
|
|
751
|
+
if (dropRecord) {
|
|
752
|
+
Repository.reorder(dragRecord, dropRecord, useBottom ? DROP_POSITION_AFTER : DROP_POSITION_BEFORE);
|
|
753
|
+
}
|
|
751
754
|
}
|
|
752
755
|
} else {
|
|
753
756
|
function arrayMove(arr, fromIndex, toIndex) {
|
|
@@ -766,21 +769,13 @@ function GridComponent(props) {
|
|
|
766
769
|
const
|
|
767
770
|
headerHeight = showHeaders ? 50 : 0,
|
|
768
771
|
footerHeight = !disablePagination ? 50 : 0,
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
// rows.forEach((row) => {
|
|
777
|
-
// totalRowHeight += row.getBoundingClientRect().height;
|
|
778
|
-
// });
|
|
779
|
-
// const rowsPerContainer = Math.floor(height / (totalRowHeight / rows.length));
|
|
780
|
-
|
|
781
|
-
let pageSize = rowsPerContainer;
|
|
782
|
-
if (showHeaders) {
|
|
783
|
-
pageSize--;
|
|
772
|
+
availableHeight = containerHeight - headerHeight - footerHeight,
|
|
773
|
+
maxClassNormal = styles.GRID_ROW_MAX_HEIGHT_NORMAL, // e.g. max-h-[40px]
|
|
774
|
+
rowNormalHeight = parseInt(maxClassNormal.match(/\d+/)[0]);
|
|
775
|
+
|
|
776
|
+
let pageSize = Math.floor(availableHeight / rowNormalHeight);
|
|
777
|
+
if (pageSize < 1) {
|
|
778
|
+
pageSize = 1;
|
|
784
779
|
}
|
|
785
780
|
return pageSize;
|
|
786
781
|
},
|
|
@@ -1162,6 +1157,7 @@ function GridComponent(props) {
|
|
|
1162
1157
|
toolbarItems={footerToolbarItemComponents}
|
|
1163
1158
|
disablePageSize={disablePageSize}
|
|
1164
1159
|
showMoreOnly={showMoreOnly}
|
|
1160
|
+
{..._paginationToolbarProps}
|
|
1165
1161
|
/>;
|
|
1166
1162
|
} else if (footerToolbarItemComponents.length) {
|
|
1167
1163
|
listFooterComponent = <Toolbar>
|
|
@@ -92,8 +92,8 @@ function GridRow(props) {
|
|
|
92
92
|
justify-center
|
|
93
93
|
border-r-black-100
|
|
94
94
|
block
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
overflow-auto
|
|
96
|
+
${styles.GRID_ROW_MAX_HEIGHT_EXTRA}
|
|
97
97
|
`;
|
|
98
98
|
if (isOnlyOneVisibleColumn) {
|
|
99
99
|
colClassName = ' w-full';
|
|
@@ -167,8 +167,9 @@ function GridRow(props) {
|
|
|
167
167
|
if (type.match(/(Tag|TagEditor|Json)$/)) {
|
|
168
168
|
elementProps.isViewOnly = true; // TODO: this won't work for InlineGridEditor, bc that Grid can't use isViewOnly when actually editing
|
|
169
169
|
}
|
|
170
|
+
let cellProps = {};
|
|
170
171
|
if (config.getCellProps) {
|
|
171
|
-
_.assign(
|
|
172
|
+
_.assign(cellProps, config.getCellProps(item));
|
|
172
173
|
}
|
|
173
174
|
let elementClassName = `
|
|
174
175
|
GridRow-Element
|
|
@@ -177,16 +178,19 @@ function GridRow(props) {
|
|
|
177
178
|
px-2
|
|
178
179
|
py-3
|
|
179
180
|
block
|
|
180
|
-
max-h-[40px]
|
|
181
181
|
overflow-scroll
|
|
182
182
|
${colClassName}
|
|
183
183
|
${styles.GRID_CELL_CLASSNAME}
|
|
184
|
+
${styles.GRID_ROW_MAX_HEIGHT_NORMAL}
|
|
184
185
|
`;
|
|
185
186
|
if (config.className) {
|
|
186
187
|
elementClassName += ' ' + config.className;
|
|
187
188
|
}
|
|
189
|
+
if (cellProps.className) {
|
|
190
|
+
elementClassName += ' ' + cellProps.className;
|
|
191
|
+
}
|
|
188
192
|
if (type.match(/(Tag|TagEditor)$/)) {
|
|
189
|
-
elementClassName += '
|
|
193
|
+
elementClassName += ' ' + styles.GRID_ROW_MAX_HEIGHT_EXTRA;
|
|
190
194
|
}
|
|
191
195
|
return <Element
|
|
192
196
|
{...testProps('cell-' + config.fieldName)}
|
|
@@ -232,14 +236,9 @@ function GridRow(props) {
|
|
|
232
236
|
GridRow-TextNative
|
|
233
237
|
self-center
|
|
234
238
|
overflow-hidden
|
|
235
|
-
text-ellipsis
|
|
236
|
-
truncate
|
|
237
|
-
whitespace-nowrap
|
|
238
|
-
overflow-hidden
|
|
239
239
|
${colClassName}
|
|
240
|
-
${styles.GRID_CELL_CLASSNAME}
|
|
241
|
-
${styles.
|
|
242
|
-
${styles.GRID_CELL_PY}
|
|
240
|
+
${styles.GRID_CELL_CLASSNAME}
|
|
241
|
+
${styles.GRID_ROW_MAX_HEIGHT_EXTRA}
|
|
243
242
|
`;
|
|
244
243
|
if (config.className) {
|
|
245
244
|
textClassName += ' ' + config.className;
|
|
@@ -101,6 +101,15 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
101
101
|
onEditorClose();
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
|
+
setIsWaitModalShown = (bool) => {
|
|
105
|
+
const
|
|
106
|
+
dispatch = UiGlobals.redux?.dispatch,
|
|
107
|
+
setIsWaitModalShownAction = UiGlobals.debugReducer?.setIsWaitModalShownAction;
|
|
108
|
+
if (setIsWaitModalShownAction) {
|
|
109
|
+
console.log('withEditor:setIsWaitModalShownAction', bool);
|
|
110
|
+
dispatch(setIsWaitModalShownAction(bool));
|
|
111
|
+
}
|
|
112
|
+
},
|
|
104
113
|
setSelectionDecorated = (newSelection) => {
|
|
105
114
|
function doIt() {
|
|
106
115
|
setSelection(newSelection);
|
|
@@ -386,36 +395,66 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
386
395
|
return;
|
|
387
396
|
}
|
|
388
397
|
|
|
389
|
-
// check permissions for duplicate
|
|
390
|
-
|
|
391
398
|
const selection = getSelection();
|
|
392
399
|
if (selection.length !== 1) {
|
|
393
400
|
return;
|
|
394
401
|
}
|
|
402
|
+
|
|
395
403
|
if (useRemoteDuplicate) {
|
|
396
|
-
|
|
397
|
-
|
|
404
|
+
return await onRemoteDuplicate();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
let isSuccess = false,
|
|
408
|
+
duplicateEntity;
|
|
409
|
+
try {
|
|
410
|
+
const
|
|
411
|
+
entity = selection[0],
|
|
412
|
+
idProperty = Repository.getSchema().model.idProperty,
|
|
413
|
+
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
414
|
+
rawValues.id = null; // unset the id of the duplicate
|
|
415
|
+
|
|
416
|
+
setIsWaitModalShown(true);
|
|
417
|
+
|
|
418
|
+
duplicateEntity = await Repository.add(rawValues, false, true);
|
|
419
|
+
isSuccess = true;
|
|
420
|
+
|
|
421
|
+
} catch(err) {
|
|
422
|
+
// do nothing
|
|
423
|
+
} finally {
|
|
424
|
+
setIsWaitModalShown(false);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (isSuccess) {
|
|
428
|
+
setIsIgnoreNextSelectionChange(true);
|
|
429
|
+
setSelection([duplicateEntity]);
|
|
430
|
+
setEditorMode(EDITOR_MODE__EDIT);
|
|
431
|
+
setIsEditorShown(true);
|
|
398
432
|
}
|
|
399
|
-
const
|
|
400
|
-
entity = selection[0],
|
|
401
|
-
idProperty = Repository.getSchema().model.idProperty,
|
|
402
|
-
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
403
|
-
rawValues.id = null; // unset the id of the duplicate
|
|
404
|
-
const duplicate = await Repository.add(rawValues, false, true);
|
|
405
|
-
setIsIgnoreNextSelectionChange(true);
|
|
406
|
-
setSelection([duplicate]);
|
|
407
|
-
setEditorMode(EDITOR_MODE__EDIT);
|
|
408
|
-
setIsEditorShown(true);
|
|
409
433
|
},
|
|
410
434
|
onRemoteDuplicate = async () => {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
435
|
+
let isSuccess = false,
|
|
436
|
+
duplicateEntity;
|
|
437
|
+
try {
|
|
438
|
+
const
|
|
439
|
+
selection = getSelection(),
|
|
440
|
+
entity = selection[0];
|
|
441
|
+
|
|
442
|
+
setIsWaitModalShown(true);
|
|
415
443
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
444
|
+
duplicateEntity = await Repository.remoteDuplicate(entity);
|
|
445
|
+
isSuccess = true;
|
|
446
|
+
|
|
447
|
+
} catch(err) {
|
|
448
|
+
// do nothing
|
|
449
|
+
} finally {
|
|
450
|
+
setIsWaitModalShown(false);
|
|
451
|
+
}
|
|
452
|
+
if (isSuccess) {
|
|
453
|
+
setIsIgnoreNextSelectionChange(true);
|
|
454
|
+
setSelection([duplicateEntity]);
|
|
455
|
+
doEdit();
|
|
456
|
+
return duplicateEntity;
|
|
457
|
+
}
|
|
419
458
|
},
|
|
420
459
|
doEditorSave = async (data, e) => {
|
|
421
460
|
let mode = getEditorMode() === EDITOR_MODE__ADD ? ADD : EDIT;
|
|
@@ -654,7 +654,7 @@ export default function withFilters(WrappedComponent) {
|
|
|
654
654
|
<HStack className="withFilters-scrollViewContainer flex-1 items-center">
|
|
655
655
|
<ScrollView
|
|
656
656
|
ref={scrollViewRef}
|
|
657
|
-
className={`withFilters-ScrollView ${scrollViewClass}`}
|
|
657
|
+
className={`withFilters-ScrollView ${scrollViewClass} pb-1`}
|
|
658
658
|
horizontal={true}
|
|
659
659
|
contentContainerStyle={{ alignItems: 'center' }}
|
|
660
660
|
onContentSizeChange={onContentSizeChange}
|
|
@@ -141,6 +141,9 @@ export default function withPdfButtons(WrappedComponent) {
|
|
|
141
141
|
if (!_.isEmpty(items)) {
|
|
142
142
|
const defaults = item.defaults;
|
|
143
143
|
item.items = _.map(items, (item, ix) => {
|
|
144
|
+
if (!item){
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
144
147
|
return buildNextLayer(item, ix, defaults);
|
|
145
148
|
});
|
|
146
149
|
}
|
|
@@ -150,7 +150,9 @@ export default function withSelection(WrappedComponent) {
|
|
|
150
150
|
currentlySelectedRowIndices = [];
|
|
151
151
|
const Repository = getRepository();
|
|
152
152
|
if (Repository) {
|
|
153
|
-
|
|
153
|
+
if (!Repository.isDestroyed) {
|
|
154
|
+
items = Repository.getEntitiesOnPage();
|
|
155
|
+
}
|
|
154
156
|
} else {
|
|
155
157
|
items = data;
|
|
156
158
|
}
|
|
@@ -214,8 +216,12 @@ export default function withSelection(WrappedComponent) {
|
|
|
214
216
|
|
|
215
217
|
// Gets ix of entity on page, or element in data array
|
|
216
218
|
if (Repository) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
if (!Repository.isDestroyed) {
|
|
220
|
+
const entities = Repository.getEntitiesOnPage();
|
|
221
|
+
return entities.indexOf(item);
|
|
222
|
+
} else {
|
|
223
|
+
return -1;
|
|
224
|
+
}
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
let found;
|
|
@@ -272,28 +278,30 @@ export default function withSelection(WrappedComponent) {
|
|
|
272
278
|
const Repository = getRepository();
|
|
273
279
|
let newSelection = [];
|
|
274
280
|
if (Repository) {
|
|
275
|
-
if (Repository.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (_.isArray(value)) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
281
|
+
if (!Repository.isDestroyed) {
|
|
282
|
+
if (Repository.isLoading) {
|
|
283
|
+
await Repository.waitUntilDoneLoading();
|
|
284
|
+
}
|
|
285
|
+
// Get entity or entities that match value
|
|
286
|
+
if ((_.isArray(value) && !_.isEmpty(value)) || !!value) {
|
|
287
|
+
if (_.isArray(value)) {
|
|
288
|
+
newSelection = Repository.getBy((entity) => inArray(entity.id, value));
|
|
289
|
+
} else {
|
|
290
|
+
let found = Repository.getById(value);
|
|
291
|
+
if (found) {
|
|
292
|
+
newSelection.push(found);
|
|
293
|
+
// } else if (Repository?.isRemote && Repository?.entities.length) {
|
|
294
|
+
|
|
295
|
+
// // Value cannot be found in Repository, but actually exists on server
|
|
296
|
+
// // Try to get this value from the server directly
|
|
297
|
+
// Repository.filter(Repository.schema.model.idProperty, value);
|
|
298
|
+
// await Repository.load();
|
|
299
|
+
// found = Repository.getById(value);
|
|
300
|
+
// if (found) {
|
|
301
|
+
// newSelection.push(found);
|
|
302
|
+
// }
|
|
303
|
+
|
|
304
|
+
}
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
}
|
|
@@ -326,6 +334,9 @@ export default function withSelection(WrappedComponent) {
|
|
|
326
334
|
|
|
327
335
|
if (Repository) {
|
|
328
336
|
useEffect(() => {
|
|
337
|
+
if (Repository.isDestroyed) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
329
340
|
Repository.on('load', refreshSelection);
|
|
330
341
|
return () => {
|
|
331
342
|
Repository.off('load', refreshSelection);
|
|
@@ -356,8 +367,10 @@ export default function withSelection(WrappedComponent) {
|
|
|
356
367
|
} else if (autoSelectFirstItem) {
|
|
357
368
|
let newSelection = [];
|
|
358
369
|
if (Repository) {
|
|
359
|
-
|
|
360
|
-
|
|
370
|
+
if (!Repository.isDestroyed) {
|
|
371
|
+
const entitiesOnPage = Repository.getEntitiesOnPage();
|
|
372
|
+
newSelection = entitiesOnPage[0] ? [entitiesOnPage[0]] : [];
|
|
373
|
+
}
|
|
361
374
|
} else {
|
|
362
375
|
newSelection = data[0] ? [data[0]] : [];
|
|
363
376
|
}
|
|
@@ -70,14 +70,23 @@ export default function Pagination(props) {
|
|
|
70
70
|
}
|
|
71
71
|
if (!Repository.isLocal) {
|
|
72
72
|
items.push(<ReloadButton
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
key="reloadPageBtn"
|
|
74
|
+
className="Pagination-reloadPageBtn"
|
|
75
|
+
_icon={iconProps}
|
|
76
|
+
Repository={Repository}
|
|
77
|
+
self={self}
|
|
78
|
+
/>);
|
|
79
79
|
}
|
|
80
80
|
} else {
|
|
81
|
+
if (!Repository.isLocal) {
|
|
82
|
+
items.push(<ReloadButton
|
|
83
|
+
key="reloadPageBtn"
|
|
84
|
+
className="Pagination-reloadPageBtn"
|
|
85
|
+
_icon={iconProps}
|
|
86
|
+
Repository={Repository}
|
|
87
|
+
self={self}
|
|
88
|
+
/>);
|
|
89
|
+
}
|
|
81
90
|
isDisabled = page === 1;
|
|
82
91
|
if (showPagination) {
|
|
83
92
|
items.push(<IconButton
|
|
@@ -104,42 +113,6 @@ export default function Pagination(props) {
|
|
|
104
113
|
onPress={() => Repository.prevPage()}
|
|
105
114
|
tooltip="Previous Page"
|
|
106
115
|
/>);
|
|
107
|
-
if (!minimize) {
|
|
108
|
-
items.push(<Text
|
|
109
|
-
key="page"
|
|
110
|
-
className="Pagination-page mx-1"
|
|
111
|
-
>Page</Text>);
|
|
112
|
-
items.push(<Input
|
|
113
|
-
{...testProps('pageInput')}
|
|
114
|
-
key="pageInput"
|
|
115
|
-
reference="pageInput"
|
|
116
|
-
parent={self}
|
|
117
|
-
keyboardType="numeric"
|
|
118
|
-
value={page?.toString()}
|
|
119
|
-
onChangeValue={(value) => Repository.setPage(value)}
|
|
120
|
-
maxValue={totalPages}
|
|
121
|
-
isDisabled={totalPages === 1}
|
|
122
|
-
className={`
|
|
123
|
-
Pagination-pageInput
|
|
124
|
-
min-w-[40px]
|
|
125
|
-
w-[40px]
|
|
126
|
-
text-center
|
|
127
|
-
bg-grey-100
|
|
128
|
-
`}
|
|
129
|
-
textAlignIsCenter={true}
|
|
130
|
-
tooltip="Set Page"
|
|
131
|
-
tooltipClassName="w-[40px]"
|
|
132
|
-
/>);
|
|
133
|
-
items.push(<Text
|
|
134
|
-
key="totalPages"
|
|
135
|
-
className={`
|
|
136
|
-
Pagination-totalPages
|
|
137
|
-
whitespace-nowrap
|
|
138
|
-
inline-flex
|
|
139
|
-
mx-1
|
|
140
|
-
`}
|
|
141
|
-
>{`of ${totalPages}`}</Text>);
|
|
142
|
-
}
|
|
143
116
|
|
|
144
117
|
isDisabled = page === totalPages || totalPages <= 1;
|
|
145
118
|
items.push(<IconButton
|
|
@@ -166,17 +139,44 @@ export default function Pagination(props) {
|
|
|
166
139
|
onPress={() => Repository.setPage(totalPages)}
|
|
167
140
|
tooltip="Last Page"
|
|
168
141
|
/>);
|
|
142
|
+
if (!minimize) {
|
|
143
|
+
items.push(<Text
|
|
144
|
+
key="page"
|
|
145
|
+
className="Pagination-page mx-1"
|
|
146
|
+
>Page</Text>);
|
|
147
|
+
items.push(<Input
|
|
148
|
+
{...testProps('pageInput')}
|
|
149
|
+
key="pageInput"
|
|
150
|
+
reference="pageInput"
|
|
151
|
+
parent={self}
|
|
152
|
+
keyboardType="numeric"
|
|
153
|
+
value={page?.toString()}
|
|
154
|
+
onChangeValue={(value) => Repository.setPage(value)}
|
|
155
|
+
maxValue={totalPages}
|
|
156
|
+
isDisabled={totalPages === 1}
|
|
157
|
+
className={`
|
|
158
|
+
Pagination-pageInput
|
|
159
|
+
min-w-[40px]
|
|
160
|
+
w-[40px]
|
|
161
|
+
text-center
|
|
162
|
+
bg-grey-100
|
|
163
|
+
`}
|
|
164
|
+
textAlignIsCenter={true}
|
|
165
|
+
tooltip="Set Page"
|
|
166
|
+
tooltipClassName="w-[40px]"
|
|
167
|
+
/>);
|
|
168
|
+
items.push(<Text
|
|
169
|
+
key="totalPages"
|
|
170
|
+
className={`
|
|
171
|
+
Pagination-totalPages
|
|
172
|
+
whitespace-nowrap
|
|
173
|
+
inline-flex
|
|
174
|
+
mx-1
|
|
175
|
+
`}
|
|
176
|
+
>{`of ${totalPages}`}</Text>);
|
|
177
|
+
}
|
|
169
178
|
}
|
|
170
179
|
|
|
171
|
-
if (!Repository.isLocal) {
|
|
172
|
-
items.push(<ReloadButton
|
|
173
|
-
key="reloadPageBtn"
|
|
174
|
-
className="Pagination-reloadPageBtn"
|
|
175
|
-
_icon={iconProps}
|
|
176
|
-
Repository={Repository}
|
|
177
|
-
self={self}
|
|
178
|
-
/>);
|
|
179
|
-
}
|
|
180
180
|
if (showPagination && !minimize && !disablePageSize) {
|
|
181
181
|
items.push(<PageSizeSelect
|
|
182
182
|
{...testProps('pageSize')}
|
|
@@ -204,15 +204,14 @@ export default function Pagination(props) {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
return <HStack
|
|
207
|
-
style={{
|
|
207
|
+
style={{
|
|
208
|
+
userSelect: 'none',
|
|
209
|
+
}}
|
|
208
210
|
className={`
|
|
209
211
|
Pagination
|
|
210
|
-
flex-none
|
|
211
|
-
gap-1
|
|
212
|
-
justify-start
|
|
213
212
|
items-center
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
shrink-0
|
|
214
|
+
gap-2
|
|
216
215
|
`}
|
|
217
216
|
>
|
|
218
217
|
{items}
|
|
@@ -10,11 +10,15 @@ export default function PaginationToolbar(props) {
|
|
|
10
10
|
const {
|
|
11
11
|
toolbarItems = [],
|
|
12
12
|
disablePageSize = false,
|
|
13
|
+
minimize,
|
|
13
14
|
} = props,
|
|
14
|
-
[
|
|
15
|
+
[minimizeLocal, setMinimizeLocal] = useState(minimize),
|
|
15
16
|
propsToPass = _.omit(props, 'toolbarItems'),
|
|
16
17
|
showPagination = true,//props.Repository?.totalPages > 1,
|
|
17
18
|
onLayout = (e) => {
|
|
19
|
+
if (minimize) {
|
|
20
|
+
return; // skip if already minimized
|
|
21
|
+
}
|
|
18
22
|
// Note to future self: this is using hard-coded values.
|
|
19
23
|
// Eventually might want to make it responsive to actual sizes
|
|
20
24
|
|
|
@@ -28,7 +32,7 @@ export default function PaginationToolbar(props) {
|
|
|
28
32
|
shouldMinimize = width < threshold;
|
|
29
33
|
|
|
30
34
|
if (shouldMinimize !== minimize) {
|
|
31
|
-
|
|
35
|
+
setMinimizeLocal(shouldMinimize);
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
38
|
|
|
@@ -36,27 +40,26 @@ export default function PaginationToolbar(props) {
|
|
|
36
40
|
className={`
|
|
37
41
|
border-t
|
|
38
42
|
border-t-grey-400
|
|
39
|
-
w-full
|
|
40
43
|
`}
|
|
41
44
|
onLayout={(e) => onLayout(e)}
|
|
42
45
|
>
|
|
46
|
+
{toolbarItems.length ?
|
|
47
|
+
<HStack
|
|
48
|
+
className={`
|
|
49
|
+
PaginationToolbar-HStack
|
|
50
|
+
shrink-0
|
|
51
|
+
border-r
|
|
52
|
+
border-r-grey-400
|
|
53
|
+
mr-3
|
|
54
|
+
pr-3
|
|
55
|
+
`}
|
|
56
|
+
>{toolbarItems}</HStack> : null}
|
|
43
57
|
<Pagination
|
|
44
58
|
{...propsToPass}
|
|
45
59
|
showPagination={showPagination}
|
|
46
60
|
w={toolbarItems.length ? null : '100%'}
|
|
47
|
-
minimize={
|
|
61
|
+
minimize={minimizeLocal}
|
|
48
62
|
disablePageSize={disablePageSize}
|
|
49
63
|
/>
|
|
50
|
-
{toolbarItems.length ?
|
|
51
|
-
<HStack className={`
|
|
52
|
-
PaginationToolbar-HStack
|
|
53
|
-
flex-1
|
|
54
|
-
space-x-1
|
|
55
|
-
border-l
|
|
56
|
-
border-l-grey-400
|
|
57
|
-
ml-3
|
|
58
|
-
pl-3
|
|
59
|
-
`}
|
|
60
|
-
>{toolbarItems}</HStack> : null}
|
|
61
64
|
</Toolbar>;
|
|
62
65
|
};
|
|
@@ -9,14 +9,11 @@ export default function Toolbar(props) {
|
|
|
9
9
|
|
|
10
10
|
let className = `
|
|
11
11
|
Toolbar
|
|
12
|
-
flex
|
|
13
|
-
w-full
|
|
14
|
-
justify-start
|
|
15
|
-
items-center
|
|
16
12
|
overflow-auto
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
items-center
|
|
14
|
+
justify-start
|
|
15
|
+
gap-2
|
|
16
|
+
p-2
|
|
20
17
|
border-b
|
|
21
18
|
border-solid
|
|
22
19
|
border-b-grey-400
|
|
@@ -534,10 +534,12 @@ function TreeComponent(props) {
|
|
|
534
534
|
buildAndSetTreeNodeData = async () => {
|
|
535
535
|
let nodes = [];
|
|
536
536
|
if (Repository) {
|
|
537
|
-
if (!Repository.
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
537
|
+
if (!Repository.isDestroyed) {
|
|
538
|
+
if (!Repository.areRootNodesLoaded) {
|
|
539
|
+
nodes = await Repository.loadRootNodes(1);
|
|
540
|
+
} else {
|
|
541
|
+
nodes = Repository.getRootNodes();
|
|
542
|
+
}
|
|
541
543
|
}
|
|
542
544
|
} else {
|
|
543
545
|
nodes = assembleDataTreeNodes();
|
|
@@ -611,7 +613,9 @@ function TreeComponent(props) {
|
|
|
611
613
|
},
|
|
612
614
|
getTreeNodeByNodeId = (node_id) => {
|
|
613
615
|
if (Repository) {
|
|
614
|
-
|
|
616
|
+
if (!Repository.isDestroyed) {
|
|
617
|
+
return Repository.getById(node_id);
|
|
618
|
+
}
|
|
615
619
|
}
|
|
616
620
|
return data[node_id]; // TODO: This is probably not right!
|
|
617
621
|
},
|
|
@@ -1217,11 +1221,11 @@ function TreeComponent(props) {
|
|
|
1217
1221
|
dropRowRecord = dropRowDatum.item;
|
|
1218
1222
|
|
|
1219
1223
|
if (Repository) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1224
|
+
if (!Repository.isDestroyed) {
|
|
1225
|
+
const commonAncestorId = await Repository.moveTreeNode(dragRowRecord, dropRowRecord.id);
|
|
1226
|
+
const commonAncestorDatum = getDatumById(commonAncestorId);
|
|
1227
|
+
reloadNode(commonAncestorDatum.item);
|
|
1228
|
+
}
|
|
1225
1229
|
} else {
|
|
1226
1230
|
|
|
1227
1231
|
throw Error('Not yet implemented');
|
package/src/Constants/Styles.js
CHANGED
|
@@ -78,6 +78,8 @@ const defaults = {
|
|
|
78
78
|
GRID_ROW_BG_HOVER: '#ccc', // must be hex
|
|
79
79
|
GRID_ROW_SELECTED_BG: '#ff0', // must be hex
|
|
80
80
|
GRID_ROW_SELECTED_BG_HOVER: '#cc0', // must be hex
|
|
81
|
+
GRID_ROW_MAX_HEIGHT_NORMAL: 'max-h-[40px]',
|
|
82
|
+
GRID_ROW_MAX_HEIGHT_EXTRA: 'max-h-[80px]',
|
|
81
83
|
GRID_REORDER_BORDER_COLOR: 'border-[#23d9ea]',
|
|
82
84
|
GRID_REORDER_BORDER_WIDTH: 'border-4',
|
|
83
85
|
GRID_REORDER_BORDER_STYLE: 'border-dashed',
|