@onehat/ui 0.4.96 → 0.4.98
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/Container/Container.js +137 -80
- package/src/Components/Form/Form.js +15 -6
- package/src/Components/Grid/Grid.js +71 -37
- package/src/Components/Hoc/withEditor.js +16 -4
- package/src/Components/Hoc/withPresetButtons.js +5 -0
- package/src/Components/Panel/TabPanel.js +1 -1
- package/src/Components/Panel/TreePanel.js +1 -1
- package/src/Components/Tree/Tree.js +26 -3
- package/src/Components/Tree/TreeNode.js +3 -0
- package/src/Components/Viewer/DateTimeViewer.js +25 -0
- package/src/Components/Viewer/DateViewer.js +25 -0
- package/src/Components/Viewer/PmCalcDebugViewer.js +299 -0
- package/src/Components/Viewer/PmStatusesViewer.js +51 -0
- package/src/Components/Viewer/TimeViewer.js +25 -0
- package/src/Components/Viewer/Viewer.js +8 -1
- package/src/Components/index.js +10 -0
- package/src/Constants/Dates.js +1 -0
- package/src/Constants/EditorModes.js +2 -0
- package/src/Constants/MeterSources.js +5 -0
- package/src/Constants/MeterTypes.js +4 -2
- package/src/Constants/PmEventTypes.js +11 -0
- package/src/Constants/PmScheduleModes.js +4 -0
- package/src/Constants/PmStatuses.js +16 -0
- package/src/PlatformImports/Web/Attachments.js +2 -1
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cloneElement, useState, useEffect, useRef, } from 'react';
|
|
1
|
+
import { cloneElement, useState, useEffect, useRef, useCallback, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
BoxNative,
|
|
4
4
|
HStack,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '../../Constants/UiModes.js';
|
|
17
17
|
import withComponent from '../Hoc/withComponent.js';
|
|
18
18
|
import useForceUpdate from '../../Hooks/useForceUpdate.js';
|
|
19
|
+
import getComponentFromType from '../../Functions/getComponentFromType.js';
|
|
19
20
|
import getSaved from '../../Functions/getSaved.js';
|
|
20
21
|
import setSaved from '../../Functions/setSaved.js';
|
|
21
22
|
import Splitter from './Splitter.js';
|
|
@@ -106,6 +107,8 @@ function Container(props) {
|
|
|
106
107
|
} = props,
|
|
107
108
|
id = props.id || props.self?.path,
|
|
108
109
|
isWeb = CURRENT_MODE === UI_MODE_WEB,
|
|
110
|
+
useWindowSize = getComponentFromType('useWindowSize'),
|
|
111
|
+
windowSize = useWindowSize(),
|
|
109
112
|
forceUpdate = useForceUpdate(),
|
|
110
113
|
centerRef = useRef(null),
|
|
111
114
|
northRef = useRef(null),
|
|
@@ -118,77 +121,111 @@ function Container(props) {
|
|
|
118
121
|
westWidthRef = useRef(westInitialWidth),
|
|
119
122
|
[isReady, setIsReady] = useState(false),
|
|
120
123
|
[isComponentsDisabled, setIsComponentsDisabled] = useState(false),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
localNorthIsCollapsedRef = useRef(northInitialIsCollapsed),
|
|
125
|
+
localSouthIsCollapsedRef = useRef(southInitialIsCollapsed),
|
|
126
|
+
localEastIsCollapsedRef = useRef(eastInitialIsCollapsed),
|
|
127
|
+
localWestIsCollapsedRef = useRef(westInitialIsCollapsed),
|
|
128
|
+
onLayout = async (e) => {
|
|
129
|
+
console.log('Container onLayout', e.nativeEvent.layout.width);
|
|
130
|
+
if (id) {
|
|
131
|
+
// save prevScreenSize if changed
|
|
132
|
+
const
|
|
133
|
+
height = parseFloat(e.nativeEvent.layout.height),
|
|
134
|
+
width = parseFloat(e.nativeEvent.layout.width),
|
|
135
|
+
key = id + '-prevScreenSize',
|
|
136
|
+
prevScreenSize = await getSaved(key);
|
|
137
|
+
if (!prevScreenSize || prevScreenSize.width !== width || prevScreenSize.height !== height) {
|
|
138
|
+
await setSaved(key, {
|
|
139
|
+
height,
|
|
140
|
+
width,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// reset all sizes to null, so they recalculate
|
|
144
|
+
setNorthHeight(null);
|
|
145
|
+
setSouthHeight(null);
|
|
146
|
+
setEastWidth(null);
|
|
147
|
+
setWestWidth(null);
|
|
148
|
+
forceUpdate();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
debouncedOnLayout = useCallback(
|
|
153
|
+
_.debounce((e) => {
|
|
154
|
+
onLayout(e);
|
|
155
|
+
}, 2000), // delay is signficant, as all we're trying to do is catch screen size changes
|
|
156
|
+
[]
|
|
157
|
+
),
|
|
125
158
|
setNorthIsCollapsed = (bool) => {
|
|
126
159
|
if (setExternalNorthIsCollapsed) {
|
|
127
160
|
setExternalNorthIsCollapsed(bool);
|
|
128
161
|
} else {
|
|
129
|
-
|
|
162
|
+
localNorthIsCollapsedRef.current = bool;
|
|
130
163
|
}
|
|
131
164
|
|
|
132
165
|
if (id) {
|
|
133
166
|
setSaved(id + '-northIsCollapsed', bool);
|
|
134
167
|
}
|
|
168
|
+
forceUpdate();
|
|
135
169
|
},
|
|
136
170
|
getNorthIsCollapsed = () => {
|
|
137
171
|
if (setExternalNorthIsCollapsed) {
|
|
138
172
|
return northIsCollapsed;
|
|
139
173
|
}
|
|
140
|
-
return
|
|
174
|
+
return localNorthIsCollapsedRef.current;
|
|
141
175
|
},
|
|
142
176
|
setSouthIsCollapsed = (bool) => {
|
|
143
177
|
if (setExternalSouthIsCollapsed) {
|
|
144
178
|
setExternalSouthIsCollapsed(bool);
|
|
145
179
|
} else {
|
|
146
|
-
|
|
180
|
+
localSouthIsCollapsedRef.current = bool;
|
|
147
181
|
}
|
|
148
182
|
|
|
149
183
|
if (id) {
|
|
150
184
|
setSaved(id + '-southIsCollapsed', bool);
|
|
151
185
|
}
|
|
186
|
+
forceUpdate();
|
|
152
187
|
},
|
|
153
188
|
getSouthIsCollapsed = () => {
|
|
154
189
|
if (setExternalSouthIsCollapsed) {
|
|
155
190
|
return southIsCollapsed;
|
|
156
191
|
}
|
|
157
|
-
return
|
|
192
|
+
return localSouthIsCollapsedRef.current;
|
|
158
193
|
},
|
|
159
194
|
setEastIsCollapsed = (bool) => {
|
|
160
195
|
if (setExternalEastIsCollapsed) {
|
|
161
196
|
setExternalEastIsCollapsed(bool);
|
|
162
197
|
} else {
|
|
163
|
-
|
|
198
|
+
localEastIsCollapsedRef.current = bool;
|
|
164
199
|
}
|
|
165
200
|
|
|
166
201
|
if (id) {
|
|
167
202
|
setSaved(id + '-eastIsCollapsed', bool);
|
|
168
203
|
}
|
|
204
|
+
forceUpdate();
|
|
169
205
|
},
|
|
170
206
|
getEastIsCollapsed = () => {
|
|
171
207
|
if (setExternalEastIsCollapsed) {
|
|
172
208
|
return eastIsCollapsed;
|
|
173
209
|
}
|
|
174
|
-
return
|
|
210
|
+
return localEastIsCollapsedRef.current;
|
|
175
211
|
},
|
|
176
212
|
setWestIsCollapsed = (bool) => {
|
|
177
213
|
if (setExternalWestIsCollapsed) {
|
|
178
214
|
setExternalWestIsCollapsed(bool);
|
|
179
215
|
} else {
|
|
180
|
-
|
|
216
|
+
localWestIsCollapsedRef.current = bool;
|
|
181
217
|
}
|
|
182
218
|
|
|
183
219
|
if (id) {
|
|
184
220
|
setSaved(id + '-westIsCollapsed', bool);
|
|
185
221
|
}
|
|
222
|
+
forceUpdate();
|
|
186
223
|
},
|
|
187
224
|
getWestIsCollapsed = () => {
|
|
188
225
|
if (setExternalWestIsCollapsed) {
|
|
189
226
|
return westIsCollapsed;
|
|
190
227
|
}
|
|
191
|
-
return
|
|
228
|
+
return localWestIsCollapsedRef.current;
|
|
192
229
|
},
|
|
193
230
|
setNorthHeight = (height) => {
|
|
194
231
|
if (!getNorthIsCollapsed()) {
|
|
@@ -289,53 +326,72 @@ function Container(props) {
|
|
|
289
326
|
|
|
290
327
|
if (id) {
|
|
291
328
|
let key, val;
|
|
292
|
-
key = id + '-northIsCollapsed';
|
|
293
|
-
val = await getSaved(key);
|
|
294
|
-
if (!_.isNil(val)) {
|
|
295
|
-
setNorthIsCollapsed(val);
|
|
296
|
-
}
|
|
297
329
|
|
|
298
|
-
|
|
330
|
+
// does screensize from previous render exist?
|
|
331
|
+
key = id + '-prevScreenSize';
|
|
299
332
|
val = await getSaved(key);
|
|
333
|
+
let prevScreenSize = null;
|
|
300
334
|
if (!_.isNil(val)) {
|
|
301
|
-
|
|
335
|
+
prevScreenSize = val;
|
|
302
336
|
}
|
|
337
|
+
const currentScreenSize = {
|
|
338
|
+
width: windowSize?.width ?? null,
|
|
339
|
+
height: windowSize?.height ?? null,
|
|
340
|
+
};
|
|
341
|
+
if (!prevScreenSize || (prevScreenSize.width === currentScreenSize.width && prevScreenSize.height === currentScreenSize.height)) {
|
|
342
|
+
|
|
343
|
+
// only load these saved settings if the screen size is the same as when they were saved
|
|
344
|
+
key = id + '-northIsCollapsed';
|
|
345
|
+
val = await getSaved(key);
|
|
346
|
+
if (!_.isNil(val)) {
|
|
347
|
+
setNorthIsCollapsed(val);
|
|
348
|
+
}
|
|
303
349
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
350
|
+
key = id + '-southIsCollapsed';
|
|
351
|
+
val = await getSaved(key);
|
|
352
|
+
if (!_.isNil(val)) {
|
|
353
|
+
setSouthIsCollapsed(val);
|
|
354
|
+
}
|
|
309
355
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
356
|
+
key = id + '-eastIsCollapsed';
|
|
357
|
+
val = await getSaved(key);
|
|
358
|
+
if (!_.isNil(val)) {
|
|
359
|
+
setEastIsCollapsed(val);
|
|
360
|
+
}
|
|
315
361
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
362
|
+
key = id + '-westIsCollapsed';
|
|
363
|
+
val = await getSaved(key);
|
|
364
|
+
if (!_.isNil(val)) {
|
|
365
|
+
setWestIsCollapsed(val);
|
|
366
|
+
}
|
|
321
367
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
368
|
+
key = id + '-northHeight';
|
|
369
|
+
val = await getSaved(key);
|
|
370
|
+
if (!_.isNil(val)) {
|
|
371
|
+
setNorthHeight(val);
|
|
372
|
+
}
|
|
327
373
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
374
|
+
key = id + '-southHeight';
|
|
375
|
+
val = await getSaved(key);
|
|
376
|
+
if (!_.isNil(val)) {
|
|
377
|
+
setSouthHeight(val);
|
|
378
|
+
}
|
|
333
379
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
380
|
+
key = id + '-eastWidth';
|
|
381
|
+
val = await getSaved(key);
|
|
382
|
+
if (!_.isNil(val)) {
|
|
383
|
+
setEastWidth(val);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
key = id + '-westWidth';
|
|
387
|
+
val = await getSaved(key);
|
|
388
|
+
if (!_.isNil(val)) {
|
|
389
|
+
setWestWidth(val);
|
|
390
|
+
}
|
|
391
|
+
|
|
338
392
|
}
|
|
393
|
+
|
|
394
|
+
|
|
339
395
|
}
|
|
340
396
|
|
|
341
397
|
if (!isReady) {
|
|
@@ -348,7 +404,7 @@ function Container(props) {
|
|
|
348
404
|
return null;
|
|
349
405
|
}
|
|
350
406
|
|
|
351
|
-
let componentProps = {},
|
|
407
|
+
let componentProps = { _panel: { ...center?.props?._panel }, },
|
|
352
408
|
wrapperProps = null,
|
|
353
409
|
centerComponent = null,
|
|
354
410
|
northComponent = null,
|
|
@@ -360,15 +416,16 @@ function Container(props) {
|
|
|
360
416
|
westComponent = null,
|
|
361
417
|
westSplitter = null;
|
|
362
418
|
|
|
363
|
-
componentProps.isCollapsible = false;
|
|
364
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
419
|
+
componentProps._panel.isCollapsible = false;
|
|
420
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
421
|
+
componentProps.onLayout = debouncedOnLayout;
|
|
365
422
|
centerComponent = cloneElement(center, componentProps);
|
|
366
423
|
if (north) {
|
|
367
|
-
componentProps = {};
|
|
424
|
+
componentProps = { _panel: { ...north.props?._panel }, };
|
|
368
425
|
wrapperProps = {};
|
|
369
426
|
|
|
370
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
371
|
-
componentProps.className = 'h-full w-full ' + (north.props.className || '');
|
|
427
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
428
|
+
componentProps._panel.className = 'h-full w-full ' + (north.props.className || '');
|
|
372
429
|
wrapperProps.onLayout = (e) => {
|
|
373
430
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
374
431
|
if (height && height !== northHeight) {
|
|
@@ -387,9 +444,9 @@ function Container(props) {
|
|
|
387
444
|
wrapperProps.style = { height: northHeight, };
|
|
388
445
|
}
|
|
389
446
|
}
|
|
390
|
-
componentProps.collapseDirection = VERTICAL;
|
|
391
|
-
componentProps.isCollapsed = getNorthIsCollapsed();
|
|
392
|
-
componentProps.setIsCollapsed = setNorthIsCollapsed;
|
|
447
|
+
componentProps._panel.collapseDirection = VERTICAL;
|
|
448
|
+
componentProps._panel.isCollapsed = getNorthIsCollapsed();
|
|
449
|
+
componentProps._panel.setIsCollapsed = setNorthIsCollapsed;
|
|
393
450
|
if (isWeb && northIsResizable) {
|
|
394
451
|
northSplitter = <Splitter
|
|
395
452
|
mode={VERTICAL}
|
|
@@ -402,11 +459,11 @@ function Container(props) {
|
|
|
402
459
|
</BoxNative>;
|
|
403
460
|
}
|
|
404
461
|
if (south) {
|
|
405
|
-
componentProps = {};
|
|
462
|
+
componentProps = { _panel: { ...south.props?._panel }, };
|
|
406
463
|
wrapperProps = {};
|
|
407
464
|
|
|
408
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
409
|
-
componentProps.className = 'h-full w-full ' + (south.props.className || '');
|
|
465
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
466
|
+
componentProps._panel.className = 'h-full w-full ' + (south.props.className || '');
|
|
410
467
|
wrapperProps.onLayout = (e) => {
|
|
411
468
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
412
469
|
if (height && height !== getSouthHeight()) {
|
|
@@ -425,9 +482,9 @@ function Container(props) {
|
|
|
425
482
|
wrapperProps.style = { height: southHeight, };
|
|
426
483
|
}
|
|
427
484
|
}
|
|
428
|
-
componentProps.collapseDirection = VERTICAL;
|
|
429
|
-
componentProps.isCollapsed = getSouthIsCollapsed();
|
|
430
|
-
componentProps.setIsCollapsed = setSouthIsCollapsed;
|
|
485
|
+
componentProps._panel.collapseDirection = VERTICAL;
|
|
486
|
+
componentProps._panel.isCollapsed = getSouthIsCollapsed();
|
|
487
|
+
componentProps._panel.setIsCollapsed = setSouthIsCollapsed;
|
|
431
488
|
if (isWeb && southIsResizable) {
|
|
432
489
|
southSplitter = <Splitter
|
|
433
490
|
mode={VERTICAL}
|
|
@@ -440,11 +497,11 @@ function Container(props) {
|
|
|
440
497
|
</BoxNative>;
|
|
441
498
|
}
|
|
442
499
|
if (east) {
|
|
443
|
-
componentProps = {};
|
|
500
|
+
componentProps = { _panel: { ...east.props?._panel }, };
|
|
444
501
|
wrapperProps = {};
|
|
445
502
|
|
|
446
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
447
|
-
componentProps.className = 'h-full w-full ' + (east.props.className || '');
|
|
503
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
504
|
+
componentProps._panel.className = 'h-full w-full ' + (east.props.className || '');
|
|
448
505
|
wrapperProps.onLayout = (e) => {
|
|
449
506
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
450
507
|
if (width && width !== getEastWidth()) {
|
|
@@ -463,9 +520,9 @@ function Container(props) {
|
|
|
463
520
|
wrapperProps.style = { width: eastWidth, };
|
|
464
521
|
}
|
|
465
522
|
}
|
|
466
|
-
componentProps.collapseDirection = HORIZONTAL;
|
|
467
|
-
componentProps.isCollapsed = getEastIsCollapsed();
|
|
468
|
-
componentProps.setIsCollapsed = setEastIsCollapsed;
|
|
523
|
+
componentProps._panel.collapseDirection = HORIZONTAL;
|
|
524
|
+
componentProps._panel.isCollapsed = getEastIsCollapsed();
|
|
525
|
+
componentProps._panel.setIsCollapsed = setEastIsCollapsed;
|
|
469
526
|
if (isWeb && eastIsResizable) {
|
|
470
527
|
eastSplitter = <Splitter
|
|
471
528
|
mode={HORIZONTAL}
|
|
@@ -478,11 +535,11 @@ function Container(props) {
|
|
|
478
535
|
</BoxNative>;
|
|
479
536
|
}
|
|
480
537
|
if (west) {
|
|
481
|
-
componentProps = {};
|
|
538
|
+
componentProps = { _panel: { ...west.props?._panel }, };
|
|
482
539
|
wrapperProps = {};
|
|
483
540
|
|
|
484
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
485
|
-
componentProps.className = 'h-full w-full ' + (west.props.className || '');
|
|
541
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
542
|
+
componentProps._panel.className = 'h-full w-full ' + (west.props.className || '');
|
|
486
543
|
wrapperProps.onLayout = (e) => {
|
|
487
544
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
488
545
|
if (width && width !== getWestWidth()) {
|
|
@@ -501,9 +558,9 @@ function Container(props) {
|
|
|
501
558
|
wrapperProps.style = { width: westWidth, };
|
|
502
559
|
}
|
|
503
560
|
}
|
|
504
|
-
componentProps.collapseDirection = HORIZONTAL;
|
|
505
|
-
componentProps.isCollapsed = getWestIsCollapsed();
|
|
506
|
-
componentProps.setIsCollapsed = setWestIsCollapsed;
|
|
561
|
+
componentProps._panel.collapseDirection = HORIZONTAL;
|
|
562
|
+
componentProps._panel.isCollapsed = getWestIsCollapsed();
|
|
563
|
+
componentProps._panel.setIsCollapsed = setWestIsCollapsed;
|
|
507
564
|
if (isWeb && westIsResizable) {
|
|
508
565
|
westSplitter = <Splitter
|
|
509
566
|
mode={HORIZONTAL}
|
|
@@ -517,17 +574,17 @@ function Container(props) {
|
|
|
517
574
|
}
|
|
518
575
|
return <VStack className="Container-all w-full flex-1">
|
|
519
576
|
{northComponent}
|
|
520
|
-
{!
|
|
577
|
+
{!getNorthIsCollapsed() && northSplitter}
|
|
521
578
|
<HStack className="Container-mid w-full flex-[100]">
|
|
522
579
|
{westComponent}
|
|
523
|
-
{!
|
|
580
|
+
{!getWestIsCollapsed() && westSplitter}
|
|
524
581
|
<VStack className="Container-center h-full overflow-auto flex-[100]">
|
|
525
582
|
{centerComponent}
|
|
526
583
|
</VStack>
|
|
527
|
-
{!
|
|
584
|
+
{!getEastIsCollapsed() && eastSplitter}
|
|
528
585
|
{eastComponent}
|
|
529
586
|
</HStack>
|
|
530
|
-
{!
|
|
587
|
+
{!getSouthIsCollapsed() && southSplitter}
|
|
531
588
|
{southComponent}
|
|
532
589
|
</VStack>;
|
|
533
590
|
}
|
|
@@ -522,6 +522,8 @@ function Form(props) {
|
|
|
522
522
|
}
|
|
523
523
|
let {
|
|
524
524
|
type,
|
|
525
|
+
editorType: itemEditorType,
|
|
526
|
+
viewerType,
|
|
525
527
|
title,
|
|
526
528
|
name,
|
|
527
529
|
isEditable = true,
|
|
@@ -560,12 +562,18 @@ function Form(props) {
|
|
|
560
562
|
}
|
|
561
563
|
if (!type) {
|
|
562
564
|
if (isEditable) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
565
|
+
if (itemEditorType) {
|
|
566
|
+
type = itemEditorType;
|
|
567
|
+
} else {
|
|
568
|
+
const {
|
|
569
|
+
type: t,
|
|
570
|
+
...p
|
|
571
|
+
} = propertyDef?.editorType;
|
|
572
|
+
type = t;
|
|
573
|
+
editorTypeProps = p;
|
|
574
|
+
}
|
|
575
|
+
} else if (viewerType) {
|
|
576
|
+
type = viewerType;
|
|
569
577
|
} else if (propertyDef?.viewerType) {
|
|
570
578
|
const {
|
|
571
579
|
type: t,
|
|
@@ -1390,6 +1398,7 @@ function Form(props) {
|
|
|
1390
1398
|
onPress={() => doReset()}
|
|
1391
1399
|
icon={Rotate}
|
|
1392
1400
|
isDisabled={!formState.isDirty}
|
|
1401
|
+
tooltip="Reset Form"
|
|
1393
1402
|
/>}
|
|
1394
1403
|
|
|
1395
1404
|
{showCancelBtn &&
|
|
@@ -423,7 +423,16 @@ function GridComponent(props) {
|
|
|
423
423
|
}
|
|
424
424
|
},
|
|
425
425
|
getFooterToolbarItems = () => {
|
|
426
|
-
|
|
426
|
+
// Process additionalToolbarButtons to evaluate getIsButtonDisabled functions
|
|
427
|
+
const processedButtons = _.map(additionalToolbarButtons, (config) => {
|
|
428
|
+
const processedConfig = { ...config };
|
|
429
|
+
// If the button has an getIsButtonDisabled function, evaluate it with current selection
|
|
430
|
+
if (_.isFunction(config.getIsButtonDisabled)) {
|
|
431
|
+
processedConfig.isDisabled = config.getIsButtonDisabled(selection);
|
|
432
|
+
}
|
|
433
|
+
return processedConfig;
|
|
434
|
+
});
|
|
435
|
+
const items = _.map(processedButtons, (config, ix) => getIconButtonFromConfig(config, ix, self));
|
|
427
436
|
if (canRowsReorder && CURRENT_MODE === UI_MODE_WEB) { // DND is currently web-only TODO: implement for RN
|
|
428
437
|
items.unshift(<IconButton
|
|
429
438
|
{...testProps('reorderBtn')}
|
|
@@ -476,33 +485,41 @@ function GridComponent(props) {
|
|
|
476
485
|
}
|
|
477
486
|
break;
|
|
478
487
|
case DOUBLE_CLICK:
|
|
479
|
-
if (
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if (UiGlobals.doubleClickingGridRowOpensEditorInViewMode) { // global setting
|
|
484
|
-
if (onView) {
|
|
485
|
-
if (canUser && !canUser(VIEW)) { // permissions
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
onView(!props.isEditorViewOnly);
|
|
488
|
+
if (editorType === EDITOR_TYPE__SIDE) {
|
|
489
|
+
// For side-editors, a double-click just acts like a single click
|
|
490
|
+
if (!getIsEditorShown()) {
|
|
491
|
+
onRowClick(item, e); // sets selection
|
|
489
492
|
}
|
|
490
493
|
} else {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (onEdit && canUser && canUser(EDIT) && (!canRecordBeEdited || canRecordBeEdited(selection)) && !props.disableEdit && !isEditorViewOnly) {
|
|
494
|
-
canDoEdit = true;
|
|
495
|
-
} else
|
|
496
|
-
if (onView && canUser && canUser(VIEW) && !props.disableView) {
|
|
497
|
-
canDoView = true;
|
|
494
|
+
if (!isSelected) { // If a row was already selected when double-clicked, the first click will deselect it,
|
|
495
|
+
onRowClick(item, e); // so reselect it
|
|
498
496
|
}
|
|
497
|
+
if (UiGlobals.doubleClickingGridRowOpensEditorInViewMode) { // global setting
|
|
498
|
+
if (onView) {
|
|
499
|
+
if (canUser && !canUser(VIEW)) { // permissions
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
onView(!props.isEditorViewOnly);
|
|
503
|
+
}
|
|
504
|
+
} else {
|
|
505
|
+
let canDoEdit = false,
|
|
506
|
+
canDoView = false;
|
|
507
|
+
if (onEdit && canUser && canUser(EDIT) && (!canRecordBeEdited || canRecordBeEdited(selection)) && !props.disableEdit && !isEditorViewOnly) {
|
|
508
|
+
canDoEdit = true;
|
|
509
|
+
} else
|
|
510
|
+
if (onView && canUser && canUser(VIEW) && !props.disableView) {
|
|
511
|
+
canDoView = true;
|
|
512
|
+
}
|
|
499
513
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
514
|
+
if (canDoEdit) {
|
|
515
|
+
onEdit();
|
|
516
|
+
} else if (canDoView) {
|
|
517
|
+
onView();
|
|
518
|
+
}
|
|
504
519
|
}
|
|
520
|
+
|
|
505
521
|
}
|
|
522
|
+
|
|
506
523
|
break;
|
|
507
524
|
case TRIPLE_CLICK:
|
|
508
525
|
break;
|
|
@@ -1562,10 +1579,19 @@ function GridComponent(props) {
|
|
|
1562
1579
|
const
|
|
1563
1580
|
currentLength = entities?.length || 0,
|
|
1564
1581
|
wasEmpty = previousEntitiesLength.current === 0,
|
|
1565
|
-
isNowPopulated = currentLength > 0
|
|
1582
|
+
isNowPopulated = currentLength > 0,
|
|
1583
|
+
hasPhantomRecord = entities?.some(entity => entity?.isPhantom);
|
|
1584
|
+
|
|
1585
|
+
// NOTE: The Repository was reloading when a phantom record was added,
|
|
1586
|
+
// and this broke the Editor because selection was being reset to zero.
|
|
1587
|
+
// This is because adjustPageSizeToHeight calls setPageSize,
|
|
1588
|
+
// which calls _onChangePagination, which calls reload.
|
|
1589
|
+
// The reloaded repository doesn’t get the new phantom record,
|
|
1590
|
+
// so it’s not found, and selection goes to zero.
|
|
1591
|
+
// So we skip this adjustment when there is a phantom record.
|
|
1566
1592
|
|
|
1567
1593
|
// Only remeasure the FIRST time rows appear after being empty
|
|
1568
|
-
if (autoAdjustPageSizeToHeight && wasEmpty && isNowPopulated && !hasRemeasuredAfterRowsAppeared.current) {
|
|
1594
|
+
if (!hasPhantomRecord && autoAdjustPageSizeToHeight && wasEmpty && isNowPopulated && !hasRemeasuredAfterRowsAppeared.current) {
|
|
1569
1595
|
// Rows just appeared for the first time - restart measurement cycle to use actual heights
|
|
1570
1596
|
if (DEBUG) {
|
|
1571
1597
|
console.log(`${getMeasurementPhase()}, useEffect 5 - rows appeared for first time, restarting measurement cycle`);
|
|
@@ -1602,13 +1628,24 @@ function GridComponent(props) {
|
|
|
1602
1628
|
// first time through, render a placeholder so we can get container dimensions
|
|
1603
1629
|
return <VStackNative
|
|
1604
1630
|
onLayout={(e) => {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1631
|
+
const hasPhantomRecord = entities?.some(entity => entity?.isPhantom);
|
|
1632
|
+
if (!hasPhantomRecord) {
|
|
1633
|
+
// NOTE: The Repository was reloading when a phantom record was added,
|
|
1634
|
+
// and this broke the Editor because selection was being reset to zero.
|
|
1635
|
+
// This is because adjustPageSizeToHeight calls setPageSize,
|
|
1636
|
+
// which calls _onChangePagination, which calls reload.
|
|
1637
|
+
// The reloaded repository doesn’t get the new phantom record,
|
|
1638
|
+
// so it’s not found, and selection goes to zero.
|
|
1639
|
+
// So we skip this adjustment when there is a phantom record.
|
|
1640
|
+
|
|
1641
|
+
if (DEBUG) {
|
|
1642
|
+
console.log(`${getMeasurementPhase()}, placeholder onLayout, call adjustPageSizeToHeight()`);
|
|
1643
|
+
}
|
|
1644
|
+
const containerHeight = e.nativeEvent.layout.height;
|
|
1645
|
+
adjustPageSizeToHeight(containerHeight);
|
|
1646
|
+
if (DEBUG) {
|
|
1647
|
+
console.log(`${getMeasurementPhase()}, placeholder onLayout, call setIsInited(true)`);
|
|
1648
|
+
}
|
|
1612
1649
|
}
|
|
1613
1650
|
setIsInited(true);
|
|
1614
1651
|
}}
|
|
@@ -1785,14 +1822,11 @@ function GridComponent(props) {
|
|
|
1785
1822
|
)}
|
|
1786
1823
|
>
|
|
1787
1824
|
{grid}
|
|
1788
|
-
{/*
|
|
1789
|
-
|
|
1790
|
-
(getMeasurementPhase() === PHASES__INITIAL || getMeasurementPhase() === PHASES__MEASURING) &&
|
|
1791
|
-
entities?.length > 0 && (
|
|
1825
|
+
{/* Load overlay during initial phase to prevent visual flashing * /
|
|
1826
|
+
autoAdjustPageSizeToHeight && getMeasurementPhase() === PHASES__INITIAL &&
|
|
1792
1827
|
<VStack className="absolute inset-0 z-10 bg-white">
|
|
1793
1828
|
<Loading />
|
|
1794
|
-
</VStack
|
|
1795
|
-
)}
|
|
1829
|
+
</VStack>*/}
|
|
1796
1830
|
</VStack>
|
|
1797
1831
|
|
|
1798
1832
|
{listFooterComponent}
|
|
@@ -38,6 +38,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
38
38
|
disableDuplicate = false,
|
|
39
39
|
disableView = false,
|
|
40
40
|
useRemoteDuplicate = false, // call specific copyToNew function on server, rather than simple duplicate on client
|
|
41
|
+
getDuplicateValues, // fn(entity) to get default values for duplication
|
|
41
42
|
getRecordIdentifier = (selection) => {
|
|
42
43
|
if (selection.length > 1) {
|
|
43
44
|
return 'records?';
|
|
@@ -89,6 +90,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
89
90
|
editorModeRef = useRef(initialEditorMode),
|
|
90
91
|
isIgnoreNextSelectionChangeRef = useRef(false),
|
|
91
92
|
isEditorShownRef = useRef(false),
|
|
93
|
+
defaultValuesRef = useRef(defaultValues),
|
|
92
94
|
canEditorBeInEditModeRef = useRef(true), // whether the editor is allowed to be in edit mode based on canRecordBeEdited
|
|
93
95
|
[currentRecord, setCurrentRecord] = useState(null),
|
|
94
96
|
[isAdding, setIsAdding] = useState(false),
|
|
@@ -111,6 +113,12 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
111
113
|
getIsEditorShown = () => {
|
|
112
114
|
return isEditorShownRef.current;
|
|
113
115
|
},
|
|
116
|
+
getDefaultValues = () => {
|
|
117
|
+
return defaultValuesRef.current;
|
|
118
|
+
},
|
|
119
|
+
setDefaultValues = (vals) => {
|
|
120
|
+
defaultValuesRef.current = vals;
|
|
121
|
+
},
|
|
114
122
|
setCanEditorBeInEditMode = (bool) => {
|
|
115
123
|
canEditorBeInEditModeRef.current = bool;
|
|
116
124
|
forceUpdate();
|
|
@@ -164,6 +172,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
164
172
|
getNewEntityDisplayValue = () => {
|
|
165
173
|
return newEntityDisplayValueRef.current;
|
|
166
174
|
},
|
|
175
|
+
setNewEntityDisplayValue = (val) => {
|
|
176
|
+
newEntityDisplayValueRef.current = val;
|
|
177
|
+
},
|
|
167
178
|
doAdd = async (e, values) => {
|
|
168
179
|
if (canUser && !canUser(ADD)) {
|
|
169
180
|
showPermissionsError(ADD);
|
|
@@ -191,8 +202,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
191
202
|
// 2. Use the repository's default values (defined on each property as 'defaultValue'), or
|
|
192
203
|
// 3. Individually override the repository's default values with submitted 'defaultValues' (given as a prop to this HOC)
|
|
193
204
|
let defaultValuesToUse = Repository.getSchema().getDefaultValues();
|
|
194
|
-
if (
|
|
195
|
-
_.merge(defaultValuesToUse,
|
|
205
|
+
if (getDefaultValues()) {
|
|
206
|
+
_.merge(defaultValuesToUse, getDefaultValues());
|
|
196
207
|
}
|
|
197
208
|
addValues = {...defaultValuesToUse};
|
|
198
209
|
}
|
|
@@ -458,7 +469,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
458
469
|
const
|
|
459
470
|
entity = selection[0],
|
|
460
471
|
idProperty = Repository.getSchema().model.idProperty,
|
|
461
|
-
rawValues = _.omit(entity.getOriginalData(), idProperty);
|
|
472
|
+
rawValues = getDuplicateValues ? getDuplicateValues(entity) : _.omit(entity.getOriginalData(), idProperty);
|
|
462
473
|
rawValues.id = null; // unset the id of the duplicate
|
|
463
474
|
|
|
464
475
|
setIsWaitModalShown(true);
|
|
@@ -738,7 +749,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
738
749
|
self.duplicate = doDuplicate;
|
|
739
750
|
self.setIsEditorShown = setIsEditorShown;
|
|
740
751
|
}
|
|
741
|
-
|
|
752
|
+
setNewEntityDisplayValue(newEntityDisplayValue);
|
|
753
|
+
setDefaultValues(defaultValues);
|
|
742
754
|
|
|
743
755
|
if (lastSelection !== selection) {
|
|
744
756
|
// NOTE: If I don't calculate this on the fly for selection changes,
|