Skip to content

Commit 236931c

Browse files
kie-issues#237: Implement DMN 1.4 Boxed iterator expression (#2243)
Co-authored-by: Tiago Bento <[email protected]>
1 parent a403f6f commit 236931c

File tree

10 files changed

+632
-94
lines changed

10 files changed

+632
-94
lines changed

packages/boxed-expression-component/src/api/BoxedExpression.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export enum BoxedFunctionKind {
5151
Pmml = "PMML",
5252
}
5353

54+
export type BoxedIterator = BoxedFor | BoxedEvery | BoxedSome;
55+
5456
export type BoxedExpression =
5557
| BoxedLiteral
5658
| BoxedRelation

packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import { CutIcon } from "@patternfly/react-icons/dist/js/icons/cut-icon";
2929
import { ListIcon } from "@patternfly/react-icons/dist/js/icons/list-icon";
3030
import { PasteIcon } from "@patternfly/react-icons/dist/js/icons/paste-icon";
3131
import { TableIcon } from "@patternfly/react-icons/dist/js/icons/table-icon";
32+
import { RebootingIcon } from "@patternfly/react-icons/dist/js/icons/rebooting-icon";
33+
import { ResourcesAlmostEmptyIcon } from "@patternfly/react-icons/dist/js/icons/resources-almost-empty-icon";
34+
import { ResourcesFullIcon } from "@patternfly/react-icons/dist/js/icons/resources-full-icon";
3235
import * as React from "react";
3336
import { useCallback, useEffect, useMemo, useState } from "react";
3437
import { BoxedExpression } from "../../api";
@@ -47,13 +50,14 @@ import { LiteralExpression } from "../LiteralExpression/LiteralExpression";
4750
import { RelationExpression } from "../RelationExpression/RelationExpression";
4851
import {
4952
BoxedExpressionClipboard,
50-
DMN_BOXED_EXPRESSION_CLIPBOARD_MIME_TYPE,
5153
buildClipboardFromExpression,
54+
DMN_BOXED_EXPRESSION_CLIPBOARD_MIME_TYPE,
5255
} from "../../clipboard/clipboard";
5356
import { findAllIdsDeep, mutateExpressionRandomizingIds } from "../../ids/ids";
5457
import "./ExpressionDefinitionLogicTypeSelector.css";
5558
import { NavigationKeysUtils } from "../../keysUtils/keyUtils";
5659
import { ConditionalExpression } from "../ConditionalExpression/ConditionalExpression";
60+
import { IteratorExpressionComponent } from "../IteratorExpression/IteratorExpressionComponent";
5761

