-
Notifications
You must be signed in to change notification settings - Fork 185
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#1298: Decision Services & multiple DRDs: make it possible o add external Decisions to a Decision Service #2508
Changes from 3 commits
b690ebb
33de8ea
2db60f6
b55113d
24f1b15
f916099
99924ea
d64a04e
a078041
c9f88bf
411e61d
6cd536f
a44b7da
fad6167
3ee4271
a84bea2
90c03ff
c3c23dd
54b419c
40a0fdf
227ee5a
3d8abb5
9d7a04e
a5f3e71
8bbb1cf
81d260f
1bdc614
ffa1867
2921171
e22fcd1
3cb35a5
334cf35
bd5786c
0e90a76
a03e182
d9408e7
4759ae3
91a815f
702f44f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -245,7 +245,11 @@ export function Palette({ pulse }: { pulse: boolean }) { | |
<br /> | ||
<aside className={"kie-dmn-editor--external-nodes-panel-toggle"}> | ||
{diagram.openLhsPanel === DiagramLhsPanel.EXTERNAL_NODES && ( | ||
<div className={"kie-dmn-editor--palette-nodes-popover"} style={{ maxHeight }}> | ||
<div | ||
className={"kie-dmn-editor--palette-nodes-popover"} | ||
style={{ maxHeight }} | ||
data-testid={"kie-tools--dmn-editor--external-nodes-container"} | ||
> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "DRG nodes" panel doesn't have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have tests for "DRG Nodes" panel? I only found for drag nodes from the palette not from the "DRG Nodes" panel. 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tiagobento actually we are about to add One thing we could unify is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All good then! Thanks for the insights. I have no preference for the suffix, just please coordinate that it is consistent. @jomarko @danielzhe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll change it to |
||
<ExternalNodesPanel /> | ||
</div> | ||
)} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,6 +159,7 @@ export function ExternalNodesPanel() { | |
externalDrgElementId: drgElement["@_id"]!, | ||
}) | ||
} | ||
data-testid={`kie-tools--dmn-editor--external-node-${_import["@_name"]}-${drgElement["@_name"]}`} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is ${_import["@_name"]} always non empty? I mean containing some non white characters? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it can be an empty string. Great catch. |
||
> | ||
<Flex | ||
alignItems={{ default: "alignItemsCenter" }} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,25 +25,42 @@ import { SnapGrid } from "../store/Store"; | |
import { MIN_NODE_SIZES } from "../diagram/nodes/DefaultSizes"; | ||
import { NODE_TYPES } from "../diagram/nodes/NodeTypes"; | ||
import { Normalized } from "../normalization/normalize"; | ||
import { | ||
DMN15__tBusinessKnowledgeModel, | ||
DMN15__tDecision, | ||
DMN15__tDecisionService, | ||
DMN15__tInputData, | ||
DMN15__tKnowledgeSource, | ||
} from "@kie-tools/dmn-marshaller/src/schemas/dmn-1_5/ts-gen/types"; | ||
|
||
export type DrgElement = | ||
| Normalized<{ __$$element: "decision" } & DMN15__tDecision> | ||
| Normalized<{ __$$element: "businessKnowledgeModel" } & DMN15__tBusinessKnowledgeModel> | ||
| Normalized<{ __$$element: "decisionService" } & DMN15__tDecisionService> | ||
| Normalized<{ __$$element: "inputData" } & DMN15__tInputData> | ||
| Normalized<{ __$$element: "knowledgeSource" } & DMN15__tKnowledgeSource>; | ||
|
||
export function addDecisionToDecisionService({ | ||
definitions, | ||
decisionId, | ||
drgElement, | ||
decisionServiceId, | ||
drdIndex, | ||
snapGrid, | ||
decisionShape, | ||
elementId, | ||
}: { | ||
definitions: Normalized<DMN15__tDefinitions>; | ||
decisionId: string; | ||
drgElement: DrgElement; | ||
decisionServiceId: string; | ||
drdIndex: number; | ||
snapGrid: SnapGrid; | ||
decisionShape: Normalized<DMNDI15__DMNShape>; | ||
elementId: string; | ||
}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I understand There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the previous code we was getting the ID, in
So I think it is safe to assume that
About the ID, I can't see any case where the ID of the selected node will be different than the DRG, except for the imported nodes the ID in the DRG is not full, it is only the local ID (the Guid), but from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, we don't have DRG element always in the definitions: the external nodes do not have DRG element, only DMNDI. The DRG we have in
Notice only the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We only need the ID, but we need to know that this ID represents a Decision. The only way to know that is having the externalModelsByNamespace passed as parameter to the "addDecisionToDecisionService" mutation, so we can make that validation. You're mentioning the arguments you're passing when calling this mutation, but the mutation itself, after your changes, can be called with {
elementId: "bar"
drgElement: {
"@_id": "foo"
...
}
} which has the potential of being wrong. What I'm saying is that we rollback to the way it was before, and we include the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think got your point! I guarantee in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you can guarantee that you're calling it correctly now, but you can't guarantee that this will be true forever :P |
||
console.debug(`DMN MUTATION: Adding Decision '${decisionId}' to Decision Service '${decisionServiceId}'`); | ||
console.debug(`DMN MUTATION: Adding Decision '${elementId}' to Decision Service '${decisionServiceId}'`); | ||
|
||
const decision = definitions.drgElement?.find((s) => s["@_id"] === decisionId); | ||
if (decision?.__$$element !== "decision") { | ||
throw new Error(`DMN MUTATION: DRG Element with id '${decisionId}' is either not a Decision or doesn't exist.`); | ||
if (drgElement?.__$$element !== "decision") { | ||
throw new Error(`DMN MUTATION: DRG Element with id '${elementId}' is either not a Decision or doesn't exist.`); | ||
} | ||
|
||
const decisionService = definitions.drgElement?.find((s) => s["@_id"] === decisionServiceId); | ||
|
@@ -54,9 +71,6 @@ export function addDecisionToDecisionService({ | |
} | ||
|
||
const diagram = addOrGetDrd({ definitions, drdIndex }); | ||
const decisionShape = diagram.diagramElements.find( | ||
(s) => s["@_dmnElementRef"] === decisionId && s.__$$element === "dmndi:DMNShape" | ||
) as Normalized<DMNDI15__DMNShape>; | ||
|
||
const decisionServiceShape = diagram.diagramElements.find( | ||
(s) => s["@_dmnElementRef"] === decisionServiceId && s.__$$element === "dmndi:DMNShape" | ||
|
@@ -65,10 +79,10 @@ export function addDecisionToDecisionService({ | |
const section = getSectionForDecisionInsideDecisionService({ decisionShape, decisionServiceShape, snapGrid }); | ||
if (section === "encapsulated") { | ||
decisionService.encapsulatedDecision ??= []; | ||
decisionService.encapsulatedDecision.push({ "@_href": `#${decisionId}` }); | ||
decisionService.encapsulatedDecision.push({ "@_href": `${elementId}` }); | ||
} else if (section === "output") { | ||
decisionService.outputDecision ??= []; | ||
decisionService.outputDecision.push({ "@_href": `#${decisionId}` }); | ||
decisionService.outputDecision.push({ "@_href": `${elementId}` }); | ||
} else { | ||
throw new Error(`DMN MUTATION: Invalid section to add decision to: '${section}' `); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,20 +18,19 @@ | |
*/ | ||
|
||
import * as React from "react"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { useCallback, useMemo, useRef, useState } from "react"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those changes are made automatically by the Prettier There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think Prettier doesn't change the imports... Maybe it's your VS Code "Organize imports"? |
||
import "@patternfly/react-core/dist/styles/base.css"; | ||
import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; | ||
import { Page, PageSection } from "@patternfly/react-core/dist/js/components/Page"; | ||
import { DmnLatestModel, getMarshaller, DmnMarshaller } from "@kie-tools/dmn-marshaller"; | ||
import { Normalized, normalize } from "@kie-tools/dmn-editor/dist/normalization/normalize"; | ||
import { DmnLatestModel, DmnMarshaller, getMarshaller } from "@kie-tools/dmn-marshaller"; | ||
import { normalize, Normalized } from "@kie-tools/dmn-editor/dist/normalization/normalize"; | ||
import { availableModelsByPath, modelsByNamespace } from "./availableModelsToInclude"; | ||
import { generateEmptyDmn15 } from "../misc/empty/Empty.stories"; | ||
import { loanPreQualificationDmn } from "../useCases/loanPreQualification/LoanPreQualification.stories"; | ||
import { DmnEditorWrapper } from "../dmnEditorStoriesWrapper"; | ||
import { | ||
DmnEditorProps, | ||
DmnEditorRef, | ||
ExternalModelsIndex, | ||
OnDmnModelChange, | ||
OnRequestExternalModelByPath, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import EmptyWithAvailableExternalModelsStories from "./EmptyWithAvailableExternalModels.stories"; | ||
import { Meta } from "@storybook/blocks"; | ||
|
||
<Meta title="MDX/Misc/EmptyWithAvailableExternalModelsStories" of={EmptyWithAvailableExternalModelsStories} /> | ||
|
||
## Empty With Available External Models | ||
|
||
When user starts with an empty diagram, a wizard for quick content initialization is displayed. | ||
The wizard enables to create simple diagram with one input and one output or a diagram with one decision table expression. | ||
This model also have some external models available to be included. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import * as React from "react"; | ||
import { useCallback, useMemo, useState } from "react"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { DmnLatestModel, DmnMarshaller, getMarshaller } from "@kie-tools/dmn-marshaller"; | ||
import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta"; | ||
import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api"; | ||
import { DMN15_SPEC } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/Dmn15Spec"; | ||
import { | ||
DmnEditor, | ||
DmnEditorProps, | ||
ExternalModelsIndex, | ||
OnRequestExternalModelByPath, | ||
OnRequestExternalModelsAvailableToInclude, | ||
OnDmnModelChange, | ||
} from "@kie-tools/dmn-editor/dist/DmnEditor"; | ||
import { normalize, Normalized } from "@kie-tools/dmn-editor/dist/normalization/normalize"; | ||
|
||
import { DmnEditorWrapper, StorybookDmnEditorProps } from "../../dmnEditorStoriesWrapper"; | ||
|
||
import { availableModelsByPath, modelsByNamespace } from "./availableModelsToInclude"; | ||
|
||
export const generateEmptyDmn15 = () => `<?xml version="1.0" encoding="UTF-8"?> | ||
<definitions | ||
xmlns="${dmn15ns.get("")}" | ||
expressionLanguage="${DMN15_SPEC.expressionLanguage.default}" | ||
namespace="https://kie.apache.org/dmn/${generateUuid()}" | ||
id="${generateUuid()}" | ||
name="DMN${generateUuid()}"> | ||
</definitions>`; | ||
|
||
const initialModel = generateEmptyDmn15(); | ||
|
||
function EmptyStoryWithIncludedModels(args: DmnEditorProps) { | ||
const [state, setState] = useState<{ | ||
marshaller: DmnMarshaller; | ||
stack: Normalized<DmnLatestModel>[]; | ||
pointer: number; | ||
}>(() => { | ||
const initialDmnMarshaller = getMarshaller(initialModel, { upgradeTo: "latest" }); | ||
return { | ||
marshaller: initialDmnMarshaller, | ||
stack: [normalize(initialDmnMarshaller.parser.parse())], | ||
pointer: 0, | ||
}; | ||
}); | ||
|
||
const currentModel = state.stack[state.pointer]; | ||
|
||
const externalModelsByNamespace = useMemo<ExternalModelsIndex>(() => { | ||
return (currentModel.definitions.import ?? []).reduce((acc, i) => { | ||
acc[i["@_namespace"]] = modelsByNamespace[i["@_namespace"]]; | ||
return acc; | ||
}, {} as ExternalModelsIndex); | ||
}, [currentModel.definitions.import]); | ||
|
||
const onRequestExternalModelByPath = useCallback<OnRequestExternalModelByPath>(async (path) => { | ||
return availableModelsByPath[path] ?? null; | ||
}, []); | ||
|
||
const onRequestExternalModelsAvailableToInclude = useCallback<OnRequestExternalModelsAvailableToInclude>(async () => { | ||
return Object.keys(availableModelsByPath); | ||
}, []); | ||
|
||
const onModelChange = useCallback<OnDmnModelChange>((model) => { | ||
setState((prev) => { | ||
const newStack = prev.stack.slice(0, prev.pointer + 1); | ||
return { | ||
...prev, | ||
stack: [...newStack, model], | ||
pointer: newStack.length, | ||
}; | ||
}); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
{DmnEditorWrapper({ | ||
model: currentModel, | ||
originalVersion: args.originalVersion, | ||
onModelChange, | ||
onRequestExternalModelByPath, | ||
onRequestExternalModelsAvailableToInclude, | ||
externalModelsByNamespace: externalModelsByNamespace, | ||
externalContextName: args.externalContextName, | ||
externalContextDescription: args.externalContextDescription, | ||
validationMessages: args.validationMessages, | ||
evaluationResults: args.evaluationResults, | ||
issueTrackerHref: args.issueTrackerHref, | ||
})} | ||
</> | ||
); | ||
} | ||
|
||
const meta: Meta<DmnEditorProps> = { | ||
title: "Misc/EmptyWithAvailableExternalModels", | ||
component: DmnEditor, | ||
includeStories: /^[A-Z]/, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof EmptyStoryWithIncludedModels>; | ||
|
||
export const EmptyWithAvailableExternalModels: Story = { | ||
render: (args) => EmptyStoryWithIncludedModels(args), | ||
args: { | ||
model: getMarshaller(initialModel, { upgradeTo: "latest" }).parser.parse(), | ||
originalVersion: "1.5", | ||
evaluationResults: {}, | ||
externalContextDescription: "External context description", | ||
externalContextName: "Storybook - DMN Editor", | ||
externalModelsByNamespace: {}, | ||
issueTrackerHref: "", | ||
validationMessages: {}, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import { getMarshaller } from "@kie-tools/dmn-marshaller"; | ||
import { normalize } from "@kie-tools/dmn-editor/dist/normalization/normalize"; | ||
import { XML2PMML } from "@kie-tools/pmml-editor-marshaller"; | ||
import * as DmnEditor from "@kie-tools/dmn-editor/dist/DmnEditor"; | ||
import { getPmmlNamespace } from "@kie-tools/dmn-editor/dist/pmml/pmml"; | ||
import { sumBkm, sumDiffDs, testTreePmml } from "./externalModels"; | ||
|
||
export const sumBkmModel = normalize(getMarshaller(sumBkm, { upgradeTo: "latest" }).parser.parse()); | ||
export const sumDiffDsModel = normalize(getMarshaller(sumDiffDs, { upgradeTo: "latest" }).parser.parse()); | ||
export const testTreePmmlModel = XML2PMML(testTreePmml); | ||
|
||
export const availableModels: DmnEditor.ExternalModel[] = [ | ||
{ | ||
type: "dmn", | ||
model: sumBkmModel, | ||
svg: "", | ||
normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/sumBkm.dmn", | ||
}, | ||
{ | ||
type: "dmn", | ||
model: sumDiffDsModel, | ||
svg: "", | ||
normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/sumDiffDs.dmn", | ||
}, | ||
{ | ||
type: "dmn", | ||
model: normalize( | ||
getMarshaller(`<definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/" />`, { | ||
upgradeTo: "latest", | ||
}).parser.parse() | ||
), | ||
svg: "", | ||
normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/empty.dmn", | ||
}, | ||
{ | ||
type: "pmml", | ||
model: testTreePmmlModel, | ||
normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/testTree.pmml", | ||
}, | ||
]; | ||
|
||
export const availableModelsByPath: Record<string, DmnEditor.ExternalModel> = Object.values(availableModels).reduce( | ||
(acc, v) => { | ||
acc[v.normalizedPosixPathRelativeToTheOpenFile] = v; | ||
return acc; | ||
}, | ||
{} as Record<string, DmnEditor.ExternalModel> | ||
); | ||
|
||
export const modelsByNamespace = Object.values(availableModels).reduce((acc, v) => { | ||
if (v.type === "dmn") { | ||
acc[v.model.definitions["@_namespace"]] = v; | ||
} else if (v.type === "pmml") { | ||
acc[getPmmlNamespace({ normalizedPosixPathRelativeToTheOpenFile: v.normalizedPosixPathRelativeToTheOpenFile })] = v; | ||
} | ||
return acc; | ||
}, {} as DmnEditor.ExternalModelsIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comment about the mutation itself...