@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,13 @@
|
|
|
1
|
+
import { html } from '@genesislcap/web-core';
|
|
2
|
+
import { ExpressionGroup } from './expression-group/expression-group';
|
|
3
|
+
ExpressionGroup;
|
|
4
|
+
/** @alpha **/
|
|
5
|
+
export const template = html `
|
|
6
|
+
<div class="query-builder">
|
|
7
|
+
<expression-group
|
|
8
|
+
:model=${(x) => x.model}
|
|
9
|
+
:config=${(x) => x.config}
|
|
10
|
+
:styles=${(x) => x.styles}
|
|
11
|
+
></expression-group>
|
|
12
|
+
</div>
|
|
13
|
+
`;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, GenesisElement, observable, volatile } from '@genesislcap/web-core';
|
|
3
|
+
import { applyCustomStyles } from '../../utils/misc';
|
|
4
|
+
import { Events } from '../events';
|
|
5
|
+
import { styles } from './expression-group.styles';
|
|
6
|
+
import { template } from './expression-group.template';
|
|
7
|
+
let ExpressionGroup = class ExpressionGroup extends GenesisElement {
|
|
8
|
+
connectedCallback() {
|
|
9
|
+
super.connectedCallback();
|
|
10
|
+
applyCustomStyles(this, this.styles, 'group');
|
|
11
|
+
}
|
|
12
|
+
get allowNestedGroup() {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
if (!this.model)
|
|
15
|
+
return false;
|
|
16
|
+
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxNesting) || ((_b = this.config) === null || _b === void 0 ? void 0 : _b.maxNesting) < 1)
|
|
17
|
+
return true;
|
|
18
|
+
return this.config.maxNesting > this.model.level;
|
|
19
|
+
}
|
|
20
|
+
// configChanged(_, newConfig: Config) {
|
|
21
|
+
// if (!this.combinator) {
|
|
22
|
+
// this.combinator = newConfig.combinators[0];
|
|
23
|
+
// }
|
|
24
|
+
// }
|
|
25
|
+
//
|
|
26
|
+
// modelChanged(_, newModel: ModelGroup) {
|
|
27
|
+
// if (!newModel) return;
|
|
28
|
+
// this.combinator = newModel.combinator;
|
|
29
|
+
// }
|
|
30
|
+
dispatchAddRule(event) {
|
|
31
|
+
event.stopPropagation();
|
|
32
|
+
const detail = {
|
|
33
|
+
parentGroupId: this.model.groupId,
|
|
34
|
+
};
|
|
35
|
+
this.dispatchEvent(new CustomEvent(Events.AddRule, { detail, bubbles: true, composed: true }));
|
|
36
|
+
}
|
|
37
|
+
dispatchAddGroup(event) {
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
if (!this.allowNestedGroup)
|
|
40
|
+
throw new Error('Cannot add further nested groups');
|
|
41
|
+
const detail = {
|
|
42
|
+
parentGroupId: this.model.groupId,
|
|
43
|
+
newGroup: {
|
|
44
|
+
level: this.model.level + 1,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
this.dispatchEvent(new CustomEvent(Events.AddGroup, { detail, bubbles: true, composed: true }));
|
|
48
|
+
}
|
|
49
|
+
dispatchDeleteGroup(event) {
|
|
50
|
+
event.stopPropagation();
|
|
51
|
+
const detail = {
|
|
52
|
+
groupId: this.model.groupId,
|
|
53
|
+
};
|
|
54
|
+
this.dispatchEvent(new CustomEvent(Events.DelGroup, { detail, bubbles: true, composed: true }));
|
|
55
|
+
}
|
|
56
|
+
handleCombinatorChange(event) {
|
|
57
|
+
event.stopPropagation();
|
|
58
|
+
const target = event.target;
|
|
59
|
+
const value = target.value;
|
|
60
|
+
this.updateCombinator(value);
|
|
61
|
+
}
|
|
62
|
+
handleCustomCombinatorChange(event) {
|
|
63
|
+
var _a;
|
|
64
|
+
event.stopPropagation();
|
|
65
|
+
if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.groupId) || !event.target)
|
|
66
|
+
return; // can happen when the radio is first initialised
|
|
67
|
+
const target = event.target;
|
|
68
|
+
const value = target.getAttribute('value');
|
|
69
|
+
if (!value) {
|
|
70
|
+
throw new Error('No value found in the custom radio group event target');
|
|
71
|
+
}
|
|
72
|
+
this.updateCombinator(value);
|
|
73
|
+
}
|
|
74
|
+
updateCombinator(value) {
|
|
75
|
+
var _a, _b;
|
|
76
|
+
const combinator = this.config.combinators.find(({ type }) => type === value);
|
|
77
|
+
if (!combinator) {
|
|
78
|
+
throw new Error(`Cannot find selected combinator ${value}`);
|
|
79
|
+
}
|
|
80
|
+
// Can happen when web component is initialised
|
|
81
|
+
if (((_b = (_a = this.model) === null || _a === void 0 ? void 0 : _a.combinator) === null || _b === void 0 ? void 0 : _b.type) === combinator.type) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.dispatchGroupDataUpdated(combinator);
|
|
85
|
+
}
|
|
86
|
+
dispatchGroupDataUpdated(combinator) {
|
|
87
|
+
const detail = {
|
|
88
|
+
groupId: this.model.groupId,
|
|
89
|
+
newData: {
|
|
90
|
+
combinator,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateGroup, { detail, bubbles: true, composed: true }));
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
__decorate([
|
|
97
|
+
observable
|
|
98
|
+
], ExpressionGroup.prototype, "config", void 0);
|
|
99
|
+
__decorate([
|
|
100
|
+
observable
|
|
101
|
+
], ExpressionGroup.prototype, "styles", void 0);
|
|
102
|
+
__decorate([
|
|
103
|
+
observable
|
|
104
|
+
], ExpressionGroup.prototype, "model", void 0);
|
|
105
|
+
__decorate([
|
|
106
|
+
observable
|
|
107
|
+
], ExpressionGroup.prototype, "index", void 0);
|
|
108
|
+
__decorate([
|
|
109
|
+
volatile
|
|
110
|
+
], ExpressionGroup.prototype, "allowNestedGroup", null);
|
|
111
|
+
ExpressionGroup = __decorate([
|
|
112
|
+
customElement({
|
|
113
|
+
name: 'expression-group',
|
|
114
|
+
template,
|
|
115
|
+
styles: styles,
|
|
116
|
+
shadowOptions: {
|
|
117
|
+
delegatesFocus: true, // Ensure the element can be focused
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
], ExpressionGroup);
|
|
121
|
+
export { ExpressionGroup };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { css } from '@genesislcap/web-core';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
.rules-group-container {
|
|
4
|
+
border: 1px solid #ccc;
|
|
5
|
+
margin-bottom: 10px;
|
|
6
|
+
padding: 10px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.rules-group-header {
|
|
10
|
+
margin-bottom: 5px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.btn-group {
|
|
14
|
+
margin-right: 5px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.btn {
|
|
18
|
+
padding: 0.25rem 0.5rem;
|
|
19
|
+
font-size: 0.875rem;
|
|
20
|
+
line-height: 1.5;
|
|
21
|
+
border-radius: 0.2rem;
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.btn-success {
|
|
26
|
+
color: #fff;
|
|
27
|
+
background-color: #28a745;
|
|
28
|
+
border-color: #28a745;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.btn-danger {
|
|
32
|
+
color: #fff;
|
|
33
|
+
background-color: #dc3545;
|
|
34
|
+
border-color: #dc3545;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.radio-group-container {
|
|
38
|
+
display: flex;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.rules-list {
|
|
42
|
+
list-style: none;
|
|
43
|
+
padding-left: 0;
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { html, repeat, when, whenElse } from '@genesislcap/web-core';
|
|
2
|
+
export const template = html `
|
|
3
|
+
${(context) => {
|
|
4
|
+
var _a, _b, _c, _d;
|
|
5
|
+
const buttonTag = ((_b = (_a = context.styles) === null || _a === void 0 ? void 0 : _a.customElements) === null || _b === void 0 ? void 0 : _b.button) || 'button';
|
|
6
|
+
const maybeRadioBlock = (_d = (_c = context.styles) === null || _c === void 0 ? void 0 : _c.customElements) === null || _d === void 0 ? void 0 : _d.radio;
|
|
7
|
+
const { radioTag, radioGroupTag } = maybeRadioBlock
|
|
8
|
+
? { radioTag: maybeRadioBlock.input, radioGroupTag: maybeRadioBlock.group }
|
|
9
|
+
: { radioTag: 'input', radioGroupTag: 'div' };
|
|
10
|
+
return html `
|
|
11
|
+
<div class="rules-group-container">
|
|
12
|
+
<div class="rules-group-header">
|
|
13
|
+
<div class="btn-group float-end group-actions">
|
|
14
|
+
<${buttonTag}
|
|
15
|
+
type="button"
|
|
16
|
+
class="btn btn-sm btn-success"
|
|
17
|
+
data-add="rule"
|
|
18
|
+
@click="${(x, c) => x.dispatchAddRule(c.event)}"
|
|
19
|
+
>
|
|
20
|
+
Add Rule
|
|
21
|
+
</${buttonTag}>
|
|
22
|
+
${when((x) => x.allowNestedGroup, html `
|
|
23
|
+
<${buttonTag}
|
|
24
|
+
type="button"
|
|
25
|
+
class="btn btn-sm btn-success"
|
|
26
|
+
data-add="group"
|
|
27
|
+
@click="${(x, c) => x.dispatchAddGroup(c.event)}"
|
|
28
|
+
>
|
|
29
|
+
Add Group
|
|
30
|
+
</${buttonTag}>
|
|
31
|
+
`)}
|
|
32
|
+
${when((x) => typeof x.index === 'number', html `
|
|
33
|
+
<${buttonTag}
|
|
34
|
+
type="button"
|
|
35
|
+
class="btn btn-sm btn-danger"
|
|
36
|
+
data-delete="group"
|
|
37
|
+
@click="${(x, c) => x.dispatchDeleteGroup(c.event)}"
|
|
38
|
+
>
|
|
39
|
+
Delete Group
|
|
40
|
+
</${buttonTag}>
|
|
41
|
+
`)}
|
|
42
|
+
<div class="btn-group group-conditions">
|
|
43
|
+
${whenElse((_) => radioTag !== 'input', html `
|
|
44
|
+
<${radioGroupTag}
|
|
45
|
+
class="radio-group-container"
|
|
46
|
+
name="combinator"
|
|
47
|
+
@change="${(x, c) => x.handleCombinatorChange(c.event)}"
|
|
48
|
+
value="${(x) => { var _a, _b; return (_b = (_a = x.model) === null || _a === void 0 ? void 0 : _a.combinator) === null || _b === void 0 ? void 0 : _b.type; }}"
|
|
49
|
+
>
|
|
50
|
+
${repeat((x) => x.config.combinators, html `
|
|
51
|
+
<${radioTag}
|
|
52
|
+
value="${(x) => x.type}"
|
|
53
|
+
?checked=${(x, c) => { var _a, _b; return ((_b = (_a = c.parent.model) === null || _a === void 0 ? void 0 : _a.combinator) === null || _b === void 0 ? void 0 : _b.type) === x.type; }}
|
|
54
|
+
>
|
|
55
|
+
${(x) => { var _a; return (_a = x.label) !== null && _a !== void 0 ? _a : x.type; }}
|
|
56
|
+
</${radioTag}>
|
|
57
|
+
`)}
|
|
58
|
+
</${radioGroupTag}>
|
|
59
|
+
`, html `
|
|
60
|
+
<div class="radio-group-container">
|
|
61
|
+
${repeat((x) => x.config.combinators, html `
|
|
62
|
+
<label class="btn btn-sm btn-primary">
|
|
63
|
+
<input
|
|
64
|
+
type="radio"
|
|
65
|
+
name="combinator"
|
|
66
|
+
value="${(x) => x.type}"
|
|
67
|
+
@change="${(_, c) => c.parent.handleCombinatorChange(c.event)}"
|
|
68
|
+
?checked=${(x, c) => { var _a, _b; return ((_b = (_a = c.parent.model) === null || _a === void 0 ? void 0 : _a.combinator) === null || _b === void 0 ? void 0 : _b.type) === x.type; }}
|
|
69
|
+
/>
|
|
70
|
+
${(x) => { var _a; return (_a = x.label) !== null && _a !== void 0 ? _a : x.type; }}
|
|
71
|
+
</label>
|
|
72
|
+
`)}
|
|
73
|
+
</div>
|
|
74
|
+
`)}
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="rules-group-body">
|
|
78
|
+
<div class="rules-list">
|
|
79
|
+
${repeat((x) => { var _a, _b; return (_b = (_a = x.model) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : []; }, html `
|
|
80
|
+
${whenElse((x) => 'children' in x, html `
|
|
81
|
+
<expression-group
|
|
82
|
+
:config=${(_, c) => c.parent.config}
|
|
83
|
+
:styles=${(_, c) => c.parent.styles}
|
|
84
|
+
:model=${(x) => x}
|
|
85
|
+
:index=${(_, c) => c.index}
|
|
86
|
+
></expression-group>
|
|
87
|
+
`, html `
|
|
88
|
+
<expression-rule
|
|
89
|
+
:config=${(_, c) => c.parent.config}
|
|
90
|
+
:styles=${(_, c) => c.parent.styles}
|
|
91
|
+
:model=${(x) => x}
|
|
92
|
+
:index=${(_, c) => c.index}
|
|
93
|
+
></expression-rule>
|
|
94
|
+
`)}
|
|
95
|
+
`, { recycle: false, positioning: true })}
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
`;
|
|
101
|
+
}}
|
|
102
|
+
`;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { formatDateString, formatDateTimeString } from '../../utils';
|
|
2
|
+
export const defaultVal = (f) => f.defaultValue !== undefined ? f.defaultValue : fieldDefault(f);
|
|
3
|
+
export const fieldDefault = (f) => {
|
|
4
|
+
switch (f.type) {
|
|
5
|
+
case 'string':
|
|
6
|
+
return '';
|
|
7
|
+
case 'boolean':
|
|
8
|
+
return false;
|
|
9
|
+
case 'date':
|
|
10
|
+
return formatDateString(new Date());
|
|
11
|
+
case 'date-time':
|
|
12
|
+
return formatDateTimeString(new Date());
|
|
13
|
+
case 'double':
|
|
14
|
+
case 'int':
|
|
15
|
+
case 'bigdecimal':
|
|
16
|
+
case 'short':
|
|
17
|
+
case 'long':
|
|
18
|
+
return 0;
|
|
19
|
+
case 'enum': {
|
|
20
|
+
if (Object.keys(f.values).length === 0)
|
|
21
|
+
throw new Error('Enums require configured values');
|
|
22
|
+
return Object.keys(f.values)[0];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, GenesisElement, observable, volatile } from '@genesislcap/web-core';
|
|
3
|
+
import { applyCustomStyles } from '../../utils/misc';
|
|
4
|
+
import { Events } from '../events';
|
|
5
|
+
import { RuleField } from '../rule-field/rule-field';
|
|
6
|
+
import { RuleOperator } from '../rule-operator/rule-operator';
|
|
7
|
+
import { RuleValue } from '../rule-value/rule-value';
|
|
8
|
+
import { defaultVal } from './expression-rule.helpers';
|
|
9
|
+
import { styles } from './expression-rule.styles';
|
|
10
|
+
import { template } from './expression-rule.template';
|
|
11
|
+
RuleOperator;
|
|
12
|
+
RuleField;
|
|
13
|
+
RuleValue;
|
|
14
|
+
let ExpressionRule = class ExpressionRule extends GenesisElement {
|
|
15
|
+
connectedCallback() {
|
|
16
|
+
super.connectedCallback();
|
|
17
|
+
applyCustomStyles(this, this.styles, 'rule');
|
|
18
|
+
}
|
|
19
|
+
variadicRule(model) {
|
|
20
|
+
return model.operator.nbInputs === 'many' && 'value' in model && Array.isArray(model.value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
* Creates an array of length n to represent to number of argument to the operator
|
|
25
|
+
*/
|
|
26
|
+
get operandIterator() {
|
|
27
|
+
var _a, _b, _c;
|
|
28
|
+
if (((_a = this.model.operator) === null || _a === void 0 ? void 0 : _a.nbInputs) === 'many') {
|
|
29
|
+
if (!this.variadicRule(this.model))
|
|
30
|
+
throw new Error('Varargs disabled for many nbInputs');
|
|
31
|
+
return Array(this.model.value.length).fill(true);
|
|
32
|
+
}
|
|
33
|
+
return Array((_c = (_b = this.model.operator) === null || _b === void 0 ? void 0 : _b.nbInputs) !== null && _c !== void 0 ? _c : 0).fill(true);
|
|
34
|
+
}
|
|
35
|
+
operandValue(index) {
|
|
36
|
+
if (!this.model.operator)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (this.model.operator.nbInputs === 1 && 'value' in this.model) {
|
|
39
|
+
return this.model.value;
|
|
40
|
+
}
|
|
41
|
+
else if ((this.model.operator.nbInputs === 2 || this.model.operator.nbInputs === 'many') &&
|
|
42
|
+
'value' in this.model &&
|
|
43
|
+
Array.isArray(this.model.value)) {
|
|
44
|
+
return this.model.value[index];
|
|
45
|
+
}
|
|
46
|
+
throw new Error('Invalid operand lookup');
|
|
47
|
+
}
|
|
48
|
+
dispatchAddVarArg() {
|
|
49
|
+
if (!this.variadicRule(this.model))
|
|
50
|
+
throw new Error('Cannot add inputs for non-variadic operator, or invalid format');
|
|
51
|
+
const detail = {
|
|
52
|
+
ruleId: this.model.ruleId,
|
|
53
|
+
newData: {
|
|
54
|
+
operator: this.model.operator,
|
|
55
|
+
field: this.model.field,
|
|
56
|
+
value: [...this.model.value, defaultVal(this.model.field)],
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateRule, { detail, bubbles: true, composed: true }));
|
|
60
|
+
}
|
|
61
|
+
handleRemoveVarArg(event) {
|
|
62
|
+
const { index } = event.detail;
|
|
63
|
+
if (!this.variadicRule(this.model))
|
|
64
|
+
throw new Error('Cannot remove inputs for non-variadic operator, or invalid format');
|
|
65
|
+
const detail = {
|
|
66
|
+
ruleId: this.model.ruleId,
|
|
67
|
+
newData: {
|
|
68
|
+
operator: this.model.operator,
|
|
69
|
+
field: this.model.field,
|
|
70
|
+
value: this.model.value.filter((_, i) => i !== index),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateRule, { detail, bubbles: true, composed: true }));
|
|
74
|
+
}
|
|
75
|
+
dispatchDeleteRule(event) {
|
|
76
|
+
event.stopPropagation();
|
|
77
|
+
const detail = {
|
|
78
|
+
ruleId: this.model.ruleId,
|
|
79
|
+
};
|
|
80
|
+
this.dispatchEvent(new CustomEvent(Events.DelRule, { detail, bubbles: true, composed: true }));
|
|
81
|
+
}
|
|
82
|
+
handleFieldSelected(event) {
|
|
83
|
+
var _a;
|
|
84
|
+
event.stopPropagation();
|
|
85
|
+
const { fieldId } = event.detail;
|
|
86
|
+
const newFiler = (_a = this.config.fields.find((filter) => filter.fieldId === fieldId)) !== null && _a !== void 0 ? _a : null;
|
|
87
|
+
if (!newFiler) {
|
|
88
|
+
throw new Error(`Unable to find field with id ${fieldId}`);
|
|
89
|
+
}
|
|
90
|
+
const detail = {
|
|
91
|
+
ruleId: this.model.ruleId,
|
|
92
|
+
newData: {
|
|
93
|
+
field: newFiler,
|
|
94
|
+
value: null,
|
|
95
|
+
operator: null,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateRule, { detail, bubbles: true, composed: true }));
|
|
99
|
+
}
|
|
100
|
+
handleValueChanged(event) {
|
|
101
|
+
event.stopPropagation();
|
|
102
|
+
const { value, index } = event.detail;
|
|
103
|
+
const buildUpdatedModel = (operator) => {
|
|
104
|
+
switch (operator.nbInputs) {
|
|
105
|
+
case 0:
|
|
106
|
+
throw new Error('Cannot set the value for a UniraryOperator');
|
|
107
|
+
case 1:
|
|
108
|
+
return {
|
|
109
|
+
field: this.model.field,
|
|
110
|
+
operator: operator,
|
|
111
|
+
value,
|
|
112
|
+
};
|
|
113
|
+
case 2:
|
|
114
|
+
case 'many': {
|
|
115
|
+
if (!('value' in this.model) || !Array.isArray(this.model.value))
|
|
116
|
+
throw new Error('Invalid value shape for rule');
|
|
117
|
+
return {
|
|
118
|
+
field: this.model.field,
|
|
119
|
+
operator: operator,
|
|
120
|
+
value: this.model.value.map((v, i) => (i === index ? value : v)),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const detail = {
|
|
126
|
+
ruleId: this.model.ruleId,
|
|
127
|
+
newData: buildUpdatedModel(this.model.operator),
|
|
128
|
+
};
|
|
129
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateRule, { detail, bubbles: true, composed: true }));
|
|
130
|
+
}
|
|
131
|
+
handleOperatorSelected(event) {
|
|
132
|
+
var _a;
|
|
133
|
+
event.stopPropagation();
|
|
134
|
+
const { operatorId: operatorType } = event.detail;
|
|
135
|
+
if (!operatorType)
|
|
136
|
+
return; // occurs when selecting "Select an operator"
|
|
137
|
+
const newOperator = (_a = this.config.operators.find((operator) => operator.type === operatorType)) !== null && _a !== void 0 ? _a : null;
|
|
138
|
+
if (!newOperator) {
|
|
139
|
+
throw new Error(`Unable to find operator of type ${operatorType}`);
|
|
140
|
+
}
|
|
141
|
+
const buildUpdatedModel = (operator) => {
|
|
142
|
+
switch (operator.nbInputs) {
|
|
143
|
+
case 0:
|
|
144
|
+
return {
|
|
145
|
+
field: this.model.field,
|
|
146
|
+
operator: operator,
|
|
147
|
+
};
|
|
148
|
+
case 1:
|
|
149
|
+
return {
|
|
150
|
+
field: this.model.field,
|
|
151
|
+
operator: operator,
|
|
152
|
+
value: defaultVal(this.model.field),
|
|
153
|
+
};
|
|
154
|
+
case 2:
|
|
155
|
+
return {
|
|
156
|
+
field: this.model.field,
|
|
157
|
+
operator: operator,
|
|
158
|
+
value: [defaultVal(this.model.field), defaultVal(this.model.field)],
|
|
159
|
+
};
|
|
160
|
+
case 'many':
|
|
161
|
+
return {
|
|
162
|
+
field: this.model.field,
|
|
163
|
+
operator: operator,
|
|
164
|
+
value: [defaultVal(this.model.field)],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
this.dispatchEvent(new CustomEvent(Events.UpdateRule, {
|
|
169
|
+
detail: {
|
|
170
|
+
ruleId: this.model.ruleId,
|
|
171
|
+
newData: buildUpdatedModel(newOperator),
|
|
172
|
+
},
|
|
173
|
+
bubbles: true,
|
|
174
|
+
composed: true,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
__decorate([
|
|
179
|
+
observable
|
|
180
|
+
], ExpressionRule.prototype, "config", void 0);
|
|
181
|
+
__decorate([
|
|
182
|
+
observable
|
|
183
|
+
], ExpressionRule.prototype, "styles", void 0);
|
|
184
|
+
__decorate([
|
|
185
|
+
observable
|
|
186
|
+
], ExpressionRule.prototype, "model", void 0);
|
|
187
|
+
__decorate([
|
|
188
|
+
observable
|
|
189
|
+
], ExpressionRule.prototype, "index", void 0);
|
|
190
|
+
__decorate([
|
|
191
|
+
volatile
|
|
192
|
+
], ExpressionRule.prototype, "operandIterator", null);
|
|
193
|
+
ExpressionRule = __decorate([
|
|
194
|
+
customElement({
|
|
195
|
+
name: 'expression-rule',
|
|
196
|
+
template,
|
|
197
|
+
styles: styles,
|
|
198
|
+
shadowOptions: {
|
|
199
|
+
delegatesFocus: true, // Ensure the element can be focused
|
|
200
|
+
},
|
|
201
|
+
})
|
|
202
|
+
], ExpressionRule);
|
|
203
|
+
export { ExpressionRule };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { css } from '@genesislcap/web-core';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
.rule-container {
|
|
4
|
+
border: 1px solid #eee;
|
|
5
|
+
margin-bottom: 5px;
|
|
6
|
+
padding: 5px;
|
|
7
|
+
display: grid;
|
|
8
|
+
grid-template-columns: auto 1fr;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.margin {
|
|
12
|
+
margin-left: calc(var(--design-unit) * 1px);
|
|
13
|
+
margin-right: calc(var(--design-unit) * 1px);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.rule-header {
|
|
17
|
+
margin-bottom: 5px;
|
|
18
|
+
display: flex;
|
|
19
|
+
justify-content: flex-end;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.rule-actions {
|
|
23
|
+
display: inline-block;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.rule-content {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-wrap: wrap;
|
|
29
|
+
align-items: center;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.rule-field-container,
|
|
33
|
+
.rule-operator-container,
|
|
34
|
+
.rule-value-container {
|
|
35
|
+
display: inline-block;
|
|
36
|
+
margin: 0 5px 0 0;
|
|
37
|
+
vertical-align: middle;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.rule-value-container {
|
|
41
|
+
border-left: var(--rule-value-separator);
|
|
42
|
+
padding-left: 5px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.rule-value-container label {
|
|
46
|
+
margin-bottom: 0;
|
|
47
|
+
font-weight: normal;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.rule-value-container label.block {
|
|
51
|
+
display: block;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
expression-rule-value {
|
|
55
|
+
display: flex;
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { html, repeat, when } from '@genesislcap/web-core';
|
|
2
|
+
export const template = html `
|
|
3
|
+
${(context) => {
|
|
4
|
+
var _a, _b;
|
|
5
|
+
const buttonTag = ((_b = (_a = context.styles) === null || _a === void 0 ? void 0 : _a.customElements) === null || _b === void 0 ? void 0 : _b.button) || 'button';
|
|
6
|
+
return html `
|
|
7
|
+
<div class="rule-container">
|
|
8
|
+
<div class="rule-content">
|
|
9
|
+
<expression-rule-field
|
|
10
|
+
class="margin"
|
|
11
|
+
:fields=${(x) => x.config.fields}
|
|
12
|
+
:field=${(x) => { var _a; return (_a = x.model) === null || _a === void 0 ? void 0 : _a.field; }}
|
|
13
|
+
:config=${(x) => x.config}
|
|
14
|
+
:styles=${(x) => x.styles}
|
|
15
|
+
@field-selected=${(x, c) => x.handleFieldSelected(c.event)}
|
|
16
|
+
></expression-rule-field>
|
|
17
|
+
<expression-rule-operator
|
|
18
|
+
class="margin"
|
|
19
|
+
:operators=${(x) => x.config.operators}
|
|
20
|
+
:field=${(x) => x.model.field}
|
|
21
|
+
:operator=${(x) => { var _a; return (_a = x.model) === null || _a === void 0 ? void 0 : _a.operator; }}
|
|
22
|
+
:config=${(x) => x.config}
|
|
23
|
+
:styles=${(x) => x.styles}
|
|
24
|
+
@operator-selected=${(x, c) => x.handleOperatorSelected(c.event)}
|
|
25
|
+
></expression-rule-operator>
|
|
26
|
+
${repeat((x) => x.operandIterator, html `
|
|
27
|
+
<expression-rule-value
|
|
28
|
+
class="margin"
|
|
29
|
+
:config=${(_, c) => c.parent.config}
|
|
30
|
+
:styles=${(_, c) => c.parent.styles}
|
|
31
|
+
:field=${(_, c) => c.parent.model.field}
|
|
32
|
+
:value=${(_, c) => c.parent.operandValue(c.index)}
|
|
33
|
+
value-index=${(_, c) => c.index}
|
|
34
|
+
?variadic=${(_, c) => { var _a, _b; return ((_b = (_a = c.parent.model) === null || _a === void 0 ? void 0 : _a.operator) === null || _b === void 0 ? void 0 : _b.nbInputs) === 'many'; }}
|
|
35
|
+
@value-updated=${(_, c) => c.parent.handleValueChanged(c.event)}
|
|
36
|
+
@remove-variadic-operand=${(_, c) => c.parent.handleRemoveVarArg(c.event)}
|
|
37
|
+
></expression-rule-value>
|
|
38
|
+
`, { positioning: true, recycle: false })}
|
|
39
|
+
${when((x) => { var _a, _b; return ((_b = (_a = x.model) === null || _a === void 0 ? void 0 : _a.operator) === null || _b === void 0 ? void 0 : _b.nbInputs) === 'many'; }, html `
|
|
40
|
+
<${buttonTag}
|
|
41
|
+
type="button"
|
|
42
|
+
class="btn btn-sm btn-accept"
|
|
43
|
+
@click="${(x) => x.dispatchAddVarArg()}"
|
|
44
|
+
>
|
|
45
|
+
+
|
|
46
|
+
</${buttonTag}>
|
|
47
|
+
`)}
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="rule-header">
|
|
51
|
+
<div class="btn-group rule-actions">
|
|
52
|
+
<${buttonTag}
|
|
53
|
+
type="button"
|
|
54
|
+
class="btn btn-sm btn-danger"
|
|
55
|
+
data-delete="rule"
|
|
56
|
+
@click="${(x, c) => x.dispatchDeleteRule(c.event)}"
|
|
57
|
+
>
|
|
58
|
+
Delete Rule
|
|
59
|
+
</${buttonTag}>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
`;
|
|
64
|
+
}}
|
|
65
|
+
`;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, GenesisElement, observable, volatile } from '@genesislcap/web-core';
|
|
3
|
+
import { applyCustomStyles, processOptGroups } from '../../utils';
|
|
4
|
+
import { Events } from '../events';
|
|
5
|
+
import { template } from './rule-field.template';
|
|
6
|
+
let RuleField = class RuleField extends GenesisElement {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.fields = [];
|
|
10
|
+
}
|
|
11
|
+
connectedCallback() {
|
|
12
|
+
super.connectedCallback();
|
|
13
|
+
applyCustomStyles(this, this.styles, 'field');
|
|
14
|
+
}
|
|
15
|
+
get groupedFieldss() {
|
|
16
|
+
return processOptGroups(this.fields);
|
|
17
|
+
}
|
|
18
|
+
dispatchFieldsChanged(event) {
|
|
19
|
+
event.stopPropagation();
|
|
20
|
+
const fieldId = event.target.value;
|
|
21
|
+
const detail = {
|
|
22
|
+
fieldId: fieldId,
|
|
23
|
+
};
|
|
24
|
+
this.dispatchEvent(new CustomEvent(Events.FieldSelected, { detail, bubbles: true, composed: true }));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
__decorate([
|
|
28
|
+
observable
|
|
29
|
+
], RuleField.prototype, "fields", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
observable
|
|
32
|
+
], RuleField.prototype, "field", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
observable
|
|
35
|
+
], RuleField.prototype, "config", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
observable
|
|
38
|
+
], RuleField.prototype, "styles", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
volatile
|
|
41
|
+
], RuleField.prototype, "groupedFieldss", null);
|
|
42
|
+
RuleField = __decorate([
|
|
43
|
+
customElement({
|
|
44
|
+
name: 'expression-rule-field',
|
|
45
|
+
template: template,
|
|
46
|
+
})
|
|
47
|
+
], RuleField);
|
|
48
|
+
export { RuleField };
|