@onehat/ui 0.4.107 → 0.4.108

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.4.107",
3
+ "version": "0.4.108",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -424,6 +424,8 @@ function Container(props) {
424
424
 
425
425
  componentProps._panel.isCollapsible = false;
426
426
  componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
427
+ componentProps.isCollapsible = false;
428
+ componentProps.isDisabled = isDisabled || isComponentsDisabled;
427
429
  componentProps.onLayout = debouncedOnLayout;
428
430
  centerComponent = cloneElement(center, componentProps);
429
431
  if (north) {
@@ -432,9 +434,11 @@ function Container(props) {
432
434
 
433
435
  componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
434
436
  componentProps._panel.className = 'h-full w-full ' + (north.props.className || '');
437
+ componentProps.isDisabled = !!north.props?.isDisabled || isDisabled || isComponentsDisabled;
438
+ componentProps.className = 'h-full w-full ' + (north.props.className || '');
435
439
  wrapperProps.onLayout = (e) => {
436
440
  const height = parseFloat(e.nativeEvent.layout.height);
437
- if (height && height !== northHeight) {
441
+ if (height && height !== getNorthHeight()) {
438
442
  setNorthHeight(height);
439
443
  }
440
444
  };
@@ -453,6 +457,9 @@ function Container(props) {
453
457
  componentProps._panel.collapseDirection = VERTICAL;
454
458
  componentProps._panel.isCollapsed = getNorthIsCollapsed();
455
459
  componentProps._panel.setIsCollapsed = setNorthIsCollapsed;
460
+ componentProps.collapseDirection = VERTICAL;
461
+ componentProps.isCollapsed = getNorthIsCollapsed();
462
+ componentProps.setIsCollapsed = setNorthIsCollapsed;
456
463
  if (isWeb && northIsResizable) {
457
464
  northSplitter = <Splitter
458
465
  mode={VERTICAL}
@@ -470,6 +477,8 @@ function Container(props) {
470
477
 
471
478
  componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
472
479
  componentProps._panel.className = 'h-full w-full ' + (south.props.className || '');
480
+ componentProps.isDisabled = !!south.props?.isDisabled || isDisabled || isComponentsDisabled;
481
+ componentProps.className = 'h-full w-full ' + (south.props.className || '');
473
482
  wrapperProps.onLayout = (e) => {
474
483
  const height = parseFloat(e.nativeEvent.layout.height);
475
484
  if (height && height !== getSouthHeight()) {
@@ -491,6 +500,9 @@ function Container(props) {
491
500
  componentProps._panel.collapseDirection = VERTICAL;
492
501
  componentProps._panel.isCollapsed = getSouthIsCollapsed();
493
502
  componentProps._panel.setIsCollapsed = setSouthIsCollapsed;
503
+ componentProps.collapseDirection = VERTICAL;
504
+ componentProps.isCollapsed = getSouthIsCollapsed();
505
+ componentProps.setIsCollapsed = setSouthIsCollapsed;
494
506
  if (isWeb && southIsResizable) {
495
507
  southSplitter = <Splitter
496
508
  mode={VERTICAL}
@@ -508,6 +520,8 @@ function Container(props) {
508
520
 
509
521
  componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
510
522
  componentProps._panel.className = 'h-full w-full ' + (east.props.className || '');
523
+ componentProps.isDisabled = !!east.props?.isDisabled || isDisabled || isComponentsDisabled;
524
+ componentProps.className = 'h-full w-full ' + (east.props.className || '');
511
525
  wrapperProps.onLayout = (e) => {
512
526
  const width = parseFloat(e.nativeEvent.layout.width);
513
527
  if (width && width !== getEastWidth()) {
@@ -529,6 +543,9 @@ function Container(props) {
529
543
  componentProps._panel.collapseDirection = HORIZONTAL;
530
544
  componentProps._panel.isCollapsed = getEastIsCollapsed();
531
545
  componentProps._panel.setIsCollapsed = setEastIsCollapsed;
546
+ componentProps.collapseDirection = HORIZONTAL;
547
+ componentProps.isCollapsed = getEastIsCollapsed();
548
+ componentProps.setIsCollapsed = setEastIsCollapsed;
532
549
  if (isWeb && eastIsResizable) {
533
550
  eastSplitter = <Splitter
534
551
  mode={HORIZONTAL}
@@ -546,6 +563,8 @@ function Container(props) {
546
563
 
547
564
  componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
548
565
  componentProps._panel.className = 'h-full w-full ' + (west.props.className || '');
566
+ componentProps.isDisabled = !!west.props?.isDisabled || isDisabled || isComponentsDisabled;
567
+ componentProps.className = 'h-full w-full ' + (west.props.className || '');
549
568
  wrapperProps.onLayout = (e) => {
550
569
  const width = parseFloat(e.nativeEvent.layout.width);
551
570
  if (width && width !== getWestWidth()) {
@@ -567,6 +586,9 @@ function Container(props) {
567
586
  componentProps._panel.collapseDirection = HORIZONTAL;
568
587
  componentProps._panel.isCollapsed = getWestIsCollapsed();
569
588
  componentProps._panel.setIsCollapsed = setWestIsCollapsed;
589
+ componentProps.collapseDirection = HORIZONTAL;
590
+ componentProps.isCollapsed = getWestIsCollapsed();
591
+ componentProps.setIsCollapsed = setWestIsCollapsed;
570
592
  if (isWeb && westIsResizable) {
571
593
  westSplitter = <Splitter
572
594
  mode={HORIZONTAL}
@@ -375,9 +375,11 @@ const GridRow = forwardRef((props, ref) => {
375
375
  // TODO: incorporate better scrollbar formatting with
376
376
  // tailwind plugin 'tailwind-scrollbar' (already installed, just not yet used here)
377
377
 
378
+ const isEmptyCellValue = _.isNil(value) || value === '';
379
+
378
380
  let textClassName = clsx(
379
381
  'GridRow-TextNative',
380
- 'self-center',
382
+ isEmptyCellValue ? 'self-stretch' : 'self-center', // if the cell value is empty, stretch the cell to be full height
381
383
  areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
382
384
  '[&::-webkit-scrollbar]:h-2',
383
385
  '[&::-webkit-scrollbar-thumb]:bg-gray-300',
@@ -386,6 +388,14 @@ const GridRow = forwardRef((props, ref) => {
386
388
  styles.GRID_CELL_CLASSNAME,
387
389
  styles.GRID_ROW_MAX_HEIGHT_EXTRA,
388
390
  );
391
+ const textStyle = {
392
+ // userSelect: 'none',
393
+ ...colStyle,
394
+ ...(isEmptyCellValue ? { // if the cell value is empty, stretch the cell to be full height
395
+ height: '100%',
396
+ display: 'block',
397
+ } : {}),
398
+ };
389
399
  if (rowProps?._cell?.className) {
390
400
  textClassName += ' ' + rowProps._cell.className;
391
401
  }
@@ -395,16 +405,13 @@ const GridRow = forwardRef((props, ref) => {
395
405
  return <TextNative
396
406
  {...testProps('cell-' + config.fieldName)}
397
407
  key={key}
398
- style={{
399
- // userSelect: 'none',
400
- ...colStyle,
401
- }}
408
+ style={textStyle}
402
409
  numberOfLines={1}
403
410
  ellipsizeMode="head"
404
411
  className={textClassName}
405
412
  {...elementProps}
406
413
  {...propsToPass}
407
- >{value}</TextNative>;
414
+ >{isEmptyCellValue ? ' ' : value}</TextNative>;
408
415
  });
409
416
  } else {
410
417
  // TODO: if 'columnsConfig' is an object, parse its contents
@@ -36,6 +36,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
36
36
  disableAdd = false,
37
37
  disableEdit = false,
38
38
  disableDelete = false,
39
+ enableMultiDelete = false, // deleting multiple records at once is opt-in only
39
40
  disableDuplicate = false,
40
41
  disableView = false,
41
42
  useRemoteDuplicate = false, // call specific copyToNew function on server, rather than simple duplicate on client
@@ -441,7 +442,14 @@ export default function withEditor(WrappedComponent, isTree = false) {
441
442
  cb = args;
442
443
  }
443
444
  const selection = getSelection();
444
- if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
445
+ const hasTreeSelection = isTree || _.some(selection, (selected) => !!selected?.isTree);
446
+ if (
447
+ _.isEmpty(selection) ||
448
+ (_.isArray(selection) && (
449
+ selection[0]?.isDestroyed ||
450
+ (selection.length > 1 && (!enableMultiDelete || hasTreeSelection))
451
+ ))
452
+ ) {
445
453
  return;
446
454
  }
447
455
  if (onBeforeDelete) {
@@ -461,11 +469,11 @@ export default function withEditor(WrappedComponent, isTree = false) {
461
469
  const
462
470
  isSingle = selection.length === 1,
463
471
  firstSelection = selection[0],
464
- isTree = firstSelection?.isTree,
465
- hasChildren = isTree ? firstSelection?.hasChildren : false,
472
+ isTreeNode = firstSelection?.isTree,
473
+ hasChildren = isTreeNode ? firstSelection?.hasChildren : false,
466
474
  isPhantom = firstSelection?.isPhantom;
467
475
 
468
- if (isSingle && isTree && hasChildren) {
476
+ if (isSingle && isTreeNode && hasChildren) {
469
477
  alert({
470
478
  title: 'Move up children?',
471
479
  message: 'The node you have selected for deletion has children. ' +
@@ -1022,6 +1030,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
1022
1030
  isEditor={true}
1023
1031
  userCanEdit={userCanEdit}
1024
1032
  userCanView={userCanView}
1033
+ enableMultiDelete={enableMultiDelete}
1025
1034
  disableAdd={disableAdd || isEditorDisabledByParent || isCrudBlockedByInheritedView}
1026
1035
  disableEdit={disableEdit || isEditorDisabledByParent || isCrudBlockedByInheritedView}
1027
1036
  disableDelete={disableDelete || isEditorDisabledByParent || isCrudBlockedByInheritedView}
@@ -97,7 +97,7 @@ export default function withFilters(WrappedComponent) {
97
97
 
98
98
  let title, type;
99
99
  if (propertyDef) {
100
- title = propertyDef.title;
100
+ title = propertyDef.filterTitle || propertyDef.title;
101
101
  type = propertyDef.filterType;
102
102
  } else if (modelAncillaryFilters[field]) {
103
103
  const ancillaryFilter = modelFilterTypes[field];
@@ -262,7 +262,7 @@ export default function withFilters(WrappedComponent) {
262
262
 
263
263
  if (!title) {
264
264
  const propertyDef = Repository.getSchema().getPropertyDefinition(field);
265
- title = propertyDef?.title;
265
+ title = propertyDef?.filterTitle || propertyDef?.title;
266
266
  }
267
267
 
268
268
  if (_.isString(filterType)) {
@@ -398,7 +398,10 @@ export default function withFilters(WrappedComponent) {
398
398
 
399
399
  // basic property filter
400
400
  const propertyDef = Repository.getSchema().getPropertyDefinition(filterField);
401
- data.push([ filterField, propertyDef?.title ]);
401
+ if (propertyDef?.isFilteringDisabled) {
402
+ return;
403
+ }
404
+ data.push([ filterField, propertyDef?.filterTitle || propertyDef?.title ]);
402
405
  });
403
406
 
404
407
  // sort by title
@@ -179,7 +179,7 @@ export default function withPdfButtons(WrappedComponent) {
179
179
  type: 'Checkbox',
180
180
  name,
181
181
  title: resolvedTitle,
182
- isEditable: false, // hack to force all checkboxes to use same render branch in Form
182
+ label: resolvedTitle,
183
183
  };
184
184
  },
185
185
  buildValidator = () => {
@@ -228,6 +228,7 @@ export default function withPdfButtons(WrappedComponent) {
228
228
  parent={self}
229
229
  reference="chooseFieldsForm"
230
230
  editorType={EDITOR_TYPE__PLAIN}
231
+ checkIsEditingDisabled={false /* hack so layout looks right */}
231
232
  alert={alert}
232
233
  columnDefaults={{
233
234
  labelWidth: '100px',
@@ -75,6 +75,7 @@ export default function withPresetButtons(WrappedComponent) {
75
75
  disableAdd = !isEditor,
76
76
  disableEdit = !isEditor,
77
77
  disableDelete = !isEditor,
78
+ enableMultiDelete = false,
78
79
  disableView = isTree,
79
80
  disableCopy = isTree,
80
81
  disableDuplicate = !isEditor,
@@ -300,7 +301,7 @@ export default function withPresetButtons(WrappedComponent) {
300
301
  icon = Trash;
301
302
  if (isNoSelectorSelected() ||
302
303
  isEmptySelection() ||
303
- isMultiSelection() ||
304
+ (isMultiSelection() && (!enableMultiDelete || isTree)) ||
304
305
  isProtectedValue() ||
305
306
  (canRecordBeDeleted && !canRecordBeDeleted(selection))
306
307
  ) {
@@ -22,6 +22,7 @@ function ScreenHeader(props) {
22
22
  const {
23
23
  title,
24
24
  icon,
25
+ additionalButtons,
25
26
  info,
26
27
  _info = {},
27
28
  useModeIcons = false,
@@ -88,6 +89,7 @@ function ScreenHeader(props) {
88
89
  tooltip="To side editor"
89
90
  />
90
91
  </>}
92
+ {additionalButtons}
91
93
  {info &&
92
94
  <IconButton
93
95
  {...testProps('infoBtn')}