@evoke-platform/ui-components 1.15.0 → 1.16.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.
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.d.ts +8 -4
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +242 -142
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +189 -67
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.d.ts +6 -6
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +12 -25
- package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.d.ts +4 -5
- package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.js +34 -22
- package/dist/published/components/custom/CriteriaBuilder/types.d.ts +2 -11
- package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +6 -34
- package/dist/published/components/custom/CriteriaBuilder/utils.js +18 -89
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +1 -1
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js +6 -3
- package/dist/published/components/custom/Form/utils.d.ts +1 -0
- package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -1
- package/dist/published/components/custom/FormV2/FormRenderer.js +2 -8
- package/dist/published/components/custom/FormV2/FormRendererContainer.d.ts +4 -0
- package/dist/published/components/custom/FormV2/FormRendererContainer.js +229 -126
- package/dist/published/components/custom/FormV2/components/DefaultValues.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/DefaultValues.js +60 -89
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/FormContext.js +0 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +43 -16
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +3 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.d.ts +3 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +44 -11
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +4 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +41 -29
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/FileContent.d.ts +12 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/FileContent.js +197 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +2 -4
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/InstanceLookup.js +14 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +6 -2
- package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +16 -13
- package/dist/published/components/custom/FormV2/components/types.d.ts +6 -1
- package/dist/published/components/custom/FormV2/components/utils.d.ts +10 -8
- package/dist/published/components/custom/FormV2/components/utils.js +168 -82
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +6 -1
- package/dist/published/components/custom/index.d.ts +1 -0
- package/dist/published/index.d.ts +1 -1
- package/dist/published/stories/CriteriaBuilder.stories.js +70 -22
- package/dist/published/stories/FormRenderer.stories.d.ts +6 -3
- package/dist/published/stories/FormRendererContainer.stories.d.ts +20 -0
- package/dist/published/theme/hooks.d.ts +3 -3
- package/package.json +3 -1
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { Property } from '@evoke-platform/context';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import 'react-querybuilder/dist/query-builder.css';
|
|
3
|
-
import {
|
|
4
|
-
import { ObjectProperty, Operator, PresetValue, TreeViewObject } from './types';
|
|
4
|
+
import { Operator, PresetValue, TreeViewObject } from './types';
|
|
5
5
|
import { ValueEditorProps } from './ValueEditor';
|
|
6
6
|
export type CriteriaInputProps = {
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The ability to input free text for property selection.
|
|
9
|
+
*/
|
|
10
|
+
propertyFreeSolo?: boolean;
|
|
11
|
+
properties: Property[];
|
|
8
12
|
setCriteria: (criteria?: Record<string, unknown> | undefined) => void;
|
|
9
13
|
criteria?: Record<string, unknown>;
|
|
10
14
|
originalCriteria?: Record<string, unknown>;
|
|
@@ -23,7 +27,7 @@ export type CriteriaInputProps = {
|
|
|
23
27
|
hideBorder?: boolean;
|
|
24
28
|
presetGroupLabel?: string;
|
|
25
29
|
treeViewOpts?: {
|
|
26
|
-
fetchObject?: (objectId: string) => Promise<
|
|
30
|
+
fetchObject?: (objectId: string) => Promise<TreeViewObject | undefined>;
|
|
27
31
|
object: TreeViewObject;
|
|
28
32
|
};
|
|
29
33
|
/**
|
|
@@ -11,7 +11,7 @@ import { Box } from '../../layout';
|
|
|
11
11
|
import { OverflowTextField } from '../OverflowTextField';
|
|
12
12
|
import { difference, parseMongoDB } from '../util';
|
|
13
13
|
import PropertyTree from './PropertyTree';
|
|
14
|
-
import { ALL_OPERATORS
|
|
14
|
+
import { ALL_OPERATORS } from './utils';
|
|
15
15
|
import ValueEditor from './ValueEditor';
|
|
16
16
|
const styles = {
|
|
17
17
|
buttons: {
|
|
@@ -88,99 +88,114 @@ const customButton = (props) => {
|
|
|
88
88
|
},
|
|
89
89
|
} }, buttonLabel))));
|
|
90
90
|
};
|
|
91
|
-
const
|
|
92
|
-
const { options, value, handleOnChange,
|
|
91
|
+
const customOperatorSelector = (props) => {
|
|
92
|
+
const { options, value, handleOnChange, context, level } = props;
|
|
93
93
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
94
94
|
const rule = props.rule;
|
|
95
|
-
let width = '90px';
|
|
96
95
|
let val = value;
|
|
97
96
|
let opts = options;
|
|
97
|
+
const placeholder = 'Select Operator';
|
|
98
|
+
const width = '25%';
|
|
98
99
|
let inputType = props.fieldData?.inputType;
|
|
99
100
|
// for tree view / related object properties, the properties are stored in the propertyTreeMap upon selection
|
|
100
101
|
if (!!context.treeViewOpts && !!context.propertyTreeMap?.[rule.field]) {
|
|
101
102
|
inputType = context.propertyTreeMap[rule.field].type;
|
|
102
103
|
}
|
|
103
|
-
const isTreeViewEnabled = context.treeViewOpts && title === 'Fields';
|
|
104
|
-
const fetchObject = context.treeViewOpts?.fetchObject;
|
|
105
|
-
const object = context.treeViewOpts?.object;
|
|
106
104
|
let readOnly = context.disabled;
|
|
107
105
|
if (!readOnly && context.disabledCriteria) {
|
|
108
106
|
readOnly =
|
|
109
107
|
Object.entries(context.disabledCriteria.criteria).some(([key, value]) => key === rule.field && value === rule.value && rule.operator === '=') && level === context.disabledCriteria.level;
|
|
110
|
-
const keys = Object.keys(context.disabledCriteria.criteria);
|
|
111
|
-
if (title === 'Fields') {
|
|
112
|
-
opts = opts.filter((o) => readOnly || !keys.includes(o.name));
|
|
113
|
-
}
|
|
114
108
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
109
|
+
if (inputType === 'array') {
|
|
110
|
+
opts = options
|
|
111
|
+
.filter((option) => ['null', 'notNull', 'in'].includes(option.name))
|
|
112
|
+
.map((option) => ({ name: option.name, label: option.label }));
|
|
113
|
+
val = val === '=' ? '' : options.find((option) => option.name === val).name;
|
|
114
|
+
}
|
|
115
|
+
else if (inputType === 'document' || inputType === 'criteria') {
|
|
116
|
+
opts = options
|
|
117
|
+
.filter((option) => ['null', 'notNull'].includes(option.name))
|
|
118
|
+
.map((option) => ({ name: option.name, label: option.label }));
|
|
119
|
+
val = val === '=' ? '' : options.find((option) => option.name === val).name;
|
|
120
|
+
}
|
|
121
|
+
else if (inputType === 'date' || inputType === 'date-time' || inputType === 'time') {
|
|
122
|
+
opts = options
|
|
123
|
+
.filter((option) => ['=', '!=', '<', '>', '<=', '>=', 'null', 'notNull'].includes(option.name))
|
|
124
|
+
.map((option) => ({
|
|
125
|
+
...option,
|
|
126
|
+
label: option.name === '>'
|
|
127
|
+
? inputType === 'time'
|
|
128
|
+
? 'Later than'
|
|
129
|
+
: 'After'
|
|
130
|
+
: option.name === '>='
|
|
131
|
+
? inputType === 'time'
|
|
132
|
+
? 'Later than or at'
|
|
133
|
+
: 'After or on'
|
|
134
|
+
: option.name === '<'
|
|
138
135
|
? inputType === 'time'
|
|
139
|
-
? '
|
|
140
|
-
: '
|
|
141
|
-
: option.name === '
|
|
136
|
+
? 'Earlier than'
|
|
137
|
+
: 'Before'
|
|
138
|
+
: option.name === '<='
|
|
142
139
|
? inputType === 'time'
|
|
143
|
-
? '
|
|
144
|
-
: '
|
|
145
|
-
: option.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
140
|
+
? 'Earlier than or at'
|
|
141
|
+
: 'Before or on'
|
|
142
|
+
: option.label,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
else if (inputType === 'integer' || inputType === 'number') {
|
|
146
|
+
opts = options.filter((option) => ['=', '!=', '<', '<=', '>', '>=', 'null', 'notNull', 'in', 'notIn'].includes(option.name));
|
|
147
|
+
// checks if it is a single-select property
|
|
148
|
+
}
|
|
149
|
+
else if (inputType === 'string' && isArray(props.fieldData?.values)) {
|
|
150
|
+
opts = options.filter((option) => ['in', 'notIn', '=', '!=', 'notNull', 'null'].includes(option.name));
|
|
151
|
+
}
|
|
152
|
+
else if (inputType === 'string') {
|
|
153
|
+
opts = options.filter((option) => !['>', '<', '<=', '>='].includes(option.name));
|
|
154
|
+
}
|
|
155
|
+
else if (inputType === 'image' || inputType === 'boolean') {
|
|
156
|
+
opts = options.filter((option) => ['=', '!=', 'null', 'notNull'].includes(option.name));
|
|
157
|
+
}
|
|
158
|
+
return (React.createElement(Autocomplete, { options: opts, value: val ?? null, getOptionLabel: (option) => {
|
|
159
|
+
if (typeof option === 'string') {
|
|
160
|
+
return opts.find((o) => option === o.name)?.label || option;
|
|
162
161
|
}
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
return option.label;
|
|
163
|
+
}, getOptionKey: (option) => option.name, isOptionEqualToValue: (option, value) => {
|
|
164
|
+
if (typeof option === 'string') {
|
|
165
|
+
return option === value;
|
|
165
166
|
}
|
|
166
|
-
else
|
|
167
|
-
|
|
167
|
+
else {
|
|
168
|
+
return option.name === value;
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
},
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
+
onChange: (event, newValue) => {
|
|
173
|
+
handleOnChange(typeof newValue === 'string' ? newValue : newValue?.value.name);
|
|
174
|
+
}, renderInput: (params) => (React.createElement(OverflowTextField, { value: opts.find((o) => value === o.name)?.label || val || '', ...params, placeholder: placeholder, size: "small", inputProps: {
|
|
175
|
+
...params.inputProps,
|
|
176
|
+
'aria-label': placeholder,
|
|
177
|
+
} })), sx: { width: width, background: readOnly ? '#f4f6f8' : '#fff' }, disableClearable: true, readOnly: readOnly }));
|
|
178
|
+
};
|
|
179
|
+
const customFieldSelector = (props) => {
|
|
180
|
+
const { options, value, handleOnChange, context, level } = props;
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
const rule = props.rule;
|
|
183
|
+
const val = options.find((option) => option.name === value)?.name || value;
|
|
184
|
+
let opts = options;
|
|
185
|
+
const placeholder = 'Select Property';
|
|
186
|
+
const width = '37%';
|
|
187
|
+
const isTreeViewEnabled = context.treeViewOpts;
|
|
188
|
+
const fetchObject = context.treeViewOpts?.fetchObject;
|
|
189
|
+
const object = context.treeViewOpts?.object;
|
|
190
|
+
const setObject = context.treeViewOpts?.setObject;
|
|
191
|
+
let readOnly = context.disabled;
|
|
192
|
+
if (!readOnly && context.disabledCriteria) {
|
|
193
|
+
readOnly =
|
|
194
|
+
Object.entries(context.disabledCriteria.criteria).some(([key, value]) => key === rule.field && value === rule.value && rule.operator === '=') && level === context.disabledCriteria.level;
|
|
195
|
+
const keys = Object.keys(context.disabledCriteria.criteria);
|
|
196
|
+
opts = opts.filter((o) => readOnly || !keys.includes(o.name));
|
|
175
197
|
}
|
|
176
|
-
|
|
177
|
-
const propertyInfo = await traversePropertyPath(propertyId, object, fetchObject);
|
|
178
|
-
context.setPropertyTreeMap((prev) => {
|
|
179
|
-
return { ...prev, [propertyId]: propertyInfo };
|
|
180
|
-
});
|
|
181
|
-
handleOnChange(propertyId);
|
|
182
|
-
};
|
|
183
|
-
return (React.createElement(React.Fragment, null, isTreeViewEnabled ? (React.createElement(PropertyTree, { value: val ?? value, rootObject: object, fetchObject: fetchObject, propertyTreeMap: context.propertyTreeMap ?? {}, handleTreePropertySelect: handleTreePropertySelect })) : (React.createElement(Autocomplete, { options: opts, value: val ?? null, getOptionLabel: (option) => {
|
|
198
|
+
return (React.createElement(React.Fragment, null, isTreeViewEnabled ? (React.createElement(PropertyTree, { value: val ?? value, rootObject: object, setRootObject: setObject, fetchObject: fetchObject, propertyTreeMap: context.propertyTreeMap ?? {}, handleTreePropertySelect: handleOnChange })) : (React.createElement(Autocomplete, { freeSolo: context.propertyFreeSolo, options: opts, value: val || null, getOptionLabel: (option) => {
|
|
184
199
|
if (typeof option === 'string') {
|
|
185
200
|
return opts.find((o) => option === o.name)?.label || option;
|
|
186
201
|
}
|
|
@@ -195,8 +210,10 @@ const customSelector = (props) => {
|
|
|
195
210
|
},
|
|
196
211
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
197
212
|
onChange: (event, newValue) => {
|
|
198
|
-
handleOnChange(newValue?.value.name);
|
|
199
|
-
},
|
|
213
|
+
handleOnChange(typeof newValue === 'string' ? newValue : newValue?.value.name);
|
|
214
|
+
}, onInputChange: context.propertyFreeSolo
|
|
215
|
+
? (event, newInputValue) => handleOnChange(newInputValue)
|
|
216
|
+
: undefined, renderInput: (params) => (React.createElement(OverflowTextField, { value: val || '', ...params, placeholder: placeholder, size: "small", inputProps: {
|
|
200
217
|
...params.inputProps,
|
|
201
218
|
'aria-label': placeholder,
|
|
202
219
|
} })), sx: { width: width, background: readOnly ? '#f4f6f8' : '#fff' }, disableClearable: true, readOnly: readOnly }))));
|
|
@@ -275,77 +292,159 @@ const getAllRuleIds = (rules) => {
|
|
|
275
292
|
});
|
|
276
293
|
return ids;
|
|
277
294
|
};
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
let adjustedValue = rule.value;
|
|
292
|
-
if ((rule.operator === 'null' || rule.operator === 'notNull') && rule.value) {
|
|
293
|
-
adjustedValue = null;
|
|
294
|
-
}
|
|
295
|
-
return {
|
|
296
|
-
...rule,
|
|
297
|
-
operator: propertyType === 'array' && rule.operator === '=' ? 'in' : rule.operator,
|
|
298
|
-
value: adjustedValue,
|
|
299
|
-
};
|
|
295
|
+
const processRules = (rules, properties) => {
|
|
296
|
+
return rules.map((rule) => {
|
|
297
|
+
if ('rules' in rule) {
|
|
298
|
+
return {
|
|
299
|
+
...rule,
|
|
300
|
+
rules: processRules(rule.rules, properties),
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
const propertyType = properties.find((property) => property.id === rule.field)?.type;
|
|
305
|
+
let adjustedValue = rule.value;
|
|
306
|
+
if ((rule.operator === 'null' || rule.operator === 'notNull') && rule.value) {
|
|
307
|
+
adjustedValue = null;
|
|
300
308
|
}
|
|
301
|
-
|
|
309
|
+
return {
|
|
310
|
+
...rule,
|
|
311
|
+
operator: propertyType === 'array' && rule.operator === '=' ? 'in' : rule.operator,
|
|
312
|
+
value: adjustedValue,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
const insertChangesOnly = (prev, newObject) => {
|
|
318
|
+
const mergedProperties = newObject.properties.map((newProp) => {
|
|
319
|
+
const prevProp = prev.properties.find((prop) => prop.id === newProp.id);
|
|
320
|
+
if (prevProp) {
|
|
321
|
+
return {
|
|
322
|
+
...newProp,
|
|
323
|
+
children: newProp.children &&
|
|
324
|
+
newProp.children[0].type === 'loading' &&
|
|
325
|
+
prevProp.children
|
|
326
|
+
? prevProp.children
|
|
327
|
+
: newProp.children && prevProp.children
|
|
328
|
+
? insertChangesOnly({ id: prevProp.id, name: prevProp.name, properties: prevProp.children }, { id: newProp.id, name: newProp.name, properties: newProp.children }).properties
|
|
329
|
+
: newProp.children,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
return newProp;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
return {
|
|
337
|
+
...newObject,
|
|
338
|
+
properties: mergedProperties,
|
|
302
339
|
};
|
|
340
|
+
};
|
|
341
|
+
const CriteriaBuilder = (props) => {
|
|
342
|
+
const { propertyFreeSolo, properties, criteria, setCriteria, originalCriteria, enablePresetValues, presetValues, operators, disabled, disabledCriteria, hideBorder, presetGroupLabel, customValueEditor, treeViewOpts, disableRegexEscapeChars, } = props;
|
|
343
|
+
const [propertyTreeMap, setPropertyTreeMap] = useState({});
|
|
344
|
+
const [treeViewObject, setTreeViewObject] = useState();
|
|
303
345
|
useEffect(() => {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
346
|
+
let obj;
|
|
347
|
+
if (treeViewOpts?.object) {
|
|
348
|
+
obj = {
|
|
349
|
+
...treeViewOpts.object,
|
|
350
|
+
properties: treeViewOpts.object.properties
|
|
351
|
+
.filter((prop) => prop.type !== 'collection')
|
|
352
|
+
.map((prop) => ({
|
|
353
|
+
...prop,
|
|
354
|
+
children: prop.children
|
|
355
|
+
?.filter((child) => child.type !== 'collection')
|
|
356
|
+
.map((child) => ({
|
|
357
|
+
...child,
|
|
358
|
+
id: `${prop.id}.${child.id}`,
|
|
359
|
+
})),
|
|
360
|
+
})),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if ((criteria || originalCriteria) && obj && treeViewOpts?.fetchObject) {
|
|
364
|
+
const updateTreeViewObject = async (criteria, treeViewObject, fetchObject) => {
|
|
365
|
+
const newQuery = parseMongoDB(criteria);
|
|
313
366
|
const ids = getAllRuleIds(newQuery.rules);
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
367
|
+
const newTreeViewObject = { ...treeViewObject };
|
|
368
|
+
const traversePath = async (path, properties, fetchObject) => {
|
|
369
|
+
const prop = properties?.find((prop) => path.startsWith(`${prop.id}.`) || path === prop.id);
|
|
370
|
+
if (prop?.type === 'object' && prop.objectId && prop.children) {
|
|
371
|
+
if (prop.children.length === 1 &&
|
|
372
|
+
prop.children[0]?.type === 'loading') {
|
|
373
|
+
try {
|
|
374
|
+
const fetchedObject = await fetchObject(prop.objectId);
|
|
375
|
+
prop.children = fetchedObject?.properties
|
|
376
|
+
?.filter((item) => item.type !== 'collection')
|
|
377
|
+
.map((item) => {
|
|
378
|
+
return {
|
|
379
|
+
...item,
|
|
380
|
+
id: `${prop.id}.${item.id}`,
|
|
381
|
+
children: item.children?.map((child) => ({
|
|
382
|
+
...child,
|
|
383
|
+
id: `${prop.id}.${item.id}.${child.id}`,
|
|
384
|
+
})),
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
fetchedObject && (await traversePath(path, fetchedObject.properties, fetchObject));
|
|
324
388
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
389
|
+
catch (error) {
|
|
390
|
+
prop.children = [
|
|
391
|
+
{
|
|
392
|
+
id: `${prop.id}-failed`,
|
|
393
|
+
name: 'Loading Failed',
|
|
394
|
+
type: 'loadingFailed',
|
|
395
|
+
},
|
|
396
|
+
];
|
|
397
|
+
console.error('Error fetching object for criteria builder:', error);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
await traversePath(path, prop.children, fetchObject);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
for (const id of ids) {
|
|
406
|
+
await traversePath(id, newTreeViewObject.properties, fetchObject);
|
|
407
|
+
}
|
|
408
|
+
setTreeViewObject((prevTreeViewObject) => prevTreeViewObject ? insertChangesOnly(prevTreeViewObject, newTreeViewObject) : newTreeViewObject);
|
|
409
|
+
};
|
|
410
|
+
updateTreeViewObject(criteria || originalCriteria || {}, obj, treeViewOpts.fetchObject);
|
|
411
|
+
}
|
|
412
|
+
}, [treeViewOpts, criteria, originalCriteria]);
|
|
413
|
+
useEffect(() => {
|
|
414
|
+
if (!treeViewObject)
|
|
415
|
+
return;
|
|
416
|
+
const getNamePath = (path, object) => {
|
|
417
|
+
const helper = (path, object) => {
|
|
418
|
+
let namePath = '';
|
|
419
|
+
const prop = (object.properties ?? []).find((prop) => path.startsWith(`${prop.id}.`) || path === prop.id);
|
|
420
|
+
if (prop) {
|
|
421
|
+
if (prop.children) {
|
|
422
|
+
const result = helper(path, { id: prop.id, name: prop.name, properties: prop.children });
|
|
423
|
+
namePath = result ? prop.name + ' / ' + result : '';
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
namePath = prop.name;
|
|
331
427
|
}
|
|
332
428
|
}
|
|
333
|
-
|
|
334
|
-
setPropertyTreeMap((prevPropertyTreeMap) => ({
|
|
335
|
-
...prevPropertyTreeMap,
|
|
336
|
-
...newPropertyTreeMap,
|
|
337
|
-
}));
|
|
429
|
+
return namePath;
|
|
338
430
|
};
|
|
339
|
-
|
|
431
|
+
return helper(path, object) || path;
|
|
432
|
+
};
|
|
433
|
+
const newQuery = parseMongoDB(criteria || originalCriteria || {});
|
|
434
|
+
const ids = getAllRuleIds(newQuery.rules);
|
|
435
|
+
const result = {};
|
|
436
|
+
for (const id of ids) {
|
|
437
|
+
result[id] = getNamePath(id, treeViewObject);
|
|
340
438
|
}
|
|
341
|
-
|
|
439
|
+
setPropertyTreeMap(result);
|
|
440
|
+
}, [criteria, originalCriteria, treeViewObject]);
|
|
342
441
|
const initializeQuery = () => {
|
|
343
442
|
const criteriaToParse = criteria || originalCriteria;
|
|
344
443
|
const updatedQuery = criteriaToParse ? parseMongoDB(criteriaToParse || {}) : undefined;
|
|
345
444
|
return updatedQuery
|
|
346
445
|
? {
|
|
347
446
|
...updatedQuery,
|
|
348
|
-
rules: processRules(updatedQuery.rules),
|
|
447
|
+
rules: processRules(updatedQuery.rules, properties),
|
|
349
448
|
}
|
|
350
449
|
: { combinator: 'and', rules: [] };
|
|
351
450
|
};
|
|
@@ -371,7 +470,7 @@ const CriteriaBuilder = (props) => {
|
|
|
371
470
|
const handleQueryChange = (q) => {
|
|
372
471
|
const processedQuery = {
|
|
373
472
|
...q,
|
|
374
|
-
rules: processRules(q.rules),
|
|
473
|
+
rules: processRules(q.rules, properties),
|
|
375
474
|
};
|
|
376
475
|
setQuery(processedQuery);
|
|
377
476
|
const newCriteria = JSON.parse(formatQuery(processedQuery, {
|
|
@@ -390,7 +489,10 @@ const CriteriaBuilder = (props) => {
|
|
|
390
489
|
return defaultRuleProcessorMongoDB(newRule, options);
|
|
391
490
|
},
|
|
392
491
|
}));
|
|
393
|
-
if (
|
|
492
|
+
if (isEmpty(difference(newCriteria, criteria))) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
else if (!isEmpty(difference(newCriteria, { $and: [{ $expr: true }] }))) {
|
|
394
496
|
setCriteria(newCriteria);
|
|
395
497
|
}
|
|
396
498
|
else {
|
|
@@ -510,8 +612,8 @@ const CriteriaBuilder = (props) => {
|
|
|
510
612
|
},
|
|
511
613
|
}, showCombinatorsBetweenRules: true, listsAsArrays: true, disabled: disabled, addRuleToNewGroups: true, controlElements: {
|
|
512
614
|
combinatorSelector: customCombinator,
|
|
513
|
-
fieldSelector:
|
|
514
|
-
operatorSelector:
|
|
615
|
+
fieldSelector: customFieldSelector,
|
|
616
|
+
operatorSelector: customOperatorSelector,
|
|
515
617
|
addGroupAction: customButton,
|
|
516
618
|
addRuleAction: customButton,
|
|
517
619
|
ruleGroup: CustomRuleGroup,
|
|
@@ -525,17 +627,15 @@ const CriteriaBuilder = (props) => {
|
|
|
525
627
|
presetGroupLabel,
|
|
526
628
|
disabled,
|
|
527
629
|
disabledCriteria,
|
|
528
|
-
treeViewOpts: treeViewOpts
|
|
630
|
+
treeViewOpts: treeViewObject && treeViewOpts
|
|
529
631
|
? {
|
|
530
632
|
...treeViewOpts,
|
|
531
|
-
object:
|
|
532
|
-
|
|
533
|
-
properties: treeViewOpts?.object.properties.filter(({ type }) => type !== 'collection'),
|
|
534
|
-
},
|
|
633
|
+
object: treeViewObject,
|
|
634
|
+
setObject: setTreeViewObject,
|
|
535
635
|
}
|
|
536
636
|
: undefined,
|
|
537
637
|
propertyTreeMap,
|
|
538
|
-
|
|
638
|
+
propertyFreeSolo,
|
|
539
639
|
}, controlClassnames: {
|
|
540
640
|
ruleGroup: 'container',
|
|
541
641
|
}, operators: operators
|