@evoke-platform/ui-components 1.4.0-testing.8 → 1.4.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: {
@@ -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);
@@ -22,7 +22,6 @@ export class ObjectComponent extends ReactComponent {
22
22
  this.handleValidation();
23
23
  this.emit('changed-' + this.component.key, value);
24
24
  this.attach(this.element);
25
- this.attachReact(this.element);
26
25
  this.component.autoSave && this.component.autoSave({ [key]: updatedValue });
27
26
  };
28
27
  this.errorDetails = {};
@@ -72,7 +71,7 @@ export class ObjectComponent extends ReactComponent {
72
71
  }
73
72
  this.updatedCriteria = updateCriteriaInputs(this.criteria ?? {}, data, this.component.user);
74
73
  if (this.visible) {
75
- this.attachReact(this.element);
74
+ this.attach(this.element);
76
75
  }
77
76
  });
78
77
  }
@@ -116,7 +115,7 @@ export class ObjectComponent extends ReactComponent {
116
115
  }
117
116
  this.updatedDefaultValueCriteria = updateCriteriaInputs(this.defaultValueCriteria ?? {}, data, this.component.user);
118
117
  if (this.visible) {
119
- this.attachReact(this.element);
118
+ this.attach(this.element);
120
119
  }
121
120
  });
122
121
  }
@@ -159,7 +158,6 @@ export class ObjectComponent extends ReactComponent {
159
158
  delete this.errorDetails['api-error'];
160
159
  }
161
160
  this.attach(this.element);
162
- this.attachReact(this.element);
163
161
  });
164
162
  if (this.component.defaultValue) {
165
163
  this.expandInstance();
@@ -217,11 +215,16 @@ export class ObjectComponent extends ReactComponent {
217
215
  if (!root) {
218
216
  root = element;
219
217
  }
218
+ let updatedValue;
219
+ if (this.shouldSetValue)
220
+ updatedValue = this.dataForSetting;
221
+ else
222
+ updatedValue = this.dataValue;
220
223
  const updatedComponent = {
221
224
  ...this.component,
222
225
  instance: {
223
226
  ...this.component.instance,
224
- [this.component.key]: isEmpty(this.dataValue) ? null : this.dataValue,
227
+ [this.component.key]: isEmpty(updatedValue) || isNil(updatedValue) || updatedValue.length === 0 ? null : updatedValue,
225
228
  },
226
229
  defaultValueCriteria: this.updatedDefaultValueCriteria,
227
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.8",
3
+ "version": "1.4.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",