@onehat/ui 0.3.18 → 0.3.21

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.18",
3
+ "version": "0.3.21",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -7,6 +7,7 @@ import {
7
7
  import {
8
8
  VERTICAL,
9
9
  } from '../../Constants/Directions.js';
10
+ import getComponentFromType from '../../Functions/getComponentFromType.js';
10
11
  import UiGlobals from '../../UiGlobals.js';
11
12
  import withDraggable from '../Hoc/withDraggable.js';
12
13
  import AngleRight from '../Icons/AngleRight.js';
@@ -25,10 +26,17 @@ export default function GridRow(props) {
25
26
  item,
26
27
  isInlineEditorShown,
27
28
  } = props,
28
- styles = UiGlobals.styles,
29
+ styles = UiGlobals.styles;
30
+
31
+ if (item.isDestroyed) {
32
+ return null;
33
+ }
34
+
35
+ const
29
36
  isPhantom = item.isPhantom,
30
37
  hash = item?.hash || item;
31
38
 
39
+
32
40
  return useMemo(() => {
33
41
  const renderColumns = (item) => {
34
42
  if (_.isArray(columnsConfig)) {
@@ -86,9 +94,30 @@ export default function GridRow(props) {
86
94
  return <Row key={key} {...propsToPass} {...extraProps}>{config.renderer(item)}</Row>;
87
95
  }
88
96
  if (config.fieldName) {
89
- if (item.properties && item.properties[config.fieldName]) {
90
- const property = item.properties[config.fieldName];
97
+ if (item?.properties && item.properties[config.fieldName]) {
98
+ const property = item.properties[config.fieldName];
91
99
  value = property.displayValue;
100
+
101
+ if (property?.viewerType?.type) {
102
+ const Element = getComponentFromType(property?.viewerType?.type);
103
+ return <Element
104
+ value={value}
105
+ key={key}
106
+ overflow="hidden"
107
+ textOverflow="ellipsis"
108
+ alignSelf="center"
109
+ style={{
110
+ userSelect: 'none',
111
+ }}
112
+ fontSize={styles.GRID_CELL_FONTSIZE}
113
+ px={styles.GRID_CELL_PX}
114
+ py={styles.GRID_CELL_PY}
115
+ numberOfLines={1}
116
+ ellipsizeMode="head"
117
+ {...propsToPass}
118
+ {...propsToPass}
119
+ />;
120
+ }
92
121
  } else if (item[config.fieldName]) {
93
122
  value = item[config.fieldName];
94
123
  } else if (fields) {
@@ -121,6 +121,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
121
121
  }
122
122
  },
123
123
  onEdit = async () => {
124
+ if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
125
+ return;
126
+ }
124
127
  if (getListeners().onBeforeEdit) {
125
128
  const listenerResult = await getListeners().onBeforeEdit();
126
129
  if (listenerResult === false) {
@@ -132,6 +135,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
132
135
  setIsEditorShown(true);
133
136
  },
134
137
  onDelete = async (cb) => {
138
+ if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
139
+ return;
140
+ }
135
141
  if (getListeners().onBeforeDelete) {
136
142
  const listenerResult = await getListeners().onBeforeDelete();
137
143
  if (listenerResult === false) {
@@ -165,7 +171,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
165
171
  deleteRecord(cb);
166
172
  } else {
167
173
  const identifier = getRecordIdentifier(selection);
168
- confirm('Are you sure you want to delete the ' + identifier, () => deleteRecord(cb));
174
+ confirm('Are you sure you want to delete the ' + identifier, () => deleteRecord(null, cb));
169
175
  }
170
176
  },
171
177
  onMoveChildren = (cb) => {
@@ -268,7 +274,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
268
274
  async function doIt() {
269
275
  const
270
276
  isSingle = selection.length === 1,
271
- isPhantom = selection[0] && selection[0].isPhantom;
277
+ isPhantom = selection[0] && !selection[0]?.isDestroyed && selection[0].isPhantom;
272
278
  if (isSingle && isPhantom) {
273
279
  await deleteRecord();
274
280
  }
@@ -301,7 +307,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
301
307
  // For multiple entities selected, change it to edit multiple mode
302
308
  mode = EDITOR_MODE__EDIT;
303
309
  }
304
- } else if (selection.length === 1 && selection[0].isPhantom) {
310
+ } else if (selection.length === 1 && !selection[0].isDestroyed && selection[0].isPhantom) {
305
311
  if (!disableAdd) {
306
312
  // When a phantom entity is selected, change it to add mode.
307
313
  mode = EDITOR_MODE__ADD;
@@ -354,12 +360,12 @@ export default function withEditor(WrappedComponent, isTree = false) {
354
360
  setIsEditorShown={setIsEditorShown}
355
361
  onAdd={(!userCanEdit || disableAdd) ? null : onAdd}
356
362
  onEdit={(!userCanEdit || disableEdit) ? null : onEdit}
357
- onDelete={(!userCanEdit || disableDelete || (editorMode === EDITOR_MODE__ADD && (selection[0]?.isPhantom || currentRecord?.isPhantom))) ? null : onDelete}
363
+ onDelete={(!userCanEdit || disableDelete) ? null : onDelete}
358
364
  onView={viewRecord}
359
365
  onDuplicate={duplicateRecord}
360
366
  onEditorSave={onEditorSave}
361
367
  onEditorCancel={onEditorCancel}
362
- onEditorDelete={(!userCanEdit || disableDelete || (editorMode === EDITOR_MODE__ADD && (selection[0]?.isPhantom || currentRecord?.isPhantom))) ? null : onEditorDelete}
368
+ onEditorDelete={(!userCanEdit || disableDelete) ? null : onEditorDelete}
363
369
  onEditorClose={onEditorClose}
364
370
  setWithEditListeners={setListeners}
365
371
  isEditor={true}
@@ -80,13 +80,12 @@ export default function withFilters(WrappedComponent) {
80
80
  if (propertyDef) {
81
81
  title = propertyDef.title;
82
82
  type = propertyDef.filterType;
83
- } else {
84
- if (!modelFilterTypes[field]) {
85
- throw Error('not a propertyDef, and not an ancillaryFilter!');
86
- }
83
+ } else if (modelAncillaryFilters[field]) {
87
84
  const ancillaryFilter = modelFilterTypes[field];
88
85
  title = ancillaryFilter.title;
89
86
  type = FILTER_TYPE_ANCILLARY;
87
+ } else {
88
+ throw Error('not a propertyDef, and not an ancillaryFilter!');
90
89
  }
91
90
  formatted = {
92
91
  field,
@@ -330,6 +329,7 @@ export default function withFilters(WrappedComponent) {
330
329
  const {
331
330
  field,
332
331
  value,
332
+ type,
333
333
  } = filter,
334
334
  isFilterRange = getIsFilterRange(filter);
335
335
  if (isFilterRange) {
@@ -345,8 +345,11 @@ export default function withFilters(WrappedComponent) {
345
345
  newRepoFilters.push({ name: lowField, value: lowValue, });
346
346
  }
347
347
  } else {
348
- newFilterNames.push(field);
349
- newRepoFilters.push({ name: field, value, });
348
+ const
349
+ isAncillary = type === FILTER_TYPE_ANCILLARY,
350
+ filterName = (isAncillary ? 'ancillary___' : '') + field;
351
+ newFilterNames.push(filterName);
352
+ newRepoFilters.push({ name: filterName, value, });
350
353
  }
351
354
  });
352
355
 
@@ -421,7 +424,7 @@ export default function withFilters(WrappedComponent) {
421
424
  _.each(modalSlots, (field, ix) => {
422
425
 
423
426
  // Create the data for the combobox. (i.e. List all the possible filters for this slot)
424
- const data = [];
427
+ let data = [];
425
428
  _.each(modelFilterTypes, (filterType, filterField) => {
426
429
  if (inArray(filterField, usedFields) && field !== filterField) { // Show all filters not yet applied, but include the current filter
427
430
  return; // skip, since it's already been used
@@ -430,7 +433,7 @@ export default function withFilters(WrappedComponent) {
430
433
  // Is it an ancillary filter?
431
434
  const isAncillary = _.isPlainObject(filterType) && filterType.isAncillary;
432
435
  if (isAncillary) {
433
- data.push([ filterField, filterType.title ]);
436
+ data.push([ filterField, filterType.title + ' •' ]);
434
437
  return;
435
438
  }
436
439
 
@@ -439,6 +442,9 @@ export default function withFilters(WrappedComponent) {
439
442
  data.push([ filterField, propertyDef.title ]);
440
443
  });
441
444
 
445
+ // sort by title
446
+ data = _.sortBy(data, [function(datum) { return datum[1]; }]);
447
+
442
448
  const
443
449
  ixPlusOne = (ix +1),
444
450
  filterName = 'filter' + ixPlusOne;
@@ -143,7 +143,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
143
143
  if (selectorId && !selectorSelected) {
144
144
  isDisabled = true;
145
145
  }
146
- if (_.isEmpty(selection)) {
146
+ if (_.isEmpty(selection) || (_.isArray(selection) && selection.length > 1)) {
147
147
  isDisabled = true;
148
148
  }
149
149
  break;
@@ -154,7 +154,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
154
154
  if (selectorId && !selectorSelected) {
155
155
  isDisabled = true;
156
156
  }
157
- if (_.isEmpty(selection) || selection.length > 1) {
157
+ if (_.isEmpty(selection) || (_.isArray(selection) && selection.length > 1)) {
158
158
  isDisabled = true;
159
159
  }
160
160
  break;
@@ -0,0 +1,28 @@
1
+ import {
2
+ Text,
3
+ } from 'native-base';
4
+ import UiGlobals from '../../UiGlobals.js';
5
+ import _ from 'lodash';
6
+
7
+ function TagViewer(props) {
8
+ const {
9
+ value,
10
+ } = props,
11
+ parsedValue = value ? JSON.parse(value) : null,
12
+ values = parsedValue ? _.map(parsedValue, (val) => {
13
+ const ret = val?.text;
14
+ return ret;
15
+ }).join(', ') : [],
16
+ styles = UiGlobals.styles;
17
+
18
+ return <Text
19
+ numberOfLines={1}
20
+ ellipsizeMode="head"
21
+ // fontSize={styles.FORM_TEXT_FONTSIZE}
22
+ // minHeight='40px'
23
+ // px={3}
24
+ // py={2}
25
+ {...props}
26
+ >{values}</Text>;
27
+ }
28
+ export default TagViewer;
@@ -38,6 +38,7 @@ import PlusMinusButton from './Buttons/PlusMinusButton.js';
38
38
  import RadioGroup from './Form/Field/RadioGroup/RadioGroup.js';
39
39
  import TabPanel from './Panel/TabPanel.js';
40
40
  import Tag from './Form/Field/Combo/Tag.js';
41
+ import TagViewer from './Viewer/TagViewer.js';
41
42
  import TextArea from './Form/Field/TextArea.js';
42
43
  import Text from './Form/Field/Text.js';
43
44
  import TimezonesCombo from './Form/Field/Combo/TimezonesCombo.js';
@@ -87,6 +88,7 @@ const components = {
87
88
  RadioGroup,
88
89
  TabPanel,
89
90
  Tag,
91
+ TagViewer,
90
92
  Text,
91
93
  TextArea,
92
94
  TimezonesCombo,
File without changes