@onehat/ui 0.3.381 → 0.3.382

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.3.381",
3
+ "version": "0.3.382",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -692,6 +692,7 @@ export function ComboComponent(props) {
692
692
  'disablePrint',
693
693
  'selectorId',
694
694
  'selectorSelected',
695
+ 'selectorSelectedField',
695
696
  'usePermissions',
696
697
  ]);
697
698
  if (!Repository) {
@@ -239,6 +239,7 @@ function TagComponent(props) {
239
239
  if (propsToPass.selectorId) {
240
240
  _combo.selectorId = propsToPass.selectorId;
241
241
  _combo.selectorSelected = propsToPass.selectorSelected;
242
+ _combo.selectorSelectedField = propsToPass.selectorSelectedField;
242
243
  }
243
244
 
244
245
  return <>
@@ -127,6 +127,7 @@ function Form(props) {
127
127
  // parent container
128
128
  selectorId,
129
129
  selectorSelected,
130
+ selectorSelectedField,
130
131
 
131
132
  // withAlert
132
133
  alert,
@@ -337,6 +338,7 @@ function Form(props) {
337
338
 
338
339
  if (useSelectorId) { // This causes the whole form to use selectorId
339
340
  editorTypeProps.selectorId = selectorId;
341
+ editorTypeProps.selectorSelectedField = selectorSelectedField;
340
342
  }
341
343
  if (propsToPass.selectorId || editorTypeProps.selectorId) { // editorTypeProps.selectorId causes just this one field to use selectorId
342
344
  if (_.isNil(propsToPass.selectorSelected)) {
@@ -589,6 +591,7 @@ function Form(props) {
589
591
 
590
592
  if (useSelectorId) { // This causes the whole form to use selectorId
591
593
  editorTypeProps.selectorId = selectorId;
594
+ editorTypeProps.selectorSelectedField = selectorSelectedField;
592
595
  }
593
596
  if (propsToPass.selectorId || editorTypeProps.selectorId) { // editorTypeProps.selectorId causes just this one field to use selectorId
594
597
  if (_.isNil(propsToPass.selectorSelected)) {
@@ -708,6 +711,7 @@ function Form(props) {
708
711
  title = null,
709
712
  description = null,
710
713
  selectorId,
714
+ selectorSelectedField,
711
715
  ...propsToPass
712
716
  } = item;
713
717
  if (isMultiple && type !== 'Attachments') {
@@ -721,6 +725,7 @@ function Form(props) {
721
725
  element = <Element
722
726
  {...testProps('ancillary-' + type)}
723
727
  selectorId={selectorId}
728
+ selectorSelectedField={selectorSelectedField}
724
729
  selectorSelected={selectorSelected || record}
725
730
  flex={1}
726
731
  uniqueRepository={true}
@@ -111,7 +111,6 @@ function GridComponent(props) {
111
111
  hideNavColumn = true,
112
112
  noneFoundText,
113
113
  autoAdjustPageSizeToHeight = true,
114
- disableSelectorSelected = false,
115
114
  showRowExpander = false,
116
115
  getExpandedRowContent,
117
116
  showHeaders = true,
@@ -140,6 +139,22 @@ function GridComponent(props) {
140
139
  alternatingInterval = 2,
141
140
  defaultRowHeight = 48,
142
141
 
142
+ // The selectorSelected mechanism allows us to filter results of the primary model, (e.g. WorkOrders)
143
+ // by the selection on the secondary model (e.g. Equipment). It's used on Grids, Trees, Forms, etc.
144
+ // The 'selectorId' is the name of the primary model's filter (e.g. 'WorkOrders.equipment_id').
145
+ // which gets submitted to the server as a condition (e.g. 'conditions[WorkOrders.equipment_id]').
146
+ // The 'selectorSelected' is the Entity on the secondary model which is selected (e.g. Equipment).
147
+ // The 'selectorSelectedField' is the field on the secondary model to use as the value for the filter
148
+ // (e.g. 'fleet_id'). If not given, it defaults to 'id'.
149
+ // It can be disabled altogether for a specific grid ('disableSelectorSelected'), and configured
150
+ // so that no selection means no results ('noSelectorMeansNoResults').
151
+
152
+ selectorId,
153
+ selectorSelected,
154
+ selectorSelectedField = 'id',
155
+ noSelectorMeansNoResults = false,
156
+ disableSelectorSelected = false,
157
+
143
158
  // withComponent
144
159
  self,
145
160
 
@@ -182,16 +197,11 @@ function GridComponent(props) {
182
197
  deselectAll,
183
198
  selectRangeTo,
184
199
  isInSelection,
185
- noSelectorMeansNoResults = false,
186
200
  selectNext,
187
201
  selectPrev,
188
202
  addNextToSelection,
189
203
  addPrevToSelection,
190
204
 
191
- // DataMgt
192
- selectorId,
193
- selectorSelected,
194
-
195
205
  // withInlineEditor
196
206
  inlineEditor = null,
197
207
  isInlineEditorShown = false,
@@ -212,6 +222,7 @@ function GridComponent(props) {
212
222
  expandedRowsRef = useRef({}),
213
223
  cachedDragElements = useRef(),
214
224
  dragSelectionRef = useRef([]),
225
+ previousSelectorId = useRef(),
215
226
  [isInited, setIsInited] = useState(false),
216
227
  [isReady, setIsReady] = useState(false),
217
228
  [isLoading, setIsLoading] = useState(false),
@@ -755,11 +766,23 @@ function GridComponent(props) {
755
766
  if (disableSelectorSelected || !selectorId) {
756
767
  return
757
768
  }
758
- let id = selectorSelected?.id;
759
- if (_.isEmpty(selectorSelected)) {
760
- id = noSelectorMeansNoResults ? 'NO_MATCHES' : null;
769
+
770
+ if (previousSelectorId.current && selectorId !== previousSelectorId.current) {
771
+ Repository.pauseEvents();
772
+ Repository.clearFilters(previousSelectorId.current);
773
+ Repository.resumeEvents();
774
+ }
775
+ previousSelectorId.current = selectorId;
776
+
777
+ let value = null;
778
+ if (selectorSelected) {
779
+ value = selectorSelected[selectorSelectedField];
780
+ }
781
+ if (noSelectorMeansNoResults && _.isEmpty(selectorSelected)) {
782
+ value = 'NO_MATCHES';
761
783
  }
762
- Repository.filter(selectorId, id, false); // so it doesn't clear existing filters
784
+
785
+ Repository.filter(selectorId, value, false); // false so it doesn't clear existing filters
763
786
  },
764
787
  onGridKeyDown = (e) => {
765
788
  if (isInlineEditorShown) {
@@ -968,7 +991,7 @@ function GridComponent(props) {
968
991
 
969
992
  applySelectorSelected();
970
993
 
971
- }, [selectorSelected]);
994
+ }, [selectorId, selectorSelected]);
972
995
 
973
996
  if (canUser && !canUser('view')) {
974
997
  return <Unauthorized />;
@@ -60,6 +60,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
60
60
  // parent container
61
61
  secondarySelectorId,
62
62
  secondarySelectorSelected,
63
+ secondarySelectorSelectedField = 'id',
63
64
 
64
65
  // withSecondaryData
65
66
  SecondaryRepository,
@@ -150,7 +151,7 @@ export default function withSecondaryEditor(WrappedComponent, isTree = false) {
150
151
  }
151
152
 
152
153
  if (secondarySelectorId && !_.isEmpty(secondarySelectorSelected)) {
153
- addValues[secondarySelectorId] = secondarySelectorSelected.id;
154
+ addValues[secondarySelectorId] = secondarySelectorSelected[secondarySelectorSelectedField];
154
155
  }
155
156
 
156
157
  if (getNewEntityDisplayValue()) {
@@ -35,6 +35,7 @@ export default function withSecondarySideEditor(WrappedComponent, isTree = false
35
35
  // pull these out, as we don't want them going to the Editor
36
36
  secondarySelectorId,
37
37
  secondarySelectorSelected,
38
+ secondarySelectorSelectedField,
38
39
 
39
40
  ...propsToPass
40
41
  } = props;
@@ -41,6 +41,7 @@ export default function withSecondaryWindowedEditor(WrappedComponent, isTree = f
41
41
  // pull these out, as we don't want them going to the SecondaryEditor
42
42
  secondarySelectorId,
43
43
  secondarySelectorSelected,
44
+ secondarySelectorSelectedField,
44
45
  h,
45
46
 
46
47
  ...propsToPass
@@ -60,6 +60,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
60
60
  // parent container
61
61
  selectorId,
62
62
  selectorSelected,
63
+ selectorSelectedField = 'id',
63
64
 
64
65
  // withData
65
66
  Repository,
@@ -149,7 +150,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
149
150
  }
150
151
 
151
152
  if (selectorId && !_.isEmpty(selectorSelected)) {
152
- addValues[selectorId] = selectorSelected.id;
153
+ addValues[selectorId] = selectorSelected[selectorSelectedField];
153
154
  }
154
155
 
155
156
  if (getNewEntityDisplayValue()) {
@@ -34,6 +34,7 @@ export default function withInlineEditor(WrappedComponent, skipWrappers = false)
34
34
  // pull these out, as we don't want them going to the Editor
35
35
  selectorId,
36
36
  selectorSelected,
37
+ selectorSelectedField,
37
38
  h,
38
39
 
39
40
  ...propsToPass
@@ -33,6 +33,7 @@ export default function withSideEditor(WrappedComponent, isTree = false) {
33
33
  // pull these out, as we don't want them going to the Editor
34
34
  selectorId,
35
35
  selectorSelected,
36
+ selectorSelectedField,
36
37
 
37
38
  ...propsToPass
38
39
  } = props;
@@ -55,6 +55,7 @@ export default function withWindowedEditor(WrappedComponent, isTree = false) {
55
55
  // pull these out, as we don't want them going to the Editor
56
56
  selectorId,
57
57
  selectorSelected,
58
+ selectorSelectedField,
58
59
  h,
59
60
 
60
61
  ...propsToPass
@@ -43,6 +43,7 @@ import getIconButtonFromConfig from '../../Functions/getIconButtonFromConfig.js'
43
43
  import inArray from '../../Functions/inArray.js';
44
44
  import testProps from '../../Functions/testProps.js';
45
45
  import nbToRgb from '../../Functions/nbToRgb.js';
46
+ import CenterBox from '../Layout/CenterBox.js';
46
47
  import ReloadTreeButton from '../Buttons/ReloadTreeButton.js';
47
48
  import TreeNode, { DraggableTreeNode } from './TreeNode.js';
48
49
  import FormPanel from '../Panel/FormPanel.js';
@@ -114,6 +115,10 @@ function TreeComponent(props) {
114
115
  canRecordBeEdited,
115
116
  onTreeLoad,
116
117
 
118
+ selectorId,
119
+ selectorSelected,
120
+ selectorSelectedField = 'id',
121
+
117
122
  // withComponent
118
123
  self,
119
124
 
@@ -155,10 +160,6 @@ function TreeComponent(props) {
155
160
  isInSelection,
156
161
  noSelectorMeansNoResults = false,
157
162
 
158
- // DataMgt
159
- selectorId,
160
- selectorSelected,
161
-
162
163
  } = props,
163
164
  styles = UiGlobals.styles,
164
165
  forceUpdate = useForceUpdate(),
@@ -1246,7 +1247,7 @@ function TreeComponent(props) {
1246
1247
  return () => {};
1247
1248
  }
1248
1249
  if (!disableSelectorSelected && selectorId) {
1249
- let id = selectorSelected?.id;
1250
+ let id = selectorSelected?.[selectorSelectedField] ?? null;
1250
1251
  if (_.isEmpty(selectorSelected)) {
1251
1252
  id = noSelectorMeansNoResults ? 'NO_MATCHES' : null;
1252
1253
  }
@@ -1255,7 +1256,9 @@ function TreeComponent(props) {
1255
1256
  }, [selectorId, selectorSelected]);
1256
1257
 
1257
1258
  if (canUser && !canUser('view')) {
1258
- return <Unauthorized />;
1259
+ return <CenterBox>
1260
+ <Unauthorized />
1261
+ </CenterBox>;
1259
1262
  }
1260
1263
 
1261
1264
  if (setWithEditListeners) {
@@ -1282,7 +1285,9 @@ function TreeComponent(props) {
1282
1285
  footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, isDragMode, getTreeNodeData()]);
1283
1286
 
1284
1287
  if (!isReady) {
1285
- return <Loading />;
1288
+ return <CenterBox>
1289
+ <Loading />
1290
+ </CenterBox>;
1286
1291
  }
1287
1292
 
1288
1293
  const treeNodes = renderTreeNodes(getTreeNodeData());
@@ -1339,7 +1344,9 @@ function TreeComponent(props) {
1339
1344
  >
1340
1345
  <ScrollView {...testProps('ScrollView')} flex={1} w="100%">
1341
1346
  {!treeNodes?.length ?
1342
- <NoRecordsFound text={noneFoundText} onRefresh={reloadTree} /> :
1347
+ <CenterBox>
1348
+ <NoRecordsFound text={noneFoundText} onRefresh={reloadTree} />
1349
+ </CenterBox> :
1343
1350
  treeNodes}
1344
1351
  </ScrollView>
1345
1352
  </Column>
@@ -58,6 +58,7 @@ function Viewer(props) {
58
58
  // parent container
59
59
  selectorId,
60
60
  selectorSelected,
61
+ selectorSelectedField,
61
62
 
62
63
  } = props,
63
64
  scrollViewRef = useRef(),
@@ -209,6 +210,7 @@ function Viewer(props) {
209
210
  {...testProps('ancillary-' + type)}
210
211
  selectorId={selectorId}
211
212
  selectorSelected={selectorSelected || record}
213
+ selectorSelectedField={selectorSelectedField}
212
214
  flex={1}
213
215
  h={350}
214
216
  canEditorViewOnly={true}
@@ -94,6 +94,7 @@ function AttachmentsElement(props) {
94
94
 
95
95
  // parentContainer
96
96
  selectorSelected,
97
+ selectorSelectedField = 'id',
97
98
 
98
99
  // withData
99
100
  Repository,
@@ -105,7 +106,7 @@ function AttachmentsElement(props) {
105
106
  } = props,
106
107
  styles = UiGlobals.styles,
107
108
  model = _.isArray(selectorSelected) && selectorSelected[0] ? selectorSelected[0].repository?.name : selectorSelected?.repository?.name,
108
- modelidCalc = _.isArray(selectorSelected) ? _.map(selectorSelected, (entity) => entity.id) : selectorSelected?.id,
109
+ modelidCalc = _.isArray(selectorSelected) ? _.map(selectorSelected, (entity) => entity[selectorSelectedField]) : selectorSelected?.[selectorSelectedField],
109
110
  modelid = useRef(modelidCalc),
110
111
  [isReady, setIsReady] = useState(false),
111
112
  [isUploading, setIsUploading] = useState(false),