@genesislcap/expression-builder 14.248.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/FUTURE.md +164 -0
- package/README.md +3 -0
- package/custom-elements-manifest.config.js +14 -0
- package/dist/custom-elements.json +1971 -0
- package/dist/dts/config/combinators.d.ts +6 -0
- package/dist/dts/config/combinators.d.ts.map +1 -0
- package/dist/dts/config/index.d.ts +3 -0
- package/dist/dts/config/index.d.ts.map +1 -0
- package/dist/dts/config/operators.d.ts +4 -0
- package/dist/dts/config/operators.d.ts.map +1 -0
- package/dist/dts/index.d.ts +6 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/main/events.d.ts +50 -0
- package/dist/dts/main/events.d.ts.map +1 -0
- package/dist/dts/main/expression-builder.d.ts +44 -0
- package/dist/dts/main/expression-builder.d.ts.map +1 -0
- package/dist/dts/main/expression-builder.helpers.d.ts +19 -0
- package/dist/dts/main/expression-builder.helpers.d.ts.map +1 -0
- package/dist/dts/main/expression-builder.styles.d.ts +3 -0
- package/dist/dts/main/expression-builder.styles.d.ts.map +1 -0
- package/dist/dts/main/expression-builder.template.d.ts +4 -0
- package/dist/dts/main/expression-builder.template.d.ts.map +1 -0
- package/dist/dts/main/expression-group/expression-group.d.ts +18 -0
- package/dist/dts/main/expression-group/expression-group.d.ts.map +1 -0
- package/dist/dts/main/expression-group/expression-group.styles.d.ts +2 -0
- package/dist/dts/main/expression-group/expression-group.styles.d.ts.map +1 -0
- package/dist/dts/main/expression-group/expression-group.template.d.ts +3 -0
- package/dist/dts/main/expression-group/expression-group.template.d.ts.map +1 -0
- package/dist/dts/main/expression-rule/expression-rule.d.ts +27 -0
- package/dist/dts/main/expression-rule/expression-rule.d.ts.map +1 -0
- package/dist/dts/main/expression-rule/expression-rule.helpers.d.ts +4 -0
- package/dist/dts/main/expression-rule/expression-rule.helpers.d.ts.map +1 -0
- package/dist/dts/main/expression-rule/expression-rule.styles.d.ts +2 -0
- package/dist/dts/main/expression-rule/expression-rule.styles.d.ts.map +1 -0
- package/dist/dts/main/expression-rule/expression-rule.template.d.ts +3 -0
- package/dist/dts/main/expression-rule/expression-rule.template.d.ts.map +1 -0
- package/dist/dts/main/index.d.ts +4 -0
- package/dist/dts/main/index.d.ts.map +1 -0
- package/dist/dts/main/rule-field/rule-field.d.ts +15 -0
- package/dist/dts/main/rule-field/rule-field.d.ts.map +1 -0
- package/dist/dts/main/rule-field/rule-field.template.d.ts +3 -0
- package/dist/dts/main/rule-field/rule-field.template.d.ts.map +1 -0
- package/dist/dts/main/rule-operator/rule-operator.d.ts +17 -0
- package/dist/dts/main/rule-operator/rule-operator.d.ts.map +1 -0
- package/dist/dts/main/rule-operator/rule-operator.template.d.ts +3 -0
- package/dist/dts/main/rule-operator/rule-operator.template.d.ts.map +1 -0
- package/dist/dts/main/rule-value/rule-value.d.ts +17 -0
- package/dist/dts/main/rule-value/rule-value.d.ts.map +1 -0
- package/dist/dts/main/rule-value/rule-value.helpers.d.ts +6 -0
- package/dist/dts/main/rule-value/rule-value.helpers.d.ts.map +1 -0
- package/dist/dts/main/rule-value/rule-value.styles.d.ts +2 -0
- package/dist/dts/main/rule-value/rule-value.styles.d.ts.map +1 -0
- package/dist/dts/main/rule-value/rule-value.template.d.ts +3 -0
- package/dist/dts/main/rule-value/rule-value.template.d.ts.map +1 -0
- package/dist/dts/types/index.d.ts +3 -0
- package/dist/dts/types/index.d.ts.map +1 -0
- package/dist/dts/types/private.types.d.ts +21 -0
- package/dist/dts/types/private.types.d.ts.map +1 -0
- package/dist/dts/types/public.types.d.ts +160 -0
- package/dist/dts/types/public.types.d.ts.map +1 -0
- package/dist/dts/utils/data-model.d.ts +27 -0
- package/dist/dts/utils/data-model.d.ts.map +1 -0
- package/dist/dts/utils/formatting.d.ts +13 -0
- package/dist/dts/utils/formatting.d.ts.map +1 -0
- package/dist/dts/utils/index.d.ts +4 -0
- package/dist/dts/utils/index.d.ts.map +1 -0
- package/dist/dts/utils/misc.d.ts +14 -0
- package/dist/dts/utils/misc.d.ts.map +1 -0
- package/dist/esm/config/combinators.js +31 -0
- package/dist/esm/config/index.js +2 -0
- package/dist/esm/config/operators.js +91 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/main/events.js +13 -0
- package/dist/esm/main/expression-builder.helpers.js +129 -0
- package/dist/esm/main/expression-builder.js +157 -0
- package/dist/esm/main/expression-builder.styles.js +177 -0
- package/dist/esm/main/expression-builder.template.js +13 -0
- package/dist/esm/main/expression-group/expression-group.js +121 -0
- package/dist/esm/main/expression-group/expression-group.styles.js +45 -0
- package/dist/esm/main/expression-group/expression-group.template.js +102 -0
- package/dist/esm/main/expression-rule/expression-rule.helpers.js +25 -0
- package/dist/esm/main/expression-rule/expression-rule.js +203 -0
- package/dist/esm/main/expression-rule/expression-rule.styles.js +57 -0
- package/dist/esm/main/expression-rule/expression-rule.template.js +65 -0
- package/dist/esm/main/index.js +3 -0
- package/dist/esm/main/rule-field/rule-field.js +48 -0
- package/dist/esm/main/rule-field/rule-field.template.js +46 -0
- package/dist/esm/main/rule-operator/rule-operator.js +60 -0
- package/dist/esm/main/rule-operator/rule-operator.template.js +46 -0
- package/dist/esm/main/rule-value/rule-value.helpers.js +17 -0
- package/dist/esm/main/rule-value/rule-value.js +115 -0
- package/dist/esm/main/rule-value/rule-value.styles.js +11 -0
- package/dist/esm/main/rule-value/rule-value.template.js +106 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/private.types.js +1 -0
- package/dist/esm/types/public.types.js +1 -0
- package/dist/esm/utils/data-model.js +51 -0
- package/dist/esm/utils/formatting.js +23 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/esm/utils/misc.js +62 -0
- package/dist/expression-builder.api.json +212 -0
- package/dist/expression-builder.d.ts +322 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/docs/.gitattributes +2 -0
- package/docs/api/expression-builder.config.md +6 -0
- package/docs/api/expression-builder.md +13 -0
- package/docs/api/expression-builder.types.md +6 -0
- package/docs/api/index.md +12 -0
- package/docs/api-report.md +260 -0
- package/license.txt +46 -0
- package/package.json +66 -0
- package/playwright.config.ts +5 -0
- package/test/unit/test.ts +1 -0
- package/tsdoc.json +4 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Config, Group, ModelGroup, ModelRule, Rule } from '../types';
|
|
2
|
+
/** @internal */
|
|
3
|
+
export interface MetadataProvider {
|
|
4
|
+
getGroupId(): string;
|
|
5
|
+
getRuleId(): string;
|
|
6
|
+
getConfig(): Config;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Converts a Group to a ModelGroup (adds required metadata)
|
|
10
|
+
*/
|
|
11
|
+
export declare function groupToModelGroup(group: Group, provider: MetadataProvider): ModelGroup;
|
|
12
|
+
/**
|
|
13
|
+
* Converts a ModelGroup (internal data structure) to a public Group structure.
|
|
14
|
+
* This function recursively processes the rules within the group.
|
|
15
|
+
*
|
|
16
|
+
* @param modelGroup The internal ModelGroup to convert.
|
|
17
|
+
* @returns A public Group object.
|
|
18
|
+
*/
|
|
19
|
+
export declare function modelGroupToGroup(modelGroup: ModelGroup): Group;
|
|
20
|
+
/**
|
|
21
|
+
* Converts a ModelRule (internal data structure) to a public Rule structure.
|
|
22
|
+
*
|
|
23
|
+
* @param modelRule The internal ModelRule to convert.
|
|
24
|
+
* @returns A public Rule object.
|
|
25
|
+
*/
|
|
26
|
+
export declare function modelRuleToRule(modelRule: ModelRule): Rule;
|
|
27
|
+
//# sourceMappingURL=data-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-model.d.ts","sourceRoot":"","sources":["../../../src/utils/data-model.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEtE,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,MAAM,CAAC;IACrB,SAAS,IAAI,MAAM,CAAC;IACpB,SAAS,IAAI,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,gBAAgB,GAAG,UAAU,CA4BtF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,KAAK,CAe/D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAO1D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the string representation from a `Date` which is the format a `date` input uses.
|
|
3
|
+
* `yyyy-mm-dd`
|
|
4
|
+
* @alpha
|
|
5
|
+
*/
|
|
6
|
+
export declare const formatDateString: (date: Date) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the string representation from a `Date` which is the format a `datetime-local` input uses.
|
|
9
|
+
* `yyyy-mm-ddThh:mm:ss`
|
|
10
|
+
* @alpha
|
|
11
|
+
*/
|
|
12
|
+
export declare const formatDateTimeString: (date: Date) => string;
|
|
13
|
+
//# sourceMappingURL=formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../../src/utils/formatting.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,SAAU,IAAI,WAK1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,SAAU,IAAI,WAM9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Field, Operator, Styles } from '../types';
|
|
2
|
+
export declare const processOptGroups: <T extends Operator | Field>(xs: T[]) => (T | {
|
|
3
|
+
optgroup: string | null;
|
|
4
|
+
xs: T[];
|
|
5
|
+
})[];
|
|
6
|
+
/**
|
|
7
|
+
* Utility function to add custom styles to a web component's shadow root
|
|
8
|
+
*
|
|
9
|
+
* @param component The web component instance
|
|
10
|
+
* @param styles The styles configuration object
|
|
11
|
+
* @param styleKey The key in styles.customStyles to use for custom styles
|
|
12
|
+
*/
|
|
13
|
+
export declare function applyCustomStyles(component: HTMLElement, styles: Styles | undefined | null, styleKey: keyof NonNullable<Styles['customStyles']>): void;
|
|
14
|
+
//# sourceMappingURL=misc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/utils/misc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEnD,eAAO,MAAM,gBAAgB;cAET,MAAM,GAAG,IAAI;;IAyChC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACjC,QAAQ,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,GAClD,IAAI,CAeN"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** @alpha */
|
|
2
|
+
export const BASE_LOGICAL_COMBINATORS = [
|
|
3
|
+
{
|
|
4
|
+
type: 'AND',
|
|
5
|
+
maxRules: 'many',
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
type: 'OR',
|
|
9
|
+
maxRules: 'many',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
/** @alpha */
|
|
13
|
+
export const LOGICAL_COMBINATORS = [
|
|
14
|
+
...BASE_LOGICAL_COMBINATORS,
|
|
15
|
+
{
|
|
16
|
+
type: 'NOT',
|
|
17
|
+
maxRules: 2,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'NAND',
|
|
21
|
+
maxRules: 'many',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: 'NOR',
|
|
25
|
+
maxRules: 'many',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'XOR',
|
|
29
|
+
maxRules: 2,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const enumTypes = ['enum'];
|
|
2
|
+
const numericTypes = ['int', 'short', 'long', 'bigdecimal', 'double'];
|
|
3
|
+
const stringTypes = ['string'];
|
|
4
|
+
const dateTypes = ['date', 'date-time'];
|
|
5
|
+
const booleanTypes = ['boolean'];
|
|
6
|
+
const allTypes = [
|
|
7
|
+
...enumTypes,
|
|
8
|
+
...numericTypes,
|
|
9
|
+
...stringTypes,
|
|
10
|
+
...dateTypes,
|
|
11
|
+
...booleanTypes,
|
|
12
|
+
];
|
|
13
|
+
/** @alpha **/
|
|
14
|
+
export const BASE_OPERATORS = [
|
|
15
|
+
{
|
|
16
|
+
type: 'equal',
|
|
17
|
+
nbInputs: 1,
|
|
18
|
+
applyTo: allTypes,
|
|
19
|
+
optgroup: 'Equality',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: 'not_equal',
|
|
23
|
+
nbInputs: 1,
|
|
24
|
+
applyTo: allTypes,
|
|
25
|
+
optgroup: 'Equality',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'greater',
|
|
29
|
+
nbInputs: 1,
|
|
30
|
+
applyTo: [...numericTypes, ...dateTypes],
|
|
31
|
+
optgroup: 'Comparison',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'less',
|
|
35
|
+
nbInputs: 1,
|
|
36
|
+
applyTo: [...numericTypes, ...dateTypes],
|
|
37
|
+
optgroup: 'Comparison',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'contains',
|
|
41
|
+
nbInputs: 1,
|
|
42
|
+
applyTo: ['string'],
|
|
43
|
+
optgroup: 'String',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'starts_with',
|
|
47
|
+
nbInputs: 1,
|
|
48
|
+
applyTo: ['string'],
|
|
49
|
+
optgroup: 'String',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'ends_with',
|
|
53
|
+
nbInputs: 1,
|
|
54
|
+
applyTo: ['string'],
|
|
55
|
+
optgroup: 'String',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'one_of',
|
|
59
|
+
nbInputs: 'many',
|
|
60
|
+
applyTo: [...allTypes].filter((t) => t !== 'boolean'),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: 'not_any_of',
|
|
64
|
+
nbInputs: 'many',
|
|
65
|
+
applyTo: [...allTypes].filter((t) => t !== 'boolean'),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'within_inclusive',
|
|
69
|
+
nbInputs: 2,
|
|
70
|
+
applyTo: [...numericTypes, ...dateTypes],
|
|
71
|
+
optgroup: 'Range',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'within_exclusive',
|
|
75
|
+
nbInputs: 2,
|
|
76
|
+
applyTo: [...numericTypes, ...dateTypes],
|
|
77
|
+
optgroup: 'Range',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: 'is_null',
|
|
81
|
+
nbInputs: 0,
|
|
82
|
+
applyTo: [...allTypes],
|
|
83
|
+
optgroup: 'Null',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'not_null',
|
|
87
|
+
nbInputs: 0,
|
|
88
|
+
applyTo: [...allTypes],
|
|
89
|
+
optgroup: 'Null',
|
|
90
|
+
},
|
|
91
|
+
];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export var Events;
|
|
2
|
+
(function (Events) {
|
|
3
|
+
Events["AddGroup"] = "add-group";
|
|
4
|
+
Events["DelGroup"] = "del-group";
|
|
5
|
+
Events["AddRule"] = "add-rule";
|
|
6
|
+
Events["DelRule"] = "del-rule";
|
|
7
|
+
Events["UpdateGroup"] = "update-group";
|
|
8
|
+
Events["UpdateRule"] = "update-rule";
|
|
9
|
+
Events["FieldSelected"] = "field-selected";
|
|
10
|
+
Events["OperatorSelected"] = "operator-selected";
|
|
11
|
+
Events["ValueUpdated"] = "value-updated";
|
|
12
|
+
Events["RemoveVarArg"] = "remove-variadic-operand";
|
|
13
|
+
})(Events || (Events = {}));
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import rfdc from 'rfdc';
|
|
2
|
+
const deepClone = rfdc(); // create the fast deep copy function
|
|
3
|
+
/**
|
|
4
|
+
* Finds a group within a model and applies a function to create a new children
|
|
5
|
+
* @param model The root group to start searching from
|
|
6
|
+
* @param groupId The Group ID to find
|
|
7
|
+
* @param fn The function to apply to the children of the found group. A *new* object must be created and returned
|
|
8
|
+
* @returns A *new* root `Group` object which the function has been applied to. If the group isn't found an error is thrown
|
|
9
|
+
*/
|
|
10
|
+
export function findOperateOnGroup(model, groupId, fn) {
|
|
11
|
+
function findAndUpdate(node) {
|
|
12
|
+
const newNode = deepClone(node);
|
|
13
|
+
if (newNode.groupId === groupId) {
|
|
14
|
+
newNode.children = fn(newNode.children);
|
|
15
|
+
return newNode;
|
|
16
|
+
}
|
|
17
|
+
const updatedChildren = [];
|
|
18
|
+
let found = false;
|
|
19
|
+
for (const child of newNode.children) {
|
|
20
|
+
if ('children' in child) {
|
|
21
|
+
const updatedGroup = findAndUpdate(child);
|
|
22
|
+
if (updatedGroup) {
|
|
23
|
+
updatedChildren.push(updatedGroup);
|
|
24
|
+
found = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
updatedChildren.push(child);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
updatedChildren.push(child);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
newNode.children = updatedChildren;
|
|
35
|
+
// Only return the modified node if a group was found and modified within it
|
|
36
|
+
return found ? newNode : null;
|
|
37
|
+
}
|
|
38
|
+
const newModel = findAndUpdate(model);
|
|
39
|
+
if (!newModel)
|
|
40
|
+
throw new Error(`Unable to find group with groupId ${groupId}`);
|
|
41
|
+
return newModel;
|
|
42
|
+
}
|
|
43
|
+
function findNode(model, targetId, predicate) {
|
|
44
|
+
function find(node) {
|
|
45
|
+
for (const child of node.children) {
|
|
46
|
+
if (predicate(child, targetId)) {
|
|
47
|
+
return node; // Found
|
|
48
|
+
}
|
|
49
|
+
if ('children' in child) {
|
|
50
|
+
const found = find(child);
|
|
51
|
+
if (found) {
|
|
52
|
+
return found;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return find(model);
|
|
59
|
+
}
|
|
60
|
+
// Helper function to find the parent
|
|
61
|
+
function findParentGroupOfGroup(model, groupId) {
|
|
62
|
+
const predicate = (node, targetId) => {
|
|
63
|
+
return 'children' in node && node.groupId === targetId;
|
|
64
|
+
};
|
|
65
|
+
const res = findNode(model, groupId, predicate);
|
|
66
|
+
if (!res)
|
|
67
|
+
throw new Error(`No parent group found for group with ID ${groupId}`);
|
|
68
|
+
return res;
|
|
69
|
+
}
|
|
70
|
+
// Helper function to find the parent of a Rule
|
|
71
|
+
function findParentGroupOfRule(model, ruleId) {
|
|
72
|
+
const predicate = (node, targetId) => {
|
|
73
|
+
return 'ruleId' in node && node.ruleId === targetId;
|
|
74
|
+
};
|
|
75
|
+
const res = findNode(model, ruleId, predicate);
|
|
76
|
+
if (!res)
|
|
77
|
+
throw new Error(`No parent group found for rule with ID ${ruleId}`);
|
|
78
|
+
return res;
|
|
79
|
+
}
|
|
80
|
+
export function addGroupOrRule(model, parentGroupId, newItem) {
|
|
81
|
+
const addGroupFn = (children) => {
|
|
82
|
+
return [...children, newItem];
|
|
83
|
+
};
|
|
84
|
+
return findOperateOnGroup(model, parentGroupId, addGroupFn);
|
|
85
|
+
}
|
|
86
|
+
export function deleteGroup(model, groupIdToDelete) {
|
|
87
|
+
const deleteGroupFn = (children) => children.filter((child) => {
|
|
88
|
+
if ('groupId' in child) {
|
|
89
|
+
return child.groupId !== groupIdToDelete;
|
|
90
|
+
}
|
|
91
|
+
return true; // Keep rules
|
|
92
|
+
});
|
|
93
|
+
const parentGroup = findParentGroupOfGroup(model, groupIdToDelete);
|
|
94
|
+
return findOperateOnGroup(model, parentGroup.groupId, deleteGroupFn);
|
|
95
|
+
}
|
|
96
|
+
export function deleteRule(model, ruleIdToDelete) {
|
|
97
|
+
const deleteRuleFn = (children) => children.filter((child) => {
|
|
98
|
+
if ('ruleId' in child) {
|
|
99
|
+
return child.ruleId !== ruleIdToDelete;
|
|
100
|
+
}
|
|
101
|
+
return true; // Keep Groups
|
|
102
|
+
});
|
|
103
|
+
const parentGroup = findParentGroupOfRule(model, ruleIdToDelete);
|
|
104
|
+
return findOperateOnGroup(model, parentGroup.groupId, deleteRuleFn);
|
|
105
|
+
}
|
|
106
|
+
export const ROOT_GROUP = 'group-root';
|
|
107
|
+
export function updateGroupData(model, groupIdToUpdate, newData) {
|
|
108
|
+
if (groupIdToUpdate === ROOT_GROUP) {
|
|
109
|
+
return Object.assign(Object.assign({}, model), newData);
|
|
110
|
+
}
|
|
111
|
+
const updateGroupFn = (children) => children.map((child) => {
|
|
112
|
+
if ('groupId' in child && child.groupId === groupIdToUpdate) {
|
|
113
|
+
return Object.assign(Object.assign({}, child), newData);
|
|
114
|
+
}
|
|
115
|
+
return child;
|
|
116
|
+
});
|
|
117
|
+
const parentGroup = findParentGroupOfGroup(model, groupIdToUpdate);
|
|
118
|
+
return findOperateOnGroup(model, parentGroup.groupId, updateGroupFn);
|
|
119
|
+
}
|
|
120
|
+
export function updateRuleData(model, ruleIdToUpdate, newData) {
|
|
121
|
+
const updateRuleFn = (children) => children.map((child) => {
|
|
122
|
+
if ('ruleId' in child && child.ruleId === ruleIdToUpdate) {
|
|
123
|
+
return Object.assign(Object.assign({}, child), newData);
|
|
124
|
+
}
|
|
125
|
+
return child;
|
|
126
|
+
});
|
|
127
|
+
const parentGroup = findParentGroupOfRule(model, ruleIdToUpdate);
|
|
128
|
+
return findOperateOnGroup(model, parentGroup.groupId, updateRuleFn);
|
|
129
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, GenesisElement, observable } from '@genesislcap/web-core';
|
|
3
|
+
import { groupToModelGroup, modelGroupToGroup } from '../utils/data-model';
|
|
4
|
+
import { Events } from './events';
|
|
5
|
+
import { addGroupOrRule, deleteGroup, deleteRule, ROOT_GROUP, updateGroupData, updateRuleData, } from './expression-builder.helpers';
|
|
6
|
+
import { styles } from './expression-builder.styles';
|
|
7
|
+
import { template } from './expression-builder.template';
|
|
8
|
+
import { ExpressionGroup } from './expression-group/expression-group';
|
|
9
|
+
import { ExpressionRule } from './expression-rule/expression-rule';
|
|
10
|
+
ExpressionGroup;
|
|
11
|
+
ExpressionRule;
|
|
12
|
+
/** @alpha **/
|
|
13
|
+
let ExpressionBuilder = class ExpressionBuilder extends GenesisElement {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.model = null;
|
|
17
|
+
this.ruleCount = 0;
|
|
18
|
+
this.groupCount = 0;
|
|
19
|
+
this.handleAddGroup = this._handleAddGroup.bind(this);
|
|
20
|
+
this.handleAddRule = this._handleAddRule.bind(this);
|
|
21
|
+
this.handleDeleteGroup = this._handleDeleteGroup.bind(this);
|
|
22
|
+
this.handleDeleteRule = this._handleDeleteRule.bind(this);
|
|
23
|
+
this.handleUpdateGroupData = this._handleUpdateGroupData.bind(this);
|
|
24
|
+
this.handleUpdateRuleData = this._handleUpdateRuleData.bind(this);
|
|
25
|
+
}
|
|
26
|
+
/** @internal */
|
|
27
|
+
configChanged(_, newConfig) {
|
|
28
|
+
if (newConfig.model) {
|
|
29
|
+
this.ruleCount = 0;
|
|
30
|
+
this.groupCount = 0;
|
|
31
|
+
this.model = groupToModelGroup(newConfig.model, this);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** @internal */
|
|
35
|
+
modelChanged(_, newModel) {
|
|
36
|
+
if (!newModel)
|
|
37
|
+
return;
|
|
38
|
+
const group = modelGroupToGroup(newModel);
|
|
39
|
+
this.dispatchChangeEvent(group);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* @alpha
|
|
43
|
+
* Dispatches the provided model to the DOM.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* Override this to change the shape of model the component returns
|
|
47
|
+
*/
|
|
48
|
+
dispatchChangeEvent(group) {
|
|
49
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
50
|
+
detail: group,
|
|
51
|
+
bubbles: true,
|
|
52
|
+
cancelable: true,
|
|
53
|
+
composed: true,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
// Implement MetadataProvider interface
|
|
57
|
+
/** @internal */
|
|
58
|
+
getConfig() {
|
|
59
|
+
return this.config;
|
|
60
|
+
}
|
|
61
|
+
/** @internal */
|
|
62
|
+
getGroupId() {
|
|
63
|
+
this.groupCount += 1;
|
|
64
|
+
return `group-${this.groupCount}`;
|
|
65
|
+
}
|
|
66
|
+
/** @internal */
|
|
67
|
+
getRuleId() {
|
|
68
|
+
this.ruleCount += 1;
|
|
69
|
+
return `rule-${this.ruleCount}`;
|
|
70
|
+
}
|
|
71
|
+
// Behaviour
|
|
72
|
+
connectedCallback() {
|
|
73
|
+
super.connectedCallback();
|
|
74
|
+
if (!this.config || !this.config.combinators || !this.config.operators || !this.config.fields) {
|
|
75
|
+
throw new Error("Invalid config passed to ExpressionBuilder. Verify you've defined operators, fields, and combinators.");
|
|
76
|
+
}
|
|
77
|
+
this.addEventListener(Events.AddGroup, this.handleAddGroup);
|
|
78
|
+
this.addEventListener(Events.DelGroup, this.handleDeleteGroup);
|
|
79
|
+
this.addEventListener(Events.AddRule, this.handleAddRule);
|
|
80
|
+
this.addEventListener(Events.DelRule, this.handleDeleteRule);
|
|
81
|
+
this.addEventListener(Events.UpdateGroup, this.handleUpdateGroupData);
|
|
82
|
+
this.addEventListener(Events.UpdateRule, this.handleUpdateRuleData);
|
|
83
|
+
if (this.config.model)
|
|
84
|
+
return;
|
|
85
|
+
this.model = {
|
|
86
|
+
children: [],
|
|
87
|
+
level: 1,
|
|
88
|
+
groupId: ROOT_GROUP,
|
|
89
|
+
config: this.config,
|
|
90
|
+
combinator: this.config.combinators[0],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
disconnectedCallback() {
|
|
94
|
+
super.disconnectedCallback();
|
|
95
|
+
this.removeEventListener(Events.AddGroup, this.handleAddGroup);
|
|
96
|
+
this.removeEventListener(Events.DelGroup, this.handleDeleteGroup);
|
|
97
|
+
this.removeEventListener(Events.AddRule, this.handleAddRule);
|
|
98
|
+
this.removeEventListener(Events.DelRule, this.handleDeleteRule);
|
|
99
|
+
this.removeEventListener(Events.UpdateGroup, this.handleUpdateGroupData);
|
|
100
|
+
this.removeEventListener(Events.UpdateRule, this.handleUpdateRuleData);
|
|
101
|
+
}
|
|
102
|
+
_handleAddGroup(event) {
|
|
103
|
+
const { parentGroupId, newGroup: _newGroup } = event.detail;
|
|
104
|
+
const newGroup = {
|
|
105
|
+
groupId: this.getGroupId(),
|
|
106
|
+
level: _newGroup.level,
|
|
107
|
+
children: [],
|
|
108
|
+
config: this.config,
|
|
109
|
+
combinator: this.config.combinators[0],
|
|
110
|
+
};
|
|
111
|
+
this.model = addGroupOrRule(this.model, parentGroupId, newGroup);
|
|
112
|
+
}
|
|
113
|
+
_handleAddRule(event) {
|
|
114
|
+
const { parentGroupId } = event.detail;
|
|
115
|
+
const newRule = {
|
|
116
|
+
ruleId: this.getRuleId(),
|
|
117
|
+
config: this.config,
|
|
118
|
+
field: null,
|
|
119
|
+
operator: null,
|
|
120
|
+
value: null,
|
|
121
|
+
};
|
|
122
|
+
this.model = addGroupOrRule(this.model, parentGroupId, newRule);
|
|
123
|
+
}
|
|
124
|
+
_handleDeleteGroup(event) {
|
|
125
|
+
const { groupId } = event.detail;
|
|
126
|
+
this.model = deleteGroup(this.model, groupId);
|
|
127
|
+
}
|
|
128
|
+
_handleDeleteRule(event) {
|
|
129
|
+
const { ruleId } = event.detail;
|
|
130
|
+
this.model = deleteRule(this.model, ruleId);
|
|
131
|
+
}
|
|
132
|
+
_handleUpdateGroupData(event) {
|
|
133
|
+
const { groupId, newData } = event.detail;
|
|
134
|
+
this.model = updateGroupData(this.model, groupId, newData);
|
|
135
|
+
}
|
|
136
|
+
_handleUpdateRuleData(event) {
|
|
137
|
+
const { ruleId, newData } = event.detail;
|
|
138
|
+
this.model = updateRuleData(this.model, ruleId, newData);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
__decorate([
|
|
142
|
+
observable
|
|
143
|
+
], ExpressionBuilder.prototype, "config", void 0);
|
|
144
|
+
__decorate([
|
|
145
|
+
observable
|
|
146
|
+
], ExpressionBuilder.prototype, "styles", void 0);
|
|
147
|
+
__decorate([
|
|
148
|
+
observable
|
|
149
|
+
], ExpressionBuilder.prototype, "model", void 0);
|
|
150
|
+
ExpressionBuilder = __decorate([
|
|
151
|
+
customElement({
|
|
152
|
+
name: 'expression-builder',
|
|
153
|
+
template,
|
|
154
|
+
styles,
|
|
155
|
+
})
|
|
156
|
+
], ExpressionBuilder);
|
|
157
|
+
export { ExpressionBuilder };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { css } from '@genesislcap/web-core';
|
|
2
|
+
/** @alpha **/
|
|
3
|
+
export const styles = css `
|
|
4
|
+
:host {
|
|
5
|
+
--item-vertical-spacing: 4px;
|
|
6
|
+
--item-border-radius: 5px;
|
|
7
|
+
--group-background-color: rgb(250 240 210 / 50%);
|
|
8
|
+
--group-border-color: #dcc896;
|
|
9
|
+
--group-border: 1px solid var(--group-border-color);
|
|
10
|
+
--group-padding: 10px;
|
|
11
|
+
--rule-background-color: rgb(255 255 255 / 90%);
|
|
12
|
+
--rule-border-color: #eee;
|
|
13
|
+
--rule-border: 1px solid var(--rule-border-color);
|
|
14
|
+
--rule-padding: 5px;
|
|
15
|
+
--rule-value-separator: 1px solid #ddd;
|
|
16
|
+
--error-icon-color: #f00;
|
|
17
|
+
--error-border-color: #f99;
|
|
18
|
+
--error-background-color: #fdd;
|
|
19
|
+
--ticks-width: 2px;
|
|
20
|
+
--ticks-color: #ccc;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
p.test {
|
|
24
|
+
color: black;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.query-builder {
|
|
28
|
+
font-family: sans-serif;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.rules-group-container {
|
|
32
|
+
position: relative;
|
|
33
|
+
margin: var(--item-vertical-spacing) 0;
|
|
34
|
+
border-radius: var(--item-border-radius);
|
|
35
|
+
padding: var(--group-padding);
|
|
36
|
+
border: var(--group-border);
|
|
37
|
+
background: var(--group-background-color);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.rules-group-header {
|
|
41
|
+
margin-bottom: var(--group-padding);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.group-conditions {
|
|
45
|
+
display: inline-block;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.group-conditions .btn {
|
|
49
|
+
padding: 0.25rem 0.5rem;
|
|
50
|
+
font-size: 0.875rem;
|
|
51
|
+
line-height: 1.5;
|
|
52
|
+
border-radius: 0.2rem;
|
|
53
|
+
border: 1px solid #007bff;
|
|
54
|
+
color: #007bff;
|
|
55
|
+
background-color: transparent;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.group-conditions .btn:hover {
|
|
60
|
+
background-color: #007bff;
|
|
61
|
+
color: #fff;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.group-conditions .btn.active {
|
|
65
|
+
background-color: #007bff;
|
|
66
|
+
color: #fff;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.group-actions {
|
|
70
|
+
display: inline-block;
|
|
71
|
+
float: right;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.rules-list {
|
|
75
|
+
list-style: none;
|
|
76
|
+
padding: 0 0 0 20px; /* Adjusted ticks position */
|
|
77
|
+
margin: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.rule-container {
|
|
81
|
+
position: relative;
|
|
82
|
+
margin: var(--item-vertical-spacing) 0;
|
|
83
|
+
border-radius: var(--item-border-radius);
|
|
84
|
+
padding: var(--rule-padding);
|
|
85
|
+
border: var(--rule-border);
|
|
86
|
+
background: var(--rule-background-color);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.rule-header {
|
|
90
|
+
margin-bottom: 5px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.rule-actions {
|
|
94
|
+
display: inline-block;
|
|
95
|
+
float: right;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.rule-field-container,
|
|
99
|
+
.rule-operator-container,
|
|
100
|
+
.rule-value-container {
|
|
101
|
+
display: inline-block;
|
|
102
|
+
margin: 0 5px 0 0;
|
|
103
|
+
vertical-align: middle;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.rule-value-container {
|
|
107
|
+
border-left: var(--rule-value-separator);
|
|
108
|
+
padding-left: 5px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.rule-value-container label {
|
|
112
|
+
margin-bottom: 0;
|
|
113
|
+
font-weight: normal;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.rule-value-container label.block {
|
|
117
|
+
display: block;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.error-container {
|
|
121
|
+
display: none;
|
|
122
|
+
cursor: help;
|
|
123
|
+
color: var(--error-icon-color);
|
|
124
|
+
margin-left: 5px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.rule-container.has-error,
|
|
128
|
+
.rules-group-container.has-error {
|
|
129
|
+
background-color: var(--error-background-color);
|
|
130
|
+
border-color: var(--error-border-color);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.rule-container.has-error .error-container,
|
|
134
|
+
.rules-group-container.has-error .error-container {
|
|
135
|
+
display: inline-block !important;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Ticks */
|
|
139
|
+
.rules-list > * {
|
|
140
|
+
position: relative;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.rules-list > *::before,
|
|
144
|
+
.rules-list > *::after {
|
|
145
|
+
content: '';
|
|
146
|
+
position: absolute;
|
|
147
|
+
left: -10px; /* Adjusted ticks position */
|
|
148
|
+
width: 10px; /* Adjusted ticks position */
|
|
149
|
+
border-color: var(--ticks-color);
|
|
150
|
+
border-style: solid;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.rules-list > *::before {
|
|
154
|
+
top: -2px; /* Adjusted ticks position */
|
|
155
|
+
height: calc(50% + var(--item-vertical-spacing));
|
|
156
|
+
border-width: 0 0 var(--ticks-width) var(--ticks-width);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.rules-list > *::after {
|
|
160
|
+
top: 50%;
|
|
161
|
+
border-width: 0 0 0 var(--ticks-width);
|
|
162
|
+
height: 50%;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.rules-list > *:first-child::before {
|
|
166
|
+
top: calc(-1 * var(--group-padding) - var(--ticks-width));
|
|
167
|
+
height: calc(50% + var(--group-padding) + var(--item-vertical-spacing));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.rules-list > *:last-child::before {
|
|
171
|
+
border-radius: 0 0 0 calc(2 * var(--ticks-width));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.rules-list > *:last-child::after {
|
|
175
|
+
display: none;
|
|
176
|
+
}
|
|
177
|
+
`;
|