Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kie-issues#237: Implement DMN 1.4 Boxed iterator expression #2243

Merged
merged 2 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export enum BoxedFunctionKind {
Pmml = "PMML",
}

export type BoxedIterator = BoxedFor | BoxedEvery | BoxedSome;

export type BoxedExpression =
| BoxedLiteral
| BoxedRelation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import { CutIcon } from "@patternfly/react-icons/dist/js/icons/cut-icon";
import { ListIcon } from "@patternfly/react-icons/dist/js/icons/list-icon";
import { PasteIcon } from "@patternfly/react-icons/dist/js/icons/paste-icon";
import { TableIcon } from "@patternfly/react-icons/dist/js/icons/table-icon";
import { RebootingIcon } from "@patternfly/react-icons/dist/js/icons/rebooting-icon";
import { ResourcesAlmostEmptyIcon } from "@patternfly/react-icons/dist/js/icons/resources-almost-empty-icon";
import { ResourcesFullIcon } from "@patternfly/react-icons/dist/js/icons/resources-full-icon";
import * as React from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { BoxedExpression } from "../../api";
Expand All @@ -47,13 +50,14 @@ import { LiteralExpression } from "../LiteralExpression/LiteralExpression";
import { RelationExpression } from "../RelationExpression/RelationExpression";
import {
BoxedExpressionClipboard,
DMN_BOXED_EXPRESSION_CLIPBOARD_MIME_TYPE,
buildClipboardFromExpression,
DMN_BOXED_EXPRESSION_CLIPBOARD_MIME_TYPE,
} from "../../clipboard/clipboard";
import { findAllIdsDeep, mutateExpressionRandomizingIds } from "../../ids/ids";
import "./ExpressionDefinitionLogicTypeSelector.css";
import { NavigationKeysUtils } from "../../keysUtils/keyUtils";
import { ConditionalExpression } from "../ConditionalExpression/ConditionalExpression";
import { IteratorExpressionComponent } from "../IteratorExpression/IteratorExpressionComponent";

export interface ExpressionDefinitionLogicTypeSelectorProps {
/** Expression properties */
Expand Down Expand Up @@ -95,9 +99,9 @@ export function ExpressionDefinitionLogicTypeSelector({
"invocation",
...(isNested ? (["functionDefinition"] as const) : []),
...(!hideDmn14BoxedExpressions ? (["conditional"] as const) : []),
// "for",
// "every",
// "some",
"for",
"every",
"some",
// "filter",
],
[hideDmn14BoxedExpressions, isNested]
Expand Down Expand Up @@ -134,6 +138,9 @@ export function ExpressionDefinitionLogicTypeSelector({
case "for":
case "every":
case "some":
return (
<IteratorExpressionComponent expression={expression} isNested={isNested} parentElementId={parentElementId} />
);
case "filter":
return <></>;
default:
Expand Down Expand Up @@ -235,8 +242,11 @@ export function ExpressionDefinitionLogicTypeSelector({
</span>
);
case "for":
return <RebootingIcon />;
case "every":
return <ResourcesFullIcon />;
case "some":
return <ResourcesAlmostEmptyIcon />;
case "filter":
return <></>;
default:
Expand Down Expand Up @@ -330,6 +340,25 @@ export function ExpressionDefinitionLogicTypeSelector({
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.";
case "conditional":
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.';
case "for":
return (
"A boxed iterator offers a visual representation of an iterator statement. " +
'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.' +
" The last row contains the expression that will process each element of the collection."
);

case "every":
return (
"A boxed iterator offers a visual representation of an iterator statement. " +
'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.' +
"The last line is an expression that will be evaluated on each item. The expression defined in the satisfies MUST resolve to a boolean."
);
case "some":
return (
"A boxed iterator offers a visual representation of an iterator statement. " +
'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. ' +
"The last line is an expression that will be evaluated on each item. The expression defined in the satisfies MUST resolve to a boolean."
);
default:
return "";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { BoxedIterator } from "../../api";

import {
NestedExpressionDispatchContextProvider,
useBoxedExpressionEditorDispatch,
} from "../../BoxedExpressionEditorContext";
import * as React from "react";
import { useCallback, useMemo } from "react";
import { ExpressionContainer } from "../ExpressionDefinitionRoot/ExpressionContainer";
import { IteratorClause } from "./IteratorExpressionComponent";

export interface IteratorExpressionCellExpressionCellProps {
iteratorClause: IteratorClause;
rowIndex: number;
columnIndex: number;
columnId: string;
}

export function IteratorExpressionCell({
rowIndex,
columnIndex,
parentElementId,
iteratorClause,
}: IteratorExpressionCellExpressionCellProps & { parentElementId: string }) {
const { setExpression } = useBoxedExpressionEditorDispatch();

const onSetExpression = useCallback(
({ getNewExpression }) => {
setExpression((prev: BoxedIterator) => {
switch (rowIndex) {
case 1:
return {
...prev,
in: {
expression: getNewExpression(prev.in.expression),
},
};
case 2:
default:
if (prev.__$$element === "for") {
return {
...prev,
return: {
expression: getNewExpression(),
},
};
} else {
return {
...prev,
satisfies: {
expression: getNewExpression(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not pass prev here, like you're doing at the in part?

},
};
}
}
});
},
[rowIndex, setExpression]
);

const currentExpression = useMemo(() => {
if (typeof iteratorClause.child !== "string") {
return iteratorClause.child?.expression as any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why "as any"?

}
}, [iteratorClause.child]);

return (
<NestedExpressionDispatchContextProvider onSetExpression={onSetExpression}>
<ExpressionContainer
expression={currentExpression}
isResetSupported={true}
isNested={true}
rowIndex={rowIndex}
columnIndex={columnIndex}
parentElementId={parentElementId}
parentElementTypeRef={undefined}
/>
</NestedExpressionDispatchContextProvider>
);
}
Loading
Loading