@onehat/ui 0.4.76 → 0.4.78

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.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/src/Components/Editor/AttachmentDirectoriesEditor.js +51 -0
  3. package/src/Components/Editor/AttachmentsEditor.js +81 -0
  4. package/src/Components/Form/Field/Combo/AttachmentDirectoriesCombo.js +20 -0
  5. package/src/Components/Form/Field/Combo/AttachmentDirectoriesComboEditor.js +22 -0
  6. package/src/Components/Form/Field/Combo/AttachmentsCombo.js +20 -0
  7. package/src/Components/Form/Field/Combo/AttachmentsComboEditor.js +22 -0
  8. package/src/Components/Form/Field/Tag/AttachmentDirectoriesTag.js +22 -0
  9. package/src/Components/Form/Field/Tag/AttachmentDirectoriesTagEditor.js +22 -0
  10. package/src/Components/Form/Field/Tag/AttachmentsTag.js +22 -0
  11. package/src/Components/Form/Field/Tag/AttachmentsTagEditor.js +22 -0
  12. package/src/Components/Form/Form.js +52 -18
  13. package/src/Components/Grid/AttachmentDirectoriesFilteredGrid.js +17 -0
  14. package/src/Components/Grid/AttachmentDirectoriesFilteredGridEditor.js +17 -0
  15. package/src/Components/Grid/AttachmentDirectoriesFilteredInlineGridEditor.js +17 -0
  16. package/src/Components/Grid/AttachmentDirectoriesFilteredSideGridEditor.js +17 -0
  17. package/src/Components/Grid/AttachmentDirectoriesGrid.js +20 -0
  18. package/src/Components/Grid/AttachmentDirectoriesGridEditor.js +27 -0
  19. package/src/Components/Grid/AttachmentDirectoriesInlineGridEditor.js +25 -0
  20. package/src/Components/Grid/AttachmentDirectoriesSideGridEditor.js +24 -0
  21. package/src/Components/Grid/AttachmentsFilteredGrid.js +17 -0
  22. package/src/Components/Grid/AttachmentsFilteredGridEditor.js +17 -0
  23. package/src/Components/Grid/AttachmentsFilteredInlineGridEditor.js +17 -0
  24. package/src/Components/Grid/AttachmentsFilteredSideGridEditor.js +17 -0
  25. package/src/Components/Grid/AttachmentsGrid.js +20 -0
  26. package/src/Components/Grid/AttachmentsGridEditor.js +27 -0
  27. package/src/Components/Grid/AttachmentsInlineGridEditor.js +25 -0
  28. package/src/Components/Grid/AttachmentsSideGridEditor.js +24 -0
  29. package/src/Components/Grid/Columns/AttachmentDirectoriesGridColumns.js +32 -0
  30. package/src/Components/Grid/Columns/AttachmentsGridColumns.js +133 -0
  31. package/src/Components/Grid/Grid.js +193 -20
  32. package/src/Components/Grid/GridHeaderRow.js +10 -17
  33. package/src/Components/Grid/GridRow.js +49 -22
  34. package/src/Components/Grid/RowHandle.js +8 -6
  35. package/src/Components/Hoc/withEditor.js +1 -1
  36. package/src/Components/Hoc/withPdfButtons.js +1 -1
  37. package/src/Components/Hoc/withSelection.js +26 -4
  38. package/src/Components/Layout/AsyncOperation.js +299 -195
  39. package/src/Components/Messages/GlobalModals.js +1 -2
  40. package/src/Components/Panel/Panel.js +14 -2
  41. package/src/Components/Panel/TabPanel.js +1 -1
  42. package/src/Components/Panel/TreePanel.js +1 -1
  43. package/src/Components/Report/Report.js +106 -17
  44. package/src/Components/Toolbar/PaginationToolbar.js +4 -3
  45. package/src/Components/Toolbar/Toolbar.js +6 -3
  46. package/src/Components/Tree/Tree.js +218 -147
  47. package/src/Components/Tree/TreeNode.js +20 -13
  48. package/src/Components/Window/AttachmentDirectoriesEditorWindow.js +34 -0
  49. package/src/Components/Window/AttachmentsEditorWindow.js +34 -0
  50. package/src/Components/index.js +92 -1
  51. package/src/Constants/Attachments.js +2 -0
  52. package/src/Constants/Dates.js +2 -2
  53. package/src/Constants/Progress.js +5 -1
  54. package/src/Models/Schemas/AttachmentDirectories.js +66 -0
  55. package/src/Models/Schemas/Attachments.js +88 -0
  56. package/src/Models/Slices/SystemSlice.js +220 -0
  57. package/src/PlatformImports/Web/Attachments.js +783 -145
  58. package/src/Styles/Global.css +7 -2
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useMemo, } from 'react';
1
+ import { useState, useEffect, useMemo, forwardRef, } from 'react';
2
2
  import {
3
3
  Box,
4
4
  HStack,
@@ -30,9 +30,7 @@ import SortDown from '../Icons/SortDown.js';
30
30
  import SortUp from '../Icons/SortUp.js';
31
31
  import _ from 'lodash';
32
32
 
33
- // This was broken out from Grid simply so we can memoize it
34
-
35
- export default function GridHeaderRow(props) {
33
+ export default forwardRef(function GridHeaderRow(props, ref) {
36
34
  let {
37
35
  canColumnsReorder,
38
36
  canColumnsResize,
@@ -49,7 +47,7 @@ export default function GridHeaderRow(props) {
49
47
  isInlineEditorShown,
50
48
  areRowsDragSource,
51
49
  showColumnsSelector,
52
- showSelectHandle,
50
+ showRowHandle,
53
51
  } = props,
54
52
  styles = UiGlobals.styles,
55
53
  sortFn = Repository && Repository.getSortFn(),
@@ -467,18 +465,10 @@ export default function GridHeaderRow(props) {
467
465
  />}
468
466
  </Pressable>;
469
467
  });
470
- if (showSelectHandle) {
471
- headerColumns.unshift(<Box
472
- key="RowSelectHandle"
473
- className="Spacer-RowSelectHandle px-2 items-center justify-center flex-none w-[40px]"
474
- >
475
- <Icon as={Arcs} className={`Arcs w-[20px] h-[20px] text-[#aaa]`} />
476
- </Box>);
477
- }
478
- if (areRowsDragSource) {
468
+ if (showRowHandle) {
479
469
  headerColumns.unshift(<Box
480
- key="spacer"
481
- className="Spacer w-[7px]"
470
+ key="RowHandleSpacer"
471
+ className="Spacer-RowHandle w-[40px] flex-none"
482
472
  />);
483
473
  }
484
474
  if (!hideNavColumn) {
@@ -488,6 +478,7 @@ export default function GridHeaderRow(props) {
488
478
  };
489
479
 
490
480
  return <HStack
481
+ ref={ref}
491
482
  style={{
492
483
  scrollbarWidth: 'none',
493
484
  }}
@@ -515,6 +506,8 @@ export default function GridHeaderRow(props) {
515
506
  sortFn,
516
507
  sortField,
517
508
  isInlineEditorShown,
509
+ areRowsDragSource,
510
+ showRowHandle,
518
511
  ]);
519
- }
512
+ });
520
513
 
@@ -1,4 +1,4 @@
1
- import { useMemo, useState, useEffect, } from 'react';
1
+ import { useMemo, useState, useEffect, forwardRef, isValidElement, cloneElement, } from 'react';
2
2
  import {
3
3
  Box,
4
4
  HStack,
@@ -25,25 +25,20 @@ import useAsyncRenderers from './useAsyncRenderers.js';
25
25
  import _ from 'lodash';
26
26
 
27
27
  // Conditional import for web only
28
- let getEmptyImage;
29
- if (CURRENT_MODE === UI_MODE_WEB) {
30
- import('react-dnd-html5-backend').then((module) => {
31
- getEmptyImage = module.getEmptyImage;
32
- }).catch(() => {
33
- getEmptyImage = null;
34
- });
35
- }
28
+ let getEmptyImage = null;
36
29
 
37
30
  // This was broken out from Grid simply so we can memoize it
38
31
 
39
- function GridRow(props) {
32
+ const GridRow = forwardRef(function GridRow(props, ref) {
40
33
  const {
41
34
  columnsConfig,
42
35
  columnProps,
43
36
  fields,
44
37
  rowProps,
45
38
  hideNavColumn,
46
- showSelectHandle,
39
+ showRowHandle,
40
+ rowCanSelect,
41
+ rowCanDrag,
47
42
  isRowHoverable,
48
43
  isSelected,
49
44
  isHovered,
@@ -79,8 +74,15 @@ function GridRow(props) {
79
74
  // Hide the default drag preview only when using custom drag proxy (and only on web)
80
75
  useEffect(() => {
81
76
  if (dragPreviewRef && typeof dragPreviewRef === 'function' && getDragProxy && CURRENT_MODE === UI_MODE_WEB) {
82
- // Only suppress default drag preview when we have a custom one and we're on web
83
- dragPreviewRef(getEmptyImage(), { captureDraggingState: true });
77
+ // Load getEmptyImage dynamically and apply it
78
+ import('react-dnd-html5-backend').then((module) => {
79
+ const getEmptyImage = module.getEmptyImage;
80
+ if (getEmptyImage) {
81
+ dragPreviewRef(getEmptyImage(), { captureDraggingState: true });
82
+ }
83
+ }).catch((error) => {
84
+ console.warn('Failed to load react-dnd-html5-backend:', error);
85
+ });
84
86
  }
85
87
  }, [dragPreviewRef, getDragProxy]);
86
88
 
@@ -126,12 +128,13 @@ function GridRow(props) {
126
128
  if (_.isArray(columnsConfig)) {
127
129
  return _.map(columnsConfig, (config, key, all) => {
128
130
  if (config.isHidden) {
129
- return null;
131
+ // every element needs a key, so return an empty element with a key
132
+ return <Box key={key} style={{ display: 'none' }} />;
130
133
  }
131
134
  const
132
135
  propsToPass = columnProps[key] || {},
133
136
  colStyle = {},
134
- whichCursor = showSelectHandle ? 'cursor-text' : 'cursor-pointer'; // when using rowSelectHandle, indicate that the row text is selectable, otherwise indicate that the row itself is selectable
137
+ whichCursor = showRowHandle ? 'cursor-text' : 'cursor-pointer'; // when using rowSelectHandle, indicate that the row text is selectable, otherwise indicate that the row itself is selectable
135
138
  let colClassName = clsx(
136
139
  'GridRow-column',
137
140
  'p-1',
@@ -161,7 +164,12 @@ function GridRow(props) {
161
164
 
162
165
  let value;
163
166
  if (_.isFunction(config)) {
164
- return config(item, key);
167
+ const element = config(item, key);
168
+ if (isValidElement(element)) {
169
+ // ensure element has a key
170
+ return element.key != null ? element : cloneElement(element, { key });
171
+ }
172
+ return <Box key={key}>{element}</Box>; // create a box (with key) to wrap non-elements
165
173
  }
166
174
  if (_.isPlainObject(config)) {
167
175
  if (config.renderer) {
@@ -219,7 +227,7 @@ function GridRow(props) {
219
227
  throw Error('Not yet working correctly!');
220
228
  // Async renderer
221
229
  if (isLoading) {
222
- content = <Loading />;
230
+ content = <Loading key={key} />;
223
231
  } else if (asyncResult) {
224
232
  if (asyncResult.error) {
225
233
  content = <Text key={key}>Render Error: {asyncResult.error.message || String(asyncResult.error)}</Text>;
@@ -240,7 +248,15 @@ function GridRow(props) {
240
248
  content = <Text key={key}>Render Error: {error}</Text>;
241
249
  }
242
250
  }
243
- return content;
251
+
252
+
253
+
254
+ // Ensure content has a key prop
255
+ if (isValidElement(content)) {
256
+ // ensure element has a key
257
+ return content.key != null ? content : cloneElement(content, { key });
258
+ }
259
+ return <Box key={key}>{content}</Box>; // create a box (with key) to wrap non-elements
244
260
  }
245
261
  if (config.fieldName) {
246
262
 
@@ -315,7 +331,13 @@ function GridRow(props) {
315
331
  }
316
332
  }
317
333
  if (_.isFunction(value)) {
318
- return value(key);
334
+ const result = value(key);
335
+ // Ensure the result has a key prop
336
+ if (isValidElement(result)) {
337
+ // Only clone if the result doesn't already have a key
338
+ return result.key != null ? result : cloneElement(result, { key });
339
+ }
340
+ return <Box key={key}>{result}</Box>;
319
341
  }
320
342
  const elementProps = {};
321
343
  if (config.getCellProps) {
@@ -353,12 +375,13 @@ function GridRow(props) {
353
375
  };
354
376
 
355
377
  let rowContents = <>
356
- {(isDragSource || isDraggable || showSelectHandle) &&
378
+ {showRowHandle &&
357
379
  <RowHandle
358
380
  ref={dragSourceRef}
359
381
  isDragSource={isDragSource}
360
382
  isDraggable={isDraggable}
361
- showSelectHandle={showSelectHandle}
383
+ canSelect={rowCanSelect}
384
+ canDrag={rowCanDrag}
362
385
  />}
363
386
 
364
387
  {isPhantom &&
@@ -418,6 +441,7 @@ function GridRow(props) {
418
441
  rowClassName += ' border-4 border-[#0ff]';
419
442
  }
420
443
  return <HStackNative
444
+ ref={ref}
421
445
  {...testProps('Row ' + (isSelected ? 'row-selected' : ''))}
422
446
  {...rowProps}
423
447
  key={hash}
@@ -449,8 +473,11 @@ function GridRow(props) {
449
473
  dragSourceRef,
450
474
  dragPreviewRef,
451
475
  dropTargetRef,
476
+ showRowHandle,
477
+ rowCanSelect,
478
+ rowCanDrag,
452
479
  ]);
453
- }
480
+ });
454
481
 
455
482
  // export default withDraggable(withDragSource(withDropTarget(GridRow)));
456
483
  export default GridRow;
@@ -7,7 +7,7 @@ import withTooltip from '@onehat/ui/src/Components/Hoc/withTooltip';
7
7
  import clsx from 'clsx';
8
8
  import Arcs from '../Icons/Arcs.js';
9
9
 
10
- const RowHandle = forwardRef(function RowHandle(props, ref) {
10
+ const RowHandle = forwardRef((props, ref) => {
11
11
  const {
12
12
  isDragSource,
13
13
  isDraggable
@@ -31,25 +31,27 @@ const RowHandle = forwardRef(function RowHandle(props, ref) {
31
31
  });
32
32
 
33
33
  function withAdditionalProps(WrappedComponent) {
34
- return (props) => {
34
+ return forwardRef((props, ref) => {
35
35
  const {
36
- showSelectHandle,
36
+ canSelect,
37
+ canDrag,
37
38
  isDragSource,
38
39
  isDraggable
39
40
  } = props;
40
41
  let tooltipParts = [];
41
- if (showSelectHandle) {
42
+ if (canSelect) {
42
43
  tooltipParts.push('Select');
43
44
  }
44
- if (isDragSource || isDraggable) {
45
+ if (canDrag) {
45
46
  tooltipParts.push('Drag');
46
47
  }
47
48
  const tooltip = tooltipParts.length === 2 ? tooltipParts.join(' or ') : tooltipParts[0];
48
49
  return <WrappedComponent
49
50
  tooltip={tooltip}
50
51
  {...props}
52
+ ref={ref}
51
53
  />;
52
- };
54
+ });
53
55
  }
54
56
 
55
57
  export default withAdditionalProps(withTooltip(RowHandle));
@@ -106,7 +106,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
106
106
  setIsWaitModalShown = (bool) => {
107
107
  const
108
108
  dispatch = UiGlobals.redux?.dispatch,
109
- setIsWaitModalShownAction = UiGlobals.debugReducer?.setIsWaitModalShownAction;
109
+ setIsWaitModalShownAction = UiGlobals.systemReducer?.setIsWaitModalShownAction;
110
110
  if (setIsWaitModalShownAction) {
111
111
  console.log('withEditor:setIsWaitModalShownAction', bool);
112
112
  dispatch(setIsWaitModalShownAction(bool));
@@ -332,7 +332,7 @@ export default function withPdfButtons(WrappedComponent) {
332
332
 
333
333
  const
334
334
  dispatch = UiGlobals.redux.dispatch,
335
- setIsWaitModalShownAction = UiGlobals.debugReducer.setIsWaitModalShownAction;
335
+ setIsWaitModalShownAction = UiGlobals.systemReducer.setIsWaitModalShownAction;
336
336
 
337
337
  dispatch(setIsWaitModalShownAction(true));
338
338
 
@@ -42,8 +42,24 @@ export default function withSelection(WrappedComponent) {
42
42
  forceUpdate = useForceUpdate(),
43
43
  selectionRef = useRef(initialSelection),
44
44
  RepositoryRef = useRef(Repository),
45
+ isSelectionChangesEnabledRef = useRef(true),
45
46
  [isReady, setIsReady] = useState(selection || false), // if selection is already defined, or value is not null and we don't need to load repository, it's ready
47
+ getIsSelectionChangesEnabled = () => {
48
+ return isSelectionChangesEnabledRef.current;
49
+ },
50
+ setIsSelectionChangesEnabled = (bool) => {
51
+ isSelectionChangesEnabledRef.current = bool;
52
+ },
53
+ disableSelectionChanges = () => {
54
+ setIsSelectionChangesEnabled(false);
55
+ },
56
+ enableSelectionChanges = () => {
57
+ setIsSelectionChangesEnabled(true);
58
+ },
46
59
  setSelection = (selection) => {
60
+ if (!getIsSelectionChangesEnabled()) {
61
+ return;
62
+ }
47
63
  if (_.isEqual(selection, getSelection())) {
48
64
  return;
49
65
  }
@@ -195,13 +211,16 @@ export default function withSelection(WrappedComponent) {
195
211
  },
196
212
  isInSelection = (item) => {
197
213
  const Repository = getRepository();
214
+ let found = null;
198
215
  if (Repository) {
199
- return inArray(item, getSelection());
200
- }
201
-
202
- const found = _.find(getSelection(), (selectedItem) => {
216
+ found = _.find(getSelection(), (selectedItem) => {
217
+ return selectedItem.id === item.id;
218
+ });
219
+ } else {
220
+ found = _.find(getSelection(), (selectedItem) => {
203
221
  return selectedItem[idIx] === item[idIx];
204
222
  });
223
+ }
205
224
  return !!found;
206
225
  },
207
226
  getIndexOfSelectedItem = (item) => {
@@ -436,6 +455,9 @@ export default function withSelection(WrappedComponent) {
436
455
  isInSelection={isInSelection}
437
456
  getIdsFromSelection={getIdsFromLocalSelection}
438
457
  getDisplayValuesFromSelection={getDisplayValuesFromSelection}
458
+ disableSelectionChanges={disableSelectionChanges}
459
+ enableSelectionChanges={enableSelectionChanges}
460
+ refreshSelection={refreshSelection}
439
461
  />;
440
462
  });
441
463
  }