5862
export interface ExpressionDefinitionLogicTypeSelectorProps {
5963
/** Expression properties */
@@ -95,9 +99,9 @@ export function ExpressionDefinitionLogicTypeSelector({
9599
"invocation",
96100
...(isNested ? (["functionDefinition"] as const) : []),
97101
...(!hideDmn14BoxedExpressions ? (["conditional"] as const) : []),
98-
// "for",
99-
// "every",
100-
// "some",
102+
"for",
103+
"every",
104+
"some",
101105
// "filter",
102106
],
103107
[hideDmn14BoxedExpressions, isNested]
@@ -134,6 +138,9 @@ export function ExpressionDefinitionLogicTypeSelector({
134138
case "for":
135139
case "every":
136140
case "some":
141+
return (
142+
<IteratorExpressionComponent expression={expression} isNested={isNested} parentElementId={parentElementId} />
143+
);
137144
case "filter":
138145
return <></>;
139146
default:
@@ -235,8 +242,11 @@ export function ExpressionDefinitionLogicTypeSelector({
235242
</span>
236243
);
237244
case "for":
245+
return <RebootingIcon />;
238246
case "every":
247+
return <ResourcesFullIcon />;
239248
case "some":
249+
return <ResourcesAlmostEmptyIcon />;
240250
case "filter":
241251
return <></>;
242252
default:
@@ -330,6 +340,25 @@ export function ExpressionDefinitionLogicTypeSelector({
330340
return "A boxed list expression in DMN represents a FEEL list of items. You use boxed lists to define lists of relevant items for a particular node in a decision.";
331341
case "conditional":
332342
return 'A boxed conditional offers a visual representation of an if statement using three rows. The expression in the "if" part MUST resolve to a boolean.';
343+
case "for":
344+
return (
345+
"A boxed iterator offers a visual representation of an iterator statement. " +
346+
'For the for loop, the right part of the "for" displays the iterator variable name. The second row holds an expression representing the collection that will be iterated over. The expression in the "in" row MUST resolve to a collection.' +
347+
" The last row contains the expression that will process each element of the collection."
348+
);
349+
350+
case "every":
351+
return (
352+
"A boxed iterator offers a visual representation of an iterator statement. " +
353+
'For the "every" loop, the right part of the "every" displays the iterator variable name. The second row holds an expression representing the collection that will be iterated over. The expression in the "in" row MUST resolve to a collection.' +
354+
"The last line is an expression that will be evaluated on each item. The expression defined in the satisfies MUST resolve to a boolean."
355+
);
356+
case "some":
357+
return (
358+
"A boxed iterator offers a visual representation of an iterator statement. " +
359+
'For the "some" loop, the right part of the "some" displays the iterator variable name. The second row holds an expression representing the collection that will be iterated over. The expression in the "in" row MUST resolve to a collection. ' +
360+
"The last line is an expression that will be evaluated on each item. The expression defined in the satisfies MUST resolve to a boolean."
361+
);
333362
default:
334363
return "";
335364
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { BoxedIterator } from "../../api";
2+
3+
import {
4+
NestedExpressionDispatchContextProvider,
5+
useBoxedExpressionEditorDispatch,
6+
} from "../../BoxedExpressionEditorContext";
7+
import * as React from "react";
8+
import { useCallback, useMemo } from "react";
9+
import { ExpressionContainer } from "../ExpressionDefinitionRoot/ExpressionContainer";
10+
import { IteratorClause } from "./IteratorExpressionComponent";
11+
12+
export interface IteratorExpressionCellExpressionCellProps {
13+
iteratorClause: IteratorClause;
14+
rowIndex: number;
15+
columnIndex: number;
16+
columnId: string;
17+
}
18+
19+
export function IteratorExpressionCell({
20+
rowIndex,
21+
columnIndex,
22+
parentElementId,
23+
iteratorClause,
24+
}: IteratorExpressionCellExpressionCellProps & { parentElementId: string }) {
25+
const { setExpression } = useBoxedExpressionEditorDispatch();
26+
27+
const onSetExpression = useCallback(
28+
({ getNewExpression }) => {
29+
setExpression((prev: BoxedIterator) => {
30+
switch (rowIndex) {
31+
case 1:
32+
return {
33+
...prev,
34+
in: {
35+
expression: getNewExpression(prev.in.expression),
36+
},
37+
};
38+
case 2:
39+
default:
40+
if (prev.__$$element === "for") {
41+
return {
42+
...prev,
43+
return: {
44+
expression: getNewExpression(prev.return.expression),
45+
},
46+
};
47+
} else {
48+
return {
49+
...prev,
50+
satisfies: {
51+
expression: getNewExpression(prev.satisfies.expression),
52+
},
53+
};
54+
}
55+
}
56+
});
57+
},
58+
[rowIndex, setExpression]
59+
);
60+
61+
const currentExpression = useMemo(() => {
62+
if (typeof iteratorClause.child !== "string") {
63+
return iteratorClause.child?.expression;
64+
}
65+
}, [iteratorClause.child]);
66+
67+
return (
68+
<NestedExpressionDispatchContextProvider onSetExpression={onSetExpression}>
69+
<ExpressionContainer
70+
expression={currentExpression}
71+
isResetSupported={true}
72+
isNested={true}
73+
rowIndex={rowIndex}
74+
columnIndex={columnIndex}
75+
parentElementId={parentElementId}
76+
parentElementTypeRef={undefined}
77+
/>
78+
</NestedExpressionDispatchContextProvider>
79+
);
80+
}

0 commit comments

Comments
 (0)