@evoke-platform/ui-components 1.4.0-testing.9 → 1.5.0-testing.0

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.
@@ -21,7 +21,7 @@ const DatePicker = (props) => {
21
21
  if (newValue instanceof Error) {
22
22
  newValue = new InvalidDate(keyboardInputValue);
23
23
  }
24
- handleChange(newValue, keyboardInputValue);
24
+ handleChange(newValue instanceof InvalidDate || newValue === null ? newValue : LocalDate.from(newValue), keyboardInputValue);
25
25
  };
26
26
  return (React.createElement(UIThemeProvider, null,
27
27
  React.createElement(MUIDatePicker, { value: value, onChange: onChange, renderInput: (params) => React.createElement(TextField, { ...params }), PaperProps: {
@@ -48,6 +48,8 @@ export { Typography } from './Typography';
48
48
  export { TabContext, TabList, TabPanel, TreeItem, TreeView } from '@mui/lab';
49
49
  export { CardActionArea, CardActions, CardContent, CardHeader, CardMedia, Input, InputAdornment, InputLabel, ListItemButton, ListItemText, SvgIcon, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TableSortLabel, } from '@mui/material';
50
50
  export { useGridApiRef } from '@mui/x-data-grid';
51
+ export { TreeItem as RichTreeItem, RichTreeView } from '@mui/x-tree-view';
51
52
  export type { GridSize } from '@mui/material';
52
- export type { GridCellParams, GridColDef, GridEventListener, GridFilterModel, GridInitialState, GridRowParams, GridValueFormatterParams, GridValueGetterParams, } from '@mui/x-data-grid';
53
+ export type { GridCellParams, GridColDef, GridEventListener, GridFilterModel, GridInitialState, GridRowParams, GridSortModel, GridValueFormatterParams, GridValueGetterParams, } from '@mui/x-data-grid';
54
+ export type { TreeItemProps, TreeViewBaseItem } from '@mui/x-tree-view';
53
55
  export type { AutocompleteOption } from './Autocomplete/Autocomplete';
@@ -49,3 +49,4 @@ export { Typography } from './Typography';
49
49
  export { TabContext, TabList, TabPanel, TreeItem, TreeView } from '@mui/lab';
50
50
  export { CardActionArea, CardActions, CardContent, CardHeader, CardMedia, Input, InputAdornment, InputLabel, ListItemButton, ListItemText, SvgIcon, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TableSortLabel, } from '@mui/material';
51
51
  export { useGridApiRef } from '@mui/x-data-grid';
52
+ export { TreeItem as RichTreeItem, RichTreeView } from '@mui/x-tree-view';
@@ -170,7 +170,7 @@ const customSelector = (props) => {
170
170
  break;
171
171
  case 'Fields':
172
172
  placeholder = 'Select Property';
173
- width = '33%';
173
+ width = '37%';
174
174
  val = options.find((option) => option.name === val)?.name;
175
175
  break;
176
176
  }
@@ -266,22 +266,7 @@ export const valueEditor = (props) => {
266
266
  };
267
267
  const CriteriaBuilder = (props) => {
268
268
  const { properties, criteria, setCriteria, originalCriteria, enablePresetValues, presetValues, operators, disabled, disabledCriteria, hideBorder, presetGroupLabel, customValueEditor, treeViewOpts, disableRegexEscapeChars, } = props;
269
- const [query, setQuery] = useState(undefined);
270
269
  const [propertyTreeMap, setPropertyTreeMap] = useState();
271
- useEffect(() => {
272
- if (criteria || originalCriteria) {
273
- const criteriaToParse = criteria || originalCriteria || {};
274
- const updatedQuery = parseMongoDB(criteriaToParse);
275
- !isEmpty(treeViewOpts) && updatePropertyTreeMap(updatedQuery);
276
- setQuery({
277
- ...updatedQuery,
278
- rules: processRules(updatedQuery.rules, true),
279
- });
280
- }
281
- else {
282
- setQuery({ combinator: 'and', rules: [] });
283
- }
284
- }, [originalCriteria]);
285
270
  const processRules = (rules, isSavedValue) => {
286
271
  return rules.map((rule) => {
287
272
  if ('rules' in rule) {
@@ -293,13 +278,7 @@ const CriteriaBuilder = (props) => {
293
278
  else {
294
279
  const propertyType = properties.find((property) => property.id === rule.field)?.type;
295
280
  let adjustedValue = rule.value;
296
- if ((propertyType === 'array' ||
297
- ((propertyType === 'string' || propertyType === 'richText') &&
298
- (rule.operator === 'in' || rule.operator === 'notIn'))) &&
299
- isSavedValue) {
300
- adjustedValue = rule.value?.split(',');
301
- }
302
- else if ((rule.operator === 'null' || rule.operator === 'notNull') && rule.value) {
281
+ if ((rule.operator === 'null' || rule.operator === 'notNull') && rule.value) {
303
282
  adjustedValue = null;
304
283
  }
305
284
  return {
@@ -310,31 +289,67 @@ const CriteriaBuilder = (props) => {
310
289
  }
311
290
  });
312
291
  };
313
- // this retrieves the properties from a treeview for each property in the query
314
- // they are then used in the custom query builder components to determine the input type etc
315
- const updatePropertyTreeMap = (q) => {
316
- const ids = [];
317
- const traverseRulesForIds = (rules) => {
318
- rules.forEach((rule) => {
319
- if ('rules' in rule) {
320
- traverseRulesForIds(rule.rules);
321
- }
322
- else {
323
- ids.push(rule.field);
292
+ useEffect(() => {
293
+ if ((criteria || originalCriteria) &&
294
+ !isEmpty(treeViewOpts) &&
295
+ treeViewOpts.object &&
296
+ treeViewOpts.fetchObject) {
297
+ const { object, fetchObject } = treeViewOpts;
298
+ // this retrieves the properties from a treeview for each property in the query
299
+ // they are then used in the custom query builder components to determine the input type etc
300
+ const updatePropertyTreeMap = async () => {
301
+ const newQuery = parseMongoDB(criteria || originalCriteria || {});
302
+ const ids = [];
303
+ const traverseRulesForIds = (rules) => {
304
+ rules.forEach((rule) => {
305
+ if ('rules' in rule) {
306
+ traverseRulesForIds(rule.rules);
307
+ }
308
+ else {
309
+ ids.push(rule.field);
310
+ }
311
+ });
312
+ };
313
+ traverseRulesForIds(newQuery.rules);
314
+ let newPropertyTreeMap = {};
315
+ const newPropertyTreeMapPromises = [];
316
+ for (const id of ids) {
317
+ if (!propertyTreeMap?.[id]) {
318
+ newPropertyTreeMapPromises.push(traversePropertyPath(id, object, fetchObject)
319
+ .then((property) => {
320
+ if (property) {
321
+ return {
322
+ [id]: property,
323
+ };
324
+ }
325
+ return {};
326
+ })
327
+ .catch((err) => {
328
+ console.error(err);
329
+ return {};
330
+ }));
331
+ }
324
332
  }
325
- });
326
- };
327
- traverseRulesForIds(q.rules);
328
- const tempPropertyMap = { ...propertyTreeMap };
329
- ids.forEach(async (id) => {
330
- if (!propertyTreeMap?.[id] && treeViewOpts?.object && treeViewOpts?.fetchObject) {
331
- const prop = await traversePropertyPath(id, treeViewOpts?.object, treeViewOpts?.fetchObject);
332
- if (prop)
333
- tempPropertyMap[id] = prop;
333
+ newPropertyTreeMap = (await Promise.all(newPropertyTreeMapPromises)).reduce((acc, currentProperty) => ({ ...acc, ...currentProperty }), {});
334
+ setPropertyTreeMap((prevPropertyTreeMap) => ({
335
+ ...prevPropertyTreeMap,
336
+ ...newPropertyTreeMap,
337
+ }));
338
+ };
339
+ updatePropertyTreeMap().catch((err) => console.error(err));
340
+ }
341
+ }, [criteria, originalCriteria, treeViewOpts]);
342
+ const initializeQuery = () => {
343
+ const criteriaToParse = criteria || originalCriteria;
344
+ const updatedQuery = criteriaToParse ? parseMongoDB(criteriaToParse || {}) : undefined;
345
+ return updatedQuery
346
+ ? {
347
+ ...updatedQuery,
348
+ rules: processRules(updatedQuery.rules, true),
334
349
  }
335
- setPropertyTreeMap(tempPropertyMap);
336
- });
350
+ : { combinator: 'and', rules: [] };
337
351
  };
352
+ const [query, setQuery] = useState(initializeQuery);
338
353
  const handleClearAll = () => {
339
354
  handleQueryChange({ combinator: 'and', rules: [] });
340
355
  };
@@ -509,7 +524,7 @@ const CriteriaBuilder = (props) => {
509
524
  justifyContent: 'space-between',
510
525
  alignItems: 'center',
511
526
  marginBottom: '10px',
512
- maxWidth: '71vw',
527
+ width: '100%',
513
528
  } },
514
529
  React.createElement(Box, null,
515
530
  React.createElement(Button, { sx: {
@@ -102,7 +102,7 @@ const PropertyTree = ({ fetchObject, handleTreePropertySelect, rootObject, value
102
102
  }
103
103
  };
104
104
  return (React.createElement(Autocomplete, { "aria-label": "Property Selector", value: value, fullWidth: true, sx: {
105
- width: '33%',
105
+ width: '37%',
106
106
  }, disableClearable: true, options: propertyOptions.map((property) => {
107
107
  return {
108
108
  label: objectPropertyNamePathMap[property.id],
@@ -27,10 +27,7 @@ const ValueEditor = (props) => {
27
27
  if (!!context.treeViewOpts && !!property) {
28
28
  inputType = property.type;
29
29
  if (property.enum) {
30
- values = property.enum.map((item) => ({
31
- name: item,
32
- label: item,
33
- }));
30
+ values = property.enum.map((item) => ({ name: item, label: item }));
34
31
  }
35
32
  }
36
33
  const [invalidDateTime, setInvalidDateTime] = useState(false);
@@ -42,8 +39,8 @@ const ValueEditor = (props) => {
42
39
  const disabled = ['null', 'notNull'].includes(operator);
43
40
  const presetValues = context.presetValues?.filter((val) => !val.type || val.type === inputType) ?? [];
44
41
  const isPresetValue = (value) => value?.startsWith('{{{') && value?.endsWith('}}}');
45
- const isPresetValueSelected = presetValues && typeof value === 'string' && isPresetValue(value);
46
- const presetDisplayValue = presetValues?.find((option) => option.value.name === value)?.label ?? '';
42
+ const presetDisplayValue = presetValues?.find((option) => option.value.name === value)?.label;
43
+ const isPresetValueSelected = presetValues && typeof value === 'string' && isPresetValue(value) && !!presetDisplayValue;
47
44
  let readOnly = context.disabled;
48
45
  if (!readOnly && context.disabledCriteria) {
49
46
  readOnly =
@@ -54,9 +51,7 @@ const ValueEditor = (props) => {
54
51
  width: '33%',
55
52
  background: readOnly ? '#f4f6f8' : '#fff',
56
53
  borderRadius: '8px',
57
- '& .MuiAutocomplete-tag': {
58
- backgroundColor: '#edeff1',
59
- },
54
+ '& .MuiAutocomplete-tag': { backgroundColor: '#edeff1' },
60
55
  },
61
56
  };
62
57
  useEffect(() => {
@@ -181,9 +176,7 @@ const ValueEditor = (props) => {
181
176
  console.error('Error processing date value:', error);
182
177
  setInvalidDateTime(true);
183
178
  }
184
- }, onClose: onClose, PopperProps: {
185
- anchorEl,
186
- }, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
179
+ }, onClose: onClose, PopperProps: { anchorEl }, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
187
180
  React.createElement(TextField, { ...params, disabled: disabled, onClick: onClick, placeholder: "Value", size: "small", inputRef: inputRef, error: invalidDateTime }))), readOnly: readOnly })));
188
181
  }
189
182
  else if (inputType === 'number' || inputType === 'integer') {
@@ -246,14 +246,14 @@ export function parseMongoDB(mongoQuery) {
246
246
  return {
247
247
  field: key,
248
248
  operator: 'in',
249
- value: (value.$in || []).join(','),
249
+ value: value.$in ?? [],
250
250
  };
251
251
  }
252
252
  else if ('$nin' in value) {
253
253
  return {
254
254
  field: key,
255
255
  operator: 'notIn',
256
- value: (value.$nin || []).join(','),
256
+ value: value.$nin ?? [],
257
257
  };
258
258
  }
259
259
  else {
@@ -18,7 +18,58 @@ export const Criteria = (props) => {
18
18
  setLoadingError(true);
19
19
  }
20
20
  if (properties) {
21
- setProperties(properties);
21
+ const flattenProperties = properties.flatMap((prop) => {
22
+ if (prop.type === 'object' || prop.type === 'user') {
23
+ return [
24
+ {
25
+ id: `${prop.id}.id`,
26
+ name: `${prop.name} Id`,
27
+ type: 'string',
28
+ },
29
+ {
30
+ id: `${prop.id}.name`,
31
+ name: `${prop.name} Name`,
32
+ type: 'string',
33
+ },
34
+ ];
35
+ }
36
+ else if (prop.type === 'address') {
37
+ return [
38
+ {
39
+ id: `${prop.id}.line1`,
40
+ name: `${prop.name} Line 1`,
41
+ type: 'string',
42
+ },
43
+ {
44
+ id: `${prop.id}.line2`,
45
+ name: `${prop.name} Line 2`,
46
+ type: 'string',
47
+ },
48
+ {
49
+ id: `${prop.id}.city`,
50
+ name: `${prop.name} City`,
51
+ type: 'string',
52
+ },
53
+ {
54
+ id: `${prop.id}.county`,
55
+ name: `${prop.name} County`,
56
+ type: 'string',
57
+ },
58
+ {
59
+ id: `${prop.id}.state`,
60
+ name: `${prop.name} State`,
61
+ type: 'string',
62
+ },
63
+ {
64
+ id: `${prop.id}.zipCode`,
65
+ name: `${prop.name} Zip Code`,
66
+ type: 'string',
67
+ },
68
+ ];
69
+ }
70
+ return prop;
71
+ });
72
+ setProperties(flattenProperties);
22
73
  setLoadingError(false);
23
74
  }
24
75
  setLoading(false);
@@ -71,7 +71,7 @@ export class ObjectComponent extends ReactComponent {
71
71
  }
72
72
  this.updatedCriteria = updateCriteriaInputs(this.criteria ?? {}, data, this.component.user);
73
73
  if (this.visible) {
74
- this.attachReact(this.element);
74
+ this.attach(this.element);
75
75
  }
76
76
  });
77
77
  }
@@ -115,7 +115,7 @@ export class ObjectComponent extends ReactComponent {
115
115
  }
116
116
  this.updatedDefaultValueCriteria = updateCriteriaInputs(this.defaultValueCriteria ?? {}, data, this.component.user);
117
117
  if (this.visible) {
118
- this.attachReact(this.element);
118
+ this.attach(this.element);
119
119
  }
120
120
  });
121
121
  }
@@ -158,7 +158,6 @@ export class ObjectComponent extends ReactComponent {
158
158
  delete this.errorDetails['api-error'];
159
159
  }
160
160
  this.attach(this.element);
161
- this.attachReact(this.element);
162
161
  });
163
162
  if (this.component.defaultValue) {
164
163
  this.expandInstance();
@@ -216,11 +215,16 @@ export class ObjectComponent extends ReactComponent {
216
215
  if (!root) {
217
216
  root = element;
218
217
  }
218
+ let updatedValue;
219
+ if (this.shouldSetValue)
220
+ updatedValue = this.dataForSetting;
221
+ else
222
+ updatedValue = this.dataValue;
219
223
  const updatedComponent = {
220
224
  ...this.component,
221
225
  instance: {
222
226
  ...this.component.instance,
223
- [this.component.key]: isEmpty(this.dataValue) ? null : this.dataValue,
227
+ [this.component.key]: isEmpty(updatedValue) || isNil(updatedValue) || updatedValue.length === 0 ? null : updatedValue,
224
228
  },
225
229
  defaultValueCriteria: this.updatedDefaultValueCriteria,
226
230
  };
@@ -719,7 +719,7 @@ formComponents, allCriteriaInputs, instance, objectPropertyInputProps, associate
719
719
  // Set the associated instance as a default value and hide the field.
720
720
  if (associatedObject?.instanceId &&
721
721
  associatedObject?.propertyId &&
722
- item.property.id === associatedObject.propertyId) {
722
+ item.property?.id === associatedObject.propertyId) {
723
723
  item.defaultValue = { id: associatedObject.instanceId };
724
724
  item.hidden = true;
725
725
  // If "conditional" is defined, the "hidden" property isn't respected.
@@ -23,7 +23,7 @@ const DisplayedProperty = (props) => {
23
23
  return stringAddress;
24
24
  };
25
25
  const formatData = (property, value) => {
26
- if (property?.objectId && property?.type === 'object') {
26
+ if (property?.objectId && (property?.type === 'object' || property?.type === 'collection')) {
27
27
  return value?.name ?? value?.id;
28
28
  }
29
29
  switch (property?.type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evoke-platform/ui-components",
3
- "version": "1.4.0-testing.9",
3
+ "version": "1.5.0-testing.0",
4
4
  "description": "",
5
5
  "main": "dist/published/index.js",
6
6
  "module": "dist/published/index.js",
@@ -84,6 +84,7 @@
84
84
  "webpack": "^5.74.0"
85
85
  },
86
86
  "peerDependencies": {
87
+ "@evoke-platform/context": "^1.1.0-testing.5",
87
88
  "react": "^18.1.0",
88
89
  "react-dom": "^18.1.0"
89
90
  },
@@ -94,7 +95,6 @@
94
95
  "@dnd-kit/sortable": "^7.0.1",
95
96
  "@emotion/react": "^11.13.5",
96
97
  "@emotion/styled": "^11.8.1",
97
- "@evoke-platform/context": "^1.1.0-testing.4",
98
98
  "@formio/react": "^5.2.4-rc.1",
99
99
  "@js-joda/core": "^3.2.0",
100
100
  "@js-joda/locale_en-us": "^3.2.2",
@@ -103,6 +103,7 @@
103
103
  "@mui/material": "^5.16.7",
104
104
  "@mui/x-data-grid": "^6.4.0",
105
105
  "@mui/x-date-pickers": "^5.0.13",
106
+ "@mui/x-tree-view": "^7.29.1",
106
107
  "@react-querybuilder/dnd": "^5.4.1",
107
108
  "@react-querybuilder/material": "^6.5.0",
108
109
  "clean-deep": "^3.4.0",