@servicetitan/dte-unlayer 0.94.0 → 0.95.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/display-conditions/ConditionGroup.d.ts +12 -0
- package/dist/display-conditions/ConditionGroup.d.ts.map +1 -0
- package/dist/display-conditions/ConditionGroup.js +181 -0
- package/dist/display-conditions/ConditionGroup.js.map +1 -0
- package/dist/display-conditions/ConditionGroupsSection.d.ts +11 -0
- package/dist/display-conditions/ConditionGroupsSection.d.ts.map +1 -0
- package/dist/display-conditions/ConditionGroupsSection.js +71 -0
- package/dist/display-conditions/ConditionGroupsSection.js.map +1 -0
- package/dist/display-conditions/ConditionRow.d.ts +11 -0
- package/dist/display-conditions/ConditionRow.d.ts.map +1 -0
- package/dist/display-conditions/ConditionRow.js +206 -0
- package/dist/display-conditions/ConditionRow.js.map +1 -0
- package/dist/display-conditions/DisplayConditionModal.d.ts +5 -0
- package/dist/display-conditions/DisplayConditionModal.d.ts.map +1 -0
- package/dist/display-conditions/DisplayConditionModal.js +282 -0
- package/dist/display-conditions/DisplayConditionModal.js.map +1 -0
- package/dist/display-conditions/SeparatorWithChip.d.ts +6 -0
- package/dist/display-conditions/SeparatorWithChip.d.ts.map +1 -0
- package/dist/display-conditions/SeparatorWithChip.js +15 -0
- package/dist/display-conditions/SeparatorWithChip.js.map +1 -0
- package/dist/display-conditions/constants.d.ts +7 -0
- package/dist/display-conditions/constants.d.ts.map +1 -0
- package/dist/display-conditions/constants.js +22 -0
- package/dist/display-conditions/constants.js.map +1 -0
- package/dist/display-conditions/displayConditionController.d.ts +9 -0
- package/dist/display-conditions/displayConditionController.d.ts.map +1 -0
- package/dist/display-conditions/displayConditionController.js +29 -0
- package/dist/display-conditions/displayConditionController.js.map +1 -0
- package/dist/display-conditions/nunjucks.d.ts +8 -0
- package/dist/display-conditions/nunjucks.d.ts.map +1 -0
- package/dist/display-conditions/nunjucks.js +448 -0
- package/dist/display-conditions/nunjucks.js.map +1 -0
- package/dist/display-conditions/schemaDataPoints.d.ts +4 -0
- package/dist/display-conditions/schemaDataPoints.d.ts.map +1 -0
- package/dist/display-conditions/schemaDataPoints.js +18 -0
- package/dist/display-conditions/schemaDataPoints.js.map +1 -0
- package/dist/display-conditions/types.d.ts +130 -0
- package/dist/display-conditions/types.d.ts.map +1 -0
- package/dist/display-conditions/types.js +72 -0
- package/dist/display-conditions/types.js.map +1 -0
- package/dist/editor-core-source.d.ts +1 -1
- package/dist/editor-core-source.d.ts.map +1 -1
- package/dist/editor-core-source.js +1 -1
- package/dist/editor-core-source.js.map +1 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +4 -0
- package/dist/editor.js.map +1 -1
- package/dist/shared/schema.d.ts +2 -0
- package/dist/shared/schema.d.ts.map +1 -1
- package/dist/shared/schema.js.map +1 -1
- package/dist/unlayer.d.ts.map +1 -1
- package/dist/unlayer.js +7 -0
- package/dist/unlayer.js.map +1 -1
- package/package.json +4 -2
- package/src/display-conditions/ConditionGroup.tsx +145 -0
- package/src/display-conditions/ConditionGroupsSection.tsx +64 -0
- package/src/display-conditions/ConditionRow.tsx +185 -0
- package/src/display-conditions/DisplayConditionModal.tsx +231 -0
- package/src/display-conditions/SeparatorWithChip.tsx +14 -0
- package/src/display-conditions/constants.ts +22 -0
- package/src/display-conditions/displayConditionController.ts +42 -0
- package/src/display-conditions/nunjucks.ts +503 -0
- package/src/display-conditions/schemaDataPoints.ts +33 -0
- package/src/display-conditions/types.ts +75 -0
- package/src/editor-core-source.ts +1 -1
- package/src/editor.tsx +2 -0
- package/src/shared/schema.ts +2 -0
- package/src/unlayer.tsx +9 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ConditionGroup as ConditionGroupType } from './types';
|
|
2
|
+
import type { DataPointOption } from './types';
|
|
3
|
+
export interface ConditionGroupProps {
|
|
4
|
+
canDelete: boolean;
|
|
5
|
+
dataPointOptions: DataPointOption[];
|
|
6
|
+
group: ConditionGroupType;
|
|
7
|
+
onDelete: () => void;
|
|
8
|
+
onUpdate: (g: ConditionGroupType) => void;
|
|
9
|
+
ruleIndex: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function ConditionGroup({ canDelete, dataPointOptions, group, onDelete, onUpdate, ruleIndex, }: Readonly<ConditionGroupProps>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=ConditionGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionGroup.d.ts","sourceRoot":"","sources":["../../src/display-conditions/ConditionGroup.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,IAAI,kBAAkB,EAAoC,MAAM,SAAS,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,cAAc,CAAC,EAC3B,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,GACZ,EAAE,QAAQ,CAAC,mBAAmB,CAAC,2CAuH/B"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Flex, SegmentedControl, Text } from '@servicetitan/anvil2';
|
|
3
|
+
import PlusIcon from '@servicetitan/anvil2/assets/icons/material/round/add.svg';
|
|
4
|
+
import TrashIcon from '@servicetitan/anvil2/assets/icons/material/round/delete.svg';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
import { ConditionRow } from './ConditionRow';
|
|
7
|
+
import { defaultCondition } from './constants';
|
|
8
|
+
export function ConditionGroup({ canDelete, dataPointOptions, group, onDelete, onUpdate, ruleIndex }) {
|
|
9
|
+
const addCondition = useCallback(()=>{
|
|
10
|
+
const newCondition = {
|
|
11
|
+
...defaultCondition(),
|
|
12
|
+
logicalOperator: 'and'
|
|
13
|
+
};
|
|
14
|
+
onUpdate({
|
|
15
|
+
...group,
|
|
16
|
+
conditions: [
|
|
17
|
+
...group.conditions,
|
|
18
|
+
newCondition
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
}, [
|
|
22
|
+
group,
|
|
23
|
+
onUpdate
|
|
24
|
+
]);
|
|
25
|
+
const updateCondition = useCallback((index, c)=>{
|
|
26
|
+
const next = [
|
|
27
|
+
...group.conditions
|
|
28
|
+
];
|
|
29
|
+
next[index] = c;
|
|
30
|
+
onUpdate({
|
|
31
|
+
...group,
|
|
32
|
+
conditions: next
|
|
33
|
+
});
|
|
34
|
+
}, [
|
|
35
|
+
group,
|
|
36
|
+
onUpdate
|
|
37
|
+
]);
|
|
38
|
+
const removeCondition = useCallback((index)=>{
|
|
39
|
+
let next = group.conditions.filter((_, i)=>i !== index);
|
|
40
|
+
// If we removed the first condition, clear logicalOperator on the new first
|
|
41
|
+
if (index === 0 && next.length > 0) {
|
|
42
|
+
const { logicalOperator: unusedOp, ...rest } = next[0];
|
|
43
|
+
next = [
|
|
44
|
+
rest,
|
|
45
|
+
...next.slice(1)
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
onUpdate({
|
|
49
|
+
...group,
|
|
50
|
+
conditions: next.length ? next : [
|
|
51
|
+
defaultCondition()
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
}, [
|
|
55
|
+
group,
|
|
56
|
+
onUpdate
|
|
57
|
+
]);
|
|
58
|
+
const handleLogicalOperatorChange = useCallback((conditionIndex, value)=>{
|
|
59
|
+
const next = [
|
|
60
|
+
...group.conditions
|
|
61
|
+
];
|
|
62
|
+
next[conditionIndex] = {
|
|
63
|
+
...next[conditionIndex],
|
|
64
|
+
logicalOperator: value
|
|
65
|
+
};
|
|
66
|
+
onUpdate({
|
|
67
|
+
...group,
|
|
68
|
+
conditions: next
|
|
69
|
+
});
|
|
70
|
+
}, [
|
|
71
|
+
group,
|
|
72
|
+
onUpdate
|
|
73
|
+
]);
|
|
74
|
+
return /*#__PURE__*/ _jsxs(Flex, {
|
|
75
|
+
direction: "column",
|
|
76
|
+
gap: "2",
|
|
77
|
+
style: {
|
|
78
|
+
width: '100%'
|
|
79
|
+
},
|
|
80
|
+
children: [
|
|
81
|
+
/*#__PURE__*/ _jsxs(Flex, {
|
|
82
|
+
direction: "row",
|
|
83
|
+
alignItems: "center",
|
|
84
|
+
justifyContent: "space-between",
|
|
85
|
+
style: {
|
|
86
|
+
width: '100%'
|
|
87
|
+
},
|
|
88
|
+
children: [
|
|
89
|
+
/*#__PURE__*/ _jsxs(Text, {
|
|
90
|
+
size: "medium",
|
|
91
|
+
variant: "body",
|
|
92
|
+
style: {
|
|
93
|
+
fontWeight: 'bold'
|
|
94
|
+
},
|
|
95
|
+
children: [
|
|
96
|
+
"Rule ",
|
|
97
|
+
ruleIndex + 1
|
|
98
|
+
]
|
|
99
|
+
}),
|
|
100
|
+
canDelete && /*#__PURE__*/ _jsx(Button, {
|
|
101
|
+
appearance: "ghost",
|
|
102
|
+
"aria-label": "Delete rule",
|
|
103
|
+
icon: {
|
|
104
|
+
before: TrashIcon
|
|
105
|
+
},
|
|
106
|
+
size: "large",
|
|
107
|
+
onClick: onDelete
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
}),
|
|
111
|
+
/*#__PURE__*/ _jsxs(Flex, {
|
|
112
|
+
direction: "column",
|
|
113
|
+
gap: "3",
|
|
114
|
+
style: {
|
|
115
|
+
backgroundColor: '#fff',
|
|
116
|
+
border: '1px solid #e0e0e0',
|
|
117
|
+
borderRadius: 8,
|
|
118
|
+
padding: 12,
|
|
119
|
+
width: '100%'
|
|
120
|
+
},
|
|
121
|
+
children: [
|
|
122
|
+
group.conditions.map((c, i)=>{
|
|
123
|
+
var _c_logicalOperator;
|
|
124
|
+
return /*#__PURE__*/ _jsxs(Flex, {
|
|
125
|
+
direction: "column",
|
|
126
|
+
gap: "3",
|
|
127
|
+
style: {
|
|
128
|
+
padding: '8px 0'
|
|
129
|
+
},
|
|
130
|
+
children: [
|
|
131
|
+
i > 0 && /*#__PURE__*/ _jsx(Flex, {
|
|
132
|
+
justifyContent: "center",
|
|
133
|
+
alignItems: "center",
|
|
134
|
+
gap: "2",
|
|
135
|
+
children: /*#__PURE__*/ _jsxs(SegmentedControl, {
|
|
136
|
+
selected: (_c_logicalOperator = c.logicalOperator) !== null && _c_logicalOperator !== void 0 ? _c_logicalOperator : 'and',
|
|
137
|
+
onChange: (v)=>handleLogicalOperatorChange(i, v),
|
|
138
|
+
children: [
|
|
139
|
+
/*#__PURE__*/ _jsx(SegmentedControl.Segment, {
|
|
140
|
+
value: "and",
|
|
141
|
+
children: "And"
|
|
142
|
+
}),
|
|
143
|
+
/*#__PURE__*/ _jsx(SegmentedControl.Segment, {
|
|
144
|
+
value: "or",
|
|
145
|
+
children: "Or"
|
|
146
|
+
})
|
|
147
|
+
]
|
|
148
|
+
})
|
|
149
|
+
}),
|
|
150
|
+
/*#__PURE__*/ _jsx(ConditionRow, {
|
|
151
|
+
canRemove: true,
|
|
152
|
+
condition: c,
|
|
153
|
+
dataPointOptions: dataPointOptions,
|
|
154
|
+
onChange: (next)=>updateCondition(i, next),
|
|
155
|
+
onRemove: ()=>removeCondition(i)
|
|
156
|
+
})
|
|
157
|
+
]
|
|
158
|
+
}, c.id);
|
|
159
|
+
}),
|
|
160
|
+
/*#__PURE__*/ _jsx(Flex, {
|
|
161
|
+
justifyContent: "center",
|
|
162
|
+
style: {
|
|
163
|
+
paddingTop: 8,
|
|
164
|
+
width: '100%'
|
|
165
|
+
},
|
|
166
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
167
|
+
appearance: "secondary",
|
|
168
|
+
icon: {
|
|
169
|
+
before: PlusIcon
|
|
170
|
+
},
|
|
171
|
+
onClick: addCondition,
|
|
172
|
+
children: "Add Condition"
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
})
|
|
177
|
+
]
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=ConditionGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/display-conditions/ConditionGroup.tsx"],"sourcesContent":["import { Button, Flex, SegmentedControl, Text } from '@servicetitan/anvil2';\nimport PlusIcon from '@servicetitan/anvil2/assets/icons/material/round/add.svg';\nimport TrashIcon from '@servicetitan/anvil2/assets/icons/material/round/delete.svg';\nimport { useCallback } from 'react';\nimport { ConditionRow } from './ConditionRow';\nimport { defaultCondition } from './constants';\nimport { ConditionGroup as ConditionGroupType, LogicalOperator, SingleCondition } from './types';\nimport type { DataPointOption } from './types';\n\nexport interface ConditionGroupProps {\n canDelete: boolean;\n dataPointOptions: DataPointOption[];\n group: ConditionGroupType;\n onDelete: () => void;\n onUpdate: (g: ConditionGroupType) => void;\n ruleIndex: number;\n}\n\nexport function ConditionGroup({\n canDelete,\n dataPointOptions,\n group,\n onDelete,\n onUpdate,\n ruleIndex,\n}: Readonly<ConditionGroupProps>) {\n const addCondition = useCallback(() => {\n const newCondition: SingleCondition = {\n ...defaultCondition(),\n logicalOperator: 'and',\n };\n onUpdate({\n ...group,\n conditions: [...group.conditions, newCondition],\n });\n }, [group, onUpdate]);\n\n const updateCondition = useCallback(\n (index: number, c: SingleCondition) => {\n const next = [...group.conditions];\n next[index] = c;\n onUpdate({ ...group, conditions: next });\n },\n [group, onUpdate],\n );\n\n const removeCondition = useCallback(\n (index: number) => {\n let next = group.conditions.filter((_, i) => i !== index);\n // If we removed the first condition, clear logicalOperator on the new first\n if (index === 0 && next.length > 0) {\n const { logicalOperator: unusedOp, ...rest } = next[0];\n next = [rest as SingleCondition, ...next.slice(1)];\n }\n onUpdate({\n ...group,\n conditions: next.length ? next : [defaultCondition()],\n });\n },\n [group, onUpdate],\n );\n\n const handleLogicalOperatorChange = useCallback(\n (conditionIndex: number, value: string) => {\n const next = [...group.conditions];\n next[conditionIndex] = {\n ...next[conditionIndex],\n logicalOperator: value as LogicalOperator,\n };\n onUpdate({ ...group, conditions: next });\n },\n [group, onUpdate],\n );\n\n return (\n <Flex direction=\"column\" gap=\"2\" style={{ width: '100%' }}>\n <Flex\n direction=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n style={{ width: '100%' }}\n >\n <Text size=\"medium\" variant=\"body\" style={{ fontWeight: 'bold' }}>\n Rule {ruleIndex + 1}\n </Text>\n {canDelete && (\n <Button\n appearance=\"ghost\"\n aria-label=\"Delete rule\"\n icon={{ before: TrashIcon }}\n size=\"large\"\n onClick={onDelete}\n />\n )}\n </Flex>\n <Flex\n direction=\"column\"\n gap=\"3\"\n style={{\n backgroundColor: '#fff',\n border: '1px solid #e0e0e0',\n borderRadius: 8,\n padding: 12,\n width: '100%',\n }}\n >\n {group.conditions.map((c, i) => (\n <Flex key={c.id} direction=\"column\" gap=\"3\" style={{ padding: '8px 0' }}>\n {i > 0 && (\n <Flex justifyContent=\"center\" alignItems=\"center\" gap=\"2\">\n <SegmentedControl\n selected={c.logicalOperator ?? 'and'}\n onChange={(v: string) => handleLogicalOperatorChange(i, v)}\n >\n <SegmentedControl.Segment value=\"and\">\n And\n </SegmentedControl.Segment>\n <SegmentedControl.Segment value=\"or\">\n Or\n </SegmentedControl.Segment>\n </SegmentedControl>\n </Flex>\n )}\n <ConditionRow\n canRemove\n condition={c}\n dataPointOptions={dataPointOptions}\n onChange={next => updateCondition(i, next)}\n onRemove={() => removeCondition(i)}\n />\n </Flex>\n ))}\n <Flex justifyContent=\"center\" style={{ paddingTop: 8, width: '100%' }}>\n <Button\n appearance=\"secondary\"\n icon={{ before: PlusIcon }}\n onClick={addCondition}\n >\n Add Condition\n </Button>\n </Flex>\n </Flex>\n </Flex>\n );\n}\n"],"names":["Button","Flex","SegmentedControl","Text","PlusIcon","TrashIcon","useCallback","ConditionRow","defaultCondition","ConditionGroup","canDelete","dataPointOptions","group","onDelete","onUpdate","ruleIndex","addCondition","newCondition","logicalOperator","conditions","updateCondition","index","c","next","removeCondition","filter","_","i","length","unusedOp","rest","slice","handleLogicalOperatorChange","conditionIndex","value","direction","gap","style","width","alignItems","justifyContent","size","variant","fontWeight","appearance","aria-label","icon","before","onClick","backgroundColor","border","borderRadius","padding","map","selected","onChange","v","Segment","canRemove","condition","onRemove","id","paddingTop"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ConditionGroup as ConditionGroupType } from './types';
|
|
2
|
+
import type { DataPointOption } from './types';
|
|
3
|
+
export interface ConditionGroupsSectionProps {
|
|
4
|
+
dataPointOptions: DataPointOption[];
|
|
5
|
+
groups: ConditionGroupType[];
|
|
6
|
+
onAddGroup: () => void;
|
|
7
|
+
onRemoveGroup: (index: number) => void;
|
|
8
|
+
onUpdateGroup: (index: number, group: ConditionGroupType) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function ConditionGroupsSection({ dataPointOptions, groups, onAddGroup, onRemoveGroup, onUpdateGroup, }: Readonly<ConditionGroupsSectionProps>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=ConditionGroupsSection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionGroupsSection.d.ts","sourceRoot":"","sources":["../../src/display-conditions/ConditionGroupsSection.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,IAAI,kBAAkB,EAAmB,MAAM,SAAS,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,WAAW,2BAA2B;IACxC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACrE;AAED,wBAAgB,sBAAsB,CAAC,EACnC,gBAAgB,EAChB,MAAM,EACN,UAAU,EACV,aAAa,EACb,aAAa,GAChB,EAAE,QAAQ,CAAC,2BAA2B,CAAC,2CA2CvC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Flex, SegmentedControl } from '@servicetitan/anvil2';
|
|
3
|
+
import PlusIcon from '@servicetitan/anvil2/assets/icons/material/round/add.svg';
|
|
4
|
+
import { ConditionGroup } from './ConditionGroup';
|
|
5
|
+
export function ConditionGroupsSection({ dataPointOptions, groups, onAddGroup, onRemoveGroup, onUpdateGroup }) {
|
|
6
|
+
return /*#__PURE__*/ _jsxs(Flex, {
|
|
7
|
+
direction: "column",
|
|
8
|
+
gap: "4",
|
|
9
|
+
children: [
|
|
10
|
+
groups.map((group, index)=>{
|
|
11
|
+
var _group_logicalOperator;
|
|
12
|
+
return /*#__PURE__*/ _jsxs(Flex, {
|
|
13
|
+
direction: "column",
|
|
14
|
+
gap: "3",
|
|
15
|
+
children: [
|
|
16
|
+
index > 0 && /*#__PURE__*/ _jsx(Flex, {
|
|
17
|
+
justifyContent: "center",
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
gap: "2",
|
|
20
|
+
style: {
|
|
21
|
+
padding: '12px'
|
|
22
|
+
},
|
|
23
|
+
children: /*#__PURE__*/ _jsxs(SegmentedControl, {
|
|
24
|
+
selected: (_group_logicalOperator = group.logicalOperator) !== null && _group_logicalOperator !== void 0 ? _group_logicalOperator : 'and',
|
|
25
|
+
onChange: (value)=>onUpdateGroup(index, {
|
|
26
|
+
...group,
|
|
27
|
+
logicalOperator: value
|
|
28
|
+
}),
|
|
29
|
+
children: [
|
|
30
|
+
/*#__PURE__*/ _jsx(SegmentedControl.Segment, {
|
|
31
|
+
value: "and",
|
|
32
|
+
children: "And"
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ _jsx(SegmentedControl.Segment, {
|
|
35
|
+
value: "or",
|
|
36
|
+
children: "Or"
|
|
37
|
+
})
|
|
38
|
+
]
|
|
39
|
+
})
|
|
40
|
+
}),
|
|
41
|
+
/*#__PURE__*/ _jsx(ConditionGroup, {
|
|
42
|
+
canDelete: groups.length > 1,
|
|
43
|
+
dataPointOptions: dataPointOptions,
|
|
44
|
+
group: group,
|
|
45
|
+
onDelete: ()=>onRemoveGroup(index),
|
|
46
|
+
onUpdate: (g)=>onUpdateGroup(index, g),
|
|
47
|
+
ruleIndex: index
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
}, group.id);
|
|
51
|
+
}),
|
|
52
|
+
/*#__PURE__*/ _jsx(Flex, {
|
|
53
|
+
justifyContent: "center",
|
|
54
|
+
style: {
|
|
55
|
+
paddingTop: 8,
|
|
56
|
+
width: '100%'
|
|
57
|
+
},
|
|
58
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
59
|
+
appearance: "secondary",
|
|
60
|
+
icon: {
|
|
61
|
+
before: PlusIcon
|
|
62
|
+
},
|
|
63
|
+
onClick: onAddGroup,
|
|
64
|
+
children: "Add Rule"
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=ConditionGroupsSection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/display-conditions/ConditionGroupsSection.tsx"],"sourcesContent":["import { Button, Flex, SegmentedControl } from '@servicetitan/anvil2';\nimport PlusIcon from '@servicetitan/anvil2/assets/icons/material/round/add.svg';\nimport { ConditionGroup } from './ConditionGroup';\nimport { ConditionGroup as ConditionGroupType, LogicalOperator } from './types';\nimport type { DataPointOption } from './types';\n\nexport interface ConditionGroupsSectionProps {\n dataPointOptions: DataPointOption[];\n groups: ConditionGroupType[];\n onAddGroup: () => void;\n onRemoveGroup: (index: number) => void;\n onUpdateGroup: (index: number, group: ConditionGroupType) => void;\n}\n\nexport function ConditionGroupsSection({\n dataPointOptions,\n groups,\n onAddGroup,\n onRemoveGroup,\n onUpdateGroup,\n}: Readonly<ConditionGroupsSectionProps>) {\n return (\n <Flex direction=\"column\" gap=\"4\">\n {groups.map((group, index) => (\n <Flex key={group.id} direction=\"column\" gap=\"3\">\n {index > 0 && (\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n gap=\"2\"\n style={{ padding: '12px' }}\n >\n <SegmentedControl\n selected={group.logicalOperator ?? 'and'}\n onChange={(value: string) =>\n onUpdateGroup(index, {\n ...group,\n logicalOperator: value as LogicalOperator,\n })\n }\n >\n <SegmentedControl.Segment value=\"and\">And</SegmentedControl.Segment>\n <SegmentedControl.Segment value=\"or\">Or</SegmentedControl.Segment>\n </SegmentedControl>\n </Flex>\n )}\n <ConditionGroup\n canDelete={groups.length > 1}\n dataPointOptions={dataPointOptions}\n group={group}\n onDelete={() => onRemoveGroup(index)}\n onUpdate={g => onUpdateGroup(index, g)}\n ruleIndex={index}\n />\n </Flex>\n ))}\n <Flex justifyContent=\"center\" style={{ paddingTop: 8, width: '100%' }}>\n <Button appearance=\"secondary\" icon={{ before: PlusIcon }} onClick={onAddGroup}>\n Add Rule\n </Button>\n </Flex>\n </Flex>\n );\n}\n"],"names":["Button","Flex","SegmentedControl","PlusIcon","ConditionGroup","ConditionGroupsSection","dataPointOptions","groups","onAddGroup","onRemoveGroup","onUpdateGroup","direction","gap","map","group","index","justifyContent","alignItems","style","padding","selected","logicalOperator","onChange","value","Segment","canDelete","length","onDelete","onUpdate","g","ruleIndex","id","paddingTop","width","appearance","icon","before","onClick"],"mappings":";AAAA,SAASA,MAAM,EAAEC,IAAI,EAAEC,gBAAgB,QAAQ,uBAAuB;AACtE,OAAOC,cAAc,2DAA2D;AAChF,SAASC,cAAc,QAAQ,mBAAmB;AAYlD,OAAO,SAASC,uBAAuB,EACnCC,gBAAgB,EAChBC,MAAM,EACNC,UAAU,EACVC,aAAa,EACbC,aAAa,EACuB;IACpC,qBACI,MAACT;QAAKU,WAAU;QAASC,KAAI;;YACxBL,OAAOM,GAAG,CAAC,CAACC,OAAOC;oBAUUD;qCAT1B,MAACb;oBAAoBU,WAAU;oBAASC,KAAI;;wBACvCG,QAAQ,mBACL,KAACd;4BACGe,gBAAe;4BACfC,YAAW;4BACXL,KAAI;4BACJM,OAAO;gCAAEC,SAAS;4BAAO;sCAEzB,cAAA,MAACjB;gCACGkB,UAAUN,CAAAA,yBAAAA,MAAMO,eAAe,cAArBP,oCAAAA,yBAAyB;gCACnCQ,UAAU,CAACC,QACPb,cAAcK,OAAO;wCACjB,GAAGD,KAAK;wCACRO,iBAAiBE;oCACrB;;kDAGJ,KAACrB,iBAAiBsB,OAAO;wCAACD,OAAM;kDAAM;;kDACtC,KAACrB,iBAAiBsB,OAAO;wCAACD,OAAM;kDAAK;;;;;sCAIjD,KAACnB;4BACGqB,WAAWlB,OAAOmB,MAAM,GAAG;4BAC3BpB,kBAAkBA;4BAClBQ,OAAOA;4BACPa,UAAU,IAAMlB,cAAcM;4BAC9Ba,UAAUC,CAAAA,IAAKnB,cAAcK,OAAOc;4BACpCC,WAAWf;;;mBA5BRD,MAAMiB,EAAE;;0BAgCvB,KAAC9B;gBAAKe,gBAAe;gBAASE,OAAO;oBAAEc,YAAY;oBAAGC,OAAO;gBAAO;0BAChE,cAAA,KAACjC;oBAAOkC,YAAW;oBAAYC,MAAM;wBAAEC,QAAQjC;oBAAS;oBAAGkC,SAAS7B;8BAAY;;;;;AAMhG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SingleCondition } from './types';
|
|
2
|
+
import type { DataPointOption } from './types';
|
|
3
|
+
export interface ConditionRowProps {
|
|
4
|
+
canRemove: boolean;
|
|
5
|
+
condition: SingleCondition;
|
|
6
|
+
dataPointOptions: DataPointOption[];
|
|
7
|
+
onChange: (c: SingleCondition) => void;
|
|
8
|
+
onRemove: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function ConditionRow({ canRemove, condition, dataPointOptions, onChange, onRemove, }: Readonly<ConditionRowProps>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=ConditionRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionRow.d.ts","sourceRoot":"","sources":["../../src/display-conditions/ConditionRow.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAoB,eAAe,EAA0C,MAAM,SAAS,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,eAAe,CAAC;IAC3B,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,QAAQ,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAsBD,wBAAgB,YAAY,CAAC,EACzB,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,QAAQ,GACX,EAAE,QAAQ,CAAC,iBAAiB,CAAC,2CAgJ7B"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Chip, Combobox, Flex, TextField } from '@servicetitan/anvil2';
|
|
3
|
+
import TrashIcon from '@servicetitan/anvil2/assets/icons/material/round/delete.svg';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { NUMBER_OPERATORS, STRING_OPERATORS, VALUE_LESS_OPERATORS } from './types';
|
|
6
|
+
function sanitizeNumericInput(raw) {
|
|
7
|
+
// Allow only a single leading minus and one decimal separator.
|
|
8
|
+
let value = raw.replaceAll(/[^0-9.-]/g, '');
|
|
9
|
+
const isNegative = value.startsWith('-');
|
|
10
|
+
value = value.replaceAll('-', '');
|
|
11
|
+
if (isNegative) {
|
|
12
|
+
value = `-${value}`;
|
|
13
|
+
}
|
|
14
|
+
const firstDot = value.indexOf('.');
|
|
15
|
+
if (firstDot >= 0) {
|
|
16
|
+
value = `${value.slice(0, firstDot + 1)}${value.slice(firstDot + 1).replaceAll('.', '')}`;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
export function ConditionRow({ canRemove, condition, dataPointOptions, onChange, onRemove }) {
|
|
21
|
+
const selectedDataPoint = useMemo(()=>{
|
|
22
|
+
var _dataPointOptions_find;
|
|
23
|
+
return (_dataPointOptions_find = dataPointOptions.find((opt)=>opt.fullKey === condition.dataPointKey)) !== null && _dataPointOptions_find !== void 0 ? _dataPointOptions_find : null;
|
|
24
|
+
}, [
|
|
25
|
+
dataPointOptions,
|
|
26
|
+
condition.dataPointKey
|
|
27
|
+
]);
|
|
28
|
+
var _selectedDataPoint_fieldType;
|
|
29
|
+
const fieldType = (_selectedDataPoint_fieldType = selectedDataPoint === null || selectedDataPoint === void 0 ? void 0 : selectedDataPoint.fieldType) !== null && _selectedDataPoint_fieldType !== void 0 ? _selectedDataPoint_fieldType : 'string';
|
|
30
|
+
const operatorItems = useMemo(()=>fieldType === 'number' ? [
|
|
31
|
+
...NUMBER_OPERATORS
|
|
32
|
+
] : [
|
|
33
|
+
...STRING_OPERATORS
|
|
34
|
+
], [
|
|
35
|
+
fieldType
|
|
36
|
+
]);
|
|
37
|
+
const selectedOperator = useMemo(()=>{
|
|
38
|
+
var _operatorItems_find;
|
|
39
|
+
return (_operatorItems_find = operatorItems.find((op)=>op.value === condition.operator)) !== null && _operatorItems_find !== void 0 ? _operatorItems_find : null;
|
|
40
|
+
}, [
|
|
41
|
+
operatorItems,
|
|
42
|
+
condition.operator
|
|
43
|
+
]);
|
|
44
|
+
const isValueLess = VALUE_LESS_OPERATORS.includes(condition.operator);
|
|
45
|
+
const handleValueChange = (raw)=>{
|
|
46
|
+
const value = fieldType === 'number' ? sanitizeNumericInput(raw) : raw;
|
|
47
|
+
onChange({
|
|
48
|
+
...condition,
|
|
49
|
+
value
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const handleDataPointChange = (item)=>{
|
|
53
|
+
var _item_fieldType;
|
|
54
|
+
const nextFieldType = (_item_fieldType = item === null || item === void 0 ? void 0 : item.fieldType) !== null && _item_fieldType !== void 0 ? _item_fieldType : 'string';
|
|
55
|
+
const nextIsNumber = nextFieldType === 'number';
|
|
56
|
+
const nextOperatorItems = nextIsNumber ? NUMBER_OPERATORS : STRING_OPERATORS;
|
|
57
|
+
const operatorReset = !nextOperatorItems.some((op)=>op.value === condition.operator);
|
|
58
|
+
var _item_fullKey;
|
|
59
|
+
onChange({
|
|
60
|
+
...condition,
|
|
61
|
+
dataPointKey: (_item_fullKey = item === null || item === void 0 ? void 0 : item.fullKey) !== null && _item_fullKey !== void 0 ? _item_fullKey : '',
|
|
62
|
+
operator: operatorReset ? nextIsNumber ? 'num_eq' : 'is_equal_to' : condition.operator
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
return /*#__PURE__*/ _jsxs(Flex, {
|
|
66
|
+
direction: "row",
|
|
67
|
+
alignItems: "flex-end",
|
|
68
|
+
gap: "2",
|
|
69
|
+
style: {
|
|
70
|
+
flexWrap: 'wrap',
|
|
71
|
+
rowGap: 8,
|
|
72
|
+
width: '100%'
|
|
73
|
+
},
|
|
74
|
+
children: [
|
|
75
|
+
/*#__PURE__*/ _jsx("div", {
|
|
76
|
+
style: {
|
|
77
|
+
display: 'flex',
|
|
78
|
+
alignItems: 'flex-end',
|
|
79
|
+
flexShrink: 0,
|
|
80
|
+
padding: '6px 12px'
|
|
81
|
+
},
|
|
82
|
+
children: /*#__PURE__*/ _jsx(Chip, {
|
|
83
|
+
label: "IF",
|
|
84
|
+
size: "medium"
|
|
85
|
+
})
|
|
86
|
+
}),
|
|
87
|
+
/*#__PURE__*/ _jsx("div", {
|
|
88
|
+
style: {
|
|
89
|
+
flex: '2 1 280px',
|
|
90
|
+
minWidth: 240
|
|
91
|
+
},
|
|
92
|
+
children: /*#__PURE__*/ _jsxs(Combobox, {
|
|
93
|
+
...{
|
|
94
|
+
disableClearSelection: true
|
|
95
|
+
},
|
|
96
|
+
itemToKey: (item)=>{
|
|
97
|
+
var _item_fullKey;
|
|
98
|
+
return (_item_fullKey = item === null || item === void 0 ? void 0 : item.fullKey) !== null && _item_fullKey !== void 0 ? _item_fullKey : '';
|
|
99
|
+
},
|
|
100
|
+
itemToString: (item)=>{
|
|
101
|
+
var _item_title;
|
|
102
|
+
return (_item_title = item === null || item === void 0 ? void 0 : item.title) !== null && _item_title !== void 0 ? _item_title : '';
|
|
103
|
+
},
|
|
104
|
+
items: dataPointOptions,
|
|
105
|
+
selectedItem: selectedDataPoint,
|
|
106
|
+
onChange: handleDataPointChange,
|
|
107
|
+
children: [
|
|
108
|
+
/*#__PURE__*/ _jsx(Combobox.SelectTrigger, {
|
|
109
|
+
label: "Data point",
|
|
110
|
+
placeholder: "Select data point..."
|
|
111
|
+
}),
|
|
112
|
+
/*#__PURE__*/ _jsx(Combobox.Content, {
|
|
113
|
+
children: ({ items })=>/*#__PURE__*/ _jsx(Combobox.List, {
|
|
114
|
+
children: items.map((item, i)=>/*#__PURE__*/ _jsx(Combobox.Item, {
|
|
115
|
+
index: i,
|
|
116
|
+
item: item,
|
|
117
|
+
children: item.title
|
|
118
|
+
}, item.fullKey))
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
]
|
|
122
|
+
})
|
|
123
|
+
}),
|
|
124
|
+
/*#__PURE__*/ _jsx("div", {
|
|
125
|
+
style: {
|
|
126
|
+
flex: '1 1 220px',
|
|
127
|
+
minWidth: 180
|
|
128
|
+
},
|
|
129
|
+
children: /*#__PURE__*/ _jsxs(Combobox, {
|
|
130
|
+
...{
|
|
131
|
+
disableClearSelection: true
|
|
132
|
+
},
|
|
133
|
+
itemToKey: (item)=>{
|
|
134
|
+
var _item_value;
|
|
135
|
+
return (_item_value = item === null || item === void 0 ? void 0 : item.value) !== null && _item_value !== void 0 ? _item_value : '';
|
|
136
|
+
},
|
|
137
|
+
itemToString: (item)=>{
|
|
138
|
+
var _item_label;
|
|
139
|
+
return (_item_label = item === null || item === void 0 ? void 0 : item.label) !== null && _item_label !== void 0 ? _item_label : '';
|
|
140
|
+
},
|
|
141
|
+
items: operatorItems,
|
|
142
|
+
selectedItem: selectedOperator,
|
|
143
|
+
onChange: (item)=>{
|
|
144
|
+
var _item_value;
|
|
145
|
+
return onChange({
|
|
146
|
+
...condition,
|
|
147
|
+
operator: (_item_value = item === null || item === void 0 ? void 0 : item.value) !== null && _item_value !== void 0 ? _item_value : 'is_equal_to'
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
children: [
|
|
151
|
+
/*#__PURE__*/ _jsx(Combobox.SelectTrigger, {
|
|
152
|
+
label: "Condition",
|
|
153
|
+
placeholder: "Select..."
|
|
154
|
+
}),
|
|
155
|
+
/*#__PURE__*/ _jsx(Combobox.Content, {
|
|
156
|
+
children: ({ items })=>/*#__PURE__*/ _jsx(Combobox.List, {
|
|
157
|
+
children: items.map((item, i)=>/*#__PURE__*/ _jsx(Combobox.Item, {
|
|
158
|
+
index: i,
|
|
159
|
+
item: item,
|
|
160
|
+
children: item.label
|
|
161
|
+
}, item.value))
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
}),
|
|
167
|
+
!isValueLess && /*#__PURE__*/ _jsx("div", {
|
|
168
|
+
style: {
|
|
169
|
+
flex: '1 1 220px',
|
|
170
|
+
minWidth: 180
|
|
171
|
+
},
|
|
172
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
173
|
+
label: "Value",
|
|
174
|
+
value: condition.value,
|
|
175
|
+
onChange: (e)=>handleValueChange(e.target.value),
|
|
176
|
+
placeholder: fieldType === 'number' ? 'e.g. 1.5' : 'Enter value...',
|
|
177
|
+
style: {
|
|
178
|
+
width: '100%'
|
|
179
|
+
},
|
|
180
|
+
"aria-label": "Value",
|
|
181
|
+
...fieldType === 'number' && {
|
|
182
|
+
inputMode: 'decimal'
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
}),
|
|
186
|
+
canRemove && /*#__PURE__*/ _jsx("div", {
|
|
187
|
+
style: {
|
|
188
|
+
display: 'flex',
|
|
189
|
+
alignItems: 'flex-end',
|
|
190
|
+
flexShrink: 0,
|
|
191
|
+
padding: '6px 12px'
|
|
192
|
+
},
|
|
193
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
194
|
+
appearance: "secondary",
|
|
195
|
+
"aria-label": "Remove condition",
|
|
196
|
+
icon: {
|
|
197
|
+
before: TrashIcon
|
|
198
|
+
},
|
|
199
|
+
onClick: onRemove
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
//# sourceMappingURL=ConditionRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/display-conditions/ConditionRow.tsx"],"sourcesContent":["import { Button, Chip, Combobox, Flex, TextField } from '@servicetitan/anvil2';\nimport TrashIcon from '@servicetitan/anvil2/assets/icons/material/round/delete.svg';\nimport { useMemo } from 'react';\nimport { NUMBER_OPERATORS, SingleCondition, STRING_OPERATORS, VALUE_LESS_OPERATORS } from './types';\nimport type { DataPointOption } from './types';\n\nexport interface ConditionRowProps {\n canRemove: boolean;\n condition: SingleCondition;\n dataPointOptions: DataPointOption[];\n onChange: (c: SingleCondition) => void;\n onRemove: () => void;\n}\n\ninterface OperatorOption {\n label: string;\n value: string;\n}\n\nfunction sanitizeNumericInput(raw: string): string {\n // Allow only a single leading minus and one decimal separator.\n let value = raw.replaceAll(/[^0-9.-]/g, '');\n const isNegative = value.startsWith('-');\n value = value.replaceAll('-', '');\n if (isNegative) {\n value = `-${value}`;\n }\n const firstDot = value.indexOf('.');\n if (firstDot >= 0) {\n value = `${value.slice(0, firstDot + 1)}${value.slice(firstDot + 1).replaceAll('.', '')}`;\n }\n return value;\n}\n\nexport function ConditionRow({\n canRemove,\n condition,\n dataPointOptions,\n onChange,\n onRemove,\n}: Readonly<ConditionRowProps>) {\n const selectedDataPoint = useMemo(\n () => dataPointOptions.find(opt => opt.fullKey === condition.dataPointKey) ?? null,\n [dataPointOptions, condition.dataPointKey],\n );\n\n const fieldType = selectedDataPoint?.fieldType ?? 'string';\n\n const operatorItems: OperatorOption[] = useMemo(\n () =>\n fieldType === 'number'\n ? ([...NUMBER_OPERATORS] as OperatorOption[])\n : ([...STRING_OPERATORS] as OperatorOption[]),\n [fieldType],\n );\n\n const selectedOperator = useMemo(\n () => operatorItems.find(op => op.value === condition.operator) ?? null,\n [operatorItems, condition.operator],\n );\n\n const isValueLess = VALUE_LESS_OPERATORS.includes(condition.operator);\n\n const handleValueChange = (raw: string) => {\n const value = fieldType === 'number' ? sanitizeNumericInput(raw) : raw;\n onChange({ ...condition, value });\n };\n\n const handleDataPointChange = (item: DataPointOption | null) => {\n const nextFieldType = item?.fieldType ?? 'string';\n const nextIsNumber = nextFieldType === 'number';\n const nextOperatorItems = nextIsNumber ? NUMBER_OPERATORS : STRING_OPERATORS;\n const operatorReset = !nextOperatorItems.some(op => op.value === condition.operator);\n onChange({\n ...condition,\n dataPointKey: item?.fullKey ?? '',\n operator: operatorReset\n ? nextIsNumber\n ? 'num_eq'\n : 'is_equal_to'\n : condition.operator,\n });\n };\n\n return (\n <Flex\n direction=\"row\"\n alignItems=\"flex-end\"\n gap=\"2\"\n style={{ flexWrap: 'wrap', rowGap: 8, width: '100%' }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n flexShrink: 0,\n padding: '6px 12px',\n }}\n >\n <Chip label=\"IF\" size=\"medium\" />\n </div>\n <div style={{ flex: '2 1 280px', minWidth: 240 }}>\n <Combobox\n {...({ disableClearSelection: true } as object)}\n itemToKey={(item: DataPointOption | null) => item?.fullKey ?? ''}\n itemToString={(item: DataPointOption | null) => item?.title ?? ''}\n items={dataPointOptions}\n selectedItem={selectedDataPoint}\n onChange={handleDataPointChange}\n >\n <Combobox.SelectTrigger label=\"Data point\" placeholder=\"Select data point...\" />\n <Combobox.Content>\n {({ items }: { items: DataPointOption[] }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item index={i} item={item} key={item.fullKey}>\n {item.title}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox>\n </div>\n <div style={{ flex: '1 1 220px', minWidth: 180 }}>\n <Combobox\n {...({ disableClearSelection: true } as object)}\n itemToKey={(item: OperatorOption | null) => item?.value ?? ''}\n itemToString={(item: OperatorOption | null) => item?.label ?? ''}\n items={operatorItems}\n selectedItem={selectedOperator}\n onChange={(item: OperatorOption | null) =>\n onChange({\n ...condition,\n operator: (item?.value ?? 'is_equal_to') as SingleCondition['operator'],\n })\n }\n >\n <Combobox.SelectTrigger label=\"Condition\" placeholder=\"Select...\" />\n <Combobox.Content>\n {({ items }: { items: OperatorOption[] }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item index={i} item={item} key={item.value}>\n {item.label}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox>\n </div>\n {!isValueLess && (\n <div style={{ flex: '1 1 220px', minWidth: 180 }}>\n <TextField\n label=\"Value\"\n value={condition.value}\n onChange={e => handleValueChange(e.target.value)}\n placeholder={fieldType === 'number' ? 'e.g. 1.5' : 'Enter value...'}\n style={{ width: '100%' }}\n aria-label=\"Value\"\n {...(fieldType === 'number' && { inputMode: 'decimal' })}\n />\n </div>\n )}\n {canRemove && (\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n flexShrink: 0,\n padding: '6px 12px',\n }}\n >\n <Button\n appearance=\"secondary\"\n aria-label=\"Remove condition\"\n icon={{ before: TrashIcon }}\n onClick={onRemove}\n />\n </div>\n )}\n </Flex>\n );\n}\n"],"names":["Button","Chip","Combobox","Flex","TextField","TrashIcon","useMemo","NUMBER_OPERATORS","STRING_OPERATORS","VALUE_LESS_OPERATORS","sanitizeNumericInput","raw","value","replaceAll","isNegative","startsWith","firstDot","indexOf","slice","ConditionRow","canRemove","condition","dataPointOptions","onChange","onRemove","selectedDataPoint","find","opt","fullKey","dataPointKey","fieldType","operatorItems","selectedOperator","op","operator","isValueLess","includes","handleValueChange","handleDataPointChange","item","nextFieldType","nextIsNumber","nextOperatorItems","operatorReset","some","direction","alignItems","gap","style","flexWrap","rowGap","width","div","display","flexShrink","padding","label","size","flex","minWidth","disableClearSelection","itemToKey","itemToString","title","items","selectedItem","SelectTrigger","placeholder","Content","List","map","i","Item","index","e","target","aria-label","inputMode","appearance","icon","before","onClick"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export interface DisplayConditionModalProps {
|
|
2
|
+
schema?: import('../shared/schema').SchemaObject;
|
|
3
|
+
}
|
|
4
|
+
export declare const DisplayConditionModal: (props: DisplayConditionModalProps) => import("react").ReactPortal | null;
|
|
5
|
+
//# sourceMappingURL=DisplayConditionModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DisplayConditionModal.d.ts","sourceRoot":"","sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,0BAA0B;IACvC,MAAM,CAAC,EAAE,OAAO,kBAAkB,EAAE,YAAY,CAAC;CACpD;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAO,0BAA0B,uCAgNtE,CAAC"}
|