diff --git a/packages/dmn-editor/src/diagram/Diagram.tsx b/packages/dmn-editor/src/diagram/Diagram.tsx index 876c22ba4bb..9dbd0fe75a2 100644 --- a/packages/dmn-editor/src/diagram/Diagram.tsx +++ b/packages/dmn-editor/src/diagram/Diagram.tsx @@ -216,7 +216,7 @@ export const Diagram = React.forwardRef( diff --git a/packages/dmn-editor/src/diagram/connections/isValidConnection.ts b/packages/dmn-editor/src/diagram/connections/isValidConnection.ts index 3dbfb06a61b..94fcd75f31d 100644 --- a/packages/dmn-editor/src/diagram/connections/isValidConnection.ts +++ b/packages/dmn-editor/src/diagram/connections/isValidConnection.ts @@ -39,14 +39,18 @@ export function checkIsValidConnection( export function _checkIsValidConnection( sourceNode: { type?: string; data: DmnDiagramNodeData } | undefined, targetNode: { type?: string; data: DmnDiagramNodeData } | undefined, - edgeType: string | null | undefined + edgeType: string | null | undefined, + extraArg?: { allowExternalTarget: boolean } ) { if (!sourceNode?.type || !targetNode?.type || !edgeType) { return false; } - // External nodes cannot be targeted - if (targetNode.data.dmnObjectQName.prefix) { + // External nodes cannot be targeted by default + // However there are exceptions, for example adding a waypoint on the edge + const targetsExternalNode = targetNode.data.dmnObjectQName.prefix !== undefined; + const allowExternalTarget = extraArg?.allowExternalTarget ?? false; + if (targetsExternalNode && !allowExternalTarget) { return false; } diff --git a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts index 1a80d491a4b..d63d5014afd 100644 --- a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts +++ b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts @@ -25,6 +25,12 @@ import { snapPoint } from "../SnapGrid"; import { DC__Point } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; import { DmnDiagramNodeData } from "../nodes/Nodes"; import { DmnDiagramEdgeData } from "./Edges"; +import { useExternalModels } from "../../includedModels/DmnEditorDependenciesContext"; +import { addEdge } from "../../mutations/addEdge"; +import { EdgeType, NodeType } from "../connections/graphStructure"; +import { PositionalNodeHandleId } from "../connections/PositionalNodeHandles"; +import { getHandlePosition } from "../maths/DmnMaths"; +import { xmlHrefToQName } from "../../xml/xmlHrefToQName"; export function usePotentialWaypointControls( waypoints: DC__Point[], @@ -38,6 +44,7 @@ export function usePotentialWaypointControls( const isDraggingWaypoint = useDmnEditorStore((s) => !!s.diagram.draggingWaypoints.find((e) => e === edgeId)); const dmnEditorStoreApi = useDmnEditorStoreApi(); const reactFlowInstance = RF.useReactFlow(); + const { externalModelsByNamespace } = useExternalModels(); const [potentialWaypoint, setPotentialWaypoint] = useState | undefined>( undefined @@ -74,12 +81,83 @@ export function usePotentialWaypointControls( }, [snapGrid, potentialWaypoint]); const onDoubleClick = useCallback(() => { - if (!potentialWaypoint || !snappedPotentialWaypoint || edgeIndex === undefined) { + if (!potentialWaypoint || !snappedPotentialWaypoint) { return; } + if (edgeIndex === undefined) { + /** + * This means we are adding a first waypoint to one of following edges: + * - an edge in a non default DRD + * - an edge targeting an external node + */ + dmnEditorStoreApi.setState((state) => { + const nodesById = state.computed(state).getDiagramData(externalModelsByNamespace).nodesById; + const edge = state.computed(state).getDiagramData(externalModelsByNamespace).edgesById.get(edgeId); + if (edge === undefined || edge.data?.dmnShapeSource === undefined || edge.data?.dmnShapeTarget == undefined) { + console.debug( + `DMN DIAGRAM: We can not add DMNEdge for '${edgeId}' edge into diagram. There are missing data edge: ${edge}, edge.data: ${edge?.data}` + ); + return; + } + + const edgeSourceBounds = edge.data?.dmnShapeSource["dc:Bounds"]; + const edgeTargetBounds = edge.data?.dmnShapeTarget["dc:Bounds"]; + if (edgeSourceBounds === undefined || edgeTargetBounds === undefined) { + console.debug( + `DMN DIAGRAM: We can not add DMNEdge for '${edgeId}' edge into diagram. There are missing data edgeSourceBounds: ${edgeSourceBounds}, edgeTargetBounds: ${edgeTargetBounds}` + ); + return; + } + + const sourceNode = nodesById.get(edge.source); + const targetNode = nodesById.get(edge.target); + if (sourceNode === undefined || targetNode === undefined) { + console.debug( + `DMN DIAGRAM: We can not add DMNEdge for '${edgeId}' edge into diagram. There are missing data sourceNode: ${sourceNode}, targetNode: ${targetNode}` + ); + return; + } + + const targetsExternalNode = targetNode.data.dmnObjectQName.prefix !== undefined; + const requirementEdgeQNameRelativeToThisDmn = xmlHrefToQName(edgeId, state.dmn.model.definitions); + addEdge({ + definitions: state.dmn.model.definitions, + drdIndex: state.computed(state).getDrdIndex(), + edge: { + type: edge.type as EdgeType, + targetHandle: getHandlePosition({ shapeBounds: edgeTargetBounds, waypoint: snappedPotentialWaypoint }) + .handlePosition as PositionalNodeHandleId, + sourceHandle: getHandlePosition({ shapeBounds: edgeSourceBounds, waypoint: snappedPotentialWaypoint }) + .handlePosition as PositionalNodeHandleId, + autoPositionedEdgeMarker: undefined, + }, + sourceNode: { + type: sourceNode.type as NodeType, + data: sourceNode.data, + href: edge.source, + bounds: edgeSourceBounds, + shapeId: edge.data?.dmnShapeSource["@_id"], + }, + targetNode: { + type: targetNode.type as NodeType, + href: edge.target, + data: targetNode.data, + bounds: edgeTargetBounds, + index: nodesById.get(edge.target)?.data.index ?? 0, + shapeId: edge.data?.dmnShapeTarget["@_id"], + }, + keepWaypoints: false, + externalModelsByNamespace, + dmnElementRefOfDmnEdge: targetsExternalNode ? requirementEdgeQNameRelativeToThisDmn : undefined, + }); + + console.debug(`DMN DIAGRAM: DMNEdge for '${edgeId}' edge was added into diagram.`); + }); + } + if (isExistingWaypoint(snappedPotentialWaypoint)) { - console.debug("Preventing overlapping waypoint creation."); + console.debug("DMN DIAGRAM: Preventing overlapping waypoint creation."); return; } @@ -96,18 +174,27 @@ export function usePotentialWaypointControls( } dmnEditorStoreApi.setState((state) => { + const edgeQName = xmlHrefToQName(edgeId, state.dmn.model.definitions); + const dmnEdgeIndex = state.computed(state).indexedDrd().dmnEdgesByDmnElementRef.get(edgeQName)?.index; + if (dmnEdgeIndex === undefined) { + throw new Error(`DMN DIAGRAM: Diagram computed state does not contain DMNEdge for '${edgeId}' edge.`); + } addEdgeWaypoint({ definitions: state.dmn.model.definitions, drdIndex, beforeIndex: i - 1, - edgeIndex, + dmnEdgeIndex, waypoint: snappedPotentialWaypoint, }); + + console.debug(`DMN DIAGRAM: Waypoint on the DMNEdge for '${edgeId}' edge was added.`); }); }, [ drdIndex, dmnEditorStoreApi, + edgeId, edgeIndex, + externalModelsByNamespace, isExistingWaypoint, potentialWaypoint, snappedPotentialWaypoint, diff --git a/packages/dmn-editor/src/mutations/addEdge.ts b/packages/dmn-editor/src/mutations/addEdge.ts index 7be83b0f2ce..b45591a26a9 100644 --- a/packages/dmn-editor/src/mutations/addEdge.ts +++ b/packages/dmn-editor/src/mutations/addEdge.ts @@ -27,7 +27,6 @@ import { DMN15__tInformationRequirement, DMN15__tKnowledgeRequirement, DMNDI15__DMNEdge, - DMNDI15__DMNShape, } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; import { PositionalNodeHandleId } from "../diagram/connections/PositionalNodeHandles"; import { EdgeType, NodeType } from "../diagram/connections/graphStructure"; @@ -51,6 +50,7 @@ export function addEdge({ edge, keepWaypoints, externalModelsByNamespace, + dmnElementRefOfDmnEdge, }: { definitions: Normalized; drdIndex: number; @@ -77,14 +77,17 @@ export function addEdge({ }; keepWaypoints: boolean; externalModelsByNamespace: ExternalModelsIndex | undefined; + // QName format, used as dmnElementRef for DMNEdge targeting an external node + dmnElementRefOfDmnEdge?: string; }) { - if (!_checkIsValidConnection(sourceNode, targetNode, edge.type)) { + const externalTargetAllowed = dmnElementRefOfDmnEdge !== undefined; + if (!_checkIsValidConnection(sourceNode, targetNode, edge.type, { allowExternalTarget: externalTargetAllowed })) { throw new Error(`DMN MUTATION: Invalid structure: (${sourceNode.type}) --${edge.type}--> (${targetNode.type}) `); } const newEdgeId = generateUuid(); - let existingEdgeId: string | undefined = undefined; + let existingRequirementOrAssociationId: string | undefined = dmnElementRefOfDmnEdge; // Associations if (edge.type === EDGE_TYPES.association) { @@ -102,17 +105,17 @@ export function addEdge({ definitions.artifact, (a) => a.__$$element === "association" && areAssociationsEquivalent(a, newAssociation) ); - existingEdgeId = removed?.["@_id"]; + existingRequirementOrAssociationId = removed?.["@_id"]; // Replace with the new one. definitions.artifact?.push({ __$$element: "association", ...newAssociation, - "@_id": tryKeepingEdgeId(existingEdgeId, newEdgeId), + "@_id": tryKeepingEdgeId(existingRequirementOrAssociationId, newEdgeId), }); } // Requirements - else { + else if (!externalTargetAllowed) { const requirements = getRequirementsFromEdge(sourceNode, newEdgeId, edge.type); const drgElement = definitions.drgElement![targetNode.index] as Normalized; // We cast to tDecision here because it has all three types of requirement. if (requirements?.informationRequirement) { @@ -120,11 +123,11 @@ export function addEdge({ const removed = removeFirstMatchIfPresent(drgElement.informationRequirement, (ir) => doesInformationRequirementsPointTo(ir, sourceNode.href) ); - existingEdgeId = removed?.["@_id"]; + existingRequirementOrAssociationId = removed?.["@_id"]; drgElement.informationRequirement?.push( ...requirements.informationRequirement.map((s) => ({ ...s, - "@_id": tryKeepingEdgeId(existingEdgeId, newEdgeId), + "@_id": tryKeepingEdgeId(existingRequirementOrAssociationId, newEdgeId), })) ); } @@ -134,11 +137,11 @@ export function addEdge({ const removed = removeFirstMatchIfPresent(drgElement.knowledgeRequirement, (kr) => doesKnowledgeRequirementsPointTo(kr, sourceNode.href) ); - existingEdgeId = removed?.["@_id"]; + existingRequirementOrAssociationId = removed?.["@_id"]; drgElement.knowledgeRequirement?.push( ...requirements.knowledgeRequirement.map((s) => ({ ...s, - "@_id": tryKeepingEdgeId(existingEdgeId, newEdgeId), + "@_id": tryKeepingEdgeId(existingRequirementOrAssociationId, newEdgeId), })) ); } @@ -148,11 +151,11 @@ export function addEdge({ const removed = removeFirstMatchIfPresent(drgElement.authorityRequirement, (ar) => doesAuthorityRequirementsPointTo(ar, sourceNode.href) ); - existingEdgeId = removed?.["@_id"]; + existingRequirementOrAssociationId = removed?.["@_id"]; drgElement.authorityRequirement?.push( ...requirements.authorityRequirement.map((s) => ({ ...s, - "@_id": tryKeepingEdgeId(existingEdgeId, newEdgeId), + "@_id": tryKeepingEdgeId(existingRequirementOrAssociationId, newEdgeId), })) ); } @@ -163,7 +166,7 @@ export function addEdge({ // Remove existing const removedDmnEdge = removeFirstMatchIfPresent( diagramElements, - (e) => e.__$$element === "dmndi:DMNEdge" && e["@_dmnElementRef"] === existingEdgeId + (e) => e.__$$element === "dmndi:DMNEdge" && e["@_dmnElementRef"] === existingRequirementOrAssociationId ) as Normalized | undefined; const newWaypoints = keepWaypoints @@ -182,7 +185,7 @@ export function addEdge({ "@_id": withoutDiscreteAutoPosinitioningMarker(removedDmnEdge?.["@_id"] ?? generateUuid()) + (edge.autoPositionedEdgeMarker ?? ""), - "@_dmnElementRef": existingEdgeId ?? newEdgeId, + "@_dmnElementRef": existingRequirementOrAssociationId ?? newEdgeId, "@_sourceElement": sourceNode.shapeId, "@_targetElement": targetNode.shapeId, "di:waypoint": newWaypoints, diff --git a/packages/dmn-editor/src/mutations/addEdgeWaypoint.ts b/packages/dmn-editor/src/mutations/addEdgeWaypoint.ts index 282865f0c5e..8331ed9ca56 100644 --- a/packages/dmn-editor/src/mutations/addEdgeWaypoint.ts +++ b/packages/dmn-editor/src/mutations/addEdgeWaypoint.ts @@ -24,21 +24,21 @@ import { Normalized } from "../normalization/normalize"; export function addEdgeWaypoint({ definitions, drdIndex, - edgeIndex, + dmnEdgeIndex, beforeIndex, waypoint, }: { definitions: Normalized; drdIndex: number; - edgeIndex: number; + dmnEdgeIndex: number; beforeIndex: number; waypoint: DC__Point; }) { const { diagramElements } = addOrGetDrd({ definitions, drdIndex }); - const diagramElement = diagramElements[edgeIndex]; + const diagramElement = diagramElements[dmnEdgeIndex]; if (diagramElement.__$$element !== "dmndi:DMNEdge") { - throw new Error("DMN MUTATION: Can't remove a waypoint from an element that is not a DMNEdge."); + throw new Error("DMN MUTATION: Can't add a waypoint for an element that is not a DMNEdge."); } if (beforeIndex > (diagramElement["di:waypoint"]?.length ?? 0) - 1) { diff --git a/packages/dmn-editor/src/mutations/addShape.ts b/packages/dmn-editor/src/mutations/addShape.ts index fd716e34ae6..f81585b9106 100644 --- a/packages/dmn-editor/src/mutations/addShape.ts +++ b/packages/dmn-editor/src/mutations/addShape.ts @@ -20,7 +20,6 @@ import { DC__Point, DMN15__tDefinitions, - DMNDI15__DMNDecisionServiceDividerLine, DMNDI15__DMNShape, } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; import { NodeType } from "../diagram/connections/graphStructure"; diff --git a/packages/dmn-editor/src/mutations/addStandaloneNode.ts b/packages/dmn-editor/src/mutations/addStandaloneNode.ts index aad8ac660df..ce78b8b3ac9 100644 --- a/packages/dmn-editor/src/mutations/addStandaloneNode.ts +++ b/packages/dmn-editor/src/mutations/addStandaloneNode.ts @@ -18,7 +18,7 @@ */ import { switchExpression } from "@kie-tools-core/switch-expression-ts"; -import { DmnBuiltInDataType, generateUuid } from "@kie-tools/boxed-expression-component/dist/api"; +import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api"; import { DC__Bounds, DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; import { NodeType } from "../diagram/connections/graphStructure"; import { NODE_TYPES } from "../diagram/nodes/NodeTypes"; diff --git a/packages/dmn-editor/src/mutations/deleteEdge.ts b/packages/dmn-editor/src/mutations/deleteEdge.ts index 58a3af9e627..38846da5c73 100644 --- a/packages/dmn-editor/src/mutations/deleteEdge.ts +++ b/packages/dmn-editor/src/mutations/deleteEdge.ts @@ -27,6 +27,7 @@ import { addOrGetDrd } from "./addOrGetDrd"; import { DmnDiagramEdgeData } from "../diagram/edges/Edges"; import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService"; import { Normalized } from "../normalization/normalize"; +import { xmlHrefToQName } from "../xml/xmlHrefToQName"; import { ExternalModelsIndex } from "../DmnEditor"; export enum EdgeDeletionMode { @@ -47,41 +48,40 @@ export function deleteEdge({ mode: EdgeDeletionMode; externalModelsByNamespace: ExternalModelsIndex | undefined; }) { - if (edge.dmnObject.namespace !== definitions["@_namespace"]) { - console.debug("DMN MUTATION: Can't delete an edge that's from an external node."); - return { dmnEdge: undefined }; - } - - const dmnObjects: Normalized["drgElement" | "artifact"] = - switchExpression(edge?.dmnObject.type, { - association: definitions.artifact, - group: definitions.artifact, - default: definitions.drgElement, - }) ?? []; + if (edge.dmnObject.namespace === definitions["@_namespace"]) { + const dmnObjects: Normalized["drgElement" | "artifact"] = + switchExpression(edge?.dmnObject.type, { + association: definitions.artifact, + group: definitions.artifact, + default: definitions.drgElement, + }) ?? []; - const dmnObjectIndex = dmnObjects.findIndex((d) => d["@_id"] === edge.dmnObject.id); - if (dmnObjectIndex < 0) { - throw new Error(`DMN MUTATION: Can't find DMN element with ID ${edge.dmnObject.id}`); - } + const dmnObjectIndex = dmnObjects.findIndex((d) => d["@_id"] === edge.dmnObject.id); + if (dmnObjectIndex < 0) { + throw new Error(`DMN MUTATION: Can't find DMN element with ID ${edge.dmnObject.id}`); + } - if (mode === EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS) { - const requirements = - switchExpression(edge?.dmnObject.requirementType, { - // Casting to DMN15__tDecision because if has all types of requirement, but not necessarily that's true. - informationRequirement: (dmnObjects[dmnObjectIndex] as Normalized).informationRequirement, - knowledgeRequirement: (dmnObjects[dmnObjectIndex] as Normalized).knowledgeRequirement, - authorityRequirement: (dmnObjects[dmnObjectIndex] as Normalized).authorityRequirement, - association: dmnObjects, - }) ?? []; + if (mode === EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS) { + const requirements = + switchExpression(edge?.dmnObject.requirementType, { + // Casting to DMN15__tDecision because if has all types of requirement, but not necessarily that's true. + informationRequirement: (dmnObjects[dmnObjectIndex] as Normalized).informationRequirement, + knowledgeRequirement: (dmnObjects[dmnObjectIndex] as Normalized).knowledgeRequirement, + authorityRequirement: (dmnObjects[dmnObjectIndex] as Normalized).authorityRequirement, + association: dmnObjects, + }) ?? []; - // Deleting the requirement - const requirementIndex = (requirements ?? []).findIndex((d) => d["@_id"] === edge.id); - if (requirementIndex >= 0) { - requirements?.splice(requirementIndex, 1); + // Deleting the requirement + const requirementIndex = (requirements ?? []).findIndex((d) => d["@_id"] === edge.id); + if (requirementIndex >= 0) { + requirements?.splice(requirementIndex, 1); + } } } // Deleting the DMNEdge's + // needs to be executed even if edge.dmnObject.namespace !== definitions["@_namespace"] + // As they may be DMNEdge depictions for edges targeting external nodes let deletedDmnEdgeOnCurrentDrd: Normalized | undefined; const drdCount = (definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"] ?? []).length; @@ -92,7 +92,9 @@ export function deleteEdge({ continue; } - const dmnEdgeIndex = (diagramElements ?? []).findIndex((d) => d["@_dmnElementRef"] === edge.id); + const dmnEdgeIndex = (diagramElements ?? []).findIndex( + (d) => d["@_dmnElementRef"] === xmlHrefToQName(edge.id, definitions) + ); if (dmnEdgeIndex >= 0) { if (i === drdIndex) { deletedDmnEdgeOnCurrentDrd = diagramElements[dmnEdgeIndex]; diff --git a/packages/dmn-editor/src/store/computed/computeDiagramData.ts b/packages/dmn-editor/src/store/computed/computeDiagramData.ts index 0c15d4839cd..6205dc4c921 100644 --- a/packages/dmn-editor/src/store/computed/computeDiagramData.ts +++ b/packages/dmn-editor/src/store/computed/computeDiagramData.ts @@ -38,6 +38,7 @@ import { Computed, State } from "../Store"; import { getDecisionServicePropertiesRelativeToThisDmn } from "../../mutations/addExistingDecisionServiceToDrd"; import { Normalized } from "../../normalization/normalize"; import { KIE_UNKNOWN_NAMESPACE } from "../../kie/kie"; +import { xmlHrefToQName } from "../../xml/xmlHrefToQName"; export const NODE_LAYERS = { GROUP_NODE: 0, @@ -99,7 +100,7 @@ export function computeDiagramData( const ackEdge: AckEdge = ({ id, type, dmnObject, source, target, sourceNamespace }) => { const data = { dmnObject, - dmnEdge: id ? indexedDrd.dmnEdgesByDmnElementRef.get(id) : undefined, + dmnEdge: id ? indexedDrd.dmnEdgesByDmnElementRef.get(xmlHrefToQName(id, definitions)) : undefined, dmnShapeSource: indexedDrd.dmnShapesByHref.get(source), dmnShapeTarget: indexedDrd.dmnShapesByHref.get(target), }; @@ -421,7 +422,11 @@ function ackRequirementEdges( (dmnObject.informationRequirement ?? []).forEach((ir, index) => { const irHref = parseXmlHref((ir.requiredDecision ?? ir.requiredInput)!["@_href"]); ackEdge({ - id: ir["@_id"]!, + // HREF format, used as RF.Edge ID + id: + drgElementsNamespace === thisDmnsNamespace + ? ir["@_id"] + : buildXmlHref({ namespace: drgElementsNamespace, id: ir["@_id"] }), dmnObject: { namespace: drgElementsNamespace, type: dmnObject.__$$element, @@ -441,7 +446,11 @@ function ackRequirementEdges( (dmnObject.knowledgeRequirement ?? []).forEach((kr, index) => { const krHref = parseXmlHref(kr.requiredKnowledge["@_href"]); ackEdge({ - id: kr["@_id"]!, + // HREF format, used as RF.Edge ID + id: + drgElementsNamespace === thisDmnsNamespace + ? kr["@_id"] + : buildXmlHref({ namespace: drgElementsNamespace, id: kr["@_id"] }), dmnObject: { namespace: drgElementsNamespace, type: dmnObject.__$$element, diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/drgNodes.ts b/packages/dmn-editor/tests-e2e/__fixtures__/drgNodes.ts index 790b3778b1b..27c0e472608 100644 --- a/packages/dmn-editor/tests-e2e/__fixtures__/drgNodes.ts +++ b/packages/dmn-editor/tests-e2e/__fixtures__/drgNodes.ts @@ -26,7 +26,7 @@ export class DrgNodes { public page: Page ) {} - public async open() { + public async toggle() { await this.page.getByTitle("DRG Nodes").click(); } diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ar-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ar-edge-depiction-waypoint.png new file mode 100644 index 00000000000..718044ce3e1 Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ar-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ir-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ir-edge-depiction-waypoint.png new file mode 100644 index 00000000000..f4c321d972f Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-ir-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-kr-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-kr-edge-depiction-waypoint.png new file mode 100644 index 00000000000..b2ba9406603 Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drds/drds-kr-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ar-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ar-edge-depiction-waypoint.png new file mode 100644 index 00000000000..42bb737451f Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ar-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ir-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ir-edge-depiction-waypoint.png new file mode 100644 index 00000000000..960bc05e324 Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-ir-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-kr-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-kr-edge-depiction-waypoint.png new file mode 100644 index 00000000000..b48c794d9da Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drds/drds-kr-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ar-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ar-edge-depiction-waypoint.png new file mode 100644 index 00000000000..cf1a32eb72d Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ar-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ir-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ir-edge-depiction-waypoint.png new file mode 100644 index 00000000000..9cc7af48e13 Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-ir-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-kr-edge-depiction-waypoint.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-kr-edge-depiction-waypoint.png new file mode 100644 index 00000000000..3b1fddcfda2 Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drds/drds-kr-edge-depiction-waypoint.png differ diff --git a/packages/dmn-editor/tests-e2e/drds/modelDrd.spec.ts b/packages/dmn-editor/tests-e2e/drds/modelDrd.spec.ts index 9ab8801f115..1bc943e3a3a 100644 --- a/packages/dmn-editor/tests-e2e/drds/modelDrd.spec.ts +++ b/packages/dmn-editor/tests-e2e/drds/modelDrd.spec.ts @@ -136,13 +136,13 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await drds.toggle(); await drds.navigateTo({ name: "Third DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await expect(nodes.get({ name: DefaultNodeName.DECISION })).toBeAttached(); @@ -166,13 +166,13 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await drds.toggle(); await drds.navigateTo({ name: "Third DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await nodes.delete({ name: DefaultNodeName.DECISION }); @@ -199,13 +199,13 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await drds.toggle(); await drds.navigateTo({ name: "Third DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await nodes.selectLabel({ name: DefaultNodeName.DECISION }); @@ -233,7 +233,7 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await drgNodes.dragNode({ name: DefaultNodeName.INPUT_DATA, targetPosition: { x: 300, y: 500 } }); await nodes.dragNewConnectedEdge({ @@ -272,7 +272,7 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await expect(diagram.get()).toHaveScreenshot("drds-decision-missing-dependency.png"); @@ -301,7 +301,7 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 300, y: 300 } }); await drgNodes.dragNode({ name: DefaultNodeName.INPUT_DATA, targetPosition: { x: 300, y: 500 } }); @@ -327,7 +327,7 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 500, y: 500 } }); await nodes.move({ name: DefaultNodeName.DECISION, targetPosition: { x: 400, y: 400 } }); @@ -357,7 +357,7 @@ test.describe("Model DRD", () => { await drds.toggle(); await drds.navigateTo({ name: "Second DRD" }); await drds.toggle(); - await drgNodes.open(); + await drgNodes.toggle(); await drgNodes.dragNode({ name: DefaultNodeName.DECISION, targetPosition: { x: 500, y: 500 } }); await nodes.resize({ nodeName: DefaultNodeName.DECISION, xOffset: 100, yOffset: 100 }); @@ -371,6 +371,164 @@ test.describe("Model DRD", () => { expect(width).toEqual("160"); expect(height).toEqual("80"); }); + + test.describe("Model DRD - Add Content - Edge Depiction Waypoint", async () => { + /** + * C A: Decision + * ^ B: Decision + * | C: Decision + * B -> A I: InputData + * ^ + * | + * I + */ + test("should add waypoint to secondary edge depiction - information requirement", async ({ + diagram, + drds, + drgNodes, + edges, + nodes, + palette, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/886", + }); + + await drds.toggle(); + await drds.navigateTo({ name: "First DRD" }); + await drds.toggle(); + await palette.dragNewNode({ type: NodeType.DECISION, targetPosition: { x: 400, y: 300 }, thenRenameTo: "A" }); + await palette.dragNewNode({ type: NodeType.DECISION, targetPosition: { x: 100, y: 300 }, thenRenameTo: "B" }); + await palette.dragNewNode({ type: NodeType.DECISION, targetPosition: { x: 400, y: 100 }, thenRenameTo: "C" }); + await palette.dragNewNode({ + type: NodeType.INPUT_DATA, + targetPosition: { x: 400, y: 500 }, + thenRenameTo: "I", + }); + await nodes.dragNewConnectedEdge({ type: EdgeType.INFORMATION_REQUIREMENT, from: "B", to: "A" }); + await nodes.dragNewConnectedEdge({ type: EdgeType.INFORMATION_REQUIREMENT, from: "A", to: "C" }); + await nodes.dragNewConnectedEdge({ type: EdgeType.INFORMATION_REQUIREMENT, from: "I", to: "A" }); + + await drds.toggle(); + await drds.navigateTo({ name: "Second DRD" }); + await drds.toggle(); + await drgNodes.toggle(); + await drgNodes.dragNode({ name: "A", targetPosition: { x: 400, y: 300 } }); + await drgNodes.dragNode({ name: "B", targetPosition: { x: 100, y: 300 } }); + await drgNodes.dragNode({ name: "C", targetPosition: { x: 400, y: 100 } }); + await drgNodes.dragNode({ name: "I", targetPosition: { x: 400, y: 500 } }); + await drgNodes.toggle(); + + await edges.addWaypoint({ from: "B", to: "A" }); + await edges.addWaypoint({ from: "A", to: "C" }); + await edges.addWaypoint({ from: "I", to: "A" }); + + await nodes.move({ name: "A", targetPosition: { x: 600, y: 400 } }); + + await expect(diagram.get()).toHaveScreenshot("drds-ir-edge-depiction-waypoint.png"); + }); + + /** + * A: Decision + * B -> A <- C B: BusinessKnowledgeModel + * C: DecisionService + */ + test("should add waypoint to secondary edge depiction - knowledge requirement", async ({ + diagram, + drds, + drgNodes, + edges, + nodes, + palette, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/886", + }); + + await drds.toggle(); + await drds.navigateTo({ name: "First DRD" }); + await drds.toggle(); + await palette.dragNewNode({ type: NodeType.DECISION, targetPosition: { x: 400, y: 300 }, thenRenameTo: "A" }); + await palette.dragNewNode({ type: NodeType.BKM, targetPosition: { x: 100, y: 300 }, thenRenameTo: "B" }); + await palette.dragNewNode({ + type: NodeType.DECISION_SERVICE, + targetPosition: { x: 600, y: 300 }, + thenRenameTo: "C", + }); + await nodes.dragNewConnectedEdge({ type: EdgeType.KNOWLEDGE_REQUIREMENT, from: "B", to: "A" }); + await nodes.dragNewConnectedEdge({ type: EdgeType.KNOWLEDGE_REQUIREMENT, from: "C", to: "A" }); + + await drds.toggle(); + await drds.navigateTo({ name: "Second DRD" }); + await drds.toggle(); + await drgNodes.toggle(); + await drgNodes.dragNode({ name: "A", targetPosition: { x: 400, y: 300 } }); + await drgNodes.dragNode({ name: "B", targetPosition: { x: 100, y: 300 } }); + await drgNodes.dragNode({ name: "C", targetPosition: { x: 600, y: 300 } }); + await drgNodes.toggle(); + + await edges.addWaypoint({ from: "B", to: "A" }); + await edges.addWaypoint({ from: "C", to: "A" }); + + await nodes.move({ name: "A", targetPosition: { x: 400, y: 200 } }); + + await expect(diagram.get()).toHaveScreenshot("drds-kr-edge-depiction-waypoint.png"); + }); + + /** + * A: Decision + * B -> A -> C B: KnowledgeSource + * C: KnowledgeSource + */ + test("should add waypoint to secondary edge depiction - authority requirement", async ({ + diagram, + drds, + drgNodes, + edges, + nodes, + palette, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/886", + }); + + await drds.toggle(); + await drds.navigateTo({ name: "First DRD" }); + await drds.toggle(); + await palette.dragNewNode({ type: NodeType.DECISION, targetPosition: { x: 400, y: 300 }, thenRenameTo: "A" }); + await palette.dragNewNode({ + type: NodeType.KNOWLEDGE_SOURCE, + targetPosition: { x: 100, y: 300 }, + thenRenameTo: "B", + }); + await palette.dragNewNode({ + type: NodeType.KNOWLEDGE_SOURCE, + targetPosition: { x: 600, y: 300 }, + thenRenameTo: "C", + }); + await nodes.dragNewConnectedEdge({ type: EdgeType.AUTHORITY_REQUIREMENT, from: "B", to: "A" }); + await nodes.dragNewConnectedEdge({ type: EdgeType.AUTHORITY_REQUIREMENT, from: "A", to: "C" }); + + await drds.toggle(); + await drds.navigateTo({ name: "Second DRD" }); + await drds.toggle(); + await drgNodes.toggle(); + await drgNodes.dragNode({ name: "A", targetPosition: { x: 400, y: 300 } }); + await drgNodes.dragNode({ name: "B", targetPosition: { x: 100, y: 300 } }); + await drgNodes.dragNode({ name: "C", targetPosition: { x: 600, y: 300 } }); + await drgNodes.toggle(); + + await edges.addWaypoint({ from: "B", to: "A" }); + await edges.addWaypoint({ from: "A", to: "C" }); + + await nodes.move({ name: "A", targetPosition: { x: 400, y: 200 } }); + + await expect(diagram.get()).toHaveScreenshot("drds-ar-edge-depiction-waypoint.png"); + }); + }); }); }); });