@evoke-platform/ui-components 1.0.0-dev.244 → 1.0.0-dev.246
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 +1 -2
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +87 -5
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.d.ts +2 -2
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +2 -2
- package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +16 -3
- package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +1 -1
- package/dist/published/components/custom/CriteriaBuilder/utils.js +1 -1
- package/dist/published/stories/CriteriaBuilder.stories.d.ts +1 -0
- package/dist/published/stories/CriteriaBuilder.stories.js +139 -3
- package/package.json +1 -1
@@ -1,8 +1,7 @@
|
|
1
1
|
import { ElementType } from 'react';
|
2
|
-
import { ObjectProperty, TreeViewObject } from './types';
|
3
2
|
import 'react-querybuilder/dist/query-builder.css';
|
4
3
|
import { EvokeObject } from '../../../types';
|
5
|
-
import { Operator, PresetValue } from './types';
|
4
|
+
import { ObjectProperty, Operator, PresetValue, TreeViewObject } from './types';
|
6
5
|
import { ValueEditorProps } from './ValueEditor';
|
7
6
|
export type CriteriaInputProps = {
|
8
7
|
properties: ObjectProperty[];
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { AddRounded, UnfoldMore } from '@mui/icons-material';
|
2
2
|
import { Typography } from '@mui/material';
|
3
3
|
import { QueryBuilderMaterial } from '@react-querybuilder/material';
|
4
|
-
import { isEmpty, startCase } from 'lodash';
|
4
|
+
import { isArray, isEmpty, startCase } from 'lodash';
|
5
5
|
import React, { useEffect, useMemo, useState } from 'react';
|
6
6
|
import { QueryBuilder, RuleGroupBodyComponents, RuleGroupHeaderComponents, TestID, formatQuery, parseMongoDB, useRuleGroup, } from 'react-querybuilder';
|
7
7
|
import 'react-querybuilder/dist/query-builder.css';
|
@@ -10,6 +10,7 @@ import { Autocomplete, Button, IconButton, TextField } from '../../core';
|
|
10
10
|
import { Box } from '../../layout';
|
11
11
|
import { difference } from '../util';
|
12
12
|
import PropertyTree from './PropertyTree';
|
13
|
+
import { traversePropertyPath } from './utils';
|
13
14
|
import ValueEditor from './ValueEditor';
|
14
15
|
const ALL_OPERATORS = [
|
15
16
|
{ name: '=', label: 'Is' },
|
@@ -107,7 +108,11 @@ const customSelector = (props) => {
|
|
107
108
|
let width = '90px';
|
108
109
|
let val = value;
|
109
110
|
let opts = options;
|
110
|
-
|
111
|
+
let inputType = props.fieldData?.inputType;
|
112
|
+
// for tree view / related object properties, the properties are stored in the propertyTreeMap upon selection
|
113
|
+
if (!!context.treeViewOpts && !!context.propertyTreeMap[rule.field]) {
|
114
|
+
inputType = context.propertyTreeMap[rule.field].type;
|
115
|
+
}
|
111
116
|
let readOnly = false;
|
112
117
|
const isTreeViewEnabled = context.treeViewOpts && title === 'Fields';
|
113
118
|
const fetchObject = context.treeViewOpts?.fetchObject;
|
@@ -120,9 +125,11 @@ const customSelector = (props) => {
|
|
120
125
|
opts = opts.filter((o) => readOnly || !keys.includes(o.name));
|
121
126
|
}
|
122
127
|
}
|
128
|
+
let placeholder = '';
|
123
129
|
switch (title) {
|
124
130
|
case 'Operators':
|
125
131
|
width = '25%';
|
132
|
+
placeholder = 'Select Operator';
|
126
133
|
if (inputType === 'array') {
|
127
134
|
opts = options
|
128
135
|
.filter((option) => ['null', 'notNull', 'in', 'notIn'].includes(option.name))
|
@@ -159,13 +166,28 @@ const customSelector = (props) => {
|
|
159
166
|
: option.label,
|
160
167
|
}));
|
161
168
|
}
|
169
|
+
else if (inputType === 'integer' || inputType === 'number') {
|
170
|
+
opts = options.filter((option) => ['=', '!=', '<', '<=', '>', '>=', 'null', 'notNull'].includes(option.name));
|
171
|
+
// checks if it is a single-select property
|
172
|
+
}
|
173
|
+
else if (inputType === 'string' && isArray(props.fieldData?.values)) {
|
174
|
+
opts = options.filter((option) => ['in', 'notIn', '=', '!=', 'notNull', 'null'].includes(option.name));
|
175
|
+
}
|
162
176
|
break;
|
163
177
|
case 'Fields':
|
178
|
+
placeholder = 'Select Property';
|
164
179
|
width = '33%';
|
165
180
|
val = options.find((option) => option.name === val)?.name;
|
166
181
|
break;
|
167
182
|
}
|
168
|
-
|
183
|
+
const handleTreePropertySelect = async (propertyId) => {
|
184
|
+
const propertyInfo = await traversePropertyPath(propertyId, object, fetchObject);
|
185
|
+
context.setPropertyTreeMap((prev) => {
|
186
|
+
return { ...prev, [propertyId]: propertyInfo };
|
187
|
+
});
|
188
|
+
handleOnChange(propertyId);
|
189
|
+
};
|
190
|
+
return (React.createElement(React.Fragment, null, isTreeViewEnabled ? (React.createElement(PropertyTree, { value: val ?? value, rootObject: object, fetchObject: fetchObject, handleTreePropertySelect: handleTreePropertySelect })) : (React.createElement(Autocomplete, { options: opts, value: val ?? null, getOptionLabel: (option) => {
|
169
191
|
if (typeof option === 'string') {
|
170
192
|
return opts.find((o) => option === o.name)?.label || '';
|
171
193
|
}
|
@@ -176,7 +198,7 @@ const customSelector = (props) => {
|
|
176
198
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
177
199
|
onChange: (event, newValue) => {
|
178
200
|
handleOnChange(newValue?.value.name);
|
179
|
-
}, renderInput: (params) => React.createElement(TextField, { ...params, size: "small" }), sx: { width: width, background: '#fff' }, disableClearable: true, readOnly: readOnly }))));
|
201
|
+
}, renderInput: (params) => React.createElement(TextField, { ...params, placeholder: placeholder, size: "small" }), sx: { width: width, background: '#fff' }, disableClearable: true, readOnly: readOnly }))));
|
180
202
|
};
|
181
203
|
const customCombinator = (props) => {
|
182
204
|
const { value, handleOnChange, context, level, path } = props;
|
@@ -243,10 +265,12 @@ export const valueEditor = (props) => {
|
|
243
265
|
const CriteriaBuilder = (props) => {
|
244
266
|
const { properties, criteria, setCriteria, originalCriteria, enablePresetValues, presetValues, operators, dynamicContentInput, disabled, disabledCriteria, hideBorder, presetGroupLabel, treeViewOpts, } = props;
|
245
267
|
const [query, setQuery] = useState(undefined);
|
268
|
+
const [propertyTreeMap, setPropertyTreeMap] = useState({});
|
246
269
|
useEffect(() => {
|
247
270
|
if (criteria || originalCriteria) {
|
248
271
|
const criteriaToParse = criteria || originalCriteria || {};
|
249
272
|
const updatedQuery = parseMongoDB(criteriaToParse);
|
273
|
+
!isEmpty(treeViewOpts) && updatePropertyTreeMap(updatedQuery);
|
250
274
|
setQuery({
|
251
275
|
...updatedQuery,
|
252
276
|
rules: processRules(updatedQuery.rules),
|
@@ -276,10 +300,40 @@ const CriteriaBuilder = (props) => {
|
|
276
300
|
}
|
277
301
|
});
|
278
302
|
}
|
303
|
+
// this retrieves the properties from a treeview for each property in the query
|
304
|
+
// they are then used in the custom query builder components to determine the input type etc
|
305
|
+
const updatePropertyTreeMap = (q) => {
|
306
|
+
const ids = [];
|
307
|
+
const traverseRulesForIds = (rules) => {
|
308
|
+
rules.forEach((rule) => {
|
309
|
+
if ('rules' in rule) {
|
310
|
+
traverseRulesForIds(rule.rules);
|
311
|
+
}
|
312
|
+
else {
|
313
|
+
ids.push(rule.field);
|
314
|
+
}
|
315
|
+
});
|
316
|
+
};
|
317
|
+
traverseRulesForIds(q.rules);
|
318
|
+
const tempPropertyMap = { ...propertyTreeMap };
|
319
|
+
ids.forEach(async (id) => {
|
320
|
+
if (!propertyTreeMap[id] && treeViewOpts?.object && treeViewOpts?.fetchObject) {
|
321
|
+
const prop = await traversePropertyPath(id, treeViewOpts?.object, treeViewOpts?.fetchObject);
|
322
|
+
if (prop)
|
323
|
+
tempPropertyMap[id] = prop;
|
324
|
+
}
|
325
|
+
setPropertyTreeMap(tempPropertyMap);
|
326
|
+
});
|
327
|
+
};
|
279
328
|
const handleQueryChange = (q) => {
|
280
329
|
setQuery(q);
|
281
330
|
const newCriteria = JSON.parse(formatQuery(q, 'mongodb'));
|
282
|
-
|
331
|
+
//when q has no rules, it formats and parses to { $and: [{ $expr: true }] }
|
332
|
+
const allRulesDeleted = isEmpty(difference(newCriteria, { $and: [{ $expr: true }] }));
|
333
|
+
// since the Add Condition / Add Group buttons add rules with all the fields empty,
|
334
|
+
// we need to check if the first rule was added because q will still parse to { $and: [{ $expr: true }] }
|
335
|
+
const firstRuleAdded = isEmpty(criteria) && q.rules.length > 0;
|
336
|
+
if (allRulesDeleted && !firstRuleAdded) {
|
283
337
|
setCriteria(undefined);
|
284
338
|
}
|
285
339
|
else {
|
@@ -346,6 +400,32 @@ const CriteriaBuilder = (props) => {
|
|
346
400
|
React.createElement(QueryBuilderMaterial, null,
|
347
401
|
React.createElement(QueryBuilder, { query: !criteria && !originalCriteria ? { combinator: 'and', rules: [] } : query, fields: fields, onQueryChange: (q) => {
|
348
402
|
handleQueryChange(q);
|
403
|
+
}, onAddRule: (rule) => {
|
404
|
+
// overrides new rule and sets up an empty rule with all three fields empty
|
405
|
+
return {
|
406
|
+
...rule,
|
407
|
+
field: '',
|
408
|
+
operator: '',
|
409
|
+
};
|
410
|
+
}, onAddGroup: (group) => {
|
411
|
+
// overrides new group and sets up a new group with an empty rule with all three fields showing
|
412
|
+
const emptyRules = group.rules.map((rule) => ({
|
413
|
+
...rule,
|
414
|
+
field: '',
|
415
|
+
operator: '',
|
416
|
+
}));
|
417
|
+
return {
|
418
|
+
...group,
|
419
|
+
rules: emptyRules,
|
420
|
+
combinator: 'and',
|
421
|
+
};
|
422
|
+
}, translations: {
|
423
|
+
fields: {
|
424
|
+
placeholderLabel: '',
|
425
|
+
},
|
426
|
+
operators: {
|
427
|
+
placeholderLabel: '',
|
428
|
+
},
|
349
429
|
}, showCombinatorsBetweenRules: true, listsAsArrays: true, disabled: disabled, addRuleToNewGroups: true, controlElements: {
|
350
430
|
combinatorSelector: customCombinator,
|
351
431
|
fieldSelector: customSelector,
|
@@ -363,6 +443,8 @@ const CriteriaBuilder = (props) => {
|
|
363
443
|
presetGroupLabel,
|
364
444
|
disabledCriteria,
|
365
445
|
treeViewOpts,
|
446
|
+
propertyTreeMap,
|
447
|
+
setPropertyTreeMap,
|
366
448
|
}, controlClassnames: {
|
367
449
|
ruleGroup: 'container',
|
368
450
|
}, operators: operators
|
@@ -3,8 +3,8 @@ import { EvokeObject } from '../../../types';
|
|
3
3
|
type PropertyTreeProps = {
|
4
4
|
fetchObject: (id: string) => Promise<EvokeObject | undefined>;
|
5
5
|
rootObject: EvokeObject;
|
6
|
-
|
6
|
+
handleTreePropertySelect: (propertyId: string) => void;
|
7
7
|
value: string | undefined;
|
8
8
|
};
|
9
|
-
declare const PropertyTree: ({ fetchObject,
|
9
|
+
declare const PropertyTree: ({ fetchObject, handleTreePropertySelect, rootObject, value }: PropertyTreeProps) => JSX.Element;
|
10
10
|
export default PropertyTree;
|
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
|
|
3
3
|
import { Autocomplete, MenuItem, TextField, Tooltip, TreeView } from '../../core';
|
4
4
|
import PropertyTreeItem from './PropertyTreeItem';
|
5
5
|
import { fetchDisplayNamePath, findPropertyById, setIdPaths, truncateNamePath, updateTreeNode } from './utils';
|
6
|
-
const PropertyTree = ({ fetchObject,
|
6
|
+
const PropertyTree = ({ fetchObject, handleTreePropertySelect, rootObject, value }) => {
|
7
7
|
const [expandedNodes, setExpandedNodes] = useState([]);
|
8
8
|
const [objectPropertyNamePathMap, setObjectPropertyNamePathMap] = useState({});
|
9
9
|
const [objectProperties, setObjectProperties] = useState(rootObject.properties ?? []);
|
@@ -99,7 +99,7 @@ const PropertyTree = ({ fetchObject, handleOnChange, rootObject, value }) => {
|
|
99
99
|
const property = findPropertyById(objectProperties, propertyId);
|
100
100
|
// this prevents the selection of a parent node
|
101
101
|
if (property && !property.children) {
|
102
|
-
|
102
|
+
handleTreePropertySelect(property.id);
|
103
103
|
}
|
104
104
|
};
|
105
105
|
return (React.createElement(Autocomplete, { "aria-label": "Property Selector", value: value, fullWidth: true, sx: {
|
@@ -17,7 +17,20 @@ const GroupHeader = styled('div')(({ theme }) => ({
|
|
17
17
|
}));
|
18
18
|
const GroupItems = styled('ul')({ padding: 0 });
|
19
19
|
const ValueEditor = (props) => {
|
20
|
-
const { handleOnChange, value,
|
20
|
+
const { handleOnChange, value, operator, context, level, rule } = props;
|
21
|
+
let inputType = props.inputType;
|
22
|
+
let values = props.values;
|
23
|
+
const property = context.propertyTreeMap[rule.field];
|
24
|
+
// for tree view / related object properties, the properties are stored in the propertyTreeMap upon selection
|
25
|
+
if (!!context.treeViewOpts && !!property) {
|
26
|
+
inputType = property.type;
|
27
|
+
if (property.enum) {
|
28
|
+
values = property.enum.map((item) => ({
|
29
|
+
name: item,
|
30
|
+
label: item,
|
31
|
+
}));
|
32
|
+
}
|
33
|
+
}
|
21
34
|
const inputRef = useRef(null);
|
22
35
|
const [openPresetValues, setOpenPresetValues] = useState(false);
|
23
36
|
const disabled = ['null', 'notNull'].includes(operator);
|
@@ -79,7 +92,7 @@ const ValueEditor = (props) => {
|
|
79
92
|
handleOnChange(uniqueSelections.length ? uniqueSelections : '');
|
80
93
|
},
|
81
94
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
82
|
-
isOptionEqualToValue: (option, value) => option === value, renderInput: (params) => (React.createElement(TextField, { label: params.label, ...params, size: "small" })), groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sx: { width: '33%', background: '#fff' }, readOnly: readOnly }));
|
95
|
+
isOptionEqualToValue: (option, value) => option === value, renderInput: (params) => (React.createElement(TextField, { label: params.label, ...params, size: "small", sx: { backgroundColor: '#fff' } })), groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sx: { width: '33%', background: '#fff' }, readOnly: readOnly }));
|
83
96
|
}
|
84
97
|
else {
|
85
98
|
return (React.createElement(TextField, { inputRef: inputRef, value: ['null', 'notNull'].includes(operator) ? '' : value, disabled: ['null', 'notNull'].includes(operator), onChange: (e) => {
|
@@ -114,7 +127,7 @@ const ValueEditor = (props) => {
|
|
114
127
|
value = newValue?.name ?? newValue?.value?.name ?? '';
|
115
128
|
}
|
116
129
|
handleOnChange(value);
|
117
|
-
}, renderInput: (params) => (React.createElement(TextField, { inputRef: inputRef, label: params?.label, ...params, size: "small" })),
|
130
|
+
}, renderInput: (params) => (React.createElement(TextField, { inputRef: inputRef, label: params?.label, ...params, size: "small", sx: { backgroundColor: '#fff' } })),
|
118
131
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
119
132
|
getOptionLabel: (option) => {
|
120
133
|
if (typeof option === 'string') {
|
@@ -39,7 +39,7 @@ export declare const setIdPaths: (properties: ObjectProperty[], parentPath: stri
|
|
39
39
|
*
|
40
40
|
* @param {string} propertyPath - The dot-separated path of the property to traverse.
|
41
41
|
* @param {Obj} rootObject - The root object from which to start the traversal.
|
42
|
-
* @param {
|
42
|
+
* @param {FetchObjectFunction} fetchObject - A function to fetch an object by its ID.
|
43
43
|
* @returns {Promise<ObjectProperty | null>} A promise that resolves to an ObjectProperty if found, or null otherwise.
|
44
44
|
*/
|
45
45
|
export declare const traversePropertyPath: (propertyPath: string, rootObject: Obj, fetchObject: (objectId: string) => Promise<Obj | undefined>) => Promise<ObjectProperty | null>;
|
@@ -72,7 +72,7 @@ export const setIdPaths = (properties, parentPath) => {
|
|
72
72
|
*
|
73
73
|
* @param {string} propertyPath - The dot-separated path of the property to traverse.
|
74
74
|
* @param {Obj} rootObject - The root object from which to start the traversal.
|
75
|
-
* @param {
|
75
|
+
* @param {FetchObjectFunction} fetchObject - A function to fetch an object by its ID.
|
76
76
|
* @returns {Promise<ObjectProperty | null>} A promise that resolves to an ObjectProperty if found, or null otherwise.
|
77
77
|
*/
|
78
78
|
export const traversePropertyPath = async (propertyPath, rootObject, fetchObject) => {
|
@@ -3,6 +3,7 @@ import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
3
3
|
import { CriteriaInputProps } from '../components/custom/CriteriaBuilder/CriteriaBuilder';
|
4
4
|
declare const _default: ComponentMeta<(props: CriteriaInputProps) => JSX.Element>;
|
5
5
|
export default _default;
|
6
|
+
export declare const CriteriaBuilderEmpty: ComponentStory<(props: CriteriaInputProps) => JSX.Element>;
|
6
7
|
export declare const CriteriaBuilder: ComponentStory<(props: CriteriaInputProps) => JSX.Element>;
|
7
8
|
export declare const CriteriaBuilderPresetUserID: ComponentStory<(props: CriteriaInputProps) => JSX.Element>;
|
8
9
|
export declare const CriteriaBuilderGroupedPresetValues: ComponentStory<(props: CriteriaInputProps) => JSX.Element>;
|
@@ -4,7 +4,101 @@ export default {
|
|
4
4
|
title: 'Input/CriteriaBuilder',
|
5
5
|
component: BuildCriteria,
|
6
6
|
};
|
7
|
-
const CriteriaBuilderTemplate = (args) =>
|
7
|
+
const CriteriaBuilderTemplate = (args) => {
|
8
|
+
const [criteria, setCriteria] = React.useState(args.criteria);
|
9
|
+
args.setCriteria = setCriteria;
|
10
|
+
args.criteria = criteria;
|
11
|
+
console.log('reset criteria= ', criteria);
|
12
|
+
return React.createElement(BuildCriteria, { ...args });
|
13
|
+
};
|
14
|
+
export const CriteriaBuilderEmpty = CriteriaBuilderTemplate.bind({});
|
15
|
+
CriteriaBuilderEmpty.args = {
|
16
|
+
properties: [
|
17
|
+
{
|
18
|
+
id: 'name',
|
19
|
+
name: 'name',
|
20
|
+
type: 'string',
|
21
|
+
required: true,
|
22
|
+
},
|
23
|
+
{
|
24
|
+
id: 'licenseNumber',
|
25
|
+
name: 'license number',
|
26
|
+
type: 'string',
|
27
|
+
required: true,
|
28
|
+
},
|
29
|
+
{
|
30
|
+
id: 'issueDate',
|
31
|
+
name: 'issue date',
|
32
|
+
type: 'date',
|
33
|
+
required: false,
|
34
|
+
objectId: '',
|
35
|
+
},
|
36
|
+
{
|
37
|
+
id: 'status',
|
38
|
+
name: 'status',
|
39
|
+
type: 'string',
|
40
|
+
enum: ['active', 'expired', 'pending approval'],
|
41
|
+
required: false,
|
42
|
+
objectId: '',
|
43
|
+
},
|
44
|
+
{
|
45
|
+
id: 'licenseeName',
|
46
|
+
name: 'Licensee Name',
|
47
|
+
type: 'string',
|
48
|
+
required: false,
|
49
|
+
formula: '{{person.firstName}} {{person.middleName}} {{person.lastName}}',
|
50
|
+
},
|
51
|
+
{
|
52
|
+
id: 'calculated',
|
53
|
+
name: 'calculated',
|
54
|
+
type: 'string',
|
55
|
+
required: false,
|
56
|
+
objectId: '',
|
57
|
+
formula: '{{status}} - {{licensee.firstName}}',
|
58
|
+
},
|
59
|
+
{
|
60
|
+
id: 'application',
|
61
|
+
name: 'applicant',
|
62
|
+
type: 'object',
|
63
|
+
required: false,
|
64
|
+
objectId: 'application',
|
65
|
+
},
|
66
|
+
{
|
67
|
+
id: 'applicantName',
|
68
|
+
name: 'Application Info',
|
69
|
+
type: 'string',
|
70
|
+
required: false,
|
71
|
+
formula: '{{application.name}} - {{status}}',
|
72
|
+
},
|
73
|
+
{
|
74
|
+
id: 'licensedFor',
|
75
|
+
name: 'licensed for',
|
76
|
+
type: 'array',
|
77
|
+
enum: [
|
78
|
+
'amusements',
|
79
|
+
'food and beverage',
|
80
|
+
'entertainment',
|
81
|
+
'transportation',
|
82
|
+
'hot dogs',
|
83
|
+
'swimming pools',
|
84
|
+
'ferris wheels',
|
85
|
+
'bungee jumping',
|
86
|
+
],
|
87
|
+
required: true,
|
88
|
+
searchable: false,
|
89
|
+
},
|
90
|
+
{
|
91
|
+
id: 'inState',
|
92
|
+
name: 'In State',
|
93
|
+
type: 'string',
|
94
|
+
enum: ['Yes', 'No'],
|
95
|
+
required: false,
|
96
|
+
searchable: false,
|
97
|
+
},
|
98
|
+
],
|
99
|
+
criteria: {},
|
100
|
+
setCriteria: (criteria) => console.log('criteria= ', criteria),
|
101
|
+
};
|
8
102
|
export const CriteriaBuilder = CriteriaBuilderTemplate.bind({});
|
9
103
|
CriteriaBuilder.args = {
|
10
104
|
properties: [
|
@@ -418,6 +512,13 @@ CriteriaBuilderRelatedObject.args = {
|
|
418
512
|
type: 'date',
|
419
513
|
required: false,
|
420
514
|
},
|
515
|
+
{
|
516
|
+
id: 'approvalStatus',
|
517
|
+
name: 'Approval Status',
|
518
|
+
type: 'string',
|
519
|
+
enum: ['Approved', 'Denied', 'InProgress', 'Received'],
|
520
|
+
required: false,
|
521
|
+
},
|
421
522
|
{
|
422
523
|
id: 'licenseNumber',
|
423
524
|
name: 'LicenseNumber',
|
@@ -464,6 +565,13 @@ CriteriaBuilderRelatedObject.args = {
|
|
464
565
|
type: 'string',
|
465
566
|
required: true,
|
466
567
|
},
|
568
|
+
{
|
569
|
+
id: 'status',
|
570
|
+
name: 'Status',
|
571
|
+
type: 'string',
|
572
|
+
enum: ['RN', 'NP', 'DNP', 'MA'],
|
573
|
+
required: false,
|
574
|
+
},
|
467
575
|
{
|
468
576
|
id: 'description',
|
469
577
|
name: 'Description',
|
@@ -703,10 +811,38 @@ CriteriaBuilderRelatedObject.args = {
|
|
703
811
|
criteria: {
|
704
812
|
$and: [
|
705
813
|
{
|
706
|
-
|
814
|
+
'applicant.vehicleCount': {
|
815
|
+
$gt: 2,
|
816
|
+
},
|
817
|
+
},
|
818
|
+
{
|
819
|
+
'applicant.license.expirationDate': {
|
820
|
+
$gt: '2025-01-16',
|
821
|
+
},
|
822
|
+
},
|
823
|
+
{
|
824
|
+
'applicant.license.person.phone': {
|
825
|
+
$regex: '410',
|
826
|
+
},
|
827
|
+
},
|
828
|
+
{
|
829
|
+
$or: [
|
830
|
+
{
|
831
|
+
'applicant.license.approvalStatus': 'InProgress',
|
832
|
+
},
|
833
|
+
{
|
834
|
+
'applicant.license.approvalStatus': 'Approved',
|
835
|
+
},
|
836
|
+
{
|
837
|
+
'applicant.license.issueDate': '2025-01-09',
|
838
|
+
},
|
839
|
+
{
|
840
|
+
'applicant.avgVehicleRating': 1,
|
841
|
+
},
|
842
|
+
],
|
707
843
|
},
|
708
844
|
{
|
709
|
-
'
|
845
|
+
'applicationType.status': 'DNP',
|
710
846
|
},
|
711
847
|
],
|
712
848
|
},
|