@onehat/ui 0.4.95 → 0.4.97
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 +47 -43
- package/src/Components/Form/Form.js +15 -7
- package/src/Components/Grid/Grid.js +116 -41
- package/src/Components/Hoc/withAlert.js +2 -1
- package/src/Components/Hoc/withEditor.js +37 -7
- package/src/Components/Hoc/withPresetButtons.js +5 -5
- package/src/Components/Panel/GridPanel.js +2 -1
- package/src/Components/Panel/TabPanel.js +6 -3
- package/src/Components/Panel/TreePanel.js +3 -2
- package/src/Components/Tree/Tree.js +38 -4
- 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 +29 -21
- 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 +7 -0
- package/src/PlatformImports/Web/Attachments.js +1 -0
package/package.json
CHANGED
|
@@ -118,77 +118,81 @@ function Container(props) {
|
|
|
118
118
|
westWidthRef = useRef(westInitialWidth),
|
|
119
119
|
[isReady, setIsReady] = useState(false),
|
|
120
120
|
[isComponentsDisabled, setIsComponentsDisabled] = useState(false),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
localNorthIsCollapsedRef = useRef(northInitialIsCollapsed),
|
|
122
|
+
localSouthIsCollapsedRef = useRef(southInitialIsCollapsed),
|
|
123
|
+
localEastIsCollapsedRef = useRef(eastInitialIsCollapsed),
|
|
124
|
+
localWestIsCollapsedRef = useRef(westInitialIsCollapsed),
|
|
125
125
|
setNorthIsCollapsed = (bool) => {
|
|
126
126
|
if (setExternalNorthIsCollapsed) {
|
|
127
127
|
setExternalNorthIsCollapsed(bool);
|
|
128
128
|
} else {
|
|
129
|
-
|
|
129
|
+
localNorthIsCollapsedRef.current = bool;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
if (id) {
|
|
133
133
|
setSaved(id + '-northIsCollapsed', bool);
|
|
134
134
|
}
|
|
135
|
+
forceUpdate();
|
|
135
136
|
},
|
|
136
137
|
getNorthIsCollapsed = () => {
|
|
137
138
|
if (setExternalNorthIsCollapsed) {
|
|
138
139
|
return northIsCollapsed;
|
|
139
140
|
}
|
|
140
|
-
return
|
|
141
|
+
return localNorthIsCollapsedRef.current;
|
|
141
142
|
},
|
|
142
143
|
setSouthIsCollapsed = (bool) => {
|
|
143
144
|
if (setExternalSouthIsCollapsed) {
|
|
144
145
|
setExternalSouthIsCollapsed(bool);
|
|
145
146
|
} else {
|
|
146
|
-
|
|
147
|
+
localSouthIsCollapsedRef.current = bool;
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
if (id) {
|
|
150
151
|
setSaved(id + '-southIsCollapsed', bool);
|
|
151
152
|
}
|
|
153
|
+
forceUpdate();
|
|
152
154
|
},
|
|
153
155
|
getSouthIsCollapsed = () => {
|
|
154
156
|
if (setExternalSouthIsCollapsed) {
|
|
155
157
|
return southIsCollapsed;
|
|
156
158
|
}
|
|
157
|
-
return
|
|
159
|
+
return localSouthIsCollapsedRef.current;
|
|
158
160
|
},
|
|
159
161
|
setEastIsCollapsed = (bool) => {
|
|
160
162
|
if (setExternalEastIsCollapsed) {
|
|
161
163
|
setExternalEastIsCollapsed(bool);
|
|
162
164
|
} else {
|
|
163
|
-
|
|
165
|
+
localEastIsCollapsedRef.current = bool;
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
if (id) {
|
|
167
169
|
setSaved(id + '-eastIsCollapsed', bool);
|
|
168
170
|
}
|
|
171
|
+
forceUpdate();
|
|
169
172
|
},
|
|
170
173
|
getEastIsCollapsed = () => {
|
|
171
174
|
if (setExternalEastIsCollapsed) {
|
|
172
175
|
return eastIsCollapsed;
|
|
173
176
|
}
|
|
174
|
-
return
|
|
177
|
+
return localEastIsCollapsedRef.current;
|
|
175
178
|
},
|
|
176
179
|
setWestIsCollapsed = (bool) => {
|
|
177
180
|
if (setExternalWestIsCollapsed) {
|
|
178
181
|
setExternalWestIsCollapsed(bool);
|
|
179
182
|
} else {
|
|
180
|
-
|
|
183
|
+
localWestIsCollapsedRef.current = bool;
|
|
181
184
|
}
|
|
182
185
|
|
|
183
186
|
if (id) {
|
|
184
187
|
setSaved(id + '-westIsCollapsed', bool);
|
|
185
188
|
}
|
|
189
|
+
forceUpdate();
|
|
186
190
|
},
|
|
187
191
|
getWestIsCollapsed = () => {
|
|
188
192
|
if (setExternalWestIsCollapsed) {
|
|
189
193
|
return westIsCollapsed;
|
|
190
194
|
}
|
|
191
|
-
return
|
|
195
|
+
return localWestIsCollapsedRef.current;
|
|
192
196
|
},
|
|
193
197
|
setNorthHeight = (height) => {
|
|
194
198
|
if (!getNorthIsCollapsed()) {
|
|
@@ -348,7 +352,7 @@ function Container(props) {
|
|
|
348
352
|
return null;
|
|
349
353
|
}
|
|
350
354
|
|
|
351
|
-
let componentProps = {},
|
|
355
|
+
let componentProps = { _panel: { ...center?.props?._panel }, },
|
|
352
356
|
wrapperProps = null,
|
|
353
357
|
centerComponent = null,
|
|
354
358
|
northComponent = null,
|
|
@@ -360,15 +364,15 @@ function Container(props) {
|
|
|
360
364
|
westComponent = null,
|
|
361
365
|
westSplitter = null;
|
|
362
366
|
|
|
363
|
-
componentProps.isCollapsible = false;
|
|
364
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
367
|
+
componentProps._panel.isCollapsible = false;
|
|
368
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
365
369
|
centerComponent = cloneElement(center, componentProps);
|
|
366
370
|
if (north) {
|
|
367
|
-
componentProps = {};
|
|
371
|
+
componentProps = { _panel: { ...north.props?._panel }, };
|
|
368
372
|
wrapperProps = {};
|
|
369
373
|
|
|
370
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
371
|
-
componentProps.className = (north.props.className || '')
|
|
374
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
375
|
+
componentProps._panel.className = 'h-full w-full ' + (north.props.className || '');
|
|
372
376
|
wrapperProps.onLayout = (e) => {
|
|
373
377
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
374
378
|
if (height && height !== northHeight) {
|
|
@@ -387,9 +391,9 @@ function Container(props) {
|
|
|
387
391
|
wrapperProps.style = { height: northHeight, };
|
|
388
392
|
}
|
|
389
393
|
}
|
|
390
|
-
componentProps.collapseDirection = VERTICAL;
|
|
391
|
-
componentProps.isCollapsed = getNorthIsCollapsed();
|
|
392
|
-
componentProps.setIsCollapsed = setNorthIsCollapsed;
|
|
394
|
+
componentProps._panel.collapseDirection = VERTICAL;
|
|
395
|
+
componentProps._panel.isCollapsed = getNorthIsCollapsed();
|
|
396
|
+
componentProps._panel.setIsCollapsed = setNorthIsCollapsed;
|
|
393
397
|
if (isWeb && northIsResizable) {
|
|
394
398
|
northSplitter = <Splitter
|
|
395
399
|
mode={VERTICAL}
|
|
@@ -402,11 +406,11 @@ function Container(props) {
|
|
|
402
406
|
</BoxNative>;
|
|
403
407
|
}
|
|
404
408
|
if (south) {
|
|
405
|
-
componentProps = {};
|
|
409
|
+
componentProps = { _panel: { ...south.props?._panel }, };
|
|
406
410
|
wrapperProps = {};
|
|
407
411
|
|
|
408
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
409
|
-
componentProps.className = (south.props.className || '')
|
|
412
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
413
|
+
componentProps._panel.className = 'h-full w-full ' + (south.props.className || '');
|
|
410
414
|
wrapperProps.onLayout = (e) => {
|
|
411
415
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
412
416
|
if (height && height !== getSouthHeight()) {
|
|
@@ -425,9 +429,9 @@ function Container(props) {
|
|
|
425
429
|
wrapperProps.style = { height: southHeight, };
|
|
426
430
|
}
|
|
427
431
|
}
|
|
428
|
-
componentProps.collapseDirection = VERTICAL;
|
|
429
|
-
componentProps.isCollapsed = getSouthIsCollapsed();
|
|
430
|
-
componentProps.setIsCollapsed = setSouthIsCollapsed;
|
|
432
|
+
componentProps._panel.collapseDirection = VERTICAL;
|
|
433
|
+
componentProps._panel.isCollapsed = getSouthIsCollapsed();
|
|
434
|
+
componentProps._panel.setIsCollapsed = setSouthIsCollapsed;
|
|
431
435
|
if (isWeb && southIsResizable) {
|
|
432
436
|
southSplitter = <Splitter
|
|
433
437
|
mode={VERTICAL}
|
|
@@ -440,11 +444,11 @@ function Container(props) {
|
|
|
440
444
|
</BoxNative>;
|
|
441
445
|
}
|
|
442
446
|
if (east) {
|
|
443
|
-
componentProps = {};
|
|
447
|
+
componentProps = { _panel: { ...east.props?._panel }, };
|
|
444
448
|
wrapperProps = {};
|
|
445
449
|
|
|
446
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
447
|
-
componentProps.className = (east.props.className || '')
|
|
450
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
451
|
+
componentProps._panel.className = 'h-full w-full ' + (east.props.className || '');
|
|
448
452
|
wrapperProps.onLayout = (e) => {
|
|
449
453
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
450
454
|
if (width && width !== getEastWidth()) {
|
|
@@ -463,9 +467,9 @@ function Container(props) {
|
|
|
463
467
|
wrapperProps.style = { width: eastWidth, };
|
|
464
468
|
}
|
|
465
469
|
}
|
|
466
|
-
componentProps.collapseDirection = HORIZONTAL;
|
|
467
|
-
componentProps.isCollapsed = getEastIsCollapsed();
|
|
468
|
-
componentProps.setIsCollapsed = setEastIsCollapsed;
|
|
470
|
+
componentProps._panel.collapseDirection = HORIZONTAL;
|
|
471
|
+
componentProps._panel.isCollapsed = getEastIsCollapsed();
|
|
472
|
+
componentProps._panel.setIsCollapsed = setEastIsCollapsed;
|
|
469
473
|
if (isWeb && eastIsResizable) {
|
|
470
474
|
eastSplitter = <Splitter
|
|
471
475
|
mode={HORIZONTAL}
|
|
@@ -478,11 +482,11 @@ function Container(props) {
|
|
|
478
482
|
</BoxNative>;
|
|
479
483
|
}
|
|
480
484
|
if (west) {
|
|
481
|
-
componentProps = {};
|
|
485
|
+
componentProps = { _panel: { ...west.props?._panel }, };
|
|
482
486
|
wrapperProps = {};
|
|
483
487
|
|
|
484
|
-
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
485
|
-
componentProps.className = (west.props.className || '')
|
|
488
|
+
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
489
|
+
componentProps._panel.className = 'h-full w-full ' + (west.props.className || '');
|
|
486
490
|
wrapperProps.onLayout = (e) => {
|
|
487
491
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
488
492
|
if (width && width !== getWestWidth()) {
|
|
@@ -501,9 +505,9 @@ function Container(props) {
|
|
|
501
505
|
wrapperProps.style = { width: westWidth, };
|
|
502
506
|
}
|
|
503
507
|
}
|
|
504
|
-
componentProps.collapseDirection = HORIZONTAL;
|
|
505
|
-
componentProps.isCollapsed = getWestIsCollapsed();
|
|
506
|
-
componentProps.setIsCollapsed = setWestIsCollapsed;
|
|
508
|
+
componentProps._panel.collapseDirection = HORIZONTAL;
|
|
509
|
+
componentProps._panel.isCollapsed = getWestIsCollapsed();
|
|
510
|
+
componentProps._panel.setIsCollapsed = setWestIsCollapsed;
|
|
507
511
|
if (isWeb && westIsResizable) {
|
|
508
512
|
westSplitter = <Splitter
|
|
509
513
|
mode={HORIZONTAL}
|
|
@@ -517,17 +521,17 @@ function Container(props) {
|
|
|
517
521
|
}
|
|
518
522
|
return <VStack className="Container-all w-full flex-1">
|
|
519
523
|
{northComponent}
|
|
520
|
-
{!
|
|
524
|
+
{!getNorthIsCollapsed() && northSplitter}
|
|
521
525
|
<HStack className="Container-mid w-full flex-[100]">
|
|
522
526
|
{westComponent}
|
|
523
|
-
{!
|
|
527
|
+
{!getWestIsCollapsed() && westSplitter}
|
|
524
528
|
<VStack className="Container-center h-full overflow-auto flex-[100]">
|
|
525
529
|
{centerComponent}
|
|
526
530
|
</VStack>
|
|
527
|
-
{!
|
|
531
|
+
{!getEastIsCollapsed() && eastSplitter}
|
|
528
532
|
{eastComponent}
|
|
529
533
|
</HStack>
|
|
530
|
-
{!
|
|
534
|
+
{!getSouthIsCollapsed() && southSplitter}
|
|
531
535
|
{southComponent}
|
|
532
536
|
</VStack>;
|
|
533
537
|
}
|
|
@@ -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,
|
|
@@ -1247,7 +1255,7 @@ function Form(props) {
|
|
|
1247
1255
|
|
|
1248
1256
|
if (inArray(editorType, [EDITOR_TYPE__SIDE, EDITOR_TYPE__SMART, EDITOR_TYPE__WINDOWED]) &&
|
|
1249
1257
|
isSingle && getEditorMode() === EDITOR_MODE__EDIT &&
|
|
1250
|
-
(onBack ||
|
|
1258
|
+
(onBack || onViewMode)) {
|
|
1251
1259
|
modeHeader = <Toolbar>
|
|
1252
1260
|
<HStack className="flex-1 items-center">
|
|
1253
1261
|
{onBack &&
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
HStack,
|
|
6
6
|
Pressable,
|
|
7
7
|
// ScrollView,
|
|
8
|
+
Text,
|
|
8
9
|
VStack,
|
|
9
10
|
VStackNative,
|
|
10
11
|
} from '@project-components/Gluestack';
|
|
@@ -187,7 +188,17 @@ function GridComponent(props) {
|
|
|
187
188
|
canRowsReorder = false,
|
|
188
189
|
canRowDrag, // optional fn to customize whether each row can be dragged
|
|
189
190
|
canRowAcceptDrop, // optional fn to customize whether each node can accept a dropped item: (targetItem, draggedItem) => boolean
|
|
190
|
-
|
|
191
|
+
dragProxyField,
|
|
192
|
+
getCustomDragProxy = (item, selection) => { // optional fn to render custom drag preview: (item, selection) => ReactElement
|
|
193
|
+
let selectionCount = selection?.length || 1,
|
|
194
|
+
displayText = dragProxyField ? item[dragProxyField] : (item.displayValue || 'Selected Row');
|
|
195
|
+
return <VStack className="bg-white border border-gray-300 rounded-lg p-3 shadow-lg max-w-[200px]">
|
|
196
|
+
<Text className="font-semibold text-gray-800">{displayText}</Text>
|
|
197
|
+
{selectionCount > 1 &&
|
|
198
|
+
<Text className="text-sm text-gray-600">(+{selectionCount -1} more item{selectionCount > 2 ? 's' : ''})</Text>
|
|
199
|
+
}
|
|
200
|
+
</VStack>;
|
|
201
|
+
},
|
|
191
202
|
dragPreviewOptions, // optional object for drag preview positioning options
|
|
192
203
|
areRowsDragSource = false,
|
|
193
204
|
rowDragSourceType,
|
|
@@ -260,6 +271,7 @@ function GridComponent(props) {
|
|
|
260
271
|
} = props,
|
|
261
272
|
styles = UiGlobals.styles,
|
|
262
273
|
id = props.id || props.self?.path,
|
|
274
|
+
entities = Repository ? (Repository.isRemote ? Repository.entities : Repository.getEntitiesOnPage()) : data,
|
|
263
275
|
localColumnsConfigKey = id && id + '-localColumnsConfig',
|
|
264
276
|
[hasUnserializableColumns] = useState(() => {
|
|
265
277
|
return !isSerializable(columnsConfig); // (runs only once, when the component is first created)
|
|
@@ -280,6 +292,8 @@ function GridComponent(props) {
|
|
|
280
292
|
measuredRowsRef = useRef([]),
|
|
281
293
|
footerToolbarRef = useRef(null),
|
|
282
294
|
rowRefs = useRef([]),
|
|
295
|
+
previousEntitiesLength = useRef(0),
|
|
296
|
+
hasRemeasuredAfterRowsAppeared = useRef(false),
|
|
283
297
|
[isInited, setIsInited] = useState(false),
|
|
284
298
|
[isReady, setIsReady] = useState(false),
|
|
285
299
|
[isLoading, setIsLoading] = useState(false),
|
|
@@ -409,7 +423,16 @@ function GridComponent(props) {
|
|
|
409
423
|
}
|
|
410
424
|
},
|
|
411
425
|
getFooterToolbarItems = () => {
|
|
412
|
-
|
|
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));
|
|
413
436
|
if (canRowsReorder && CURRENT_MODE === UI_MODE_WEB) { // DND is currently web-only TODO: implement for RN
|
|
414
437
|
items.unshift(<IconButton
|
|
415
438
|
{...testProps('reorderBtn')}
|
|
@@ -462,33 +485,41 @@ function GridComponent(props) {
|
|
|
462
485
|
}
|
|
463
486
|
break;
|
|
464
487
|
case DOUBLE_CLICK:
|
|
465
|
-
if (
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (UiGlobals.doubleClickingGridRowOpensEditorInViewMode) { // global setting
|
|
470
|
-
if (onView) {
|
|
471
|
-
if (canUser && !canUser(VIEW)) { // permissions
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
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
|
|
475
492
|
}
|
|
476
493
|
} else {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if (onEdit && canUser && canUser(EDIT) && (!canRecordBeEdited || canRecordBeEdited(selection)) && !props.disableEdit && !isEditorViewOnly) {
|
|
480
|
-
canDoEdit = true;
|
|
481
|
-
} else
|
|
482
|
-
if (onView && canUser && canUser(VIEW) && !props.disableView) {
|
|
483
|
-
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
|
|
484
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
|
+
}
|
|
485
513
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
514
|
+
if (canDoEdit) {
|
|
515
|
+
onEdit();
|
|
516
|
+
} else if (canDoView) {
|
|
517
|
+
onView();
|
|
518
|
+
}
|
|
490
519
|
}
|
|
520
|
+
|
|
491
521
|
}
|
|
522
|
+
|
|
492
523
|
break;
|
|
493
524
|
case TRIPLE_CLICK:
|
|
494
525
|
break;
|
|
@@ -1118,12 +1149,12 @@ function GridComponent(props) {
|
|
|
1118
1149
|
// Keep the current estimated pageSize, just hide the loading overlay
|
|
1119
1150
|
}
|
|
1120
1151
|
},
|
|
1121
|
-
adjustPageSizeToHeight = (containerHeight) => {
|
|
1152
|
+
adjustPageSizeToHeight = (containerHeight, forceRemeasure = false) => {
|
|
1122
1153
|
if (!Repository || Repository.isDestroyed) { // This method gets delayed, so it's possible for Repository to have been destroyed. Check for this
|
|
1123
1154
|
return;
|
|
1124
1155
|
}
|
|
1125
1156
|
if (DEBUG) {
|
|
1126
|
-
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A`);
|
|
1157
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A forceRemeasure=${forceRemeasure}`);
|
|
1127
1158
|
}
|
|
1128
1159
|
|
|
1129
1160
|
let doAdjustment = autoAdjustPageSizeToHeight;
|
|
@@ -1135,11 +1166,11 @@ function GridComponent(props) {
|
|
|
1135
1166
|
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A2 doAdjustment=${doAdjustment}, autoAdjustPageSizeToHeight=${autoAdjustPageSizeToHeight}, UiGlobals.autoAdjustPageSizeToHeight=${UiGlobals.autoAdjustPageSizeToHeight}, containerHeight=${containerHeight}`);
|
|
1136
1167
|
}
|
|
1137
1168
|
|
|
1138
|
-
// Only proceed if height changed significantly
|
|
1169
|
+
// Only proceed if height changed significantly or forced
|
|
1139
1170
|
const
|
|
1140
1171
|
heightChanged = Math.abs(containerHeight - lastMeasuredContainerHeight) > 5, // 5px tolerance
|
|
1141
1172
|
isFirstMeasurement = lastMeasuredContainerHeight === 0;
|
|
1142
|
-
if (containerHeight > 0 && (isFirstMeasurement || heightChanged)) {
|
|
1173
|
+
if (containerHeight > 0 && (isFirstMeasurement || heightChanged || forceRemeasure)) {
|
|
1143
1174
|
if (editorType === EDITOR_TYPE__SIDE && getIsEditorShown()) {
|
|
1144
1175
|
// When side editor is shown, skip adjustment to avoid layout thrashing
|
|
1145
1176
|
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A4 height changed significantly, but side editor is shown, skipping remeasurement`);
|
|
@@ -1543,6 +1574,43 @@ function GridComponent(props) {
|
|
|
1543
1574
|
}
|
|
1544
1575
|
}, [autoAdjustPageSizeToHeight]);
|
|
1545
1576
|
|
|
1577
|
+
// Reset measurement when rows were first empty then became populated
|
|
1578
|
+
useEffect(() => {
|
|
1579
|
+
const
|
|
1580
|
+
currentLength = entities?.length || 0,
|
|
1581
|
+
wasEmpty = previousEntitiesLength.current === 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.
|
|
1592
|
+
|
|
1593
|
+
// Only remeasure the FIRST time rows appear after being empty
|
|
1594
|
+
if (!hasPhantomRecord && autoAdjustPageSizeToHeight && wasEmpty && isNowPopulated && !hasRemeasuredAfterRowsAppeared.current) {
|
|
1595
|
+
// Rows just appeared for the first time - restart measurement cycle to use actual heights
|
|
1596
|
+
if (DEBUG) {
|
|
1597
|
+
console.log(`${getMeasurementPhase()}, useEffect 5 - rows appeared for first time, restarting measurement cycle`);
|
|
1598
|
+
}
|
|
1599
|
+
hasRemeasuredAfterRowsAppeared.current = true;
|
|
1600
|
+
|
|
1601
|
+
setMeasurementPhase(PHASES__INITIAL);
|
|
1602
|
+
setMeasuredRowHeight(null);
|
|
1603
|
+
measuredRowsRef.current = [];
|
|
1604
|
+
|
|
1605
|
+
// Trigger remeasurement with force flag since actual rows are now available
|
|
1606
|
+
if (lastMeasuredContainerHeight > 0) {
|
|
1607
|
+
adjustPageSizeToHeight(lastMeasuredContainerHeight, true);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
previousEntitiesLength.current = currentLength;
|
|
1612
|
+
}, [entities?.length, autoAdjustPageSizeToHeight]);
|
|
1613
|
+
|
|
1546
1614
|
if (canUser && !canUser('view')) {
|
|
1547
1615
|
return <Unauthorized />;
|
|
1548
1616
|
}
|
|
@@ -1560,13 +1628,24 @@ function GridComponent(props) {
|
|
|
1560
1628
|
// first time through, render a placeholder so we can get container dimensions
|
|
1561
1629
|
return <VStackNative
|
|
1562
1630
|
onLayout={(e) => {
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
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
|
+
}
|
|
1570
1649
|
}
|
|
1571
1650
|
setIsInited(true);
|
|
1572
1651
|
}}
|
|
@@ -1579,7 +1658,6 @@ function GridComponent(props) {
|
|
|
1579
1658
|
}
|
|
1580
1659
|
|
|
1581
1660
|
// Actual data to show in the grid
|
|
1582
|
-
const entities = Repository ? (Repository.isRemote ? Repository.entities : Repository.getEntitiesOnPage()) : data;
|
|
1583
1661
|
let rowData = [...entities]; // don't use the original array, make a new one so alterations to it are temporary
|
|
1584
1662
|
if (showHeaders) {
|
|
1585
1663
|
rowData.unshift({ id: 'headerRow' });
|
|
@@ -1744,14 +1822,11 @@ function GridComponent(props) {
|
|
|
1744
1822
|
)}
|
|
1745
1823
|
>
|
|
1746
1824
|
{grid}
|
|
1747
|
-
{/*
|
|
1748
|
-
|
|
1749
|
-
(getMeasurementPhase() === PHASES__INITIAL || getMeasurementPhase() === PHASES__MEASURING) &&
|
|
1750
|
-
entities?.length > 0 && (
|
|
1825
|
+
{/* Load overlay during initial phase to prevent visual flashing * /
|
|
1826
|
+
autoAdjustPageSizeToHeight && getMeasurementPhase() === PHASES__INITIAL &&
|
|
1751
1827
|
<VStack className="absolute inset-0 z-10 bg-white">
|
|
1752
1828
|
<Loading />
|
|
1753
|
-
</VStack
|
|
1754
|
-
)}
|
|
1829
|
+
</VStack>*/}
|
|
1755
1830
|
</VStack>
|
|
1756
1831
|
|
|
1757
1832
|
{listFooterComponent}
|
|
@@ -61,6 +61,7 @@ function withAlert(WrappedComponent) {
|
|
|
61
61
|
'flex-1',
|
|
62
62
|
'items-start',
|
|
63
63
|
'justify-center',
|
|
64
|
+
'p-4',
|
|
64
65
|
)}>
|
|
65
66
|
<Text className={clsx(
|
|
66
67
|
'withAlert-Text',
|
|
@@ -164,7 +165,7 @@ function withAlert(WrappedComponent) {
|
|
|
164
165
|
}),
|
|
165
166
|
onOk: () => hideModal(),
|
|
166
167
|
canClose: true,
|
|
167
|
-
h:
|
|
168
|
+
h: 250,
|
|
168
169
|
w: 400,
|
|
169
170
|
whichModal: 'info',
|
|
170
171
|
});
|