You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by ti...@apache.org on 2023/12/24 07:24:23 UTC
(incubator-kie-tools) branch main updated: kie-issues#577: Build a first version of the new React-based DMN Editor with ~90% feature parity with the current GWT-based one (#2064)
This is an automated email from the ASF dual-hosted git repository.
tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new 665cc86686c kie-issues#577: Build a first version of the new React-based DMN Editor with ~90% feature parity with the current GWT-based one (#2064)
665cc86686c is described below
commit 665cc86686c1d001d75a377371a17b538ee0bb5f
Author: Tiago Bento <15...@users.noreply.github.com>
AuthorDate: Sun Dec 24 02:24:17 2023 -0500
kie-issues#577: Build a first version of the new React-based DMN Editor with ~90% feature parity with the current GWT-based one (#2064)
---
.../src/environments/environment.prod.ts | 19 +
examples/ping-pong-view-angular/src/test.ts | 19 +
package.json | 4 +-
packages/boxed-expression-component/package.json | 4 -
.../src/api/BeeGwtService.ts | 2 +-
.../boxed-expression-component/src/api/BeeTable.ts | 13 +-
.../src/api/ExpressionDefinition.ts | 2 +-
.../BoxedExpressionEditor.tsx | 1 +
.../ContextExpression/ContextExpression.tsx | 41 +-
.../DecisionTableExpression.tsx | 183 ++-
.../ExpressionContainer.tsx | 18 +-
.../ExpressionDefinitionLogicTypeSelector.tsx | 1 +
.../ExpressionDefinitionRoot.tsx | 6 -
.../FunctionExpression/FeelFunctionExpression.tsx | 8 +-
.../FunctionExpression/JavaFunctionExpression.tsx | 7 +-
.../FunctionExpression/PmmlFunctionExpression.tsx | 7 +-
.../InvocationExpression/InvocationExpression.tsx | 30 +-
.../expressions/ListExpression/ListExpression.tsx | 21 +-
.../LiteralExpression/LiteralExpression.tsx | 2 +-
.../RelationExpression/RelationExpression.tsx | 63 +-
.../src/resizing/WidthConstants.ts | 2 +-
.../src/selection/BeeTableSelectionContext.tsx | 11 +
.../src/table/BeeTable/BeeTable.tsx | 18 +-
.../src/table/BeeTable/BeeTableBody.tsx | 4 +-
.../table/BeeTable/BeeTableContextMenuHandler.tsx | 104 +-
.../src/table/BeeTable/BeeTableDefaultCell.tsx | 8 -
.../src/table/BeeTable/BeeTableHeader.tsx | 33 +-
.../src/table/BeeTable/BeeTableTd.tsx | 21 +-
.../src/table/BeeTable/BeeTableTh.tsx | 27 +-
.../src/table/BeeTable/BeeTableThResizable.tsx | 7 +-
.../boxed-context-pre-bureau-risk-category.png | Bin 58329 -> 53988 bytes
.../boxedExpressions/context/boxed-context.png | Bin 18231 -> 14355 bytes
.../decisionTable/decision-table-routing.png | Bin 32059 -> 28984 bytes
.../decisionTable/decision-table.png | Bin 16610 -> 12233 bytes
.../function/boxed-feel-function.png | Bin 14173 -> 10441 bytes
.../boxed-function-affordability-calculation.png | Bin 68326 -> 65425 bytes
.../function/boxed-java-function.png | Bin 19026 -> 15187 bytes
.../function/boxed-pmml-function.png | Bin 21444 -> 17897 bytes
.../function/nested-boxed-function.png | Bin 15057 -> 11830 bytes
.../boxed-invocation-affordability-calculation.png | Bin 43280 -> 39421 bytes
.../invocation/boxed-invocation.png | Bin 15319 -> 11245 bytes
.../boxedExpressions/list/boxed-list-age-group.png | Bin 14003 -> 11231 bytes
.../boxedExpressions/list/boxed-list.png | Bin 10650 -> 7445 bytes
.../literal/boxed-literal-can-drive.png | Bin 10357 -> 7604 bytes
.../boxedExpressions/literal/boxed-literal.png | Bin 8745 -> 5268 bytes
.../boxedExpressions/relation/relation-people.png | Bin 23131 -> 20434 bytes
.../boxedExpressions/relation/relation.png | Bin 11769 -> 7893 bytes
.../emptyExpression/empty-boxed-expression.png | Bin 6814 -> 2620 bytes
.../useCases/application-risk-score-expression.png | Bin 70545 -> 66129 bytes
...ecision-service-bureau-call-type-expression.png | Bin 23743 -> 19548 bytes
...egy-decision-service-eligibility-expression.png | Bin 30397 -> 26854 bytes
...service-pre-bureau-affordability-expression.png | Bin 46110 -> 41442 bytes
...service-pre-bureau-risk-category-expression.png | Bin 56724 -> 52122 bytes
...rategy-decision-service-strategy-expression.png | Bin 24907 -> 21184 bytes
.../useCases/can-drive-expression.png | Bin 29695 -> 25881 bytes
.../useCases/employees-expression.png | Bin 35517 -> 32263 bytes
.../useCases/find-by-employees-expression.png | Bin 23819 -> 19995 bytes
.../find-employees-by-knowledge-expression.png | Bin 46692 -> 41500 bytes
...nction-affordability-calculation-expression.png | Bin 66674 -> 62275 bytes
...function-installment-calculation-expression.png | Bin 43036 -> 39314 bytes
.../required-monthly-installment-expression.png | Bin 33060 -> 27868 bytes
...ervice-post-bureau-affordability-expression.png | Bin 46524 -> 41896 bytes
...ervice-post-bureau-risk-category-expression.png | Bin 86904 -> 81667 bytes
...routing-decision-service-routing-expression.png | Bin 48407 -> 45325 bytes
.../boxed-context-pre-bureau-risk-category.png | Bin 58329 -> 54037 bytes
.../boxedExpressions/context/boxed-context.png | Bin 18231 -> 14355 bytes
.../decisionTable/decision-table-routing.png | Bin 32059 -> 28984 bytes
.../decisionTable/decision-table.png | Bin 16610 -> 12233 bytes
.../function/boxed-feel-function.png | Bin 14173 -> 10441 bytes
.../boxed-function-affordability-calculation.png | Bin 68326 -> 65425 bytes
.../function/boxed-java-function.png | Bin 19026 -> 15187 bytes
.../function/boxed-pmml-function.png | Bin 21444 -> 17897 bytes
.../function/nested-boxed-function.png | Bin 15057 -> 11824 bytes
.../boxed-invocation-affordability-calculation.png | Bin 43280 -> 39421 bytes
.../invocation/boxed-invocation.png | Bin 15319 -> 11245 bytes
.../boxedExpressions/list/boxed-list-age-group.png | Bin 14003 -> 11231 bytes
.../chromium/boxedExpressions/list/boxed-list.png | Bin 10650 -> 7445 bytes
.../literal/boxed-literal-can-drive.png | Bin 10284 -> 7604 bytes
.../boxedExpressions/literal/boxed-literal.png | Bin 8745 -> 5268 bytes
.../boxedExpressions/relation/relation-people.png | Bin 23131 -> 20434 bytes
.../boxedExpressions/relation/relation.png | Bin 11769 -> 7893 bytes
.../emptyExpression/empty-boxed-expression.png | Bin 6814 -> 2620 bytes
.../useCases/application-risk-score-expression.png | Bin 70545 -> 66129 bytes
...ecision-service-bureau-call-type-expression.png | Bin 23743 -> 19548 bytes
...egy-decision-service-eligibility-expression.png | Bin 30397 -> 26854 bytes
...service-pre-bureau-affordability-expression.png | Bin 46110 -> 41442 bytes
...service-pre-bureau-risk-category-expression.png | Bin 56724 -> 52122 bytes
...rategy-decision-service-strategy-expression.png | Bin 24907 -> 21184 bytes
.../chromium/useCases/can-drive-expression.png | Bin 29695 -> 25881 bytes
.../chromium/useCases/employees-expression.png | Bin 35517 -> 32263 bytes
.../useCases/find-by-employees-expression.png | Bin 23819 -> 19995 bytes
.../find-employees-by-knowledge-expression.png | Bin 46692 -> 41500 bytes
...nction-affordability-calculation-expression.png | Bin 66674 -> 62275 bytes
...function-installment-calculation-expression.png | Bin 43036 -> 39314 bytes
.../required-monthly-installment-expression.png | Bin 33060 -> 27868 bytes
...ervice-post-bureau-affordability-expression.png | Bin 46524 -> 41896 bytes
...ervice-post-bureau-risk-category-expression.png | Bin 86904 -> 81667 bytes
...routing-decision-service-routing-expression.png | Bin 48407 -> 45325 bytes
.../boxed-context-pre-bureau-risk-category.png | Bin 45924 -> 43264 bytes
.../boxedExpressions/context/boxed-context.png | Bin 14639 -> 11583 bytes
.../decisionTable/decision-table-routing.png | Bin 25351 -> 22102 bytes
.../decisionTable/decision-table.png | Bin 13385 -> 9584 bytes
.../function/boxed-feel-function.png | Bin 11349 -> 8238 bytes
.../boxed-function-affordability-calculation.png | Bin 48343 -> 45235 bytes
.../function/boxed-java-function.png | Bin 15397 -> 12257 bytes
.../function/boxed-pmml-function.png | Bin 17390 -> 14485 bytes
.../function/nested-boxed-function.png | Bin 12179 -> 9517 bytes
.../boxed-invocation-affordability-calculation.png | Bin 34159 -> 31077 bytes
.../invocation/boxed-invocation.png | Bin 12348 -> 9116 bytes
.../boxedExpressions/list/boxed-list-age-group.png | Bin 11983 -> 9672 bytes
.../webkit/boxedExpressions/list/boxed-list.png | Bin 8684 -> 6023 bytes
.../literal/boxed-literal-can-drive.png | Bin 8697 -> 6204 bytes
.../boxedExpressions/literal/boxed-literal.png | Bin 7057 -> 4170 bytes
.../boxedExpressions/relation/relation-people.png | Bin 18565 -> 16223 bytes
.../webkit/boxedExpressions/relation/relation.png | Bin 9860 -> 5126 bytes
.../emptyExpression/empty-boxed-expression.png | Bin 5499 -> 2159 bytes
.../useCases/application-risk-score-expression.png | Bin 55550 -> 52213 bytes
...ecision-service-bureau-call-type-expression.png | Bin 19590 -> 15919 bytes
...egy-decision-service-eligibility-expression.png | Bin 22717 -> 19774 bytes
...service-pre-bureau-affordability-expression.png | Bin 35698 -> 32392 bytes
...service-pre-bureau-risk-category-expression.png | Bin 45564 -> 41834 bytes
...rategy-decision-service-strategy-expression.png | Bin 19686 -> 16231 bytes
.../webkit/useCases/can-drive-expression.png | Bin 25112 -> 21679 bytes
.../webkit/useCases/employees-expression.png | Bin 27124 -> 24240 bytes
.../useCases/find-by-employees-expression.png | Bin 19470 -> 16468 bytes
.../find-employees-by-knowledge-expression.png | Bin 34213 -> 30533 bytes
...nction-affordability-calculation-expression.png | Bin 47943 -> 44488 bytes
...function-installment-calculation-expression.png | Bin 32440 -> 29505 bytes
.../required-monthly-installment-expression.png | Bin 25705 -> 22022 bytes
...ervice-post-bureau-affordability-expression.png | Bin 36109 -> 32568 bytes
...ervice-post-bureau-risk-category-expression.png | Bin 69555 -> 65792 bytes
...routing-decision-service-routing-expression.png | Bin 37434 -> 34941 bytes
.../boxedExpressions/boxedExpressionHeader.spec.ts | 5 -
.../boxedExpressionHeaderMenu.spec.ts | 2 -
.../context/contextExpression.spec.ts | 1 -
.../decisionTable/decisionTableExpression.spec.ts | 1 -
.../function/functionExpression.spec.ts | 3 -
.../invocation/invocationExpression.spec.ts | 1 -
.../boxedExpressions/list/listExpression.spec.ts | 1 -
.../literal/literalExpression.spec.ts | 1 -
.../relation/relationExpression.spec.ts | 1 -
.../tests/e2e/features/resizing/resizing.spec.ts | 39 +-
.../misc/emptyExpression/emptyExpression.spec.ts | 1 -
packages/bpmn-marshaller/src/index.ts | 2 +-
packages/bpmn-vscode-extension/webpack.config.js | 8 +-
.../src/framework/github-repo/GitHubRepoPage.ts | 19 +
.../app/components/common/KogitoEditorIframe.tsx | 1 +
packages/dashbuilder-component-map/src/Map.tsx | 19 +
.../dashbuilder-component-map/src/MapComponent.tsx | 19 +
.../src/charts/PropsValidation.tsx | 19 +
.../src/monaco/augmentation/widgets/index.tsx | 19 +
packages/dashbuilder-editor/tests/jest.setup.ts | 3 -
.../code-completions/dashbuilder-completion.ts | 19 +
.../src/assets/code-completions/index.ts | 19 +
packages/dashbuilder-viewer/tests/jest.setup.ts | 3 -
.../src/main/resources/application.properties | 1 +
packages/dmn-editor-envelope/README.md | 3 +
.../env/index.js} | 10 +-
.../jest.config.js} | 25 +-
.../package.json | 41 +-
.../dmn-editor-envelope/src/DmnEditorFactory.tsx | 171 +++
packages/dmn-editor-envelope/src/DmnEditorRoot.tsx | 415 +++++
packages/dmn-editor-envelope/tsconfig.json | 7 +
packages/dmn-editor/LICENSE | 201 +++
.../dev-webapp/src/AvailableModelsToInclude.ts | 73 +
.../dev-webapp/src/DefaultDmn.ts} | 514 ++++---
packages/dmn-editor/dev-webapp/src/DevWebApp.tsx | 224 +++
.../dmn-editor/dev-webapp/src/ExternalModels.ts | 209 +++
.../dev-webapp/src/index.css} | 18 +-
.../dev-webapp/src/index.tsx} | 9 +-
packages/dmn-editor/dev-webapp/static/dmn-logo.jpg | Bin 0 -> 21167 bytes
packages/dmn-editor/dev-webapp/static/favicon.ico | Bin 0 -> 9260 bytes
packages/dmn-editor/dev-webapp/static/index.html | 40 +
packages/dmn-editor/dev-webapp/tsconfig.json | 7 +
.../dev-webapp}/webpack.config.js | 58 +-
.../jest.setup.ts => dmn-editor/env/index.js} | 16 +-
.../BeeGwtService.ts => dmn-editor/jest.config.js} | 28 +-
.../package.json | 74 +-
packages/dmn-editor/src/Dmn15Spec.ts | 104 ++
packages/dmn-editor/src/DmnEditor.css | 1022 +++++++++++++
packages/dmn-editor/src/DmnEditor.tsx | 348 +++++
packages/dmn-editor/src/DmnEditorContext.tsx | 78 +
packages/dmn-editor/src/DmnEditorErrorFallback.tsx | 94 ++
.../src/boxedExpressions/BoxedExpression.tsx | 501 ++++++
.../dmn-editor/src/boxedExpressions/beeToDmn.tsx | 248 +++
.../dmn-editor/src/boxedExpressions/dmnToBee.tsx | 257 ++++
.../boxedExpressions/getDefaultColumnWidth.tsx} | 24 +-
.../getDefaultExpressionDefinitionByLogicType.tsx | 311 ++++
packages/dmn-editor/src/clipboard/Clipboard.ts | 246 +++
.../src/dataTypes/BuiltInFeelTypes.ts} | 12 +-
.../dataTypes/ConstraintComponents/Constraint.css | 17 +
.../dataTypes/ConstraintComponents/Constraint.ts} | 19 +-
.../ConstraintComponents/ConstraintDate.css | 23 +
.../ConstraintComponents/ConstraintDate.tsx} | 28 +-
.../ConstraintComponents/ConstraintDateTime.css | 14 +
.../ConstraintComponents/ConstraintDateTime.tsx | 67 +
.../ConstraintDateTimeDuration.tsx | 211 +++
.../ConstraintComponents/ConstraintTime.css | 33 +
.../ConstraintComponents/ConstraintTime.tsx | 158 ++
.../ConstraintYearsMonthsDuration.tsx | 133 ++
packages/dmn-editor/src/dataTypes/Constraints.tsx | 517 +++++++
.../dmn-editor/src/dataTypes/ConstraintsEnum.tsx | 255 +++
.../src/dataTypes/ConstraintsExpression.css | 5 +
.../src/dataTypes/ConstraintsExpression.tsx | 108 ++
.../dmn-editor/src/dataTypes/ConstraintsRange.tsx | 346 +++++
packages/dmn-editor/src/dataTypes/DataTypeName.tsx | 142 ++
.../dmn-editor/src/dataTypes/DataTypePanel.tsx | 368 +++++
packages/dmn-editor/src/dataTypes/DataTypeSpec.ts | 299 ++++
packages/dmn-editor/src/dataTypes/DataTypes.tsx | 295 ++++
.../src/dataTypes/DataTypesEmptyState.tsx | 63 +
.../src/dataTypes/ItemComponentsTable.tsx | 621 ++++++++
packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx | 111 ++
.../dmn-editor/src/dataTypes/TypeRefSelector.tsx | 176 +++
.../dmn-editor/src/dataTypes/resolveTypeRef.ts | 90 ++
.../dmn-editor/src/dataTypes/useResolvedTypeRef.ts | 40 +
packages/dmn-editor/src/diagram/Diagram.tsx | 1617 ++++++++++++++++++++
.../src/diagram/DiagramContainerContext.tsx} | 42 +-
.../dmn-editor/src/diagram/DmnVersionLabel.tsx | 61 +
.../dmn-editor/src/diagram/DrdSelectorPanel.tsx | 80 +
packages/dmn-editor/src/diagram/DrgNodesPanel.tsx | 114 ++
packages/dmn-editor/src/diagram/Palette.tsx | 261 ++++
packages/dmn-editor/src/diagram/SnapGrid.ts | 81 +
.../src/diagram/connections/ConnectionLine.tsx | 153 ++
.../diagram/connections/PositionalNodeHandles.tsx | 79 +
.../src/diagram/connections/graphStructure.ts | 157 ++
.../src/diagram/connections/isValidConnection.ts | 60 +
.../src/diagram/connections/isValidContainment.ts} | 26 +-
.../src/diagram/edges/AutoPositionedEdgeMarker.ts} | 9 +-
.../dmn-editor/src/diagram/edges/EdgeMarkers.tsx | 77 +
.../src/diagram/edges/EdgeTypes.ts} | 10 +-
packages/dmn-editor/src/diagram/edges/Edges.tsx | 325 ++++
.../dmn-editor/src/diagram/edges/Waypoints.tsx | 128 ++
.../edges/getSnappedMultiPointAnchoredEdgePath.tsx | 147 ++
.../useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts | 110 ++
.../src/diagram/edges/useKieEdgePath.tsx | 54 +
.../diagram/edges/usePotentialWaypointControls.ts | 189 +++
packages/dmn-editor/src/diagram/graph/graph.ts | 114 ++
packages/dmn-editor/src/diagram/maths/DmnMaths.ts | 319 ++++
packages/dmn-editor/src/diagram/maths/Maths.ts | 128 ++
.../src/diagram/nodes/DataTypeNodePanel.tsx | 78 +
.../dmn-editor/src/diagram/nodes/DefaultSizes.ts | 164 ++
.../src/diagram/nodes/EditExpressionNodePanel.tsx} | 33 +-
.../src/diagram/nodes/EditableNodeLabel.css | 48 +
.../src/diagram/nodes/EditableNodeLabel.tsx | 274 ++++
.../src/diagram/nodes/InfoNodePanel.tsx} | 35 +-
packages/dmn-editor/src/diagram/nodes/NodeStyle.ts | 142 ++
packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx | 378 +++++
.../src/diagram/nodes/NodeTypes.tsx} | 14 +-
packages/dmn-editor/src/diagram/nodes/Nodes.tsx | 1201 +++++++++++++++
.../src/diagram/nodes/OutgoingStuffNodePanel.tsx | 143 ++
.../src/diagram/useIsHovered.tsx} | 43 +-
packages/dmn-editor/src/draggable/Draggable.css | 34 +
packages/dmn-editor/src/draggable/Draggable.tsx | 278 ++++
.../src/externalNodes/DmnObjectListItem.tsx | 84 +
.../src/externalNodes/ExternalNodesPanel.tsx | 196 +++
.../dmn-editor/src/feel/InlineFeelNameInput.tsx | 154 ++
packages/dmn-editor/src/feel/buildFeelQName.ts | 100 ++
.../src/feel/parseFeelQName.ts} | 31 +-
.../src/focus/useFocusableElement.ts} | 35 +-
packages/dmn-editor/src/icons/Icons.tsx | 129 ++
.../src/idRandomizer/dmnIdRandomizer.tsx | 56 +
.../DmnEditorDependenciesContext.tsx | 45 +
.../src/includedModels/ExternalModelLabel.tsx | 49 +
.../src/includedModels/IncludedModels.tsx | 643 ++++++++
.../src/includedModels/importNamespaces.ts} | 19 +-
.../jest.setup.ts => dmn-editor/src/kie/kie.ts} | 5 +-
.../src/mutations/NodeNature.ts} | 25 +-
.../dmn-editor/src/mutations/addConnectedNode.ts | 228 +++
.../src/mutations/addDecisionToDecisionService.ts | 107 ++
packages/dmn-editor/src/mutations/addEdge.ts | 225 +++
.../dmn-editor/src/mutations/addEdgeWaypoint.ts | 50 +
packages/dmn-editor/src/mutations/addImport.ts | 56 +
packages/dmn-editor/src/mutations/addOrGetDrd.ts | 50 +
packages/dmn-editor/src/mutations/addShape.ts | 49 +
.../dmn-editor/src/mutations/addStandaloneNode.ts | 140 ++
.../src/mutations/addTopLevelItemDefinition.ts} | 24 +-
.../mutations/deleteDecisionFromDecisionService.ts | 52 +
packages/dmn-editor/src/mutations/deleteEdge.ts | 78 +
.../dmn-editor/src/mutations/deleteEdgeWaypoint.ts | 48 +
.../src/mutations/deleteImport.ts} | 21 +-
packages/dmn-editor/src/mutations/deleteNode.ts | 81 +
packages/dmn-editor/src/mutations/renameImport.ts | 123 ++
.../src/mutations/renameItemDefinition.ts | 92 ++
packages/dmn-editor/src/mutations/renameNode.ts | 71 +
...pulateInputDataAndDecisionsOnDecisionService.ts | 91 ++
.../src/mutations/repositionEdgeWaypoint.ts | 50 +
.../dmn-editor/src/mutations/repositionNode.ts | 147 ++
packages/dmn-editor/src/mutations/resizeNode.ts | 151 ++
.../mutations/updateDecisionServiceDividerLine.ts | 100 ++
.../dmn-editor/src/mutations/updateExpression.ts | 91 ++
.../dmn-editor/src/overlaysPanel/OverlaysPanel.tsx | 154 ++
packages/dmn-editor/src/pmml/pmml.ts | 59 +
.../src/propertiesPanel/BeePropertiesPanel.tsx | 74 +
.../src/propertiesPanel/BkmProperties.tsx | 129 ++
.../dmn-editor/src/propertiesPanel/ColorPicker.tsx | 69 +
.../src/propertiesPanel/DecisionProperties.tsx | 180 +++
.../propertiesPanel/DecisionServiceProperties.tsx | 249 +++
.../src/propertiesPanel/DiagramPropertiesPanel.css | 4 +
.../src/propertiesPanel/DiagramPropertiesPanel.tsx | 46 +
.../DocumentationLinksFormGroup.css | 60 +
.../DocumentationLinksFormGroup.tsx | 430 ++++++
.../dmn-editor/src/propertiesPanel/FontOptions.css | 54 +
.../dmn-editor/src/propertiesPanel/FontOptions.tsx | 385 +++++
.../propertiesPanel/GlobalDiagramProperties.tsx | 214 +++
.../src/propertiesPanel/GroupProperties.tsx | 79 +
.../src/propertiesPanel/InputDataProperties.tsx | 128 ++
.../propertiesPanel/KnowledgeSourceProperties.tsx | 141 ++
.../src/propertiesPanel/MultipleNodeProperties.tsx | 83 +
.../src/propertiesPanel/PropertiesPanelHeader.css | 52 +
.../src/propertiesPanel/PropertiesPanelHeader.tsx | 75 +
.../src/propertiesPanel/ShapeOptions.css | 4 +
.../src/propertiesPanel/ShapeOptions.tsx | 413 +++++
.../src/propertiesPanel/SingleNodeProperties.css | 3 +
.../src/propertiesPanel/SingleNodeProperties.tsx | 193 +++
.../propertiesPanel/TextAnnotationProperties.tsx | 102 ++
.../src/propertiesPanel/UnknownProperties.tsx | 96 ++
.../src/responsiveness/useInViewSelect.ts} | 34 +-
packages/dmn-editor/src/spec.txt | 34 +
packages/dmn-editor/src/store/DerivedStore.tsx | 311 ++++
packages/dmn-editor/src/store/Store.ts | 311 ++++
packages/dmn-editor/src/store/useDiagramData.tsx | 470 ++++++
.../src/tsExt/tsExt.ts} | 5 +-
.../src/useEffectAfterFirstRender.ts} | 15 +-
.../src/xml/xmlHrefs.ts} | 28 +-
.../src/xml/xmlNamespaceDeclarations.ts} | 35 +-
packages/dmn-editor/tsconfig.json | 8 +
.../dmn-feel-antlr4-parser/src/FeelVariables.ts | 17 +-
.../src/parser/FeelVariable.ts | 29 +-
.../src/parser/FeelVariablesParser.ts | 17 +-
.../dmn-feel-antlr4-parser/src/parser/Variable.ts | 6 +
.../src/parser/VariableOccurrence.ts | 74 +
.../src/parser/VariablesRepository.ts | 126 +-
.../grammar/{Scopes.ts => FunctionSymbol.ts} | 25 +-
.../src/parser/grammar/ParserHelper.ts | 48 +-
.../src/parser/grammar/Scopes.ts | 6 +
.../src/parser/grammar/VariableSymbol.ts | 10 +-
packages/dmn-language-service/package.json | 1 +
.../dmn-language-service/src/DmnLanguageService.ts | 65 +-
packages/dmn-language-service/tests/index.test.ts | 86 +-
packages/dmn-marshaller/src/index.ts | 596 ++++++--
packages/dmn-marshaller/src/kie-extensions.ts | 237 ++-
.../dmn-marshaller/src/schemas/kie-1_0/KIE.xsd | 15 +-
packages/dmn-marshaller/tests/idempotency.test.ts | 4 +-
.../dmn-marshaller/tests/kie-extensions.test.ts | 4 +-
packages/dmn-marshaller/tests/migrations.test.ts | 52 +
packages/dmn-marshaller/tests/typeSafety.test.ts | 2 +-
packages/dmn-vscode-extension/README.md | 4 +-
packages/dmn-vscode-extension/package.json | 41 +-
.../src/extension/extension.ts | 17 +
.../src/webview/NewDmnEditorEnvelopeApp.ts} | 12 +-
packages/dmn-vscode-extension/webpack.config.js | 19 +-
packages/editor/src/api/KogitoEditorEnvelopeApi.ts | 3 +
.../src/embedded/embedded/EmbeddedEditor.tsx | 2 +
.../embedded/EmbeddedEditorChannelApiImpl.ts | 2 +-
packages/eslint/.eslintrc.js | 4 +-
packages/feel-input-component/src/FeelInput.tsx | 65 +-
.../src/bpmn/envelope/BpmnEditorFactory.ts | 2 +-
.../helpers/bpmn/ImplementationExecutionHelper.ts | 19 +
.../e2e-tests/cypress.config.ts | 19 +
packages/kie-sandbox-fs/src/DefaultBackend.d.ts | 19 +
packages/kie-sandbox-fs/src/DexieBackend.d.ts | 19 +
packages/kie-sandbox-fs/src/index.d.ts | 19 +
packages/online-editor/build/defaultEnvJson.ts | 4 +-
packages/online-editor/package.json | 2 +
packages/online-editor/src/App.tsx | 2 +-
.../src/accounts/git/ConnectToGitSection.tsx | 2 +-
.../src/authSessions/AuthSessionsContext.tsx | 2 +-
.../src/dmnRunner/DmnRunnerContextProvider.tsx | 8 +-
.../src/dmnRunner/DmnRunnerDrawerPanelContent.tsx | 6 +-
packages/online-editor/src/editor/EditorPage.tsx | 39 +-
.../src/editor/Toolbar/EditorToolbar.tsx | 77 +-
.../src/editor/Toolbar/FileSwitcher.tsx | 2 +-
.../GitIntegration/CreateGistOrSnippetModal.tsx | 2 +-
.../GitIntegration/CreateGitRepositoryModal.tsx | 2 +-
.../GitIntegration/GitIntegrationAlerts.tsx | 2 +-
.../GitIntegration/LoadOrganizationsSelect.tsx | 2 +-
.../GitIntegration/PushToGitAlertActionLinks.tsx | 2 +-
.../src/editor/Toolbar/Share/GitDropdownGroup.tsx | 2 +-
.../src/editor/Toolbar/SyncDropdownMenu.tsx | 2 +-
.../src/editor/Toolbar/Workspace/Hooks.tsx | 2 +-
packages/online-editor/src/editor/Validation.tsx | 12 +-
.../src/envelope/NewDmnEditorEnvelopeApp.ts} | 10 +-
.../hooks/EditorEnvelopeLocatorContext.tsx | 20 +-
.../extendedServices/ExtendedServicesContext.tsx | 3 +-
.../ExtendedServicesContextProvider.tsx | 81 +-
.../src/extendedServices/ExtendedServicesModal.tsx | 11 +-
.../online-editor/src/filesList/FileDataList.tsx | 2 +-
packages/online-editor/src/home/HomePage.tsx | 8 +
.../src/importFromUrl/fetchSingleFileContent.ts | 19 +
.../src/settings/CorsProxySettingsTab.tsx | 73 +
.../src/settings/EditorsSettingsTab.tsx | 72 +
.../src/settings/ExtendedServicesSettingsTab.tsx | 15 +-
.../online-editor/src/settings/SettingsButton.tsx | 31 +-
.../online-editor/src/settings/SettingsContext.tsx | 267 ++--
.../src/settings/SettingsModalBody.tsx | 27 +-
.../components/GitStatusIndicatorActions.tsx | 2 +-
.../src/workspace/components/WorkspaceLabel.tsx | 2 +-
.../components/WorkspaceStatusIndicator.tsx | 2 +-
.../static/envelope/new-dmn-editor-envelope.html | 45 +
packages/online-editor/static/resources/style.css | 9 +-
packages/online-editor/static/samples/Sample.dmn | 28 +-
.../Google-Chrome/createFiles/new-file-dmn.png | Bin 50413 -> 71091 bytes
.../Google-Chrome/createFiles/new-file-pmml.png | Bin 69245 -> 69595 bytes
.../Google-Chrome/createFiles/sample-bpmn.png | Bin 70301 -> 70134 bytes
.../Google-Chrome/createFiles/sample-dmn.png | Bin 79458 -> 83422 bytes
.../Google-Chrome/createFiles/sample-pmml.png | Bin 73452 -> 75012 bytes
.../chromium/createFiles/new-file-dmn.png | Bin 50413 -> 71135 bytes
.../chromium/createFiles/new-file-pmml.png | Bin 69245 -> 69595 bytes
.../chromium/createFiles/sample-bpmn.png | Bin 70328 -> 70134 bytes
.../chromium/createFiles/sample-dmn.png | Bin 79489 -> 83523 bytes
.../chromium/createFiles/sample-pmml.png | Bin 73452 -> 75012 bytes
.../webkit/createFiles/new-file-dmn.png | Bin 42285 -> 66954 bytes
.../webkit/createFiles/new-file-pmml.png | Bin 63793 -> 64240 bytes
.../webkit/createFiles/sample-bpmn.png | Bin 57728 -> 57863 bytes
.../webkit/createFiles/sample-dmn.png | Bin 73974 -> 75078 bytes
.../webkit/createFiles/sample-pmml.png | Bin 65506 -> 66762 bytes
.../tests/e2e/createFiles/newFile.spec.ts | 3 +-
.../tests/e2e/createFiles/samples.spec.ts | 3 +-
.../online-editor/tests/e2e/upload/upload.spec.ts | 2 +-
packages/online-editor/webpack.config.ts | 5 +
packages/pmml-editor/e2e-tests/cypress.config.ts | 19 +
packages/pmml-editor/package.json | 4 +-
packages/pmml-editor/src/editor/PMMLEditor.tsx | 5 +-
.../src/editor/history/HistoryProvider.ts | 2 +-
packages/pmml-editor/tests/jest.setup.ts | 5 +-
packages/pmml-vscode-extension/webpack.config.js | 7 +
.../src/useImperativePromiseHandler.ts} | 31 +-
.../scesim-editor/src/table/TestScenarioTable.tsx | 9 +-
packages/scesim-marshaller/src/index.ts | 2 +-
.../e2e-tests/cypress.config.ts | 19 +
.../client/core/image/ImageElementProxy.java | 25 +-
.../tests/mockSchema.ts | 19 +
.../textEditor/augmentation/codeLenses/index.ts | 19 +
.../textEditor/augmentation/commands/index.tsx | 19 +
.../textEditor/augmentation/widgets/index.tsx | 19 +
.../webpack.config.js | 7 +
packages/stunner-editors-dmn-loader/src/index.tsx | 2 +-
.../selenium/locator/EditorXPathLocator.java | 2 +-
packages/switch-expression-ts/LICENSE | 201 +++
packages/switch-expression-ts/README.md | 3 +
.../env/index.js} | 10 +-
packages/switch-expression-ts/jest.config.js | 34 +
.../package.json | 22 +-
.../src/index.ts} | 5 +-
.../src}/switchExpression.ts | 2 +-
.../tests}/switchExpression.test.ts | 11 +-
packages/switch-expression-ts/tsconfig.json | 7 +
packages/tsconfig/tsconfig.json | 2 +-
packages/uniforms-patternfly/src/SelectField.tsx | 19 +
packages/vscode-extension-kie-ba-bundle/README.md | 2 +-
packages/vscode-extension-kogito-bundle/README.md | 2 +-
packages/vscode-extension/__mocks__/vscode.ts | 19 +
packages/vscode-extension/package.json | 1 +
packages/vscode-extension/setupTests.ts | 19 +
.../src/DefaultVsCodeKieEditorChannelApiImpl.ts | 20 +-
.../src/VsCodeKieEditorController.ts | 4 +
.../src/VsCodeKieEditorControllerFactory.ts | 10 +-
.../src/VsCodeNodeResourceContentServiceImpl.ts | 90 --
...VsCodeResourceContentServiceForDanglingFiles.ts | 105 ++
...> VsCodeResourceContentServiceForWorkspaces.ts} | 50 +-
.../VsCodeResourceContentServiceIsomorphicGitFs.ts | 70 +
...ResourceContentServiceForDanglingFiles.test.ts} | 23 +-
.../index.d.ts | 19 +
.../src/vscode/JavaCodeCompletionConstants.ts | 19 +
.../src/services/FsUnloadManager.ts | 23 +-
packages/xml-parser-ts-codegen/src/codegen.ts | 57 +-
.../ts-gen/meta.ts | 70 +-
packages/xml-parser-ts-codegen/src/types.d.ts | 1 +
packages/xml-parser-ts/src/idRandomizer.ts | 159 ++
packages/xml-parser-ts/src/index.ts | 123 +-
.../BeeGwtService.ts => xml-parser-ts/src/ns.ts} | 29 +-
.../src/qNames.ts} | 33 +-
.../assets/code-completions/decision-completion.ts | 19 +
.../code-completions/empty-decision-completion.ts | 19 +
.../src/assets/code-completions/index.ts | 19 +
packages/yard-vscode-extension/webpack.config.js | 7 +
patches/immer@10.0.3.patch | 13 +
patches/zustand@4.4.2.patch | 13 +
pnpm-lock.yaml | 1058 ++++++++++---
repo/graph.dot | 18 +-
repo/graph.json | 17 +
481 files changed, 29413 insertions(+), 1896 deletions(-)
diff --git a/examples/ping-pong-view-angular/src/environments/environment.prod.ts b/examples/ping-pong-view-angular/src/environments/environment.prod.ts
index c9669790be1..ca84103ad66 100644
--- a/examples/ping-pong-view-angular/src/environments/environment.prod.ts
+++ b/examples/ping-pong-view-angular/src/environments/environment.prod.ts
@@ -1,3 +1,22 @@
+/*
+ * 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.
+ */
+
export const environment = {
production: true,
};
diff --git a/examples/ping-pong-view-angular/src/test.ts b/examples/ping-pong-view-angular/src/test.ts
index f693e620c17..6b3cfb58356 100644
--- a/examples/ping-pong-view-angular/src/test.ts
+++ b/examples/ping-pong-view-angular/src/test.ts
@@ -1,3 +1,22 @@
+/*
+ * 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.
+ */
+
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import "zone.js/testing";
diff --git a/package.json b/package.json
index 998d56d280a..41f7dc642e9 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,9 @@
}
},
"patchedDependencies": {
- "selenium-webdriver@4.15.0": "patches/selenium-webdriver@4.15.0.patch"
+ "immer@10.0.3": "patches/immer@10.0.3.patch",
+ "selenium-webdriver@4.15.0": "patches/selenium-webdriver@4.15.0.patch",
+ "zustand@4.4.2": "patches/zustand@4.4.2.patch"
}
},
"kieTools": {
diff --git a/packages/boxed-expression-component/package.json b/packages/boxed-expression-component/package.json
index 8053019d6be..03e63d810d1 100644
--- a/packages/boxed-expression-component/package.json
+++ b/packages/boxed-expression-component/package.json
@@ -30,10 +30,8 @@
"@patternfly/react-styles": "^4.92.6",
"@patternfly/react-table": "^4.112.39",
"lodash": "^4.17.21",
- "papaparse": "^5.3.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-id-generator": "^3.0.1",
"react-resizable": "^1.11.0",
"react-table": "^7.6.2",
"uuid": "^8.3.2"
@@ -58,7 +56,6 @@
"@storybook/react": "^7.3.2",
"@storybook/react-webpack5": "^7.3.2",
"@types/lodash": "^4.14.168",
- "@types/papaparse": "^5.3.2",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
"@types/react-resizable": "^1.7.2",
@@ -67,7 +64,6 @@
"copy-webpack-plugin": "^11.0.0",
"copyfiles": "^2.4.1",
"file-loader": "^6.2.0",
- "gh-pages": "^3.2.3",
"jest": "^26.6.3",
"jest-junit": "^14.0.0",
"jest-when": "^3.5.0",
diff --git a/packages/boxed-expression-component/src/api/BeeGwtService.ts b/packages/boxed-expression-component/src/api/BeeGwtService.ts
index efd0df23e14..1f262888d1b 100644
--- a/packages/boxed-expression-component/src/api/BeeGwtService.ts
+++ b/packages/boxed-expression-component/src/api/BeeGwtService.ts
@@ -23,7 +23,7 @@ import { ExpressionDefinition } from "./ExpressionDefinition";
* This interface defines all the API methods which BoxedExpressionEditor component can use to dialog with GWT Layer
*/
export interface BeeGwtService {
- getDefaultExpressionDefinition(logicType: string, dataType: string): ExpressionDefinition;
+ getDefaultExpressionDefinition(logicType: string, typeRef: string, isRoot?: boolean): ExpressionDefinition;
openDataTypePage: () => void; // Just open the data types tab
selectObject: (uuid?: string) => void; // Changes the Properties panel
}
diff --git a/packages/boxed-expression-component/src/api/BeeTable.ts b/packages/boxed-expression-component/src/api/BeeTable.ts
index 4be05fd9692..1a562eb3d52 100644
--- a/packages/boxed-expression-component/src/api/BeeTable.ts
+++ b/packages/boxed-expression-component/src/api/BeeTable.ts
@@ -77,7 +77,13 @@ export interface BeeTableProps<R extends object> {
onRowDuplicated?: (args: { rowIndex: number }) => void;
onRowReset?: (args: { rowIndex: number }) => void;
onRowDeleted?: (args: { rowIndex: number }) => void;
- onColumnAdded?: (args: { beforeIndex: number; currentIndex?: number; groupType: string | undefined }) => void;
+ onColumnAdded?: (args: {
+ beforeIndex: number;
+ currentIndex?: number;
+ groupType: string | undefined;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => void;
onColumnDeleted?: (args: { columnIndex: number; groupType: string | undefined }) => void;
shouldRenderRowIndexColumn: boolean;
shouldShowRowsInlineControls: boolean;
@@ -135,3 +141,8 @@ export type BeeTableContextMenuAllowedOperationsConditions = {
column: ReactTable.ColumnInstance<any> | undefined;
columns: ReactTable.ColumnInstance<any>[] | undefined;
};
+
+export enum InsertRowColumnsDirection {
+ AboveOrRight,
+ BelowOrLeft,
+}
diff --git a/packages/boxed-expression-component/src/api/ExpressionDefinition.ts b/packages/boxed-expression-component/src/api/ExpressionDefinition.ts
index 6c545280a09..79126d004ae 100644
--- a/packages/boxed-expression-component/src/api/ExpressionDefinition.ts
+++ b/packages/boxed-expression-component/src/api/ExpressionDefinition.ts
@@ -135,8 +135,8 @@ export enum DecisionTableExpressionDefinitionHitPolicy {
Unique = "UNIQUE",
First = "FIRST",
Priority = "PRIORITY",
- Any = "ANY",
Collect = "COLLECT",
+ Any = "ANY",
RuleOrder = "RULE ORDER",
OutputOrder = "OUTPUT ORDER",
}
diff --git a/packages/boxed-expression-component/src/expressions/BoxedExpressionEditor/BoxedExpressionEditor.tsx b/packages/boxed-expression-component/src/expressions/BoxedExpressionEditor/BoxedExpressionEditor.tsx
index 70ddccd0bd4..4162357b609 100644
--- a/packages/boxed-expression-component/src/expressions/BoxedExpressionEditor/BoxedExpressionEditor.tsx
+++ b/packages/boxed-expression-component/src/expressions/BoxedExpressionEditor/BoxedExpressionEditor.tsx
@@ -28,6 +28,7 @@ import {
} from "../../i18n";
import { ExpressionDefinitionRoot } from "../ExpressionDefinitionRoot";
import "./base-no-reset-wrapped.css";
+import "../../@types/react-table";
import { BoxedExpressionEditorContextProvider } from "./BoxedExpressionEditorContext";
import { FeelVariables } from "@kie-tools/dmn-feel-antlr4-parser";
diff --git a/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx b/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx
index 5989d23bc43..f27d08ed935 100644
--- a/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx
@@ -32,6 +32,7 @@ import {
ExpressionDefinitionLogicType,
generateUuid,
getNextAvailablePrefixedName,
+ InsertRowColumnsDirection,
} from "../../api";
import { useBoxedExpressionEditorI18n } from "../../i18n";
import { useNestedExpressionContainerWithNestedExpressions } from "../../resizing/Hooks";
@@ -42,7 +43,7 @@ import {
CONTEXT_ENTRY_INFO_MIN_WIDTH,
CONTEXT_EXPRESSION_EXTRA_WIDTH,
} from "../../resizing/WidthConstants";
-import { useBeeTableSelectableCellRef, useBeeTableCoordinates } from "../../selection/BeeTableSelectionContext";
+import { useBeeTableCoordinates, useBeeTableSelectableCellRef } from "../../selection/BeeTableSelectionContext";
import { BeeTable, BeeTableColumnUpdate } from "../../table/BeeTable";
import {
useBoxedExpressionEditor,
@@ -66,6 +67,7 @@ export function ContextExpression(
}
) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const { variables } = useBoxedExpressionEditor();
@@ -139,10 +141,10 @@ export function ContextExpression(
const beeTableColumns = useMemo<ReactTable.Column<ROWTYPE>[]>(() => {
return [
{
- accessor: contextExpression.id as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
label: contextExpression.name ?? DEFAULT_EXPRESSION_NAME,
isRowIndexColumn: false,
- dataType: contextExpression.dataType ?? CONTEXT_ENTRY_DEFAULT_DATA_TYPE,
+ dataType: contextExpression.dataType,
width: undefined,
columns: [
{
@@ -166,7 +168,7 @@ export function ContextExpression(
],
},
];
- }, [contextExpression.id, contextExpression.name, contextExpression.dataType, entryInfoWidth, setEntryInfoWidth]);
+ }, [decisionNodeId, contextExpression.name, contextExpression.dataType, entryInfoWidth, setEntryInfoWidth]);
const onColumnUpdates = useCallback(
([{ name, dataType }]: BeeTableColumnUpdate<ROWTYPE>[]) => {
@@ -253,7 +255,7 @@ export function ContextExpression(
return {
entryInfo: {
id: generateUuid(),
- dataType: DmnBuiltInDataType.Undefined,
+ dataType: CONTEXT_ENTRY_DEFAULT_DATA_TYPE,
name:
name ||
getNextAvailablePrefixedName(
@@ -264,7 +266,7 @@ export function ContextExpression(
entryExpression: {
id: generateUuid(),
logicType: ExpressionDefinitionLogicType.Undefined,
- dataType: DmnBuiltInDataType.Undefined,
+ dataType: CONTEXT_ENTRY_DEFAULT_DATA_TYPE,
},
};
},
@@ -304,13 +306,28 @@ export function ContextExpression(
);
const onRowAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
setExpression((prev: ContextExpressionDefinition) => {
const newContextEntries = [...(prev.contextEntries ?? [])];
- const defaultContextEntry = getDefaultContextEntry();
- addVariable(args, newContextEntries, prev, defaultContextEntry);
- newContextEntries.splice(args.beforeIndex, 0, defaultContextEntry);
+ const newEntries = [];
+ const names = contextExpression.contextEntries.map((e) => e.entryInfo.name);
+ for (let i = 0; i < args.rowsCount; i++) {
+ const name = getNextAvailablePrefixedName(names, "ContextEntry");
+ names.push(name);
+
+ const defaultContextEntry = getDefaultContextEntry(name);
+ addVariable(args, newContextEntries, prev, defaultContextEntry);
+ newEntries.push(defaultContextEntry);
+ }
+
+ for (const newEntry of newEntries) {
+ let index = args.beforeIndex;
+ newContextEntries.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ index++;
+ }
+ }
return {
...prev,
@@ -318,7 +335,7 @@ export function ContextExpression(
};
});
},
- [addVariable, getDefaultContextEntry, setExpression]
+ [addVariable, contextExpression.contextEntries, getDefaultContextEntry, setExpression]
);
const onRowDeleted = useCallback(
@@ -449,7 +466,7 @@ export function ContextResultInfoCell() {
useEffect(() => {
if (isActive) {
- beeGwtService?.selectObject("");
+ beeGwtService?.selectObject(""); // FIXME: Tiago --> This should actually be the id of the parent expression, as the <result> of a context follows its parent's data type.
}
}, [beeGwtService, isActive]);
diff --git a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx
index a743ae12a5c..a5654ccafe1 100644
--- a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx
@@ -32,6 +32,7 @@ import {
DmnBuiltInDataType,
generateUuid,
getNextAvailablePrefixedName,
+ InsertRowColumnsDirection,
} from "../../api";
import { useBoxedExpressionEditorI18n } from "../../i18n";
import { usePublishedBeeTableResizableColumns } from "../../resizing/BeeTableResizableColumnsContext";
@@ -93,6 +94,7 @@ export function DecisionTableExpression(
decisionTableExpression: DecisionTableExpressionDefinition & { isNested: boolean; parentElementId: string }
) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const { variables } = useBoxedExpressionEditor();
@@ -259,10 +261,10 @@ export function DecisionTableExpression(
const outputSection = {
groupType: DecisionTableColumnType.OutputClause,
- id: decisionTableExpression.id,
+ id: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169,
accessor: "decision-table-expression" as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
label: decisionTableExpression.name ?? DEFAULT_EXPRESSION_NAME,
- dataType: decisionTableExpression.dataType ?? DmnBuiltInDataType.Undefined,
+ dataType: decisionTableExpression.dataType,
cssClasses: "decision-table--output",
isRowIndexColumn: false,
width: undefined,
@@ -294,9 +296,9 @@ export function DecisionTableExpression(
return [...inputColumns, outputSection, ...annotationColumns];
}
}, [
+ decisionNodeId,
decisionTableExpression.annotations,
decisionTableExpression.dataType,
- decisionTableExpression.id,
decisionTableExpression.input,
decisionTableExpression.name,
decisionTableExpression.output,
@@ -488,21 +490,33 @@ export function DecisionTableExpression(
);
const onRowAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
setExpression((prev: DecisionTableExpressionDefinition) => {
const newRules = [...(prev.rules ?? [])];
- newRules.splice(args.beforeIndex, 0, {
- id: generateUuid(),
- inputEntries: Array.from(new Array(prev.input?.length ?? 0)).map(() => {
- return createInputEntry();
- }),
- outputEntries: Array.from(new Array(prev.output?.length ?? 0)).map(() => {
- return createOutputEntry();
- }),
- annotationEntries: Array.from(new Array(prev.annotations?.length ?? 0)).map(
- () => DECISION_TABLE_ANNOTATION_DEFAULT_VALUE
- ),
- });
+ const newItems = [];
+
+ for (let i = 0; i < args.rowsCount; i++) {
+ newItems.push({
+ id: generateUuid(),
+ inputEntries: Array.from(new Array(prev.input?.length ?? 0)).map(() => {
+ return createInputEntry();
+ }),
+ outputEntries: Array.from(new Array(prev.output?.length ?? 0)).map(() => {
+ return createOutputEntry();
+ }),
+ annotationEntries: Array.from(new Array(prev.annotations?.length ?? 0)).map(
+ () => DECISION_TABLE_ANNOTATION_DEFAULT_VALUE
+ ),
+ });
+ }
+
+ for (const newEntry of newItems) {
+ let index = args.beforeIndex;
+ newRules.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ index++;
+ }
+ }
addVariables(newRules);
@@ -534,7 +548,12 @@ export function DecisionTableExpression(
);
const onColumnAdded = useCallback(
- (args: { beforeIndex: number; groupType: DecisionTableColumnType | undefined }) => {
+ (args: {
+ beforeIndex: number;
+ groupType: DecisionTableColumnType | undefined;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => {
const groupType = args.groupType;
if (!groupType) {
throw new Error("Column without groupType for Decision table.");
@@ -547,23 +566,43 @@ export function DecisionTableExpression(
switch (groupType) {
case DecisionTableColumnType.InputClause:
+ const newInputClauses = [];
+
+ const currentNames = prev.input?.map((c) => c.name) ?? [];
+
+ for (let i = 0; i < args.columnsCount; i++) {
+ const name = getNextAvailablePrefixedName(currentNames, "Input");
+ currentNames.push(name);
+
+ newInputClauses.push({
+ id: generateUuid(),
+ idLiteralExpression: generateUuid(),
+ name: name,
+ dataType: DmnBuiltInDataType.Undefined,
+ width: DECISION_TABLE_INPUT_DEFAULT_WIDTH,
+ });
+ }
+
const newInputs = [...(prev.input ?? [])];
- newInputs.splice(sectionIndex, 0, {
- id: generateUuid(),
- idLiteralExpression: generateUuid(),
- name: getNextAvailablePrefixedName(prev.input?.map((c) => c.name) ?? [], "input"),
- dataType: DmnBuiltInDataType.Undefined,
- width: DECISION_TABLE_INPUT_DEFAULT_WIDTH,
- });
+
+ for (const newEntry of newInputClauses) {
+ let index = args.beforeIndex;
+ newInputs.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.BelowOrLeft) {
+ index++;
+ }
+ }
newRules.forEach((r) => {
- const inputEntry = createInputEntry();
- variables?.repository.addVariableToContext(
- inputEntry.id,
- inputEntry.id,
- decisionTableExpression.parentElementId
- );
- r.inputEntries.splice(sectionIndex, 0, inputEntry);
+ for (let i = 0; i < args.columnsCount; i++) {
+ const inputEntry = createInputEntry();
+ variables?.repository.addVariableToContext(
+ inputEntry.id,
+ inputEntry.id,
+ decisionTableExpression.parentElementId
+ );
+ r.inputEntries.splice(sectionIndex, 0, inputEntry);
+ }
});
return {
@@ -571,23 +610,43 @@ export function DecisionTableExpression(
input: newInputs,
rules: newRules,
};
+
case DecisionTableColumnType.OutputClause:
+ const newOutputClauses = [];
+ const currentOutputNames = prev.output?.map((c) => c.name) ?? [];
+
+ for (let i = 0; i < args.columnsCount; i++) {
+ const name = getNextAvailablePrefixedName(currentOutputNames, "Output");
+ currentOutputNames.push(name);
+
+ newOutputClauses.push({
+ id: generateUuid(),
+ name: name,
+ dataType: DmnBuiltInDataType.Undefined,
+ width: DECISION_TABLE_OUTPUT_DEFAULT_WIDTH,
+ });
+ }
+
const newOutputs = [...(prev.output ?? [])];
- newOutputs.splice(sectionIndex, 0, {
- id: generateUuid(),
- name: getNextAvailablePrefixedName(prev.output?.map((c) => c.name) ?? [], "output"),
- dataType: DmnBuiltInDataType.Undefined,
- width: DECISION_TABLE_OUTPUT_DEFAULT_WIDTH,
- });
+
+ for (const newEntry of newOutputClauses) {
+ let index = args.beforeIndex;
+ newOutputs.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.BelowOrLeft) {
+ index++;
+ }
+ }
newRules.forEach((r) => {
- const outputEntry = createOutputEntry();
- variables?.repository.addVariableToContext(
- outputEntry.id,
- outputEntry.id,
- decisionTableExpression.parentElementId
- );
- r.outputEntries.splice(sectionIndex, 0, outputEntry);
+ for (let i = 0; i < args.columnsCount; i++) {
+ const outputEntry = createOutputEntry();
+ variables?.repository.addVariableToContext(
+ outputEntry.id,
+ outputEntry.id,
+ decisionTableExpression.parentElementId
+ );
+ r.outputEntries.splice(sectionIndex, 0, outputEntry);
+ }
});
return {
@@ -595,28 +654,48 @@ export function DecisionTableExpression(
output: newOutputs,
rules: newRules,
};
+
case DecisionTableColumnType.Annotation:
const newAnnotations = [...(prev.annotations ?? [])];
- newAnnotations.splice(sectionIndex, 0, {
- name: getNextAvailablePrefixedName(prev.annotations?.map((c) => c.name) ?? [], "annotation"),
- width: DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH,
- });
+ const newAnnotationsItems = [];
+ const currentAnnotationNames = prev.annotations?.map((c) => c.name) ?? [];
- newRules.forEach((r) =>
- r.annotationEntries.splice(sectionIndex, 0, DECISION_TABLE_ANNOTATION_DEFAULT_VALUE)
- );
+ for (let i = 0; i < args.columnsCount; i++) {
+ const name = getNextAvailablePrefixedName(currentAnnotationNames, DecisionTableColumnType.Annotation);
+ currentAnnotationNames.push(name);
+
+ newAnnotationsItems.push({
+ name: name,
+ width: DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH,
+ });
+ }
+
+ for (const newEntry of newAnnotationsItems) {
+ let index = args.beforeIndex;
+ newAnnotations.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.BelowOrLeft) {
+ index++;
+ }
+ }
+
+ newRules.forEach((r) => {
+ for (let i = 0; i < args.columnsCount; i++) {
+ r.annotationEntries.splice(sectionIndex, 0, DECISION_TABLE_ANNOTATION_DEFAULT_VALUE);
+ }
+ });
return {
...prev,
annotations: newAnnotations,
rules: newRules,
};
+
default:
assertUnreachable(groupType);
}
});
},
- [getSectionIndexForGroupType, setExpression]
+ [decisionTableExpression.parentElementId, getSectionIndexForGroupType, setExpression, variables?.repository]
);
const onColumnDeleted = useCallback(
diff --git a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionContainer.tsx b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionContainer.tsx
index 208b2a3e0d1..63e45cd2eaa 100644
--- a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionContainer.tsx
+++ b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionContainer.tsx
@@ -159,11 +159,11 @@ export const ExpressionContainer: React.FunctionComponent<ExpressionContainerPro
);
const onLogicTypeSelected = useCallback(
- (logicType) => {
- setExpression((prev: ExpressionDefinition) => {
+ (logicType: ExpressionDefinitionLogicType) => {
+ setExpression((prev) => {
+ const defaultExpression = beeGwtService!.getDefaultExpressionDefinition(logicType, prev.dataType, !isNested);
const newExpression = {
- ...beeGwtService!.getDefaultExpressionDefinition(logicType, prev.dataType),
- logicType,
+ ...defaultExpression,
isNested,
id: prev.id ?? generateUuid(),
name: prev.name ?? DEFAULT_EXPRESSION_NAME,
@@ -174,22 +174,22 @@ export const ExpressionContainer: React.FunctionComponent<ExpressionContainerPro
switch (newExpression.logicType) {
case ExpressionDefinitionLogicType.Context:
- addContextExpressionToVariables(newExpression as ContextExpressionDefinition);
+ addContextExpressionToVariables(newExpression);
break;
case ExpressionDefinitionLogicType.Relation:
addRelationExpressionToVariables(newExpression);
break;
case ExpressionDefinitionLogicType.Invocation:
- addInvocationExpressionToVariables(newExpression as InvocationExpressionDefinition);
+ addInvocationExpressionToVariables(newExpression);
break;
case ExpressionDefinitionLogicType.List:
- addListExpressionToVariables(newExpression as ListExpressionDefinition);
+ addListExpressionToVariables(newExpression);
break;
case ExpressionDefinitionLogicType.DecisionTable:
- addDecisionTableExpressionToVariables(newExpression as DecisionTableExpressionDefinition);
+ addDecisionTableExpressionToVariables(newExpression);
break;
case ExpressionDefinitionLogicType.Function:
- addFunctionExpressionToVariables(newExpression as FunctionExpressionDefinition);
+ addFunctionExpressionToVariables(newExpression);
break;
default:
// Expression without variables
diff --git a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector/ExpressionDefinitionLogicTypeSelector.tsx b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector/ExpressionDefinitionLogicTypeSelector.tsx
index 9163640f481..c892ea6b965 100644
--- a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector/ExpressionDefinitionLogicTypeSelector.tsx
+++ b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector/ExpressionDefinitionLogicTypeSelector.tsx
@@ -354,6 +354,7 @@ export function ExpressionDefinitionLogicTypeSelector({
menuIconContainerStyle,
pasteExpression,
resetLogicType,
+ isResetSupported,
]);
const [isDropdownOpen, setDropdownOpen] = useState(false);
diff --git a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionRoot.tsx b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionRoot.tsx
index af43e6b9958..63877966263 100644
--- a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionRoot.tsx
+++ b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionRoot.tsx
@@ -37,12 +37,6 @@ export function ExpressionDefinitionRoot({
return (
<ResizingWidthsContextProvider>
<div className={`expression-container ${decisionNodeId}`}>
- <div className="expression-name-and-logic-type">
- <span className="expression-title">{expression.name}</span>
-
- <span className="expression-type">({expression.logicType})</span>
- </div>
-
<ExpressionContainer
expression={expression}
isResetSupported={isResetSupported}
diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx
index dadd66f2f0d..91ae5cebb13 100644
--- a/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx
@@ -46,6 +46,7 @@ import {
import { BeeTable, BeeTableColumnUpdate } from "../../table/BeeTable";
import {
NestedExpressionDispatchContextProvider,
+ useBoxedExpressionEditor,
useBoxedExpressionEditorDispatch,
} from "../BoxedExpressionEditor/BoxedExpressionEditorContext";
import { DEFAULT_EXPRESSION_NAME } from "../ExpressionDefinitionHeaderMenu";
@@ -60,6 +61,7 @@ export function FeelFunctionExpression({
functionExpression: FeelFunctionExpressionDefinition & { isNested: boolean; parentElementId: string };
}) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const parametersColumnHeader = useFunctionExpressionParametersColumnHeader(functionExpression.formalParameters);
@@ -68,8 +70,8 @@ export function FeelFunctionExpression({
return [
{
label: functionExpression.name ?? DEFAULT_EXPRESSION_NAME,
- accessor: functionExpression.id as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
- dataType: functionExpression.dataType ?? DmnBuiltInDataType.Undefined,
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
+ dataType: functionExpression.dataType,
isRowIndexColumn: false,
width: undefined,
columns: [
@@ -84,7 +86,7 @@ export function FeelFunctionExpression({
],
},
];
- }, [functionExpression.dataType, functionExpression.name, parametersColumnHeader]);
+ }, [decisionNodeId, functionExpression.dataType, functionExpression.name, parametersColumnHeader]);
const headerVisibility = useMemo(() => {
return functionExpression.isNested ? BeeTableHeaderVisibility.LastLevel : BeeTableHeaderVisibility.AllLevels;
diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx
index dfed891dcd3..0f5d96a9560 100644
--- a/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx
@@ -65,6 +65,7 @@ export function JavaFunctionExpression({
functionExpression: JavaFunctionExpressionDefinition & { isNested: boolean };
}) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const setClassAndMethodNamesWidth = useCallback(
@@ -87,8 +88,8 @@ export function JavaFunctionExpression({
return [
{
label: functionExpression.name ?? DEFAULT_EXPRESSION_NAME,
- accessor: functionExpression.id as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
- dataType: functionExpression.dataType ?? DmnBuiltInDataType.Undefined,
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
+ dataType: functionExpression.dataType,
isRowIndexColumn: false,
width: undefined,
columns: [
@@ -125,9 +126,9 @@ export function JavaFunctionExpression({
},
];
}, [
+ decisionNodeId,
functionExpression.classAndMethodNamesWidth,
functionExpression.dataType,
- functionExpression.id,
functionExpression.name,
parametersColumnHeader,
setClassAndMethodNamesWidth,
diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx
index e7cdc7b6307..56b4efcbbca 100644
--- a/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx
@@ -65,6 +65,7 @@ export function PmmlFunctionExpression({
functionExpression: PmmlFunctionExpressionDefinition & { isNested: boolean };
}) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const parametersColumnHeader = useFunctionExpressionParametersColumnHeader(functionExpression.formalParameters);
@@ -73,8 +74,8 @@ export function PmmlFunctionExpression({
return [
{
label: functionExpression.name ?? DEFAULT_EXPRESSION_NAME,
- accessor: functionExpression.id as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
- dataType: functionExpression.dataType ?? DmnBuiltInDataType.Undefined,
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
+ dataType: functionExpression.dataType,
isRowIndexColumn: false,
width: undefined,
columns: [
@@ -110,7 +111,7 @@ export function PmmlFunctionExpression({
],
},
];
- }, [functionExpression.dataType, functionExpression.name, parametersColumnHeader]);
+ }, [decisionNodeId, functionExpression.dataType, functionExpression.name, parametersColumnHeader]);
const headerVisibility = useMemo(() => {
return functionExpression.isNested
diff --git a/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx b/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx
index 48a76b60913..3f80c95bae0 100644
--- a/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx
@@ -31,6 +31,7 @@ import {
ExpressionDefinitionLogicType,
generateUuid,
getNextAvailablePrefixedName,
+ InsertRowColumnsDirection,
InvocationExpressionDefinition,
} from "../../api";
import { useBoxedExpressionEditorI18n } from "../../i18n";
@@ -64,7 +65,7 @@ export function InvocationExpression(
invocationExpression: InvocationExpressionDefinition & { isNested: boolean; parentElementId: string }
) {
const { i18n } = useBoxedExpressionEditorI18n();
- const { variables } = useBoxedExpressionEditor();
+ const { decisionNodeId, variables } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const parametersWidth = useMemo(() => {
@@ -139,9 +140,9 @@ export function InvocationExpression(
const beeTableColumns = useMemo<ReactTable.Column<ROWTYPE>[]>(
() => [
{
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169,
label: invocationExpression.name ?? DEFAULT_EXPRESSION_NAME,
- accessor: invocationExpression.id as keyof ROWTYPE,
- dataType: invocationExpression.dataType ?? INVOCATION_EXPRESSION_DEFAULT_PARAMETER_DATA_TYPE,
+ dataType: invocationExpression.dataType,
isRowIndexColumn: false,
width: undefined,
columns: [
@@ -178,9 +179,10 @@ export function InvocationExpression(
},
],
[
+ decisionNodeId,
invocationExpression.name,
invocationExpression.dataType,
- invocationExpression.invokedFunction,
+ invocationExpression.invokedFunction.name,
parametersWidth,
setParametersWidth,
]
@@ -237,7 +239,7 @@ export function InvocationExpression(
<ArgumentEntryExpressionCell {...props} parentElementId={invocationExpression.parentElementId} />
),
}),
- [updateEntry]
+ [invocationExpression.parentElementId, updateEntry]
);
const beeTableOperationConfig = useMemo<BeeTableOperationConfig>(() => {
@@ -288,10 +290,24 @@ export function InvocationExpression(
);
const onRowAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
+ const newEntries: ContextExpressionDefinitionEntry[] = [];
+ const names = (invocationExpression.bindingEntries ?? []).map((e) => e.entryInfo.name);
+ for (let i = 0; i < args.rowsCount; i++) {
+ const name = getNextAvailablePrefixedName(names, "p");
+ names.push(name);
+ newEntries.push(getDefaultArgumentEntry(name));
+ }
setExpression((prev: InvocationExpressionDefinition) => {
const newArgumentEntries = [...(prev.bindingEntries ?? [])];
- newArgumentEntries.splice(args.beforeIndex, 0, getDefaultArgumentEntry());
+
+ for (const newEntry of newEntries) {
+ let index = args.beforeIndex;
+ newArgumentEntries.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ index++;
+ }
+ }
return {
...prev,
diff --git a/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx b/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx
index 8429a87bb6a..3cd359565f6 100644
--- a/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx
@@ -32,6 +32,7 @@ import {
ExpressionDefinition,
ExpressionDefinitionLogicType,
generateUuid,
+ InsertRowColumnsDirection,
ListExpressionDefinition,
} from "../../api";
import { useBoxedExpressionEditorI18n } from "../../i18n";
@@ -117,7 +118,7 @@ export function ListExpression(
const beeTableColumns = useMemo<ReactTable.Column<ROWTYPE>[]>(
() => [
{
- accessor: decisionNodeId as any,
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
label: listExpression.name ?? DEFAULT_EXPRESSION_NAME,
dataType: listExpression.dataType,
isRowIndexColumn: false,
@@ -148,15 +149,25 @@ export function ListExpression(
}, []);
const onRowAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
setExpression((prev: ListExpressionDefinition) => {
const newItems = [...prev.items];
+ const newListItems = [];
- const newItem = getDefaultListItem(prev.dataType);
+ for (let i = 0; i < args.rowsCount; i++) {
+ const newItem = getDefaultListItem(prev.dataType);
+ newListItems.push(newItem);
+ variables?.repository.addVariableToContext(newItem.id, newItem.id, listExpression.parentElementId);
+ }
- variables?.repository.addVariableToContext(newItem.id, newItem.id, listExpression.parentElementId);
+ for (const newEntry of newListItems) {
+ let index = args.beforeIndex;
+ newItems.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ index++;
+ }
+ }
- newItems.splice(args.beforeIndex, 0, newItem);
return { ...prev, items: newItems };
});
},
diff --git a/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx b/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx
index dd3e4bfecee..09aff3d7447 100644
--- a/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx
@@ -175,7 +175,7 @@ export function LiteralExpression(literalExpression: LiteralExpressionDefinition
],
},
];
- }, [i18n.terms.copy, i18n.terms.cut, i18n.terms.paste, i18n.terms.reset, i18n.terms.selection]);
+ }, [i18n]);
const allowedOperations = useCallback((conditions: BeeTableContextMenuAllowedOperationsConditions) => {
if (!conditions.selection.selectionStart || !conditions.selection.selectionEnd) {
diff --git a/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx b/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx
index 25d0d539184..c747c89b74b 100644
--- a/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx
+++ b/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx
@@ -29,6 +29,7 @@ import {
DmnBuiltInDataType,
generateUuid,
getNextAvailablePrefixedName,
+ InsertRowColumnsDirection,
RelationExpressionDefinition,
RelationExpressionDefinitionRow,
} from "../../api";
@@ -57,6 +58,7 @@ export function RelationExpression(
relationExpression: RelationExpressionDefinition & { isNested: boolean; parentElementId: string }
) {
const { i18n } = useBoxedExpressionEditorI18n();
+ const { decisionNodeId } = useBoxedExpressionEditor();
const { setExpression } = useBoxedExpressionEditorDispatch();
const { variables } = useBoxedExpressionEditor();
@@ -142,7 +144,7 @@ export function RelationExpression(
const beeTableColumns = useMemo<ReactTable.Column<ROWTYPE>[]>(() => {
return [
{
- accessor: relationExpression.id as any,
+ accessor: decisionNodeId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169
label: relationExpression.name ?? DEFAULT_EXPRESSION_NAME,
dataType: relationExpression.dataType,
isRowIndexColumn: false,
@@ -158,7 +160,7 @@ export function RelationExpression(
})),
},
];
- }, [columns, relationExpression.dataType, relationExpression.id, relationExpression.name, setColumnWidth]);
+ }, [columns, decisionNodeId, relationExpression.dataType, relationExpression.name, setColumnWidth]);
const beeTableRows = useMemo<ROWTYPE[]>(
() =>
@@ -236,15 +238,27 @@ export function RelationExpression(
}, [relationExpression.parentElementId, variables?.repository]);
const onRowAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
setExpression((prev: RelationExpressionDefinition) => {
const newRows = [...(prev.rows ?? [])];
- newRows.splice(args.beforeIndex, 0, {
- id: generateUuid(),
- cells: Array.from(new Array(prev.columns?.length ?? 0)).map(() => {
- return createCell();
- }),
- });
+ const newItems = [];
+
+ for (let i = 0; i < args.rowsCount; i++) {
+ newItems.push({
+ id: generateUuid(),
+ cells: Array.from(new Array(prev.columns?.length ?? 0)).map(() => {
+ return createCell();
+ }),
+ });
+ }
+
+ for (const newEntry of newItems) {
+ let index = args.beforeIndex;
+ newRows.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ index++;
+ }
+ }
return {
...prev,
@@ -256,15 +270,32 @@ export function RelationExpression(
);
const onColumnAdded = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; columnsCount: number; insertDirection: InsertRowColumnsDirection }) => {
setExpression((prev: RelationExpressionDefinition) => {
const newColumns = [...(prev.columns ?? [])];
- newColumns.splice(args.beforeIndex, 0, {
- id: generateUuid(),
- name: getNextAvailablePrefixedName(prev.columns?.map((c) => c.name) ?? [], "column"),
- dataType: DmnBuiltInDataType.Undefined,
- width: RELATION_EXPRESSION_COLUMN_DEFAULT_WIDTH,
- });
+
+ const newItems = [];
+ const availableNames = prev.columns?.map((c) => c.name) ?? [];
+
+ for (let i = 0; i < args.columnsCount; i++) {
+ const name = getNextAvailablePrefixedName(availableNames, "column");
+ availableNames.push(name);
+
+ newItems.push({
+ id: generateUuid(),
+ name: name,
+ dataType: DmnBuiltInDataType.Undefined,
+ width: RELATION_EXPRESSION_COLUMN_DEFAULT_WIDTH,
+ });
+ }
+
+ for (const newEntry of newItems) {
+ let index = args.beforeIndex;
+ newColumns.splice(index, 0, newEntry);
+ if (args.insertDirection === InsertRowColumnsDirection.BelowOrLeft) {
+ index++;
+ }
+ }
const newRows = [...(prev.rows ?? [])].map((row) => {
const newCells = [...row.cells];
diff --git a/packages/boxed-expression-component/src/resizing/WidthConstants.ts b/packages/boxed-expression-component/src/resizing/WidthConstants.ts
index 61c9e4b7ced..2e633f35a2d 100644
--- a/packages/boxed-expression-component/src/resizing/WidthConstants.ts
+++ b/packages/boxed-expression-component/src/resizing/WidthConstants.ts
@@ -37,7 +37,7 @@ export const DECISION_TABLE_INPUT_DEFAULT_WIDTH = 100;
export const DECISION_TABLE_OUTPUT_MIN_WIDTH = 100;
export const DECISION_TABLE_OUTPUT_DEFAULT_WIDTH = 100;
export const DECISION_TABLE_ANNOTATION_MIN_WIDTH = 100;
-export const DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH = 100;
+export const DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH = 240;
// RELATION
export const RELATION_EXPRESSION_COLUMN_MIN_WIDTH = 100;
diff --git a/packages/boxed-expression-component/src/selection/BeeTableSelectionContext.tsx b/packages/boxed-expression-component/src/selection/BeeTableSelectionContext.tsx
index 1663bc724ed..ad18abd73b9 100644
--- a/packages/boxed-expression-component/src/selection/BeeTableSelectionContext.tsx
+++ b/packages/boxed-expression-component/src/selection/BeeTableSelectionContext.tsx
@@ -21,6 +21,7 @@ import * as React from "react";
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
import { assertUnreachable } from "../expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector";
import { ResizingWidth, useResizingWidthsDispatch } from "../resizing/ResizingWidthsContext";
+import { useBoxedExpressionEditor } from "../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
export const SELECTION_MIN_ACTIVE_DEPTH = -1;
export const SELECTION_MIN_MAX_DEPTH = 0;
@@ -165,6 +166,16 @@ export function BeeTableCoordinatesContextProvider({
}: React.PropsWithChildren<{ coordinates: BeeTableCellCoordinates }>) {
const { activeCell, depth } = useBeeTableSelection();
+ // FIXME: Tiago --> Temporary fix for the Boxed Expression Editor to work well. Ideally this wouldn't bee here, as the BeeTable should be decoupled from the DMN Editor's Boxed Expression Editor use-case.
+ const { beeGwtService } = useBoxedExpressionEditor();
+
+ useEffect(() => {
+ if (!activeCell && depth === SELECTION_MIN_MAX_DEPTH) {
+ beeGwtService?.selectObject(undefined);
+ }
+ }, [activeCell, beeGwtService, depth]);
+
+ //
const { setMaxDepth: setParentMaxDepth } = useBeeTableCoordinatesDispatch();
const [_maxDepth, _setMaxDepth] = useState<number>(depth);
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
index 44c61f389e9..93bf7c517b5 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
@@ -21,7 +21,7 @@ import * as _ from "lodash";
import * as React from "react";
import { useCallback, useMemo, useRef } from "react";
import * as ReactTable from "react-table";
-import { BeeTableHeaderVisibility, BeeTableProps } from "../../api";
+import { BeeTableHeaderVisibility, BeeTableProps, InsertRowColumnsDirection } from "../../api";
import { useBoxedExpressionEditor } from "../../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
import { NavigationKeysUtils } from "../../keysUtils";
import { ResizingWidth } from "../../resizing/ResizingWidthsContext";
@@ -37,8 +37,8 @@ import { BeeTableDefaultCell } from "./BeeTableDefaultCell";
import { BeeTableHeader } from "./BeeTableHeader";
import {
BeeTableSelectionContextProvider,
- SelectionPart,
SELECTION_MIN_ACTIVE_DEPTH,
+ SelectionPart,
useBeeTableSelectionDispatch,
} from "../../selection/BeeTableSelectionContext";
import { BeeTableCellWidthsToFitDataContextProvider } from "../../resizing/BeeTableCellWidthToFitDataContext";
@@ -521,12 +521,12 @@ export function BeeTableInternal<R extends object>({
);
const onRowAdded2 = useCallback(
- (args: { beforeIndex: number }) => {
+ (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => {
if (onRowAdded) {
onRowAdded(args);
adaptSelection({
atRowIndex: args.beforeIndex,
- rowCountDelta: 1,
+ rowCountDelta: args.rowsCount,
atColumnIndex: -1,
columnCountDelta: 0,
});
@@ -536,7 +536,13 @@ export function BeeTableInternal<R extends object>({
);
const onColumnAdded2 = useCallback(
- (args: { beforeIndex: number; currentIndex: number; groupType: string }) => {
+ (args: {
+ beforeIndex: number;
+ currentIndex: number;
+ groupType: string;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => {
if (onColumnAdded) {
onColumnAdded(args);
adaptSelection({
@@ -544,7 +550,7 @@ export function BeeTableInternal<R extends object>({
rowCountDelta: 0,
// The columnIndex here does not count the rowIndex columns, but the selection does. So + 1.
atColumnIndex: args.beforeIndex + 1,
- columnCountDelta: 1,
+ columnCountDelta: args.columnsCount,
});
}
},
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx
index a179740f46e..33df80ba7a5 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx
@@ -19,7 +19,7 @@
import * as React from "react";
import { useCallback, useMemo } from "react";
-import { BeeTableHeaderVisibility } from "../../api";
+import { BeeTableHeaderVisibility, InsertRowColumnsDirection } from "../../api";
import * as ReactTable from "react-table";
import { BeeTableTdForAdditionalRow } from "./BeeTableTdForAdditionalRow";
import { BeeTableTd } from "./BeeTableTd";
@@ -38,7 +38,7 @@ export interface BeeTableBodyProps<R extends object> {
/** Custom function for getting column key prop, and avoid using the column index */
getColumnKey: (column: ReactTable.ColumnInstance<R>) => string;
/** */
- onRowAdded?: (args: { beforeIndex: number }) => void;
+ onRowAdded?: (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => void;
shouldRenderRowIndexColumn: boolean;
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
index 5c58fffa17f..1a27a2e24b4 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
@@ -31,8 +31,13 @@ import TrashIcon from "@patternfly/react-icons/dist/js/icons/trash-icon";
import BlueprintIcon from "@patternfly/react-icons/dist/js/icons/blueprint-icon";
import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
import * as React from "react";
-import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
-import { BeeTableContextMenuAllowedOperationsConditions, BeeTableOperation, BeeTableOperationConfig } from "../../api";
+import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
+import {
+ BeeTableContextMenuAllowedOperationsConditions,
+ BeeTableOperation,
+ BeeTableOperationConfig,
+ InsertRowColumnsDirection,
+} from "../../api";
import { useCustomContextMenuHandler } from "../../contextMenu";
import { useBoxedExpressionEditor } from "../../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
import { assertUnreachable } from "../../expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector";
@@ -58,19 +63,20 @@ export interface BeeTableContextMenuHandlerProps {
allowedOperations: (conditions: BeeTableContextMenuAllowedOperationsConditions) => BeeTableOperation[];
reactTableInstance: ReactTable.TableInstance<any>;
//
- onRowAdded?: (args: { beforeIndex: number }) => void;
+ onRowAdded?: (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => void;
onRowDuplicated?: (args: { rowIndex: number }) => void;
onRowReset?: (args: { rowIndex: number }) => void;
onRowDeleted?: (args: { rowIndex: number }) => void;
- onColumnAdded?: (args: { beforeIndex: number; currentIndex: number; groupType: string | undefined }) => void;
+ onColumnAdded?: (args: {
+ beforeIndex: number;
+ currentIndex: number;
+ groupType: string | undefined;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => void;
onColumnDeleted?: (args: { columnIndex: number; groupType: string | undefined }) => void;
}
-export enum InsertRowColumnsDirection {
- AboveOrRight,
- BelowOrLeft,
-}
-
/** The maximum numbers of rows or columns that can be inserted from the Insert menu. */
const MAXIMUM_ROWS_COLUMNS_PER_INSERTION = 500;
@@ -308,6 +314,8 @@ export function BeeTableContextMenuHandler({
beforeIndex: columnIndex - 1,
currentIndex: columnIndex,
groupType: column?.groupType,
+ columnsCount: 1,
+ insertDirection: InsertRowColumnsDirection.BelowOrLeft,
});
console.debug(`Insert column left to ${columnIndex}`);
break;
@@ -316,10 +324,29 @@ export function BeeTableContextMenuHandler({
beforeIndex: columnIndex,
currentIndex: columnIndex,
groupType: column?.groupType,
+ columnsCount: 1,
+ insertDirection: InsertRowColumnsDirection.AboveOrRight,
});
console.debug(`Insert column right to ${columnIndex}`);
break;
case BeeTableOperation.ColumnInsertN:
+ if (direction === InsertRowColumnsDirection.AboveOrRight) {
+ onColumnAdded?.({
+ beforeIndex: columnIndex,
+ currentIndex: columnIndex,
+ groupType: column?.groupType,
+ columnsCount: insertMultipleRowColumnsValue,
+ insertDirection: InsertRowColumnsDirection.AboveOrRight,
+ });
+ } else {
+ onColumnAdded?.({
+ beforeIndex: columnIndex - 1,
+ currentIndex: columnIndex,
+ groupType: column?.groupType,
+ columnsCount: insertMultipleRowColumnsValue,
+ insertDirection: InsertRowColumnsDirection.BelowOrLeft,
+ });
+ }
console.debug(`Insert n columns to ${columnIndex}`);
break;
case BeeTableOperation.ColumnDelete:
@@ -330,14 +357,35 @@ export function BeeTableContextMenuHandler({
console.debug(`Delete column ${columnIndex}`);
break;
case BeeTableOperation.RowInsertAbove:
- onRowAdded?.({ beforeIndex: rowIndex });
+ onRowAdded?.({
+ beforeIndex: rowIndex,
+ rowsCount: 1,
+ insertDirection: InsertRowColumnsDirection.AboveOrRight,
+ });
console.debug(`Insert row above to ${rowIndex}`);
break;
case BeeTableOperation.RowInsertBelow:
- onRowAdded?.({ beforeIndex: rowIndex + 1 });
+ onRowAdded?.({
+ beforeIndex: rowIndex + 1,
+ rowsCount: 1,
+ insertDirection: InsertRowColumnsDirection.BelowOrLeft,
+ });
console.debug(`Insert row below to ${rowIndex}`);
break;
case BeeTableOperation.RowInsertN:
+ if (direction === InsertRowColumnsDirection.AboveOrRight) {
+ onRowAdded?.({
+ beforeIndex: rowIndex,
+ rowsCount: insertMultipleRowColumnsValue,
+ insertDirection: InsertRowColumnsDirection.AboveOrRight,
+ });
+ } else {
+ onRowAdded?.({
+ beforeIndex: rowIndex + 1,
+ rowsCount: insertMultipleRowColumnsValue,
+ insertDirection: InsertRowColumnsDirection.BelowOrLeft,
+ });
+ }
console.debug(`Insert n rows to ${columnIndex}`);
break;
case BeeTableOperation.RowDelete:
@@ -396,6 +444,8 @@ export function BeeTableContextMenuHandler({
cut,
paste,
erase,
+ direction,
+ insertMultipleRowColumnsValue,
]
);
@@ -502,26 +552,6 @@ export function BeeTableContextMenuHandler({
);
}
- function insertMultipleRowColumns(operation: BeeTableOperation) {
- if (operation === BeeTableOperation.ColumnInsertN) {
- for (let i = 0; i < insertMultipleRowColumnsValue; i++) {
- handleOperation(
- direction === InsertRowColumnsDirection.AboveOrRight
- ? BeeTableOperation.ColumnInsertRight
- : BeeTableOperation.ColumnInsertLeft
- );
- }
- } else if (operation === BeeTableOperation.RowInsertN) {
- for (let i = 0; i < insertMultipleRowColumnsValue; i++) {
- handleOperation(
- direction === InsertRowColumnsDirection.AboveOrRight
- ? BeeTableOperation.RowInsertAbove
- : BeeTableOperation.RowInsertBelow
- );
- }
- }
- }
-
function createDrillDownMenu(group: string, operation: BeeTableOperation) {
return (
<DrilldownMenu id={"insertNColumnsMenu" + operation.toString()}>
@@ -530,16 +560,12 @@ export function BeeTableContextMenuHandler({
</MenuItem>
<Divider />
<MenuGroup label={group}>
- <Flex
- direction={{ default: "column" }}
- style={{ padding: "16px" }}
- onClick={(event) => event.stopPropagation()}
- >
+ <Flex direction={{ default: "column" }} style={{ padding: "16px" }}>
<Flex direction={{ default: "column" }} width={"300px"}>
- <FlexItem>{insertRowColumnsNumberInput}</FlexItem>
+ <FlexItem onClick={(event) => event.stopPropagation()}>{insertRowColumnsNumberInput}</FlexItem>
</Flex>
<Flex direction={{ default: "row" }}>
- <FlexItem>
+ <FlexItem onClick={(event) => event.stopPropagation()}>
<br />
<Radio
id={"insertRightAbove" + operation}
@@ -567,7 +593,7 @@ export function BeeTableContextMenuHandler({
</Flex>
<FlexItem align={{ default: "alignLeft" }}>
<br />
- <Button onClick={() => insertMultipleRowColumns(operation)}>Insert</Button>
+ <Button onClick={() => handleOperation(operation)}>Insert</Button>
</FlexItem>
</Flex>
</MenuGroup>
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableDefaultCell.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableDefaultCell.tsx
index 2e4efebbe69..80507286dd5 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableDefaultCell.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableDefaultCell.tsx
@@ -71,14 +71,6 @@ export function BeeTableDefaultCell<R extends object>({
getValue
);
- const { beeGwtService } = useBoxedExpressionEditor();
-
- useEffect(() => {
- if (isActive) {
- beeGwtService?.selectObject(typeof cellProps.value === "string" ? "" : cellProps.value?.id);
- }
- }, [isActive, beeGwtService, cellProps]);
-
return (
<BeeTableEditableCellContent
isEditing={isEditing}
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx
index dc06b72c819..00d0080f4be 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx
@@ -21,7 +21,12 @@ import * as _ from "lodash";
import * as React from "react";
import { useCallback } from "react";
import * as ReactTable from "react-table";
-import { DmnBuiltInDataType, BeeTableHeaderVisibility, ExpressionDefinition } from "../../api";
+import {
+ DmnBuiltInDataType,
+ BeeTableHeaderVisibility,
+ ExpressionDefinition,
+ InsertRowColumnsDirection,
+} from "../../api";
import { useBoxedExpressionEditor } from "../../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
import { BeeTableTh } from "./BeeTableTh";
import { BeeTableThResizable } from "./BeeTableThResizable";
@@ -64,7 +69,12 @@ export interface BeeTableHeaderProps<R extends object> {
/** Option to enable or disable header edits */
isEditableHeader: boolean;
/** */
- onColumnAdded?: (args: { beforeIndex: number; groupType: string | undefined }) => void;
+ onColumnAdded?: (args: {
+ beforeIndex: number;
+ groupType: string | undefined;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => void;
shouldRenderRowIndexColumn: boolean;
@@ -138,6 +148,7 @@ export function BeeTableHeader<R extends object>({
rowSpan={rowSpan}
key={columnKey}
column={column}
+ columnKey={columnKey}
columnIndex={0}
rowIndex={rowIndex}
thProps={column.getHeaderProps()}
@@ -155,13 +166,6 @@ export function BeeTableHeader<R extends object>({
[getColumnKey, shouldShowRowsInlineControls]
);
- const onHeaderClick = useCallback(
- (columnKey: string) => () => {
- beeGwtService?.selectObject(columnKey);
- },
- [beeGwtService]
- );
-
const renderColumn = useCallback<
(
rowIndex: number,
@@ -190,7 +194,6 @@ export function BeeTableHeader<R extends object>({
shouldShowColumnsInlineControls={shouldShowRowsInlineControls}
getColumnKey={getColumnKey}
getColumnLabel={getColumnLabel}
- onHeaderClick={onHeaderClick}
reactTableInstance={reactTableInstance}
column={column}
columnIndex={columnIndex}
@@ -261,7 +264,6 @@ export function BeeTableHeader<R extends object>({
isEditableHeader,
shouldShowRowsInlineControls,
getColumnLabel,
- onHeaderClick,
onColumnAdded,
lastColumnMinWidth,
setEditing,
@@ -356,7 +358,14 @@ export function BeeTableHeader<R extends object>({
);
}
});
- }, [getColumnKey, reactTableInstance, renderColumn, shouldRenderHeaderGroup, shouldRenderRowIndexColumn]);
+ }, [
+ getColumnKey,
+ headerVisibility,
+ reactTableInstance,
+ renderColumn,
+ shouldRenderHeaderGroup,
+ shouldRenderRowIndexColumn,
+ ]);
return <>{<thead>{renderHeaderGroups()}</thead>}</>;
}
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx
index 7fad25c0b52..d241bbfb0ea 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx
@@ -32,10 +32,11 @@ import {
useBeeTableSelectableCellRef,
} from "../../selection/BeeTableSelectionContext";
import { useBoxedExpressionEditor } from "../../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
+import { InsertRowColumnsDirection } from "../../api";
export interface BeeTableTdProps<R extends object> {
- // Individual cells are not immutable referecens, By referencing the row, we avoid multiple re-renders and bugs.
- onRowAdded?: (args: { beforeIndex: number }) => void;
+ // Individual cells are not immutable references, By referencing the row, we avoid multiple re-renders and bugs.
+ onRowAdded?: (args: { beforeIndex: number; rowsCount: number; insertDirection: InsertRowColumnsDirection }) => void;
isActive: boolean;
shouldRenderInlineButtons: boolean;
shouldShowRowsInlineControls: boolean;
@@ -105,10 +106,14 @@ export function BeeTableTd<R extends object>({
const { beeGwtService, editorRef } = useBoxedExpressionEditor();
useEffect(() => {
- if (isActive && column.isRowIndexColumn) {
- beeGwtService?.selectObject("");
+ if (isActive) {
+ if (column.isRowIndexColumn) {
+ beeGwtService?.selectObject("");
+ } else {
+ beeGwtService?.selectObject(typeof cell.value === "string" ? "" : cell.value?.id ?? "");
+ }
}
- }, [beeGwtService, isActive, column]);
+ }, [beeGwtService, isActive, column.isRowIndexColumn, cell.value]);
useEffect(() => {
const td = tdRef.current;
@@ -157,7 +162,11 @@ export function BeeTableTd<R extends object>({
return;
}
- onRowAdded?.({ beforeIndex: hoverInfo.part === "upper" ? rowIndex : rowIndex + 1 });
+ onRowAdded?.({
+ beforeIndex: hoverInfo.part === "upper" ? rowIndex : rowIndex + 1,
+ rowsCount: 1,
+ insertDirection: InsertRowColumnsDirection.BelowOrLeft,
+ });
if (hoverInfo.part === "upper") {
setHoverInfo({ isHovered: false });
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
index a954aa3b96a..b9d2469c46f 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
@@ -24,20 +24,28 @@ import * as ReactTable from "react-table";
import {
BeeTableCellCoordinates,
BeeTableCoordinatesContextProvider,
+ useBeeTableSelectableCell,
useBeeTableSelectableCellRef,
} from "../../selection/BeeTableSelectionContext";
-import { useBeeTableSelectableCell } from "../../selection/BeeTableSelectionContext";
import { useBoxedExpressionEditor } from "../../expressions/BoxedExpressionEditor/BoxedExpressionEditorContext";
+import { InsertRowColumnsDirection } from "../../api";
export interface BeeTableThProps<R extends object> {
groupType: string | undefined;
- onColumnAdded?: (args: { beforeIndex: number; currentIndex: number; groupType: string | undefined }) => void;
+ onColumnAdded?: (args: {
+ beforeIndex: number;
+ currentIndex: number;
+ groupType: string | undefined;
+ columnsCount: number;
+ insertDirection: InsertRowColumnsDirection;
+ }) => void;
className: string;
thProps: Partial<ReactTable.TableHeaderProps>;
onClick?: React.MouseEventHandler;
isLastLevelColumn: boolean;
rowIndex: number;
rowSpan: number;
+ columnKey: string;
columnIndex: number;
column: ReactTable.ColumnInstance<R>;
shouldShowColumnsInlineControls: boolean;
@@ -61,6 +69,7 @@ export function BeeTableTh<R extends object>({
thProps,
onClick,
columnIndex,
+ columnKey,
rowIndex,
rowSpan,
groupType,
@@ -81,8 +90,10 @@ export function BeeTableTh<R extends object>({
// This index doesn't take into account the rowIndex column, so we actually need to subtract 1.
onColumnAdded?.({
beforeIndex: hoverInfo.part === "left" ? columnIndex - 1 : columnIndex,
- currentIndex: columnIndex,
groupType: groupType,
+ columnsCount: 1,
+ insertDirection: InsertRowColumnsDirection.AboveOrRight,
+ currentIndex: columnIndex,
});
if (hoverInfo.part === "left") {
@@ -97,10 +108,14 @@ export function BeeTableTh<R extends object>({
const { beeGwtService } = useBoxedExpressionEditor();
useEffect(() => {
- if (isActive && column.isRowIndexColumn) {
- beeGwtService?.selectObject("");
+ if (isActive) {
+ if (column.isRowIndexColumn) {
+ beeGwtService?.selectObject("");
+ } else {
+ beeGwtService?.selectObject(columnKey);
+ }
}
- }, [beeGwtService, isActive]);
+ }, [beeGwtService, column.isRowIndexColumn, columnKey, isActive]);
const _thRef = useRef<HTMLTableCellElement>(null);
const thRef = forwardRef ?? _thRef;
diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx
index 226bc82c579..a64065a5174 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx
@@ -46,7 +46,7 @@ export interface BeeTableThResizableProps<R extends object> {
getColumnKey: (column: ReactTable.ColumnInstance<R>) => string;
getColumnLabel: (groupType: string | undefined) => string | undefined;
onExpressionHeaderUpdated: (args: Pick<ExpressionDefinition, "name" | "dataType">) => void;
- onHeaderClick: (columnKey: string) => () => void;
+ onHeaderClick?: (columnKey: string) => () => void;
reactTableInstance: ReactTable.TableInstance<R>;
headerCellInfo: React.ReactElement;
shouldShowColumnsInlineControls: boolean;
@@ -92,7 +92,7 @@ export function BeeTableThResizable<R extends object>({
}, [columnKey, column.dataType, column.groupType]);
const onClick = useMemo(() => {
- return onHeaderClick(columnKey);
+ return onHeaderClick?.(columnKey);
}, [columnKey, onHeaderClick]);
const { resizingWidth, setResizingWidth } = useBeeTableResizableCell(
@@ -167,7 +167,7 @@ export function BeeTableThResizable<R extends object>({
const getAppendToElement = useCallback(() => {
return headerCellRef.current!;
- }, [headerCellRef, headerCellRef.current]);
+ }, [headerCellRef]);
return (
<BeeTableTh<R>
@@ -187,6 +187,7 @@ export function BeeTableThResizable<R extends object>({
},
}}
onClick={onClick}
+ columnKey={columnKey}
columnIndex={columnIndex}
rowIndex={rowIndex}
rowSpan={rowSpan}
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png
index eb321305726..4899c476fae 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context.png
index f754cee37a5..ec8c6b96dfb 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/context/boxed-context.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table-routing.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table-routing.png
index 3804c389043..cc92aa4b1d2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table-routing.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table-routing.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table.png
index a03d31d956a..c4084db3ee1 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/decisionTable/decision-table.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-feel-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-feel-function.png
index 90f95610bf5..b86f36539fe 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-feel-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-feel-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-function-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-function-affordability-calculation.png
index 53af0285eee..2778b3b076a 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-function-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-function-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-java-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-java-function.png
index d65a1ed405b..7095b469801 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-java-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-java-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-pmml-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-pmml-function.png
index 0283a85c7ce..72b80d12f31 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-pmml-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/boxed-pmml-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/nested-boxed-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/nested-boxed-function.png
index b4f2a8cb7a1..639a117a1b3 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/nested-boxed-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/function/nested-boxed-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png
index ec62768429c..3740bcea500 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation.png
index 6eea25b04e0..a18fb9432c3 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/invocation/boxed-invocation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list-age-group.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list-age-group.png
index 2718d8af075..8f98ed74a44 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list-age-group.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list-age-group.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list.png
index 1b12d5c1199..f681ad98fef 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/list/boxed-list.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal-can-drive.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal-can-drive.png
index 87214ef9cd9..4e980de6aa0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal-can-drive.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal-can-drive.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal.png
index 62baf416bbf..0c3fe171942 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/literal/boxed-literal.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation-people.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation-people.png
index 25c74818775..af08f53f679 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation-people.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation-people.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation.png
index eaae2aac832..377d61d8cb9 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/boxedExpressions/relation/relation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/misc/emptyExpression/empty-boxed-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/misc/emptyExpression/empty-boxed-expression.png
index 482304c9726..7a9bb23f252 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/misc/emptyExpression/empty-boxed-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/misc/emptyExpression/empty-boxed-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/application-risk-score-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/application-risk-score-expression.png
index 4ba6016d95d..616085ae021 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/application-risk-score-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/application-risk-score-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png
index a5eafa31f86..7d575178504 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-eligibility-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-eligibility-expression.png
index 9f377a288d0..b1d91ae90ff 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-eligibility-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-eligibility-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png
index ff698aa8918..9b74500de77 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png
index 844c255883b..dff641e32d2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-strategy-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-strategy-expression.png
index ad22e90515b..5cc5e7153b0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-strategy-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/bureau-strategy-decision-service-strategy-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/can-drive-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/can-drive-expression.png
index 9fbe6693126..d0badcae36d 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/can-drive-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/can-drive-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/employees-expression.png
index 1226befe952..3e9ad8cf838 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-by-employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-by-employees-expression.png
index 529203ce428..82113a6a17c 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-by-employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-by-employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-employees-by-knowledge-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-employees-by-knowledge-expression.png
index 5a1f701f033..1c4820f9ef7 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-employees-by-knowledge-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/find-employees-by-knowledge-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-affordability-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-affordability-calculation-expression.png
index 713a5d34aee..4ebe9bc009d 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-affordability-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-affordability-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-installment-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-installment-calculation-expression.png
index 23e62a9808f..394ddd60aec 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-installment-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/function-installment-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/required-monthly-installment-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/required-monthly-installment-expression.png
index 55c3c573ff9..9738e01f750 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/required-monthly-installment-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/required-monthly-installment-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-affordability-expression.png
index 7b38ab3d375..a9d6bec3242 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-risk-category-expression.png
index af68ae80f4b..43031e2febf 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-post-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-routing-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-routing-expression.png
index d9c3c419e2b..d5bfc85d604 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-routing-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/Google-Chrome/useCases/routing-decision-service-routing-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png
index eb321305726..ab388dafea0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context.png
index f754cee37a5..ec8c6b96dfb 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/context/boxed-context.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table-routing.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table-routing.png
index 3804c389043..cc92aa4b1d2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table-routing.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table-routing.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table.png
index a03d31d956a..c4084db3ee1 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/decisionTable/decision-table.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-feel-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-feel-function.png
index 90f95610bf5..b86f36539fe 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-feel-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-feel-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-function-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-function-affordability-calculation.png
index 53af0285eee..2778b3b076a 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-function-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-function-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-java-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-java-function.png
index d65a1ed405b..7095b469801 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-java-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-java-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-pmml-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-pmml-function.png
index 0283a85c7ce..72b80d12f31 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-pmml-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/boxed-pmml-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/nested-boxed-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/nested-boxed-function.png
index b4f2a8cb7a1..353605187c2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/nested-boxed-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/function/nested-boxed-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png
index ec62768429c..3740bcea500 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation.png
index 6eea25b04e0..a18fb9432c3 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/invocation/boxed-invocation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list-age-group.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list-age-group.png
index 2718d8af075..8f98ed74a44 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list-age-group.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list-age-group.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list.png
index 1b12d5c1199..f681ad98fef 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/list/boxed-list.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal-can-drive.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal-can-drive.png
index b3749bb86e9..4e980de6aa0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal-can-drive.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal-can-drive.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal.png
index 62baf416bbf..0c3fe171942 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/literal/boxed-literal.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation-people.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation-people.png
index 25c74818775..af08f53f679 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation-people.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation-people.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation.png
index eaae2aac832..377d61d8cb9 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/boxedExpressions/relation/relation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/misc/emptyExpression/empty-boxed-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/misc/emptyExpression/empty-boxed-expression.png
index 482304c9726..7a9bb23f252 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/misc/emptyExpression/empty-boxed-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/misc/emptyExpression/empty-boxed-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/application-risk-score-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/application-risk-score-expression.png
index 4ba6016d95d..616085ae021 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/application-risk-score-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/application-risk-score-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png
index a5eafa31f86..7d575178504 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-eligibility-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-eligibility-expression.png
index 9f377a288d0..b1d91ae90ff 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-eligibility-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-eligibility-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png
index ff698aa8918..9b74500de77 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png
index 844c255883b..dff641e32d2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-strategy-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-strategy-expression.png
index ad22e90515b..5cc5e7153b0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-strategy-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/bureau-strategy-decision-service-strategy-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/can-drive-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/can-drive-expression.png
index 9fbe6693126..d0badcae36d 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/can-drive-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/can-drive-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/employees-expression.png
index 1226befe952..3e9ad8cf838 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-by-employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-by-employees-expression.png
index 529203ce428..82113a6a17c 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-by-employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-by-employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-employees-by-knowledge-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-employees-by-knowledge-expression.png
index 5a1f701f033..1c4820f9ef7 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-employees-by-knowledge-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/find-employees-by-knowledge-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-affordability-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-affordability-calculation-expression.png
index 713a5d34aee..4ebe9bc009d 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-affordability-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-affordability-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-installment-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-installment-calculation-expression.png
index 23e62a9808f..394ddd60aec 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-installment-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/function-installment-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/required-monthly-installment-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/required-monthly-installment-expression.png
index 55c3c573ff9..9738e01f750 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/required-monthly-installment-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/required-monthly-installment-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-affordability-expression.png
index 7b38ab3d375..a9d6bec3242 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-risk-category-expression.png
index af68ae80f4b..43031e2febf 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-post-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-routing-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-routing-expression.png
index d9c3c419e2b..d5bfc85d604 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-routing-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/chromium/useCases/routing-decision-service-routing-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png
index 309505e1c6a..426b261c4cc 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context-pre-bureau-risk-category.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context.png
index 7dc32606169..76d6f38f4d7 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/context/boxed-context.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table-routing.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table-routing.png
index 31fe825af09..5d0ebbb061b 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table-routing.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table-routing.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table.png
index 546146ac7e9..ec124d5e036 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/decisionTable/decision-table.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-feel-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-feel-function.png
index 90b1afc96e0..9781d57ccb3 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-feel-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-feel-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-function-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-function-affordability-calculation.png
index 6b130bcb9c7..a92ea4fe2ab 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-function-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-function-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-java-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-java-function.png
index 8fe2fe413a8..f987b099ec9 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-java-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-java-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-pmml-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-pmml-function.png
index 47471ba5175..b0365756c86 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-pmml-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/boxed-pmml-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/nested-boxed-function.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/nested-boxed-function.png
index 0ce626c6796..cc39f96ae75 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/nested-boxed-function.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/function/nested-boxed-function.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png
index 46321cfd056..01417a5d6df 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation-affordability-calculation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation.png
index a64d04d4725..901ed159d9a 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/invocation/boxed-invocation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list-age-group.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list-age-group.png
index 9e557afb5c2..0d7b65a1017 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list-age-group.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list-age-group.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list.png
index 6c7a1df2932..a1bdc958029 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/list/boxed-list.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal-can-drive.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal-can-drive.png
index 59f115445ff..97e5f4ecfd9 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal-can-drive.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal-can-drive.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal.png
index ad606ad3a9c..047eb0681e3 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/literal/boxed-literal.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation-people.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation-people.png
index 05cae59d0d8..7788bf54bea 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation-people.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation-people.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation.png
index c054aa97229..5dffff68ca6 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/boxedExpressions/relation/relation.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/misc/emptyExpression/empty-boxed-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/misc/emptyExpression/empty-boxed-expression.png
index ed0849fce20..bd4a74e5aa8 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/misc/emptyExpression/empty-boxed-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/misc/emptyExpression/empty-boxed-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/application-risk-score-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/application-risk-score-expression.png
index 9a4fa7f2902..97e9546d5dd 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/application-risk-score-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/application-risk-score-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png
index 70cbf332755..a17a0f492a7 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-bureau-call-type-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-eligibility-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-eligibility-expression.png
index cfcce41892e..3bcc6345396 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-eligibility-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-eligibility-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png
index 6fdc94fcef6..4bc180a1a90 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png
index 9f7cd0c8e34..1ede695cc85 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-pre-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-strategy-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-strategy-expression.png
index ae0fe383004..c0507801d67 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-strategy-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/bureau-strategy-decision-service-strategy-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/can-drive-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/can-drive-expression.png
index 04de8bf341c..64d25645558 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/can-drive-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/can-drive-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/employees-expression.png
index b406453ba9f..1ca23589f12 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-by-employees-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-by-employees-expression.png
index 4a3eee53aa4..69cc4aedc47 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-by-employees-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-by-employees-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-employees-by-knowledge-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-employees-by-knowledge-expression.png
index 18a1844fa68..adda4e4e3db 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-employees-by-knowledge-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/find-employees-by-knowledge-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-affordability-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-affordability-calculation-expression.png
index 51ab6a203a6..edd3016a36d 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-affordability-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-affordability-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-installment-calculation-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-installment-calculation-expression.png
index 83d016d9bc9..f4bd04cf2da 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-installment-calculation-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/function-installment-calculation-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/required-monthly-installment-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/required-monthly-installment-expression.png
index 96485fddce7..350f4da0058 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/required-monthly-installment-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/required-monthly-installment-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-affordability-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-affordability-expression.png
index 76f5430f1e9..82b633effb2 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-affordability-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-affordability-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-risk-category-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-risk-category-expression.png
index ca32c889b04..c6533c9c6d0 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-risk-category-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-post-bureau-risk-category-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-routing-expression.png b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-routing-expression.png
index c180da52cd6..7c7f6d5c02f 100644
Binary files a/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-routing-expression.png and b/packages/boxed-expression-component/tests/e2e/__screenshots__/webkit/useCases/routing-decision-service-routing-expression.png differ
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeader.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeader.spec.ts
index 4886fd74655..beb239a9537 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeader.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeader.spec.ts
@@ -33,7 +33,6 @@ test.describe("Boxed expression header", () => {
test("should reset expression", async ({ page }) => {
await page.getByTestId("logic-type-button-test-id").click();
await page.getByRole("menuitem", { name: "Reset" }).click();
- await expect(page.getByText("Expression Name (<Undefined>)")).toBeAttached();
await expect(page.getByText("Select expression")).toBeAttached();
});
@@ -43,19 +42,15 @@ test.describe("Boxed expression header", () => {
await page.getByRole("menuitem", { name: "copy" }).click();
await page.getByTestId("logic-type-button-test-id").click();
await page.getByRole("menuitem", { name: "Reset" }).click();
- await expect(page.getByText("Expression Name (Literal)")).not.toBeAttached();
await page.getByText("Select expression").click();
await page.getByRole("menuitem", { name: "Paste" }).click();
- await expect(page.getByText("Expression Name (Literal)")).toBeAttached();
});
test("should cut and paste expression", async ({ page, clipboard }) => {
await page.getByTestId("logic-type-button-test-id").click();
clipboard.use();
await page.getByRole("menuitem", { name: "cut" }).click();
- await expect(page.getByText("Expression Name (Literal)")).not.toBeAttached();
await page.getByText("Select expression").click();
await page.getByRole("menuitem", { name: "Paste" }).click();
- await expect(page.getByText("Expression Name (Literal)")).toBeAttached();
});
});
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeaderMenu.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeaderMenu.spec.ts
index d9d0d71df96..8a19d2b0578 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeaderMenu.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/boxedExpressionHeaderMenu.spec.ts
@@ -35,7 +35,6 @@ test.describe("Boxed expression header menu popover", () => {
await expect(page.getByLabel("years and months duration")).toBeAttached();
await page.keyboard.press("Enter");
- await expect(page.getByText("Test (Literal)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Test (years and months duration)" })).toBeAttached();
});
@@ -54,7 +53,6 @@ test.describe("Boxed expression header menu popover", () => {
await expect(page.getByLabel("years and months duration")).toBeAttached();
await page.keyboard.press("Escape");
- await expect(page.getByText("Expression Name (Literal)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
});
});
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/context/contextExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/context/contextExpression.spec.ts
index c3ce2e8be21..737902e5441 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/context/contextExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/context/contextExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Create Boxed Context", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, stories, page }) => {
await stories.openBoxedContext();
- await expect(page.getByText("Expression Name (Context)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("cell", { name: "ContextEntry-1 (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("cell", { name: "<result>" })).toBeAttached();
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/decisionTable/decisionTableExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/decisionTable/decisionTableExpression.spec.ts
index 1a4e5d7dde9..ad6b5180527 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/decisionTable/decisionTableExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/decisionTable/decisionTableExpression.spec.ts
@@ -25,7 +25,6 @@ test.describe("Create Decision table", () => {
});
test("should render expression correctly", async ({ boxedExpressionEditor, page }) => {
- await expect(page.getByText("Expression Name (Decision Table)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "input-1 (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "annotation-1" })).toBeAttached();
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/function/functionExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/function/functionExpression.spec.ts
index f987bb32e37..9399d6b963d 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/function/functionExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/function/functionExpression.spec.ts
@@ -25,7 +25,6 @@ test.describe("Create Boxed Function", () => {
});
test("should render FEEL function expression correctly", async ({ boxedExpressionEditor, page }) => {
- await expect(page.getByText("Expression Name (Function)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "F", exact: true })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Edit parameters" })).toBeAttached();
@@ -36,7 +35,6 @@ test.describe("Create Boxed Function", () => {
});
test("should render Java function expression correctly", async ({ boxedExpressionEditor, page }) => {
- await expect(page.getByText("Expression Name (Function)")).toBeAttached();
await page.getByRole("columnheader", { name: "F", exact: true }).click();
await page.getByRole("menuitem", { name: "Java" }).click();
await expect(boxedExpressionEditor.getContainer()).toHaveScreenshot("boxed-java-function.png");
@@ -55,7 +53,6 @@ test.describe("Create Boxed Function", () => {
});
test("should render PMML function expression correctly", async ({ boxedExpressionEditor, page }) => {
- await expect(page.getByText("Expression Name (Function)")).toBeAttached();
await page.getByRole("columnheader", { name: "F", exact: true }).click();
await page.getByRole("menuitem", { name: "PMML" }).click();
await expect(boxedExpressionEditor.getContainer()).toHaveScreenshot("boxed-pmml-function.png");
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/invocation/invocationExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/invocation/invocationExpression.spec.ts
index b15f361bf85..0f493db18a7 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/invocation/invocationExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/invocation/invocationExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Create Boxed Invocation", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, stories, page }) => {
await stories.openBoxedInvocation();
- await expect(page.getByText("Expression Name (Invocation)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "FUNCTION" })).toBeAttached();
await expect(page.getByRole("cell", { name: "p-1" })).toBeAttached();
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/list/listExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/list/listExpression.spec.ts
index 7e20b04aea3..d90aec4833a 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/list/listExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/list/listExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Create Boxed List", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, stories, page }) => {
await stories.openBoxedList();
- await expect(page.getByText("Expression Name (List)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "#", exact: true })).toBeAttached();
await expect(page.getByText("Select expression")).toHaveCount(1);
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/literal/literalExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/literal/literalExpression.spec.ts
index 544e17e1821..d82b15ce125 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/literal/literalExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/literal/literalExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Create Boxed Literal", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, stories, page }) => {
await stories.openBoxedLiteral();
- await expect(page.getByText("Expression Name (Literal)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("cell")).toHaveCount(1);
await expect(boxedExpressionEditor.getContainer()).toHaveScreenshot("boxed-literal.png");
diff --git a/packages/boxed-expression-component/tests/e2e/boxedExpressions/relation/relationExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/boxedExpressions/relation/relationExpression.spec.ts
index a742e59a11b..389753ac97f 100644
--- a/packages/boxed-expression-component/tests/e2e/boxedExpressions/relation/relationExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/boxedExpressions/relation/relationExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Create Relation", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, stories, page }) => {
await stories.openRelation();
- await expect(page.getByText("Expression Name (Relation)")).toBeAttached();
await expect(page.getByRole("columnheader", { name: "Expression Name (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "column-1 (<Undefined>)" })).toBeAttached();
await expect(page.getByRole("columnheader", { name: "#", exact: true })).toBeAttached();
diff --git a/packages/boxed-expression-component/tests/e2e/features/resizing/resizing.spec.ts b/packages/boxed-expression-component/tests/e2e/features/resizing/resizing.spec.ts
index e789c3babe8..e541d818bb8 100644
--- a/packages/boxed-expression-component/tests/e2e/features/resizing/resizing.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/features/resizing/resizing.spec.ts
@@ -253,7 +253,7 @@ test.describe("Resizing", () => {
await resizing.resizeCell(inputHeader, { x: 0, y: 0 }, { x: 50, y: 0 });
expect(await inputHeader.boundingBox()).toHaveProperty("width", 150);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await inputHeader.hover({ position: { x: 0, y: 0 } });
await inputHeader.locator("svg").click();
@@ -263,11 +263,11 @@ test.describe("Resizing", () => {
100
);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(inputHeader);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should change input column name and reset size", async ({ page, resizing, browserName }) => {
@@ -281,7 +281,7 @@ test.describe("Resizing", () => {
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(inputHeader);
if (browserName === "webkit") {
expect(await inputHeader.boundingBox()).toHaveProperty("width", 179);
@@ -289,7 +289,7 @@ test.describe("Resizing", () => {
expect(await inputHeader.boundingBox()).toHaveProperty("width", 173);
}
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should resize output column and add new columns", async ({ page, resizing }) => {
@@ -300,7 +300,7 @@ test.describe("Resizing", () => {
await resizing.resizeCell(outputHeader, { x: 0, y: 0 }, { x: 50, y: 0 });
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 150);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await outputHeader.hover({ position: { x: 0, y: 0 } });
await outputHeader.locator("svg").click();
const output1 = page.getByRole("columnheader", { name: "output-1 (<Undefined>)" });
@@ -310,13 +310,13 @@ test.describe("Resizing", () => {
expect(await outputHeader.boundingBox()).toHaveProperty("width", 250);
expect(await output1.boundingBox()).toHaveProperty("width", 150);
expect(await output2.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(outputHeader);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 200);
expect(await output1.boundingBox()).toHaveProperty("width", 100);
expect(await output2.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should change decision name and reset to fit", async ({ page, resizing, browserName }) => {
@@ -330,7 +330,7 @@ test.describe("Resizing", () => {
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(outputHeader);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
if (browserName === "webkit") {
@@ -338,7 +338,7 @@ test.describe("Resizing", () => {
} else {
expect(await outputHeader.boundingBox()).toHaveProperty("width", 173);
}
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should add new output columns rename decision and resize to fit to proportionally distribute", async ({
@@ -365,7 +365,7 @@ test.describe("Resizing", () => {
expect(await header.boundingBox()).toHaveProperty("width", 200);
expect(await output1.boundingBox()).toHaveProperty("width", 100);
expect(await output2.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(header);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
if (browserName === "webkit") {
@@ -374,10 +374,10 @@ test.describe("Resizing", () => {
expect(await output2.boundingBox()).toHaveProperty("width", 163);
} else {
expect(await header.boundingBox()).toHaveProperty("width", 315);
- expect(await output1.boundingBox()).toHaveProperty("width", 157);
- expect(await output2.boundingBox()).toHaveProperty("width", 158);
+ expect(await output1.boundingBox()).toHaveProperty("width", 158);
+ expect(await output2.boundingBox()).toHaveProperty("width", 157);
}
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should add new output columns and resize to fit", async ({ page, resizing, browserName }) => {
@@ -398,7 +398,7 @@ test.describe("Resizing", () => {
expect(await outputHeader.boundingBox()).toHaveProperty("width", 200);
expect(await output1.boundingBox()).toHaveProperty("width", 100);
expect(await output2.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(output1);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
if (browserName === "webkit") {
@@ -409,7 +409,7 @@ test.describe("Resizing", () => {
expect(await output1.boundingBox()).toHaveProperty("width", 173);
}
expect(await output2.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
});
test("should resize annotation column and reset", async ({ page, resizing, browserName }) => {
@@ -420,11 +420,8 @@ test.describe("Resizing", () => {
await resizing.resizeCell(annotationsHeader, { x: 0, y: 0 }, { x: 50, y: 0 });
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 150);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 290);
- expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 150);
await resizing.reset(annotationsHeader);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
@@ -446,7 +443,7 @@ test.describe("Resizing", () => {
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
- expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 100);
+ expect(await annotationsHeader.boundingBox()).toHaveProperty("width", 240);
await resizing.reset(annotationsHeader);
expect(await inputHeader.boundingBox()).toHaveProperty("width", 100);
expect(await outputHeader.boundingBox()).toHaveProperty("width", 100);
diff --git a/packages/boxed-expression-component/tests/e2e/misc/emptyExpression/emptyExpression.spec.ts b/packages/boxed-expression-component/tests/e2e/misc/emptyExpression/emptyExpression.spec.ts
index 69c4a61761d..765cc4ae201 100644
--- a/packages/boxed-expression-component/tests/e2e/misc/emptyExpression/emptyExpression.spec.ts
+++ b/packages/boxed-expression-component/tests/e2e/misc/emptyExpression/emptyExpression.spec.ts
@@ -22,7 +22,6 @@ import { test, expect } from "../../__fixtures__/base";
test.describe("Empty Expression", () => {
test("should render expression correctly", async ({ boxedExpressionEditor, page }) => {
await boxedExpressionEditor.goto();
- await expect(page.getByText("Expression Name (<Undefined>)")).toBeAttached();
await expect(page.getByText("Select expression")).toHaveCount(1);
await expect(boxedExpressionEditor.getContainer()).toHaveScreenshot("empty-boxed-expression.png");
});
diff --git a/packages/bpmn-marshaller/src/index.ts b/packages/bpmn-marshaller/src/index.ts
index 841e2ddf046..434642fda7f 100644
--- a/packages/bpmn-marshaller/src/index.ts
+++ b/packages/bpmn-marshaller/src/index.ts
@@ -56,7 +56,7 @@ export function getMarshaller(xml: string): BpmnMarshaller {
version: "2.0",
root: bpmn20root,
meta: bpmn20meta,
- parser: { parse: () => p.parse({ xml, domdoc, instanceNs }).json },
+ parser: { parse: () => p.parse({ type: "domdoc", domdoc, instanceNs }).json },
builder: { build: (json: BpmnDefinitions) => p.build({ json, instanceNs }) },
};
}
diff --git a/packages/bpmn-vscode-extension/webpack.config.js b/packages/bpmn-vscode-extension/webpack.config.js
index 69b1706e3d3..b86a5bec776 100644
--- a/packages/bpmn-vscode-extension/webpack.config.js
+++ b/packages/bpmn-vscode-extension/webpack.config.js
@@ -22,6 +22,7 @@ const patternflyBase = require("@kie-tools-core/patternfly-base");
const stunnerEditors = require("@kie-tools/stunner-editors");
const vscodeJavaCodeCompletionExtensionPlugin = require("@kie-tools/vscode-java-code-completion-extension-plugin");
const { merge } = require("webpack-merge");
+const { ProvidePlugin } = require("webpack");
const common = require("@kie-tools-core/webpack-base/webpack.common.config");
const commonConfig = (env) =>
@@ -43,7 +44,12 @@ module.exports = async (env) => [
entry: {
"extension/extension": "./src/extension/extension.ts",
},
- plugins: [],
+ plugins: [
+ new ProvidePlugin({
+ process: require.resolve("process/browser.js"),
+ Buffer: ["buffer", "Buffer"],
+ }),
+ ],
}),
merge(commonConfig(env), {
target: "web",
diff --git a/packages/chrome-extension-test-helper/src/framework/github-repo/GitHubRepoPage.ts b/packages/chrome-extension-test-helper/src/framework/github-repo/GitHubRepoPage.ts
index 3c0d6563efd..36beb4bbcd8 100644
--- a/packages/chrome-extension-test-helper/src/framework/github-repo/GitHubRepoPage.ts
+++ b/packages/chrome-extension-test-helper/src/framework/github-repo/GitHubRepoPage.ts
@@ -1,3 +1,22 @@
+/*
+ * 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 { By, Key } from "selenium-webdriver";
import Page from "../Page";
diff --git a/packages/chrome-extension/src/app/components/common/KogitoEditorIframe.tsx b/packages/chrome-extension/src/app/components/common/KogitoEditorIframe.tsx
index f9324734859..49ed4085017 100644
--- a/packages/chrome-extension/src/app/components/common/KogitoEditorIframe.tsx
+++ b/packages/chrome-extension/src/app/components/common/KogitoEditorIframe.tsx
@@ -77,6 +77,7 @@ const RefForwardingKogitoEditorIframe: React.ForwardRefRenderFunction<IsolatedEd
fileExtension: props.openFileExtension,
getFileContents: props.getFileContents,
isReadOnly: props.readonly,
+ path: props.contentPath,
};
}, [props.contentPath, props.openFileExtension, props.getFileContents, props.readonly]);
diff --git a/packages/dashbuilder-component-map/src/Map.tsx b/packages/dashbuilder-component-map/src/Map.tsx
index 4792afd0300..73ad753a8fa 100644
--- a/packages/dashbuilder-component-map/src/Map.tsx
+++ b/packages/dashbuilder-component-map/src/Map.tsx
@@ -1,3 +1,22 @@
+/*
+ * 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 { ComponentController } from "@kie-tools/dashbuilder-component-api";
import React from "react";
import { ComposableMap, Geographies, Geography, Marker, ZoomableGroup } from "react-simple-maps";
diff --git a/packages/dashbuilder-component-map/src/MapComponent.tsx b/packages/dashbuilder-component-map/src/MapComponent.tsx
index 99dc58605f1..a2bbc1b18a9 100644
--- a/packages/dashbuilder-component-map/src/MapComponent.tsx
+++ b/packages/dashbuilder-component-map/src/MapComponent.tsx
@@ -1,3 +1,22 @@
+/*
+ * 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 { ComponentController, DataSet } from "@kie-tools/dashbuilder-component-api";
import React, { useCallback, useEffect, useState } from "react";
import { MapMarker, MarkType, Props as MapProps, SimpleReactMap } from "./Map";
diff --git a/packages/dashbuilder-component-victory-charts/src/charts/PropsValidation.tsx b/packages/dashbuilder-component-victory-charts/src/charts/PropsValidation.tsx
index c41b306a9c0..165d1acf60b 100644
--- a/packages/dashbuilder-component-victory-charts/src/charts/PropsValidation.tsx
+++ b/packages/dashbuilder-component-victory-charts/src/charts/PropsValidation.tsx
@@ -1,3 +1,22 @@
+/*
+ * 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 { DataSet } from "@kie-tools/dashbuilder-component-api";
import { ChartType } from "./BaseChart";
diff --git a/packages/dashbuilder-editor/src/monaco/augmentation/widgets/index.tsx b/packages/dashbuilder-editor/src/monaco/augmentation/widgets/index.tsx
index eb926f40def..57ede748bd6 100644
--- a/packages/dashbuilder-editor/src/monaco/augmentation/widgets/index.tsx
+++ b/packages/dashbuilder-editor/src/monaco/augmentation/widgets/index.tsx
@@ -1,3 +1,22 @@
+/*
+ * 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 { editor, Position } from "monaco-editor";
export interface Holder<T> {
diff --git a/packages/dashbuilder-editor/tests/jest.setup.ts b/packages/dashbuilder-editor/tests/jest.setup.ts
index f23267ef470..1c413b1660e 100644
--- a/packages/dashbuilder-editor/tests/jest.setup.ts
+++ b/packages/dashbuilder-editor/tests/jest.setup.ts
@@ -18,6 +18,3 @@
*/
import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
-
-enableAllPlugins();
diff --git a/packages/dashbuilder-language-service/src/assets/code-completions/dashbuilder-completion.ts b/packages/dashbuilder-language-service/src/assets/code-completions/dashbuilder-completion.ts
index f1b426f36d4..52b24d06d6d 100644
--- a/packages/dashbuilder-language-service/src/assets/code-completions/dashbuilder-completion.ts
+++ b/packages/dashbuilder-language-service/src/assets/code-completions/dashbuilder-completion.ts
@@ -1,3 +1,22 @@
+/*
+ * 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.
+ */
+
export const dashbuilderCompletion = `datasets:
- uuid: products
content: >-
diff --git a/packages/dashbuilder-language-service/src/assets/code-completions/index.ts b/packages/dashbuilder-language-service/src/assets/code-completions/index.ts
index 512c25ecab9..407942be9ef 100644
--- a/packages/dashbuilder-language-service/src/assets/code-completions/index.ts
+++ b/packages/dashbuilder-language-service/src/assets/code-completions/index.ts
@@ -1 +1,20 @@
+/*
+ * 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.
+ */
+
export * from "./dashbuilder-completion";
diff --git a/packages/dashbuilder-viewer/tests/jest.setup.ts b/packages/dashbuilder-viewer/tests/jest.setup.ts
index f23267ef470..1c413b1660e 100644
--- a/packages/dashbuilder-viewer/tests/jest.setup.ts
+++ b/packages/dashbuilder-viewer/tests/jest.setup.ts
@@ -18,6 +18,3 @@
*/
import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
-
-enableAllPlugins();
diff --git a/packages/dev-deployment-kogito-quarkus-blank-app/src/main/resources/application.properties b/packages/dev-deployment-kogito-quarkus-blank-app/src/main/resources/application.properties
index ca69ae00816..fd3a8268b1c 100644
--- a/packages/dev-deployment-kogito-quarkus-blank-app/src/main/resources/application.properties
+++ b/packages/dev-deployment-kogito-quarkus-blank-app/src/main/resources/application.properties
@@ -2,4 +2,5 @@ quarkus.swagger-ui.always-include=true
quarkus.http.cors=true
quarkus.http.cors.origins=/.*/
kogito.service.url=http://localhost:8080
+kogito.decisions.validation=IGNORE
quarkus.http.host=0.0.0.0
diff --git a/packages/dmn-editor-envelope/README.md b/packages/dmn-editor-envelope/README.md
new file mode 100644
index 00000000000..c5e5dad0d9f
--- /dev/null
+++ b/packages/dmn-editor-envelope/README.md
@@ -0,0 +1,3 @@
+## DMN Editor Envelopedmn
+
+Package responsible for creating the necessary pumbling for `dmn-editor` to be used inside an Envelope.
diff --git a/packages/dashbuilder-viewer/tests/jest.setup.ts b/packages/dmn-editor-envelope/env/index.js
similarity index 79%
copy from packages/dashbuilder-viewer/tests/jest.setup.ts
copy to packages/dmn-editor-envelope/env/index.js
index f23267ef470..61bc742bd66 100644
--- a/packages/dashbuilder-viewer/tests/jest.setup.ts
+++ b/packages/dmn-editor-envelope/env/index.js
@@ -17,7 +17,11 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");
-enableAllPlugins();
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+ vars: varsWithName({}),
+ get env() {
+ return {};
+ },
+});
diff --git a/packages/boxed-expression-component/src/api/BeeGwtService.ts b/packages/dmn-editor-envelope/jest.config.js
similarity index 61%
copy from packages/boxed-expression-component/src/api/BeeGwtService.ts
copy to packages/dmn-editor-envelope/jest.config.js
index efd0df23e14..6ada62559f3 100644
--- a/packages/boxed-expression-component/src/api/BeeGwtService.ts
+++ b/packages/dmn-editor-envelope/jest.config.js
@@ -17,13 +17,18 @@
* under the License.
*/
-import { ExpressionDefinition } from "./ExpressionDefinition";
-
-/**
- * This interface defines all the API methods which BoxedExpressionEditor component can use to dialog with GWT Layer
- */
-export interface BeeGwtService {
- getDefaultExpressionDefinition(logicType: string, dataType: string): ExpressionDefinition;
- openDataTypePage: () => void; // Just open the data types tab
- selectObject: (uuid?: string) => void; // Changes the Properties panel
-}
+module.exports = {
+ globals: {
+ "ts-jest": {
+ tsconfig: "<rootDir>/tsconfig.json",
+ },
+ },
+ reporters: ["default", ["jest-junit", { outputFile: "./dist-tests/junit-report.xml" }]],
+ moduleDirectories: ["node_modules"],
+ moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
+ testRegex: "/tests/.*\\.test\\.(jsx?|tsx?)$",
+ transform: {
+ "^.+\\.jsx?$": ["babel-jest", { presets: [["@babel/env", { targets: { node: "current" } }], "@babel/react"] }],
+ "^.+\\.tsx?$": "ts-jest",
+ },
+};
diff --git a/packages/vscode-extension/package.json b/packages/dmn-editor-envelope/package.json
similarity index 57%
copy from packages/vscode-extension/package.json
copy to packages/dmn-editor-envelope/package.json
index 025ff700ba8..5fae553a21f 100644
--- a/packages/vscode-extension/package.json
+++ b/packages/dmn-editor-envelope/package.json
@@ -1,43 +1,42 @@
{
- "name": "@kie-tools-core/vscode-extension",
+ "name": "@kie-tools/dmn-editor-envelope",
"version": "0.0.0",
"description": "",
"license": "Apache-2.0",
- "publisher": "kie-group",
"keywords": [],
- "homepage": "https://github.com/apache/incubator-kie-tools",
+ "homepage": "https://github.com/kiegroup/kie-tools",
"repository": {
"type": "git",
- "url": "https://github.com/apache/incubator-kie-tools.git"
+ "url": "https://github.com/kiegroup/kie-tools.git"
},
"bugs": {
- "url": "https://github.com/apache/incubator-kie-tools/issues"
+ "url": "https://github.com/kiegroup/kie-tools/issues"
},
- "types": "./dist/index.d.ts",
- "main": "dist/index.js",
"files": [
"dist",
"src"
],
"scripts": {
"build:dev": "rimraf dist && tsc -p tsconfig.json",
- "build:prod": "rimraf dist && pnpm lint && tsc -p tsconfig.json && pnpm test",
- "compile": "webpack",
+ "build:prod": "rimraf dist && pnpm lint && tsc -p tsconfig.json && pnpm test && pnpm test:it",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then \"kie-tools--eslint ./src\"",
"test": "run-script-if --ignore-errors \"$(build-env tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest --silent --verbose --passWithNoTests\"",
- "watch": "webpack"
+ "test:it": "echo 'No IT tests to run at this moment.'"
},
"dependencies": {
- "@kie-tools-core/backend": "workspace:*",
"@kie-tools-core/editor": "workspace:*",
+ "@kie-tools-core/envelope": "workspace:*",
"@kie-tools-core/envelope-bus": "workspace:*",
- "@kie-tools-core/i18n": "workspace:*",
- "@kie-tools-core/keyboard-shortcuts": "workspace:*",
"@kie-tools-core/notifications": "workspace:*",
- "@kie-tools-core/vscode-java-code-completion": "workspace:*",
+ "@kie-tools-core/react-hooks": "workspace:*",
"@kie-tools-core/workspace": "workspace:*",
- "@types/vscode": "1.67.0",
- "minimatch": "^3.0.5"
+ "@kie-tools/boxed-expression-component": "workspace:*",
+ "@kie-tools/dmn-editor": "workspace:*",
+ "@kie-tools/dmn-marshaller": "workspace:*",
+ "@kie-tools/pmml-editor-marshaller": "workspace:*",
+ "@kie-tools/xml-parser-ts": "workspace:*",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
@@ -46,15 +45,19 @@
"@kie-tools/eslint": "workspace:*",
"@kie-tools/root-env": "workspace:*",
"@kie-tools/tsconfig": "workspace:*",
+ "@testing-library/jest-dom": "^5.16.1",
+ "@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
"@types/jest-when": "^2.7.4",
- "@types/minimatch": "^3.0.5",
+ "@types/react": "^17.0.6",
+ "@types/react-dom": "^17.0.5",
+ "@types/testing-library__jest-dom": "^5.9.1",
+ "@types/testing-library__react": "^9.1.2",
"jest": "^26.6.3",
"jest-junit": "^14.0.0",
"jest-when": "^3.5.0",
"rimraf": "^3.0.2",
"ts-jest": "^26.5.6",
"typescript": "^4.6.2"
- },
- "displayName": "KIE :: Kogito Editors"
+ }
}
\ No newline at end of file
diff --git a/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx b/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx
new file mode 100644
index 00000000000..e38ac94ce97
--- /dev/null
+++ b/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx
@@ -0,0 +1,171 @@
+/*
+ * 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 {
+ Editor,
+ EditorFactory,
+ EditorInitArgs,
+ KogitoEditorEnvelopeContextType,
+ KogitoEditorChannelApi,
+ EditorTheme,
+ DEFAULT_WORKING_DIR_BASE_PATH,
+} from "@kie-tools-core/editor/dist/api";
+import { Notification } from "@kie-tools-core/notifications/dist/api";
+import { DmnEditorRoot } from "./DmnEditorRoot";
+import { ResourceContent, ResourcesList, WorkspaceEdit } from "@kie-tools-core/workspace/dist/api";
+
+export class DmnEditorFactory implements EditorFactory<Editor, KogitoEditorChannelApi> {
+ public createEditor(
+ envelopeContext: KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>,
+ initArgs: EditorInitArgs
+ ): Promise<Editor> {
+ return Promise.resolve(new DmnEditorInterface(envelopeContext, initArgs));
+ }
+}
+
+export class DmnEditorInterface implements Editor {
+ private self: DmnEditorRoot;
+ public af_isReact = true;
+ public af_componentId: "dmn-editor";
+ public af_componentTitle: "DMN Editor";
+
+ constructor(
+ private readonly envelopeContext: KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>,
+ private readonly initArgs: EditorInitArgs
+ ) {}
+
+ // Not in-editor
+
+ public getPreview(): Promise<string | undefined> {
+ return Promise.resolve(`
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
+ width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
+ <g transform="matrix(1 0 0 1 540 540)" id="ee1530d3-d469-49de-b8ad-62ffb6e5db7a"></g>
+ <g transform="matrix(1 0 0 1 540 540)" id="b6eca5e2-94e1-4e3f-a04e-16bc0ada9ea4">
+ <rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
+ </g>
+ <g transform="matrix(0.68 0 0 0.68 540 292.07)" style="" id="12bd02ec-b291-4d62-acdc-3fdd30cc84d7" >
+ <text xml:space="preserve" font-family="Raleway" font-size="105" font-style="normal" font-weight="900" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1; white-space: pre;" >
+ <tspan x="-187.11" y="-26.34" >Not yet</tspan>
+ <tspan x="-351.65" y="92.31" >implemented</tspan>
+ </text>
+ </g>
+ <g transform="matrix(1 0 0 1 523.42 454.97)" style="" id="b2ea8c5b-9fc6-43c0-9e3f-5837adab8b51" >
+ <text xml:space="preserve" font-family="Alegreya" font-size="44" font-style="normal" font-weight="700" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1; white-space: pre;" >
+ <tspan x="-270.07" y="-11.04" style="white-space: pre; ">Use the legacy DMN Editor to </tspan>
+ <tspan x="-251.26" y="38.68" >generate SVGs temporarily.</tspan>
+ </text>
+ </g>
+</svg>`);
+ }
+
+ public async validate(): Promise<Notification[]> {
+ return Promise.resolve([]);
+ }
+
+ // Forwarding to the editor
+
+ public async setTheme(theme: EditorTheme): Promise<void> {
+ return Promise.resolve(); // No-op for now. The DMN Editor only has the LIGHT theme.
+ }
+
+ public async undo(): Promise<void> {
+ return this.self.undo();
+ }
+
+ public async redo(): Promise<void> {
+ return this.self.redo();
+ }
+
+ public getContent(): Promise<string> {
+ return this.self.getContent();
+ }
+
+ public setContent(path: string, content: string): Promise<void> {
+ return this.self.setContent(path, content);
+ }
+
+ // This is the argument to ReactDOM.render. These props can be understood like "static globals".
+ public af_componentRoot() {
+ return (
+ <DmnEditorRootWrapper
+ exposing={(dmnEditorRoot) => (this.self = dmnEditorRoot)}
+ envelopeContext={this.envelopeContext}
+ workingDirBasePath={this.initArgs.workingDirBasePath ?? DEFAULT_WORKING_DIR_BASE_PATH}
+ />
+ );
+ }
+}
+
+// This component is a wrapper. It memoizes the DmnEditorRoot props beforing rendering it.
+function DmnEditorRootWrapper({
+ envelopeContext,
+ exposing,
+ workingDirBasePath,
+}: {
+ envelopeContext?: KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>;
+ exposing: (s: DmnEditorRoot) => void;
+ workingDirBasePath: string;
+}) {
+ const onNewEdit = React.useCallback(
+ (workspaceEdit: WorkspaceEdit) => {
+ envelopeContext?.channelApi.notifications.kogitoWorkspace_newEdit.send(workspaceEdit);
+ },
+ [envelopeContext]
+ );
+
+ const onRequestFileList = React.useCallback(
+ async (resource: ResourcesList) => {
+ return (
+ envelopeContext?.channelApi.requests.kogitoWorkspace_resourceListRequest(resource) ?? new ResourcesList("", [])
+ );
+ },
+ [envelopeContext]
+ );
+
+ const onRequestFileContent = React.useCallback(
+ async (resource: ResourceContent) => {
+ return envelopeContext?.channelApi.requests.kogitoWorkspace_resourceContentRequest(resource);
+ },
+ [envelopeContext]
+ );
+
+ const onOpenFile = React.useCallback(
+ (path: string) => {
+ envelopeContext?.channelApi.notifications.kogitoWorkspace_openFile.send(path);
+ },
+ [envelopeContext]
+ );
+
+ return (
+ <DmnEditorRoot
+ exposing={exposing}
+ onNewEdit={onNewEdit}
+ onRequestFileList={onRequestFileList}
+ onRequestFileContent={onRequestFileContent}
+ onOpenFile={onOpenFile}
+ workingDirBasePath={workingDirBasePath}
+ />
+ );
+}
diff --git a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
new file mode 100644
index 00000000000..87c30bd0108
--- /dev/null
+++ b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
@@ -0,0 +1,415 @@
+/*
+ * 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 __path from "path";
+import * as React from "react";
+import * as DmnEditor from "@kie-tools/dmn-editor/dist/DmnEditor";
+import { getMarshaller } from "@kie-tools/dmn-marshaller";
+import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import {
+ ContentType,
+ ResourceContent,
+ SearchType,
+ WorkspaceChannelApi,
+ WorkspaceEdit,
+} from "@kie-tools-core/workspace/dist/api";
+import { DMN15_SPEC } from "@kie-tools/dmn-editor/dist/Dmn15Spec";
+import { DMN_LATEST_VERSION, DmnLatestModel, DmnMarshaller } from "@kie-tools/dmn-marshaller";
+import { domParser } from "@kie-tools/xml-parser-ts";
+import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
+import { useEffect, useMemo, useState } from "react";
+import { XML2PMML } from "@kie-tools/pmml-editor-marshaller";
+import { getPmmlNamespace } from "@kie-tools/dmn-editor/dist/pmml/pmml";
+import { getNamespaceOfDmnImport } from "@kie-tools/dmn-editor/dist/includedModels/importNamespaces";
+import {
+ imperativePromiseHandle,
+ PromiseImperativeHandle,
+} from "@kie-tools-core/react-hooks/dist/useImperativePromiseHandler";
+
+export const EXTERNAL_MODELS_SEARCH_GLOB_PATTERN = "**/*.{dmn,pmml}";
+
+export const EMPTY_DMN = () => `<?xml version="1.0" encoding="UTF-8"?>
+<definitions
+ xmlns="${dmn15ns.get("")}"
+ expressionLanguage="${DMN15_SPEC.expressionLanguage.default}"
+ namespace="https://kie.org/dmn/${generateUuid()}"
+ id="${generateUuid()}"
+ name="DMN${generateUuid()}">
+</definitions>`;
+
+export type DmnEditorRootProps = {
+ exposing: (s: DmnEditorRoot) => void;
+ onNewEdit: (edit: WorkspaceEdit) => void;
+ onRequestFileList: WorkspaceChannelApi["kogitoWorkspace_resourceListRequest"];
+ onRequestFileContent: WorkspaceChannelApi["kogitoWorkspace_resourceContentRequest"];
+ onOpenFile: WorkspaceChannelApi["kogitoWorkspace_openFile"];
+ workingDirBasePath: string;
+};
+
+export type DmnEditorRootState = {
+ marshaller: DmnMarshaller<typeof DMN_LATEST_VERSION> | undefined;
+ stack: DmnLatestModel[];
+ pointer: number;
+ absolutePath: string | undefined;
+ externalModelsByNamespace: DmnEditor.ExternalModelsIndex;
+ readonly: boolean;
+ externalModelsManagerDoneBootstraping: boolean;
+};
+
+export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditorRootState> {
+ private readonly externalModelsManagerDoneBootstraping = imperativePromiseHandle<void>();
+
+ constructor(props: DmnEditorRootProps) {
+ super(props);
+ props.exposing(this);
+ this.state = {
+ externalModelsByNamespace: {},
+ marshaller: undefined,
+ stack: [],
+ pointer: -1,
+ absolutePath: undefined,
+ readonly: true,
+ externalModelsManagerDoneBootstraping: false,
+ };
+ }
+
+ // Exposed API
+
+ public async undo(): Promise<void> {
+ this.setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1) }));
+ }
+
+ public async redo(): Promise<void> {
+ this.setState((prev) => ({ ...prev, pointer: Math.min(prev.stack.length - 1, prev.pointer + 1) }));
+ }
+
+ public async getContent(): Promise<string> {
+ if (!this.state.marshaller || !this.model) {
+ throw new Error(
+ `DMN EDITOR ROOT: Content has not been set yet. Throwing an error to prevent returning a "default" content.`
+ );
+ }
+
+ return this.state.marshaller.builder.build(this.model);
+ }
+
+ public async setContent(absolutePath: string, content: string): Promise<void> {
+ const marshaller = getMarshaller(content || EMPTY_DMN(), { upgradeTo: "latest" });
+
+ // Save stack
+ let savedStackPointer: DmnLatestModel[] = [];
+
+ // Set the model and path for external models manager.
+ this.setState((prev) => {
+ savedStackPointer = [...prev.stack];
+ return { stack: [marshaller.parser.parse()], absolutePath, pointer: 0 };
+ });
+
+ // Wait the external manager models to load.
+ await this.externalModelsManagerDoneBootstraping.promise;
+
+ // Set the valeus to render the DMN Editor.
+ this.setState((prev) => {
+ // External change to the same file.
+ if (prev.absolutePath === absolutePath) {
+ const newStack = savedStackPointer.slice(0, prev.pointer + 1);
+ return {
+ marshaller,
+ stack: [...newStack, marshaller.parser.parse()],
+ readonly: false,
+ pointer: newStack.length,
+ externalModelsManagerDoneBootstraping: true,
+ };
+ }
+
+ // Different file opened. Need to reset everything.
+ else {
+ return {
+ marshaller,
+ stack: [marshaller.parser.parse()],
+ readonly: false,
+ pointer: 0,
+ externalModelsManagerDoneBootstraping: true,
+ };
+ }
+ });
+ }
+
+ // Internal methods
+
+ public get model(): DmnLatestModel | undefined {
+ return this.state.stack[this.state.pointer];
+ }
+
+ private setExternalModelsByNamespace = (externalModelsByNamespace: DmnEditor.ExternalModelsIndex) => {
+ this.setState((prev) => ({ ...prev, externalModelsByNamespace }));
+ };
+
+ private onModelChange: DmnEditor.OnDmnModelChange = (model) => {
+ this.setState(
+ (prev) => {
+ const newStack = prev.stack.slice(0, prev.pointer + 1);
+ return {
+ ...prev,
+ stack: [...newStack, model],
+ pointer: newStack.length,
+ };
+ },
+ () => this.props.onNewEdit({ id: `${this.state.absolutePath}__${generateUuid()}` })
+ );
+ };
+
+ private onRequestExternalModelsAvailableToInclude: DmnEditor.OnRequestExternalModelsAvailableToInclude = async () => {
+ if (!this.state.absolutePath) {
+ return [];
+ }
+
+ const list = await this.props.onRequestFileList({
+ pattern: EXTERNAL_MODELS_SEARCH_GLOB_PATTERN,
+ opts: { type: SearchType.TRAVERSAL },
+ });
+
+ return list.paths.flatMap((pathRelativeToWorkspaceRoot) =>
+ // Ignore thisDmn's file absolutePath
+ this.joinPathWithWorkingDirBasePath(pathRelativeToWorkspaceRoot) === this.state.absolutePath
+ ? []
+ : pathRelativeToWorkspaceRoot
+ );
+ };
+
+ private joinPathWithWorkingDirBasePath = (relativePath: string) => {
+ return __path.join(this.props.workingDirBasePath, relativePath);
+ };
+
+ private onRequestToResolvePath = (relativePath: string) => {
+ return __path.relative(
+ this.props.workingDirBasePath,
+ __path.resolve(__path.dirname(this.state.absolutePath!), relativePath)
+ );
+ };
+
+ private onRequestExternalModelByPath: DmnEditor.OnRequestExternalModelByPath = async (
+ pathRelativeToWorkspaceRoot
+ ) => {
+ const absolutePathOfRequestFile = this.joinPathWithWorkingDirBasePath(pathRelativeToWorkspaceRoot);
+ const resource = await this.props.onRequestFileContent({
+ path: absolutePathOfRequestFile,
+ opts: { type: ContentType.TEXT },
+ });
+ const pathRelativeToOpenFile = __path.relative(__path.dirname(this.state.absolutePath!), absolutePathOfRequestFile);
+
+ const ext = __path.extname(pathRelativeToWorkspaceRoot);
+ if (ext === ".dmn") {
+ return {
+ relativePath: pathRelativeToOpenFile,
+ type: "dmn",
+ model: getMarshaller(resource?.content ?? "", { upgradeTo: "latest" }).parser.parse(),
+ svg: "",
+ };
+ } else if (ext === ".pmml") {
+ return {
+ relativePath: pathRelativeToOpenFile,
+ type: "pmml",
+ model: XML2PMML(resource?.content ?? ""),
+ };
+ } else {
+ throw new Error(`Unknown extension '${ext}'.`);
+ }
+ };
+
+ private onOpenFileFromRelativePath = (relativePath: string) => {
+ if (!this.state.absolutePath) {
+ return;
+ }
+
+ this.props.onOpenFile(this.joinPathWithWorkingDirBasePath(relativePath));
+ };
+
+ public render() {
+ return (
+ <>
+ {this.model && (
+ <>
+ {this.state.marshaller && this.state.externalModelsManagerDoneBootstraping && (
+ <DmnEditor.DmnEditor
+ originalVersion={this.state.marshaller.originalVersion}
+ model={this.model}
+ externalModelsByNamespace={this.state.externalModelsByNamespace}
+ evaluationResults={[]}
+ validationMessages={[]}
+ externalContextName={""}
+ externalContextDescription={""}
+ issueTrackerHref={""}
+ onModelChange={this.onModelChange}
+ onRequestExternalModelByPath={this.onRequestExternalModelByPath}
+ onRequestExternalModelsAvailableToInclude={this.onRequestExternalModelsAvailableToInclude}
+ onRequestToJumpToPath={this.onOpenFileFromRelativePath}
+ onRequestToResolvePath={this.onRequestToResolvePath}
+ />
+ )}
+ <ExternalModelsManager
+ thisDmnsAbsolutePath={this.state.absolutePath}
+ model={this.model}
+ onChange={this.setExternalModelsByNamespace}
+ onRequestFileList={this.props.onRequestFileList}
+ onRequestFileContent={this.props.onRequestFileContent}
+ externalModelsManagerDoneBootstraping={this.externalModelsManagerDoneBootstraping}
+ />
+ </>
+ )}
+ </>
+ );
+ }
+}
+
+const NAMESPACES_EFFECT_SEPARATOR = " , ";
+
+function ExternalModelsManager({
+ thisDmnsAbsolutePath,
+ model,
+ onChange,
+ onRequestFileContent,
+ onRequestFileList,
+ externalModelsManagerDoneBootstraping,
+}: {
+ thisDmnsAbsolutePath: string | undefined;
+ model: DmnLatestModel;
+ onChange: (externalModelsByNamespace: DmnEditor.ExternalModelsIndex) => void;
+ onRequestFileContent: WorkspaceChannelApi["kogitoWorkspace_resourceContentRequest"];
+ onRequestFileList: WorkspaceChannelApi["kogitoWorkspace_resourceListRequest"];
+ externalModelsManagerDoneBootstraping: PromiseImperativeHandle<void>;
+}) {
+ const namespaces = useMemo(
+ () =>
+ (model.definitions.import ?? [])
+ .map((i) => getNamespaceOfDmnImport({ dmnImport: i }))
+ .join(NAMESPACES_EFFECT_SEPARATOR),
+ [model.definitions.import]
+ );
+
+ const [externalUpdatesCount, setExternalUpdatesCount] = useState(0);
+
+ // This is a hack. Every time a file is updates in KIE Sandbox, the Shared Worker emits an event to this BroadcastChannel.
+ // By listening to it, we can reload the `externalModelsByNamespace` object. This makes the DMN Editor react to external changes,
+ // Which is very important for multi-file editing.
+ //
+ // Now, this mechanism is not ideal. We would ideally only be notified on changes to relevant files, but this sub-system does not exist yet.
+ // The consequence of this "hack" is some extra reloads.
+ useEffect(() => {
+ const bc = new BroadcastChannel("workspaces_files");
+ bc.onmessage = ({ data }) => {
+ // Changes to `thisDmn` shouldn't update its references to external models.
+ if (data?.relativePath === thisDmnsAbsolutePath) {
+ return;
+ }
+
+ setExternalUpdatesCount((prev) => prev + 1);
+ };
+ return () => {
+ bc.close();
+ };
+ }, [thisDmnsAbsolutePath]);
+
+ // This effect actually populates `externalModelsByNamespace` through the `onChange` call.
+ useEffect(() => {
+ let canceled = false;
+
+ if (!thisDmnsAbsolutePath) {
+ return;
+ }
+
+ onRequestFileList({ pattern: EXTERNAL_MODELS_SEARCH_GLOB_PATTERN, opts: { type: SearchType.TRAVERSAL } })
+ .then((list) => {
+ const resources: Array<Promise<ResourceContent | undefined>> = [];
+ for (let i = 0; i < list.paths.length; i++) {
+ const absolutePath = list.paths[i];
+ if (absolutePath === thisDmnsAbsolutePath) {
+ continue;
+ }
+
+ resources.push(onRequestFileContent({ path: absolutePath, opts: { type: ContentType.TEXT } }));
+ }
+ return Promise.all(resources);
+ })
+ .then((resources) => {
+ const externalModelMap: DmnEditor.ExternalModelsIndex = {};
+
+ const namespacesSet = new Set(namespaces.split(NAMESPACES_EFFECT_SEPARATOR));
+
+ for (let i = 0; i < resources.length; i++) {
+ const r = resources[i];
+ const content = r?.content ?? "";
+ const pathRelativeToWorkspaceRoot = r?.path ?? "";
+
+ const ext = __path.extname(pathRelativeToWorkspaceRoot);
+ if (ext === ".dmn") {
+ const namespace = domParser.getDomDocument(content).documentElement.getAttribute("namespace");
+ if (namespace && namespacesSet.has(namespace)) {
+ // Check for multiplicity of namespaces on DMN models
+ if (externalModelMap[namespace]) {
+ console.warn(
+ `DMN EDITOR ROOT: Multiple DMN models encountered with the same namespace '${namespace}': '${pathRelativeToWorkspaceRoot}' and '${
+ externalModelMap[namespace]!.relativePath
+ }'. The latter will be considered.`
+ );
+ }
+
+ externalModelMap[namespace] = {
+ relativePath: pathRelativeToWorkspaceRoot,
+ model: getMarshaller(content, { upgradeTo: "latest" }).parser.parse(),
+ type: "dmn",
+ svg: "",
+ };
+ }
+ } else if (ext === ".pmml") {
+ const namespace = getPmmlNamespace({ fileRelativePath: pathRelativeToWorkspaceRoot });
+ if (namespace && namespacesSet.has(namespace)) {
+ // No need to check for namespaces being equal becuase there can't be two files with the same relativePath.
+ externalModelMap[namespace] = {
+ relativePath: pathRelativeToWorkspaceRoot,
+ model: XML2PMML(content),
+ type: "pmml",
+ };
+ }
+ } else {
+ throw new Error(`Unknown extension '${ext}'.`);
+ }
+ }
+
+ if (!canceled) {
+ onChange(externalModelMap);
+ }
+ externalModelsManagerDoneBootstraping.resolve();
+ });
+
+ return () => {
+ canceled = true;
+ };
+ }, [
+ namespaces,
+ onChange,
+ onRequestFileContent,
+ onRequestFileList,
+ thisDmnsAbsolutePath,
+ externalUpdatesCount,
+ externalModelsManagerDoneBootstraping,
+ ]);
+
+ return <></>;
+}
diff --git a/packages/dmn-editor-envelope/tsconfig.json b/packages/dmn-editor-envelope/tsconfig.json
new file mode 100644
index 00000000000..3855f0f523c
--- /dev/null
+++ b/packages/dmn-editor-envelope/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "@kie-tools/tsconfig/tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["src"]
+}
diff --git a/packages/dmn-editor/LICENSE b/packages/dmn-editor/LICENSE
new file mode 100644
index 00000000000..261eeb9e9f8
--- /dev/null
+++ b/packages/dmn-editor/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/packages/dmn-editor/dev-webapp/src/AvailableModelsToInclude.ts b/packages/dmn-editor/dev-webapp/src/AvailableModelsToInclude.ts
new file mode 100644
index 00000000000..86b4dd9302b
--- /dev/null
+++ b/packages/dmn-editor/dev-webapp/src/AvailableModelsToInclude.ts
@@ -0,0 +1,73 @@
+/*
+ * 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 { XML2PMML } from "@kie-tools/pmml-editor-marshaller";
+import * as DmnEditor from "../../src/DmnEditor";
+import { getPmmlNamespace } from "../../src/pmml/pmml";
+import { sumBkm, sumDiffDs, testTreePmml } from "./ExternalModels";
+
+export const sumBkmModel = getMarshaller(sumBkm, { upgradeTo: "latest" }).parser.parse();
+export const sumDiffDsModel = getMarshaller(sumDiffDs, { upgradeTo: "latest" }).parser.parse();
+export const testTreePmmlModel = XML2PMML(testTreePmml);
+
+export const avaiableModels: DmnEditor.ExternalModel[] = [
+ {
+ type: "dmn",
+ model: sumBkmModel,
+ svg: "",
+ relativePath: "dev-webapp/available-models-to-include/sumBkm.dmn",
+ },
+ {
+ type: "dmn",
+ model: sumDiffDsModel,
+ svg: "",
+ relativePath: "dev-webapp/available-models-to-include/sumDiffDs.dmn",
+ },
+ {
+ type: "dmn",
+ model: getMarshaller(`<definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/" />`, {
+ upgradeTo: "latest",
+ }).parser.parse(),
+ svg: "",
+ relativePath: "dev-webapp/available-models-to-include/empty.dmn",
+ },
+ {
+ type: "pmml",
+ model: testTreePmmlModel,
+ relativePath: "dev-webapp/available-models-to-include/testTree.pmml",
+ },
+];
+
+export const availableModelsByPath: Record<string, DmnEditor.ExternalModel> = Object.values(avaiableModels).reduce(
+ (acc, v) => {
+ acc[v.relativePath] = v;
+ return acc;
+ },
+ {} as Record<string, DmnEditor.ExternalModel>
+);
+
+export const modelsByNamespace = Object.values(avaiableModels).reduce((acc, v) => {
+ if (v.type === "dmn") {
+ acc[v.model.definitions["@_namespace"]] = v;
+ } else if (v.type === "pmml") {
+ acc[getPmmlNamespace({ fileRelativePath: v.relativePath })] = v;
+ }
+ return acc;
+}, {} as DmnEditor.ExternalModelsIndex);
diff --git a/packages/online-editor/static/samples/Sample.dmn b/packages/dmn-editor/dev-webapp/src/DefaultDmn.ts
similarity index 68%
copy from packages/online-editor/static/samples/Sample.dmn
copy to packages/dmn-editor/dev-webapp/src/DefaultDmn.ts
index 13920fec245..f2f12a3de30 100644
--- a/packages/online-editor/static/samples/Sample.dmn
+++ b/packages/dmn-editor/dev-webapp/src/DefaultDmn.ts
@@ -1,5 +1,37 @@
-<dmn:definitions xmlns:dmn="http://www.omg.org/spec/DMN/20180521/MODEL/" xmlns="https://kiegroup.org/dmn/_857FE424-BEDA-4772-AB8E-2F4CDDB864AB" xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/" xmlns:kie="http://www.drools.org/kie/dmn/1.2" xmlns:dmndi="http://www.omg.org/spec/DMN/20180521/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" xmlns:feel="http://www.omg.org/spec/DMN/20180521/FEEL/" id="_C6CBECEB-2BBC-4E14-80B0-17F576B2CF92" name="loan_pre_qualification" expressionL [...]
- <dmn:extensionElements/>
+/*
+ * 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.
+ */
+
+export const DEFAULT_DEV_WEBAPP_DMN = `<?xml version="1.0" encoding="UTF-8" ?>
+<dmn:definitions xmlns:dmn="http://www.omg.org/spec/DMN/20180521/MODEL/"
+ xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/"
+ xmlns:kie="https://kie.org/dmn/extensions/1.0"
+ xmlns:dmndi="http://www.omg.org/spec/DMN/20180521/DMNDI/"
+ xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/"
+ xmlns:feel="http://www.omg.org/spec/DMN/20180521/FEEL/"
+ xmlns:included0="https://kie.org/dmn/_923784BD-CD31-488A-9C31-C1A83C5483C0"
+ xmlns:included1="https://kie.org/dmn/_D19B0015-2CBD-4BA8-84A9-5F554D84A9E1"
+ expressionLanguage="http://www.omg.org/spec/DMN/20180521/FEEL/"
+ typeLanguage="http://www.omg.org/spec/DMN/20211108/FEEL/"
+ namespace="https://kiegroup.org/dmn/_857FE424-BEDA-4772-AB8E-2F4CDDB864AB"
+ id="_C6CBECEB-2BBC-4E14-80B0-17F576B2CF92"
+ name="loan_pre_qualification">
+ <dmn:extensionElements />
<dmn:itemDefinition id="_D40B0106-62E8-4AC0-A39A-C6C9506194A9" name="Requested_Product" isCollection="false">
<dmn:itemComponent id="_68b4a96c-198a-4575-b29a-a2c8b0539a2c" name="Type" isCollection="false">
<dmn:typeRef>Product_Type</dmn:typeRef>
@@ -17,7 +49,7 @@
<dmn:itemDefinition id="_2B4E9593-3239-4E04-A213-345F0AA0AF9D" name="Marital_Status" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_5BD13D9D-412F-4E6B-914A-3D8AAAC6A705">
- <dmn:text>"M","D","S"</dmn:text>
+ <dmn:text>"M","D","S"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_F090CBB7-F5C3-4C54-9905-517DC1469B52" name="Applicant_Data" isCollection="false">
@@ -30,7 +62,7 @@
<dmn:itemComponent id="_701117b8-2f8d-4e94-a5db-d503f0fba3af" name="Employment Status" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_4A8E36FC-A40C-4CB5-9AE1-73082DA24D13">
- <dmn:text>"Unemployed","Employed","Self-employed","Student"</dmn:text>
+ <dmn:text>"Unemployed","Employed","Self-employed","Student"</dmn:text>
</dmn:allowedValues>
</dmn:itemComponent>
<dmn:itemComponent id="_17ad2a24-425f-4df7-92fc-609e10217b8b" name="Existing Customer" isCollection="false">
@@ -73,55 +105,55 @@
<dmn:itemDefinition id="_9AEAE50E-67BF-4428-A6CD-B48D299FD73C" name="Eligibility" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_79C7F45D-228F-437B-AF7E-615FC72A5354">
- <dmn:text>"Ineligible","Eligible"</dmn:text>
+ <dmn:text>"Ineligible","Eligible"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_FBF245E7-9A93-4D52-9F02-AF6893011A5F" name="Strategy" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_0B005355-19D0-447B-B2DE-6D1290C7504C">
- <dmn:text>"Decline","Bureau","Through"</dmn:text>
+ <dmn:text>"Decline","Bureau","Through"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_5D34E713-E94E-403E-A681-DD6948BE4F79" name="Bureau_Call_Type" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_947DBBA1-70A0-42DA-BC37-FD2FD93BF61B">
- <dmn:text>"Full","Mini","None"</dmn:text>
+ <dmn:text>"Full","Mini","None"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_9AF58ED6-A526-4346-8780-0D1E6038CA6F" name="Product_Type" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_A2554140-8060-4F66-BA16-3A8DFE12C17C">
- <dmn:text>"Standard Loan","Special Loan"</dmn:text>
+ <dmn:text>"Standard Loan","Special Loan"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_4D36A25E-9A37-47AE-B9BF-94338AE67609" name="Risk_Category" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_041426C2-B9D2-4C18-9AC3-5A508D000839">
- <dmn:text>"High","Medium","Low","Very Low","Decline"</dmn:text>
+ <dmn:text>"High","Medium","Low","Very Low","Decline"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_46C870FC-2A99-43A0-9D1B-3D3C5516FB23" name="Credit_Score_Rating" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_8470AE69-2814-4911-953D-3FC61A681063">
- <dmn:text>"Poor","Bad","Fair","Good","Excellent"</dmn:text>
+ <dmn:text>"Poor","Bad","Fair","Good","Excellent"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_7641A6FA-BCF3-45D1-A0B6-71B0634ABB3E" name="Back_End_Ratio" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_CA1C6F0E-186F-41DD-8D8D-D405789BA3F1">
- <dmn:text>"Insufficient","Sufficient"</dmn:text>
+ <dmn:text>"Insufficient","Sufficient"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_B5E00A2D-3C95-4A9C-BCA6-BDE852939F6D" name="Front_End_Ratio" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_B8658CA2-F472-4390-8AB0-1DD49100B20C">
- <dmn:text>"Sufficient","Insufficient"</dmn:text>
+ <dmn:text>"Sufficient","Insufficient"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_B8ACE210-2C55-4C66-B3D8-4885EE1C52A0" name="Qualification" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_1F66B8BF-6AB7-4965-8A69-897DDC1A8B34">
- <dmn:text>"Not Qualified","Qualified"</dmn:text>
+ <dmn:text>"Not Qualified","Qualified"</dmn:text>
</dmn:allowedValues>
</dmn:itemDefinition>
<dmn:itemDefinition id="_2CC2E8D7-1BE2-4E4A-8072-55A1EC94DB6E" name="Credit_Score" isCollection="false">
@@ -136,7 +168,7 @@
<dmn:itemComponent id="_e11c3ac3-7370-4378-967b-91e9cb221fe1" name="Qualification" isCollection="false">
<dmn:typeRef>string</dmn:typeRef>
<dmn:allowedValues id="_B0AD0641-0023-461D-B20E-41CAE02F9BE4">
- <dmn:text>"Qualified","Not Qualified"</dmn:text>
+ <dmn:text>"Qualified","Not Qualified"</dmn:text>
</dmn:allowedValues>
</dmn:itemComponent>
<dmn:itemComponent id="_b3541f82-5bc9-4fab-ba9b-c423a9a2cd6c" name="Reason" isCollection="false">
@@ -144,12 +176,12 @@
</dmn:itemComponent>
</dmn:itemDefinition>
<dmn:inputData id="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" name="Credit Score">
- <dmn:extensionElements/>
- <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit Score" typeRef="Credit_Score"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit Score" typeRef="Credit_Score" />
</dmn:inputData>
<dmn:businessKnowledgeModel id="_4C788DBD-C672-4F41-9AFE-9C7D2C145734" name="Lender Acceptable DTI">
- <dmn:extensionElements/>
- <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender Acceptable DTI" typeRef="number"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender Acceptable DTI" typeRef="number" />
<dmn:encapsulatedLogic id="_9F0257EE-CF82-49FD-AEDD-3155890864FF" kind="FEEL">
<dmn:literalExpression id="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
<dmn:text>0.36</dmn:text>
@@ -157,144 +189,144 @@
</dmn:encapsulatedLogic>
</dmn:businessKnowledgeModel>
<dmn:decision id="_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" name="Front End Ratio">
- <dmn:extensionElements/>
- <dmn:variable id="_A0B0B032-F63F-491F-A65E-72E68A86B8FD" name="Front End Ratio" typeRef="Front_End_Ratio"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_A0B0B032-F63F-491F-A65E-72E68A86B8FD" name="Front End Ratio" typeRef="Front_End_Ratio" />
<dmn:informationRequirement id="_89EEAF9F-5A5D-4F59-91B7-EA418A7229AF">
- <dmn:requiredInput href="#_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E"/>
+ <dmn:requiredInput href="#_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" />
</dmn:informationRequirement>
<dmn:informationRequirement id="_87730C5A-5648-415B-9189-EF4D8805F8C9">
- <dmn:requiredInput href="#_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E"/>
+ <dmn:requiredInput href="#_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" />
</dmn:informationRequirement>
<dmn:knowledgeRequirement id="_63DE7C3B-A767-4B8A-A098-91ECB4B8D330">
- <dmn:requiredKnowledge href="#_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA"/>
+ <dmn:requiredKnowledge href="#_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" />
</dmn:knowledgeRequirement>
<dmn:knowledgeRequirement id="_2C95829D-FCF9-44F5-8F5A-0A6CDB60600D">
- <dmn:requiredKnowledge href="#_C98BE939-B9C7-43E0-83E8-EE7A16C5276D"/>
+ <dmn:requiredKnowledge href="#_C98BE939-B9C7-43E0-83E8-EE7A16C5276D" />
</dmn:knowledgeRequirement>
- <dmn:context id="_08A9C33D-719F-4B05-AC42-D15464798BC4">
- <dmn:contextEntry>
- <dmn:variable id="_C8F98D0F-218F-4B60-BD99-7FD98078FE56" name="Client PITI" typeRef="number"/>
- <dmn:invocation id="_EB658586-C3C8-488E-8118-E69E31583106">
+ <dmn:context id="_08A9C33D-719F-4B05-AC42-D15464798BC4" label="Front End Ratio" typeRef="Front_End_Ratio">
+ <dmn:contextEntry id="_C8F98D0F-218F-4B60-BD99-7FD98078FE56">
+ <dmn:invocation id="_EB658586-C3C8-488E-8118-E69E31583106" typeRef="<Undefined>">
<dmn:literalExpression id="_6E79E4D9-BBFB-4E90-8AA3-A6C153C3C946">
<dmn:text>PITI</dmn:text>
</dmn:literalExpression>
- <dmn:binding>
- <dmn:parameter id="_4B93E8C8-A092-4EAC-B23A-CC138225ACC3" name="pmt"/>
- <dmn:literalExpression id="_51ACEC3C-4207-4F5F-8FDD-9EDAA3270E60">
+ <dmn:binding id="_4B93E8C8-A092-4EAC-B23A-CC138225ACC3">
+ <dmn:literalExpression id="_51ACEC3C-4207-4F5F-8FDD-9EDAA3270E60" typeRef="<Undefined>">
<dmn:text>(Requested Product.Amount*((Requested Product.Rate/100)/12))/(1-(1/(1+(Requested Product.Rate/100)/12)**-Requested Product.Term))</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="pmt" typeRef="<Undefined>" />
</dmn:binding>
- <dmn:binding>
- <dmn:parameter id="_B9D0FB44-605A-42DB-81F7-4DF4C4CC1CDD" name="tax"/>
- <dmn:literalExpression id="_5D050B8D-DF55-45FD-988B-9C56BED53D5B">
+ <dmn:binding id="_B9D0FB44-605A-42DB-81F7-4DF4C4CC1CDD">
+ <dmn:literalExpression id="_5D050B8D-DF55-45FD-988B-9C56BED53D5B" typeRef="<Undefined>">
<dmn:text>Applicant Data.Monthly.Tax</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="tax" typeRef="<Undefined>" />
</dmn:binding>
- <dmn:binding>
- <dmn:parameter id="_67372884-0407-4812-986F-3A2CC4C3A7B1" name="insurance"/>
- <dmn:literalExpression id="_14C44A69-56DB-4B68-B757-4225C80E4D88">
+ <dmn:binding id="_67372884-0407-4812-986F-3A2CC4C3A7B1">
+ <dmn:literalExpression id="_14C44A69-56DB-4B68-B757-4225C80E4D88" typeRef="<Undefined>">
<dmn:text>Applicant Data.Monthly.Insurance</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="insurance" typeRef="<Undefined>" />
</dmn:binding>
- <dmn:binding>
- <dmn:parameter id="_EDE0107C-9736-4BB6-9500-173FFAFF00DB" name="income"/>
- <dmn:literalExpression id="_0DB5DE05-A2AD-4013-B191-DC1D1637A132">
+ <dmn:binding id="_EDE0107C-9736-4BB6-9500-173FFAFF00DB">
+ <dmn:literalExpression id="_0DB5DE05-A2AD-4013-B191-DC1D1637A132" typeRef="<Undefined>">
<dmn:text>Applicant Data.Monthly.Income</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="income" typeRef="<Undefined>" />
</dmn:binding>
</dmn:invocation>
+ <dmn:variable name="Client PITI" typeRef="number" />
</dmn:contextEntry>
- <dmn:contextEntry>
- <dmn:literalExpression id="_3F95EFD0-94D7-4D1A-9EA9-C8E12982D7E8">
+ <dmn:contextEntry id="_3F95EFD0-94D7-4D1A-9EA9-C8E12982D7E8">
+ <dmn:literalExpression id="_3F95EFD0-94D7-4D1A-9EA9-C8E12982D7E8" typeRef="<Undefined>">
<dmn:text>if Client PITI <= Lender Acceptable PITI()
-then "Sufficient"
-else "Insufficient"</dmn:text>
+then "Sufficient"
+else "Insufficient"</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
</dmn:context>
</dmn:decision>
<dmn:businessKnowledgeModel id="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" name="PITI">
- <dmn:extensionElements/>
- <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI" typeRef="number"/>
- <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027" kind="FEEL">
- <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62" name="pmt" typeRef="number"/>
- <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37" name="tax" typeRef="number"/>
- <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116" name="insurance" typeRef="number"/>
- <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E" name="income" typeRef="number"/>
- <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
- <dmn:text>(pmt+tax+insurance)/income</dmn:text>
+ <dmn:extensionElements />
+ <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI" typeRef="number" />
+ <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027" label="PITI" kind="FEEL" typeRef="number">
+ <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62" name="pmt" typeRef="number" />
+ <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37" name="tax" typeRef="number" />
+ <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116" name="insurance" typeRef="number" />
+ <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E" name="income" typeRef="number" />
+ <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C" typeRef="<Undefined>">
+ <dmn:text>(pmt + tax + insurance) / income</dmn:text>
</dmn:literalExpression>
</dmn:encapsulatedLogic>
</dmn:businessKnowledgeModel>
<dmn:inputData id="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" name="Applicant Data">
- <dmn:extensionElements/>
- <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant Data" typeRef="Applicant_Data"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant Data" typeRef="Applicant_Data" />
</dmn:inputData>
<dmn:decision id="_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" name="Back End Ratio">
- <dmn:extensionElements/>
- <dmn:variable id="_5AF571F7-AD41-43DC-ABFD-26672585042F" name="Back End Ratio" typeRef="Back_End_Ratio"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_5AF571F7-AD41-43DC-ABFD-26672585042F" name="Back End Ratio" typeRef="Back_End_Ratio" />
<dmn:informationRequirement id="_77BA409B-E00D-4FBC-B522-8F656D4F6F0E">
- <dmn:requiredInput href="#_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E"/>
+ <dmn:requiredInput href="#_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" />
</dmn:informationRequirement>
<dmn:knowledgeRequirement id="_4D441C11-7042-49CF-A42C-17A4348A7F29">
- <dmn:requiredKnowledge href="#_4C788DBD-C672-4F41-9AFE-9C7D2C145734"/>
+ <dmn:requiredKnowledge href="#_4C788DBD-C672-4F41-9AFE-9C7D2C145734" />
</dmn:knowledgeRequirement>
<dmn:knowledgeRequirement id="_3217D655-4484-4733-A9AE-4F9CF30D9924">
- <dmn:requiredKnowledge href="#_DA5CCF62-90A8-4CFC-A137-98B528522588"/>
+ <dmn:requiredKnowledge href="#_DA5CCF62-90A8-4CFC-A137-98B528522588" />
</dmn:knowledgeRequirement>
- <dmn:context id="_5F9FEA4E-B3FC-4BC2-913E-36B8071FA777">
- <dmn:contextEntry>
- <dmn:variable id="_F3ED9059-400F-4BE8-B250-C2ABCD9FF022" name="Client DTI" typeRef="number"/>
- <dmn:invocation id="_4A7FC8E0-25EF-4DAF-845A-93BD89C2BC8C">
+ <dmn:context id="_5F9FEA4E-B3FC-4BC2-913E-36B8071FA777" label="Back End Ratio" typeRef="Back_End_Ratio">
+ <dmn:contextEntry id="_F3ED9059-400F-4BE8-B250-C2ABCD9FF022">
+ <dmn:invocation id="_4A7FC8E0-25EF-4DAF-845A-93BD89C2BC8C" typeRef="<Undefined>">
<dmn:literalExpression id="_F0E80900-1964-4142-9A05-73E7A2E0F2CD">
<dmn:text>DTI</dmn:text>
</dmn:literalExpression>
<dmn:binding>
- <dmn:parameter id="_6408A089-A087-4855-BBB8-0C22BE6ECFDF" name="d"/>
- <dmn:literalExpression id="_3D0A1979-E59A-483F-BDA8-138F99BA5AB3">
+ <dmn:literalExpression id="_3D0A1979-E59A-483F-BDA8-138F99BA5AB3" typeRef="<Undefined>">
<dmn:text>Applicant Data.Monthly.Repayments + Applicant Data.Monthly.Expenses</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="d" typeRef="<Undefined>" />
</dmn:binding>
<dmn:binding>
- <dmn:parameter id="_45370376-8934-4FBD-BA9F-5338916EBF07" name="i"/>
- <dmn:literalExpression id="_D985F886-71C0-4F65-8808-2CEF366BECC8">
+ <dmn:literalExpression id="_D985F886-71C0-4F65-8808-2CEF366BECC8" typeRef="<Undefined>">
<dmn:text>Applicant Data.Monthly.Income</dmn:text>
</dmn:literalExpression>
+ <dmn:parameter name="i" typeRef="<Undefined>" />
</dmn:binding>
</dmn:invocation>
+ <dmn:variable name="Client DTI" typeRef="number" />
</dmn:contextEntry>
- <dmn:contextEntry>
- <dmn:literalExpression id="_D1F96102-4158-45BB-8C9A-B7A3BE2C0206">
+ <dmn:contextEntry id="_D1F96102-4158-45BB-8C9A-B7A3BE2C0206">
+ <dmn:literalExpression id="_D1F96102-4158-45BB-8C9A-B7A3BE2C0206" typeRef="<Undefined>">
<dmn:text>if Client DTI <= Lender Acceptable DTI()
-then "Sufficient"
-else "Insufficient"</dmn:text>
+then "Sufficient"
+else "Insufficient"</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
</dmn:context>
</dmn:decision>
<dmn:decision id="_2FE51DB1-3083-4BF7-AA71-0B0065310E72" name="Credit Score Rating">
- <dmn:extensionElements/>
- <dmn:variable id="_82228E41-22D1-4758-97C3-BBFE90EDB5FB" name="Credit Score Rating" typeRef="Credit_Score_Rating"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_82228E41-22D1-4758-97C3-BBFE90EDB5FB" name="Credit Score Rating" typeRef="Credit_Score_Rating" />
<dmn:informationRequirement id="_31A1B6B2-A2A6-4E03-B898-26573A5CF3BA">
- <dmn:requiredInput href="#_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE"/>
+ <dmn:requiredInput href="#_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" />
</dmn:informationRequirement>
- <dmn:decisionTable id="_4ACEFFF0-AD2C-4DB8-9BAD-7BCCFB03F295" hitPolicy="UNIQUE" preferredOrientation="Rule-as-Row">
+ <dmn:decisionTable id="_4ACEFFF0-AD2C-4DB8-9BAD-7BCCFB03F295" label="Credit Score Rating" typeRef="Credit_Score_Rating" hitPolicy="UNIQUE">
<dmn:input id="_44C93627-629C-48B8-B71A-AE2266A42674">
<dmn:inputExpression id="_00932A00-5ECE-4AEF-AA68-92E679CEF4AB" typeRef="number">
<dmn:text>Credit Score.FICO</dmn:text>
</dmn:inputExpression>
</dmn:input>
- <dmn:output id="_9C201FAB-B49C-4D22-900B-B4E82D5469FB"/>
- <dmn:annotation name=""/>
+ <dmn:output id="_9C201FAB-B49C-4D22-900B-B4E82D5469FB" name="" typeRef="<Undefined>" />
+ <dmn:annotation name="Annotations" />
<dmn:rule id="_AED703E1-8E56-4D27-A511-3875AD1D122E">
<dmn:inputEntry id="_E2C9F30B-D529-48D8-A51C-A2ACCC8109B3">
<dmn:text>>= 750</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_A1FF2B2D-EF34-42AD-A45A-5FFDFA21FA6D">
- <dmn:text>"Excellent"</dmn:text>
+ <dmn:text>"Excellent"</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_1FA12B9F-288C-42E8-B77F-BE2D3702B7B6">
@@ -302,10 +334,10 @@ else "Insufficient"</dmn:text>
<dmn:text>[700..750)</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_833307A2-B924-422C-A4F5-BFFAB27D86D5">
- <dmn:text>"Good"</dmn:text>
+ <dmn:text>"Good"</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_11976EBA-60BC-421B-A270-089A45E9B167">
@@ -313,10 +345,10 @@ else "Insufficient"</dmn:text>
<dmn:text>[650..700)</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_E18FE2B2-729C-41F0-B5CC-0E5E5EA431E3">
- <dmn:text>"Fair"</dmn:text>
+ <dmn:text>"Fair"</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_12F8077F-E601-4882-93E1-31508B1402E1">
@@ -324,10 +356,10 @@ else "Insufficient"</dmn:text>
<dmn:text>[600..650)</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_75135F4C-6BA7-4180-B726-A0D795B3D7FF">
- <dmn:text>"Poor"</dmn:text>
+ <dmn:text>"Poor"</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_D025254C-9376-4425-8084-451E09243CE2">
@@ -335,27 +367,27 @@ else "Insufficient"</dmn:text>
<dmn:text>< 600</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_1FB7308A-E37B-46EA-8070-C67E2388A869">
- <dmn:text>"Bad"</dmn:text>
+ <dmn:text>"Bad"</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
</dmn:decisionTable>
</dmn:decision>
<dmn:decision id="_21C50763-E49F-4D83-A824-16DA6AA87C64" name="Loan Pre-Qualification">
- <dmn:extensionElements/>
- <dmn:variable id="_047A25F5-DEF2-44BD-95B7-FB49A433F878" name="Loan Pre-Qualification" typeRef="Loan_Qualification"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_047A25F5-DEF2-44BD-95B7-FB49A433F878" name="Loan Pre-Qualification" typeRef="Loan_Qualification" />
<dmn:informationRequirement id="_A3E95B32-2EFD-40AD-B5E4-0A73A1542011">
- <dmn:requiredDecision href="#_D6F4234F-15B3-4F5B-B814-5F6FF29D2907"/>
+ <dmn:requiredDecision href="#_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" />
</dmn:informationRequirement>
<dmn:informationRequirement id="_0B992F01-BA77-4F06-A830-D8948B467272">
- <dmn:requiredDecision href="#_F0DC8923-5FC7-4200-8BD1-461D5F3714BE"/>
+ <dmn:requiredDecision href="#_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" />
</dmn:informationRequirement>
<dmn:informationRequirement id="_B6002F33-4888-48C5-B265-636030F8C2DC">
- <dmn:requiredDecision href="#_2FE51DB1-3083-4BF7-AA71-0B0065310E72"/>
+ <dmn:requiredDecision href="#_2FE51DB1-3083-4BF7-AA71-0B0065310E72" />
</dmn:informationRequirement>
- <dmn:decisionTable id="_EF7F404A-939E-4889-95D8-E4053DD1EED9" hitPolicy="FIRST" preferredOrientation="Rule-as-Row">
+ <dmn:decisionTable id="_EF7F404A-939E-4889-95D8-E4053DD1EED9" label="Loan Pre-Qualification" typeRef="Loan_Qualification" hitPolicy="FIRST">
<dmn:input id="_58ABD81B-FD16-45C3-9E64-DB271AA917C0">
<dmn:inputExpression id="_5262441E-F812-4554-AF02-5267BDDF80F5" typeRef="Credit_Score_Rating">
<dmn:text>Credit Score Rating</dmn:text>
@@ -371,12 +403,12 @@ else "Insufficient"</dmn:text>
<dmn:text>Front End Ratio</dmn:text>
</dmn:inputExpression>
</dmn:input>
- <dmn:output id="_B895B095-C3D6-48B4-8A50-D2D3B8CC6A45" name="Qualification" typeRef="string"/>
- <dmn:output id="_A8D2D3B1-07B3-4619-8DE0-F923F511058B" name="Reason" typeRef="string"/>
- <dmn:annotation name=""/>
+ <dmn:output id="_B895B095-C3D6-48B4-8A50-D2D3B8CC6A45" name="Qualification" typeRef="string" />
+ <dmn:output id="_A8D2D3B1-07B3-4619-8DE0-F923F511058B" name="Reason" typeRef="string" />
+ <dmn:annotation name="Annotations" />
<dmn:rule id="_B49E1642-F352-4D2E-92B6-E5DFA59AAFAC">
<dmn:inputEntry id="_6C83C446-1A9A-4FFC-B30C-23915FF9CC43">
- <dmn:text>"Poor", "Bad"</dmn:text>
+ <dmn:text>"Poor", "Bad"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_0BC93CB9-FD20-45C8-A498-39E4464B6224">
<dmn:text>-</dmn:text>
@@ -385,13 +417,13 @@ else "Insufficient"</dmn:text>
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_7B39B964-4E25-4717-92FE-A36F2B39FAB9">
- <dmn:text>"Not Qualified"</dmn:text>
+ <dmn:text>"Not Qualified"</dmn:text>
</dmn:outputEntry>
<dmn:outputEntry id="_A852F5B6-C5DF-4ADD-8B93-9701F0724912">
- <dmn:text>"Credit Score too low."</dmn:text>
+ <dmn:text>"Credit Score too low."</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_214865F4-C968-438C-A385-6B2823AF1BC3">
@@ -399,19 +431,19 @@ else "Insufficient"</dmn:text>
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_5C70BB81-CAFD-4695-A241-68F441FF9A29">
- <dmn:text>"Insufficient"</dmn:text>
+ <dmn:text>"Insufficient"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_78A3C3A0-EEBC-448B-B1C1-5CFF6C7F2AC5">
- <dmn:text>"Sufficient"</dmn:text>
+ <dmn:text>"Sufficient"</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_3C38D181-CCA1-4678-A3DD-0A5CE6D59FDC">
- <dmn:text>"Not Qualified"</dmn:text>
+ <dmn:text>"Not Qualified"</dmn:text>
</dmn:outputEntry>
<dmn:outputEntry id="_F4284B9F-C77A-429B-A689-E212CFB19CB7">
- <dmn:text>"Debt to income ratio is too high."</dmn:text>
+ <dmn:text>"Debt to income ratio is too high."</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_73E96773-064E-49F6-92B2-AA76E6BF6B8A">
@@ -419,19 +451,19 @@ else "Insufficient"</dmn:text>
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_B7F59A5C-4AF1-4E90-BB0D-83C63A8390E6">
- <dmn:text>"Sufficient"</dmn:text>
+ <dmn:text>"Sufficient"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_09A23FD4-9A98-4C34-9E9B-9E8EE652ABBC">
- <dmn:text>"Insufficient"</dmn:text>
+ <dmn:text>"Insufficient"</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_9BF1096A-1AF3-4D21-9273-460DE555F0B6">
- <dmn:text>"Not Qualified"</dmn:text>
+ <dmn:text>"Not Qualified"</dmn:text>
</dmn:outputEntry>
<dmn:outputEntry id="_4D805BB2-B79E-42C2-A562-674ECBDFA01C">
- <dmn:text>"Mortgage payment to income ratio is too high."</dmn:text>
+ <dmn:text>"Mortgage payment to income ratio is too high."</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_7C242C58-6CAB-43CF-9235-347A72AE3F9E">
@@ -439,61 +471,61 @@ else "Insufficient"</dmn:text>
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_FF3E9782-BE9C-4B0C-A63B-E906F6116251">
- <dmn:text>"Insufficient"</dmn:text>
+ <dmn:text>"Insufficient"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_544687CD-F3A2-46C7-8439-E5E2E7B6483D">
- <dmn:text>"Insufficient"</dmn:text>
+ <dmn:text>"Insufficient"</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_5A958D2E-B310-4AB9-BF5B-49623BE5DB55">
- <dmn:text>"Not Qualified"</dmn:text>
+ <dmn:text>"Not Qualified"</dmn:text>
</dmn:outputEntry>
<dmn:outputEntry id="_F0BD7DC2-A1B6-4CF4-95D0-906DBB540EFC">
- <dmn:text>"Debt to income ratio is too high AND mortgage payment to income ratio is too high."</dmn:text>
+ <dmn:text>"Debt to income ratio is too high AND mortgage payment to income ratio is too high."</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
<dmn:rule id="_C8FA33B1-AF6E-4A59-B7B9-6FDF1F495C44">
<dmn:inputEntry id="_82FBCEE2-C16C-4FFF-A7F3-5512C211E29B">
- <dmn:text>"Fair", "Good", "Excellent"</dmn:text>
+ <dmn:text>"Fair", "Good", "Excellent"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_BF7CDAE1-66E3-4B06-8729-896453AD7867">
- <dmn:text>"Sufficient"</dmn:text>
+ <dmn:text>"Sufficient"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="_41CB6123-8122-4FA4-A5C1-548B92CA31AE">
- <dmn:text>"Sufficient"</dmn:text>
+ <dmn:text>"Sufficient"</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="_9E0497D0-F2F2-419E-A558-366452B379A1">
- <dmn:text>"Qualified"</dmn:text>
+ <dmn:text>"Qualified"</dmn:text>
</dmn:outputEntry>
<dmn:outputEntry id="_113CA566-6044-4858-B8D9-5ACBA4A91CF4">
- <dmn:text>"The borrower has been successfully prequalified for the requested loan."</dmn:text>
+ <dmn:text>"The borrower has been successfully prequalified for the requested loan."</dmn:text>
</dmn:outputEntry>
<dmn:annotationEntry>
- <dmn:text/>
+ <dmn:text></dmn:text>
</dmn:annotationEntry>
</dmn:rule>
</dmn:decisionTable>
</dmn:decision>
<dmn:inputData id="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" name="Requested Product">
- <dmn:extensionElements/>
- <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested Product" typeRef="Requested_Product"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested Product" typeRef="Requested_Product" />
</dmn:inputData>
<dmn:businessKnowledgeModel id="_DA5CCF62-90A8-4CFC-A137-98B528522588" name="DTI">
- <dmn:extensionElements/>
- <dmn:variable id="_2F8921D1-6384-4ECB-848E-CE84A20B2573" name="DTI" typeRef="number"/>
- <dmn:encapsulatedLogic id="_478C815E-60C9-4637-AA42-195DF16B63A5" kind="FEEL">
- <dmn:formalParameter id="_B7A9C222-C560-4D37-A821-0CAC88611F10" name="d" typeRef="number"/>
- <dmn:formalParameter id="_43C04721-38F6-4ABF-9F2F-BD2956C05441" name="i" typeRef="number"/>
- <dmn:literalExpression id="_064FA88E-B06F-4944-85C3-DA86C3F660DD">
- <dmn:text>d/i</dmn:text>
+ <dmn:extensionElements />
+ <dmn:variable id="_2F8921D1-6384-4ECB-848E-CE84A20B2573" name="DTI" typeRef="number" />
+ <dmn:encapsulatedLogic id="_478C815E-60C9-4637-AA42-195DF16B63A5" label="DTI" kind="FEEL" typeRef="number">
+ <dmn:formalParameter id="_B7A9C222-C560-4D37-A821-0CAC88611F10" name="d" typeRef="number" />
+ <dmn:formalParameter id="_43C04721-38F6-4ABF-9F2F-BD2956C05441" name="i" typeRef="number" />
+ <dmn:literalExpression id="_064FA88E-B06F-4944-85C3-DA86C3F660DD" typeRef="<Undefined>">
+ <dmn:text>d / i</dmn:text>
</dmn:literalExpression>
</dmn:encapsulatedLogic>
</dmn:businessKnowledgeModel>
<dmn:businessKnowledgeModel id="_C98BE939-B9C7-43E0-83E8-EE7A16C5276D" name="Lender Acceptable PITI">
- <dmn:extensionElements/>
- <dmn:variable id="_9D78214B-EC07-4360-8D1B-3D927AC90A20" name="Lender Acceptable PITI" typeRef="number"/>
+ <dmn:extensionElements />
+ <dmn:variable id="_9D78214B-EC07-4360-8D1B-3D927AC90A20" name="Lender Acceptable PITI" typeRef="number" />
<dmn:encapsulatedLogic id="_E312D80E-0ECE-4D66-87EB-30DE20890BBC" kind="FEEL">
<dmn:literalExpression id="_EEDF2C15-7FD7-409F-B23B-F9A198E2135D">
<dmn:text>0.28</dmn:text>
@@ -501,7 +533,7 @@ else "Insufficient"</dmn:text>
</dmn:encapsulatedLogic>
</dmn:businessKnowledgeModel>
<dmndi:DMNDI>
- <dmndi:DMNDiagram id="_1608585F-01C8-4A66-B3E5-F4422D4DD2CA" name="DRG">
+ <dmndi:DMNDiagram id="_1608585F-01C8-4A66-B3E5-F4422D4DD2CA" name="Default DRD" useAlternativeInputDataShape="false">
<di:extension>
<kie:ComponentsWidthsExtension>
<kie:ComponentWidths dmnElementRef="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
@@ -513,32 +545,28 @@ else "Insufficient"</dmn:text>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_08A9C33D-719F-4B05-AC42-D15464798BC4">
<kie:width>50</kie:width>
- <kie:width>100</kie:width>
- <kie:width>1280</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_EB658586-C3C8-488E-8118-E69E31583106">
- <kie:width>50</kie:width>
- <kie:width>100</kie:width>
- <kie:width>1110</kie:width>
+ <kie:width>120</kie:width>
</kie:ComponentWidths>
- <kie:ComponentWidths dmnElementRef="_6E79E4D9-BBFB-4E90-8AA3-A6C153C3C946"/>
+ <kie:ComponentWidths dmnElementRef="_6E79E4D9-BBFB-4E90-8AA3-A6C153C3C946" />
<kie:ComponentWidths dmnElementRef="_51ACEC3C-4207-4F5F-8FDD-9EDAA3270E60">
- <kie:width>1110</kie:width>
+ <kie:width>1036</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_5D050B8D-DF55-45FD-988B-9C56BED53D5B">
- <kie:width>1110</kie:width>
+ <kie:width>1036</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_14C44A69-56DB-4B68-B757-4225C80E4D88">
- <kie:width>1110</kie:width>
+ <kie:width>1036</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_0DB5DE05-A2AD-4013-B191-DC1D1637A132">
- <kie:width>1110</kie:width>
+ <kie:width>1036</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_3F95EFD0-94D7-4D1A-9EA9-C8E12982D7E8">
- <kie:width>1280</kie:width>
+ <kie:width>1158</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
- <kie:width>300</kie:width>
+ <kie:width>454</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027">
<kie:width>50</kie:width>
@@ -546,38 +574,34 @@ else "Insufficient"</dmn:text>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_5F9FEA4E-B3FC-4BC2-913E-36B8071FA777">
<kie:width>50</kie:width>
- <kie:width>100</kie:width>
- <kie:width>802</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_4A7FC8E0-25EF-4DAF-845A-93BD89C2BC8C">
- <kie:width>50</kie:width>
- <kie:width>100</kie:width>
- <kie:width>632</kie:width>
+ <kie:width>120</kie:width>
</kie:ComponentWidths>
- <kie:ComponentWidths dmnElementRef="_F0E80900-1964-4142-9A05-73E7A2E0F2CD"/>
+ <kie:ComponentWidths dmnElementRef="_F0E80900-1964-4142-9A05-73E7A2E0F2CD" />
<kie:ComponentWidths dmnElementRef="_3D0A1979-E59A-483F-BDA8-138F99BA5AB3">
- <kie:width>632</kie:width>
+ <kie:width>550</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_D985F886-71C0-4F65-8808-2CEF366BECC8">
- <kie:width>632</kie:width>
+ <kie:width>550</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_D1F96102-4158-45BB-8C9A-B7A3BE2C0206">
- <kie:width>802</kie:width>
+ <kie:width>672</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_4ACEFFF0-AD2C-4DB8-9BAD-7BCCFB03F295">
- <kie:width>50</kie:width>
- <kie:width>224</kie:width>
- <kie:width>226</kie:width>
+ <kie:width>60</kie:width>
+ <kie:width>133</kie:width>
+ <kie:width>147</kie:width>
<kie:width>335</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_EF7F404A-939E-4889-95D8-E4053DD1EED9">
- <kie:width>50</kie:width>
- <kie:width>227</kie:width>
- <kie:width>125</kie:width>
- <kie:width>125</kie:width>
+ <kie:width>60</kie:width>
+ <kie:width>233</kie:width>
+ <kie:width>133</kie:width>
+ <kie:width>129</kie:width>
<kie:width>135</kie:width>
<kie:width>681</kie:width>
- <kie:width>100</kie:width>
+ <kie:width>138</kie:width>
</kie:ComponentWidths>
<kie:ComponentWidths dmnElementRef="_064FA88E-B06F-4944-85C3-DA86C3F660DD">
<kie:width>150</kie:width>
@@ -597,147 +621,151 @@ else "Insufficient"</dmn:text>
</di:extension>
<dmndi:DMNShape id="dmnshape-drg-_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" dmnElementRef="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="963" y="359" width="134" height="61"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="980" y="360" width="134" height="61" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_4C788DBD-C672-4F41-9AFE-9C7D2C145734" dmnElementRef="_4C788DBD-C672-4F41-9AFE-9C7D2C145734" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="99.09345794392524" y="223.67105263157896" width="136" height="63"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="99.09345794392524" y="223.67105263157896" width="136" height="63" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" dmnElementRef="_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="531" y="225" width="136" height="62"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="531" y="225" width="136" height="62" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" dmnElementRef="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="747" y="359.3421052631579" width="135" height="63"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="760" y="360" width="135" height="63" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" dmnElementRef="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="316.0607476635514" y="361" width="134" height="61"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="316.0607476635514" y="361" width="134" height="61" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" dmnElementRef="_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="315" y="225" width="136" height="62"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="315" y="225" width="136" height="62" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_2FE51DB1-3083-4BF7-AA71-0B0065310E72" dmnElementRef="_2FE51DB1-3083-4BF7-AA71-0B0065310E72" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="963" y="225" width="136" height="62"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="980" y="220" width="136" height="62" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_21C50763-E49F-4D83-A824-16DA6AA87C64" dmnElementRef="_21C50763-E49F-4D83-A824-16DA6AA87C64" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="532" y="89" width="136" height="62"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="532" y="89" width="136" height="62" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" dmnElementRef="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="531.1214953271028" y="360" width="134" height="61"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="531.1214953271028" y="360" width="134" height="61" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_DA5CCF62-90A8-4CFC-A137-98B528522588" dmnElementRef="_DA5CCF62-90A8-4CFC-A137-98B528522588" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="99.09345794392524" y="359" width="136" height="63"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="99.09345794392524" y="359" width="136" height="63" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNShape id="dmnshape-drg-_C98BE939-B9C7-43E0-83E8-EE7A16C5276D" dmnElementRef="_C98BE939-B9C7-43E0-83E8-EE7A16C5276D" isCollapsed="false">
<dmndi:DMNStyle>
- <dmndi:FillColor red="255" green="255" blue="255"/>
- <dmndi:StrokeColor red="0" green="0" blue="0"/>
- <dmndi:FontColor red="0" green="0" blue="0"/>
+ <dmndi:FillColor red="255" green="255" blue="255" />
+ <dmndi:StrokeColor red="0" green="0" blue="0" />
+ <dmndi:FontColor red="0" green="0" blue="0" />
</dmndi:DMNStyle>
- <dc:Bounds x="747" y="224.64473684210526" width="134" height="65"/>
- <dmndi:DMNLabel/>
+ <dc:Bounds x="760" y="220" width="134" height="65" />
+ <dmndi:DMNLabel />
</dmndi:DMNShape>
<dmndi:DMNEdge id="dmnedge-drg-_89EEAF9F-5A5D-4F59-91B7-EA418A7229AF" dmnElementRef="_89EEAF9F-5A5D-4F59-91B7-EA418A7229AF">
- <di:waypoint x="383.0607476635514" y="361"/>
- <di:waypoint x="599" y="287"/>
+ <di:waypoint x="383.0607476635514" y="361" />
+ <di:waypoint x="599" y="287" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_87730C5A-5648-415B-9189-EF4D8805F8C9" dmnElementRef="_87730C5A-5648-415B-9189-EF4D8805F8C9">
- <di:waypoint x="598.1214953271028" y="390.5"/>
- <di:waypoint x="599" y="287"/>
+ <di:waypoint x="598.1214953271028" y="390.5" />
+ <di:waypoint x="599" y="287" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_63DE7C3B-A767-4B8A-A098-91ECB4B8D330" dmnElementRef="_63DE7C3B-A767-4B8A-A098-91ECB4B8D330">
- <di:waypoint x="814.5" y="359.3421052631579"/>
- <di:waypoint x="599" y="287"/>
+ <di:waypoint x="827.5" y="360" />
+ <di:waypoint x="599" y="287" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_2C95829D-FCF9-44F5-8F5A-0A6CDB60600D" dmnElementRef="_2C95829D-FCF9-44F5-8F5A-0A6CDB60600D">
- <di:waypoint x="814" y="257.14473684210526"/>
- <di:waypoint x="667" y="256"/>
+ <di:waypoint x="827" y="252.5" />
+ <di:waypoint x="667" y="256" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_77BA409B-E00D-4FBC-B522-8F656D4F6F0E" dmnElementRef="_77BA409B-E00D-4FBC-B522-8F656D4F6F0E">
- <di:waypoint x="383.0607476635514" y="391.5"/>
- <di:waypoint x="383" y="287"/>
+ <di:waypoint x="383.0607476635514" y="391.5" />
+ <di:waypoint x="383" y="287" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_4D441C11-7042-49CF-A42C-17A4348A7F29" dmnElementRef="_4D441C11-7042-49CF-A42C-17A4348A7F29">
- <di:waypoint x="167.09345794392524" y="255.17105263157896"/>
- <di:waypoint x="315" y="256"/>
+ <di:waypoint x="167.09345794392524" y="255.17105263157896" />
+ <di:waypoint x="315" y="256" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_3217D655-4484-4733-A9AE-4F9CF30D9924" dmnElementRef="_3217D655-4484-4733-A9AE-4F9CF30D9924">
- <di:waypoint x="167.09345794392524" y="359"/>
- <di:waypoint x="383" y="287"/>
+ <di:waypoint x="167.09345794392524" y="359" />
+ <di:waypoint x="383" y="287" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_31A1B6B2-A2A6-4E03-B898-26573A5CF3BA" dmnElementRef="_31A1B6B2-A2A6-4E03-B898-26573A5CF3BA">
- <di:waypoint x="1030" y="389.5"/>
- <di:waypoint x="1031" y="287"/>
- </dmndi:DMNEdge>
- <dmndi:DMNEdge id="dmnedge-drg-_A3E95B32-2EFD-40AD-B5E4-0A73A1542011" dmnElementRef="_A3E95B32-2EFD-40AD-B5E4-0A73A1542011">
- <di:waypoint x="383" y="256"/>
- <di:waypoint x="600" y="151"/>
+ <di:waypoint x="1047" y="390.5" />
+ <di:waypoint x="1048" y="282" />
</dmndi:DMNEdge>
<dmndi:DMNEdge id="dmnedge-drg-_0B992F01-BA77-4F06-A830-D8948B467272" dmnElementRef="_0B992F01-BA77-4F06-A830-D8948B467272">
- <di:waypoint x="599" y="256"/>
- <di:waypoint x="600" y="151"/>
+ <di:waypoint x="599" y="256" />
+ <di:waypoint x="600" y="151" />
+ </dmndi:DMNEdge>
+ <dmndi:DMNEdge id="dmnedge-drg-_B6002F33-4888-48C5-B265-636030F8C2DC" dmnElementRef="_B6002F33-4888-48C5-B265-636030F8C2DC" sourceElement="dmnshape-drg-_2FE51DB1-3083-4BF7-AA71-0B0065310E72" targetElement="dmnshape-drg-_21C50763-E49F-4D83-A824-16DA6AA87C64">
+ <di:waypoint x="1048" y="220" />
+ <di:waypoint x="600" y="151" />
</dmndi:DMNEdge>
- <dmndi:DMNEdge id="dmnedge-drg-_B6002F33-4888-48C5-B265-636030F8C2DC" dmnElementRef="_B6002F33-4888-48C5-B265-636030F8C2DC">
- <di:waypoint x="1031" y="256"/>
- <di:waypoint x="600" y="151"/>
+ <dmndi:DMNEdge id="dmnedge-drg-_A3E95B32-2EFD-40AD-B5E4-0A73A1542011" dmnElementRef="_A3E95B32-2EFD-40AD-B5E4-0A73A1542011" sourceElement="dmnshape-drg-_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" targetElement="dmnshape-drg-_21C50763-E49F-4D83-A824-16DA6AA87C64">
+ <di:waypoint x="383" y="225" />
+ <di:waypoint x="600" y="151" />
</dmndi:DMNEdge>
</dmndi:DMNDiagram>
</dmndi:DMNDI>
+ <dmn:import id="_E4562608-B14C-4845-A4C3-6C1A1FBC0219" name="sumBkm" importType="https://www.omg.org/spec/DMN/20230324/MODEL/" namespace="https://kie.org/dmn/_923784BD-CD31-488A-9C31-C1A83C5483C0" />
+ <dmn:import id="_C726A824-9349-4CF8-91FA-F969250C8421" name="sumDiffDs" importType="https://www.omg.org/spec/DMN/20230324/MODEL/" namespace="https://kie.org/dmn/_D19B0015-2CBD-4BA8-84A9-5F554D84A9E1" />
+ <dmn:import id="_87CDD600-7564-CF87-547E-A8B876CD0812" name="testTreePmml" importType="https://www.dmg.org/PMML-4_2" namespace="https://kie.org/pmml#dev-webapp/available-models-to-include/testTree.pmml" />
</dmn:definitions>
+`;
diff --git a/packages/dmn-editor/dev-webapp/src/DevWebApp.tsx b/packages/dmn-editor/dev-webapp/src/DevWebApp.tsx
new file mode 100644
index 00000000000..0f90a21cd47
--- /dev/null
+++ b/packages/dmn-editor/dev-webapp/src/DevWebApp.tsx
@@ -0,0 +1,224 @@
+/*
+ * 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, useRef, useState } from "react";
+
+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 { DEFAULT_DEV_WEBAPP_DMN } from "./DefaultDmn";
+import * as DmnEditor from "../../src/DmnEditor";
+import { DmnLatestModel, getMarshaller, DmnMarshaller } from "@kie-tools/dmn-marshaller";
+
+import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
+import { DMN15_SPEC } from "../../src/Dmn15Spec";
+import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { availableModelsByPath, modelsByNamespace } from "./AvailableModelsToInclude";
+
+const initialDmnMarshaller = getMarshaller(DEFAULT_DEV_WEBAPP_DMN, { upgradeTo: "latest" });
+
+const EMPTY_DMN_15 = () => `<?xml version="1.0" encoding="UTF-8"?>
+<definitions
+ xmlns="${dmn15ns.get("")}"
+ expressionLanguage="${DMN15_SPEC.expressionLanguage.default}"
+ namespace="https://kie.org/dmn/${generateUuid()}"
+ id="${generateUuid()}"
+ name="DMN${generateUuid()}">
+</definitions>`;
+
+export function DevWebApp() {
+ const onDrop = useCallback((e: React.DragEvent) => {
+ console.log("DMN Editor :: Dev webapp :: File(s) dropped! Opening it.");
+
+ e.preventDefault(); // Necessary to disable the browser's default 'onDrop' handling.
+
+ if (e.dataTransfer.items) {
+ // Use DataTransferItemList interface to access the file(s)
+ [...e.dataTransfer.items].forEach((item, i) => {
+ if (item.kind === "file") {
+ const reader = new FileReader();
+ reader.addEventListener("load", ({ target }) => {
+ const marshaller = getMarshaller(target?.result as string, { upgradeTo: "latest" });
+ setState({ marshaller, stack: [marshaller.parser.parse()], pointer: 0 });
+ });
+ reader.readAsText(item.getAsFile() as any);
+ }
+ });
+ }
+ }, []);
+
+ const onDragOver = useCallback((e: React.DragEvent) => {
+ e.preventDefault(); // Necessary to disable the browser's default 'onDrop' handling.
+ }, []);
+
+ const ref = useRef<DmnEditor.DmnEditorRef>(null);
+
+ const reset = useCallback(() => {
+ const marshaller = getMarshaller(EMPTY_DMN_15(), { upgradeTo: "latest" });
+ setState({
+ marshaller,
+ stack: [marshaller.parser.parse()],
+ pointer: 0,
+ });
+ }, []);
+
+ const [state, setState] = useState<{ marshaller: DmnMarshaller; stack: DmnLatestModel[]; pointer: number }>({
+ marshaller: initialDmnMarshaller,
+ stack: [initialDmnMarshaller.parser.parse()],
+ pointer: 0,
+ });
+
+ const currentModel = state.stack[state.pointer];
+
+ const downloadRef = useRef<HTMLAnchorElement>(null);
+ const downloadAsXml = useCallback(() => {
+ if (downloadRef.current) {
+ const fileBlob = new Blob([state.marshaller.builder.build(currentModel)], { type: "text/xml" });
+ downloadRef.current.download = `dmn-${makeid(10)}.dmn`;
+ downloadRef.current.href = URL.createObjectURL(fileBlob);
+ downloadRef.current.click();
+ }
+ }, [currentModel, state.marshaller.builder]);
+
+ const copyAsXml = useCallback(() => {
+ navigator.clipboard.writeText(state.marshaller.builder.build(currentModel));
+ }, [currentModel, state.marshaller.builder]);
+
+ const undo = useCallback(() => {
+ setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1) }));
+ }, []);
+
+ const redo = useCallback(() => {
+ setState((prev) => ({ ...prev, pointer: Math.min(prev.stack.length - 1, prev.pointer + 1) }));
+ }, []);
+
+ const onModelChange = useCallback<DmnEditor.OnDmnModelChange>((model) => {
+ setState((prev) => {
+ const newStack = prev.stack.slice(0, prev.pointer + 1);
+ return {
+ ...prev,
+ stack: [...newStack, model],
+ pointer: newStack.length,
+ };
+ });
+ }, []);
+
+ const onRequestToJumpToPath = useCallback<DmnEditor.OnRequestToJumpToPath>((path) => {
+ alert("Jumping to file " + path);
+ }, []);
+
+ const externalModelsByNamespace = useMemo<DmnEditor.ExternalModelsIndex>(() => {
+ return (currentModel.definitions.import ?? []).reduce((acc, i) => {
+ acc[i["@_namespace"]] = modelsByNamespace[i["@_namespace"]];
+ return acc;
+ }, {} as DmnEditor.ExternalModelsIndex);
+ }, [currentModel.definitions.import]);
+
+ const onRequestExternalModelByPath = useCallback<DmnEditor.OnRequestExternalModelByPath>(async (path) => {
+ return availableModelsByPath[path] ?? null;
+ }, []);
+
+ const onRequestExternalModelsAvailableToInclude =
+ useCallback<DmnEditor.OnRequestExternalModelsAvailableToInclude>(async () => {
+ return Object.keys(availableModelsByPath);
+ }, []);
+
+ const evaluationResults = useMemo<DmnEditor.EvaluationResults>(() => {
+ return {};
+ }, []);
+
+ const validationMessages = useMemo<DmnEditor.ValidationMessages>(() => {
+ return {};
+ }, []);
+
+ const isUndoEnabled = state.pointer > 0;
+ const isRedoEnabled = state.pointer !== state.stack.length - 1;
+
+ return (
+ <>
+ <Page onDragOver={onDragOver} onDrop={onDrop}>
+ <PageSection variant={"light"} isFilled={false} padding={{ default: "padding" }}>
+ <Flex justifyContent={{ default: "justifyContentSpaceBetween" }}>
+ <FlexItem shrink={{ default: "shrink" }}>
+ <h3>DMN Editor :: Dev webapp </h3>
+ </FlexItem>
+ <FlexItem>
+ <h5>(Drag & drop a file anywhere to open it)</h5>
+ </FlexItem>
+ <FlexItem shrink={{ default: "shrink" }}>
+ <button disabled={!isUndoEnabled} style={{ opacity: isUndoEnabled ? 1 : 0.5 }} onClick={undo}>
+ {`Undo (${state.pointer})`}
+ </button>
+
+ <button disabled={!isRedoEnabled} style={{ opacity: isRedoEnabled ? 1 : 0.5 }} onClick={redo}>
+ {`Redo (${state.stack.length - 1 - state.pointer})`}
+ </button>
+ |
+ <button onClick={reset}>Reset</button>
+
+ <button onClick={copyAsXml}>Copy as XML</button>
+
+ <button onClick={downloadAsXml}>Download as XML</button>
+ </FlexItem>
+ </Flex>
+ <a ref={downloadRef} />
+ </PageSection>
+ <hr />
+ <PageSection
+ variant={"light"}
+ isFilled={true}
+ hasOverflowScroll={true}
+ aria-label={"editor"}
+ padding={{ default: "noPadding" }}
+ >
+ <DmnEditor.DmnEditor
+ ref={ref}
+ model={currentModel}
+ originalVersion={state.marshaller.originalVersion}
+ onModelChange={onModelChange}
+ onRequestExternalModelByPath={onRequestExternalModelByPath}
+ onRequestExternalModelsAvailableToInclude={onRequestExternalModelsAvailableToInclude}
+ externalModelsByNamespace={externalModelsByNamespace}
+ externalContextName={`Dev webapp`}
+ externalContextDescription={`You're using the DMN Dev webapp, so there's only two simple external models that can be included.`}
+ validationMessages={validationMessages}
+ evaluationResults={evaluationResults}
+ issueTrackerHref={`https://github.com/kiegroup/kie-issues/issues/new`}
+ onRequestToJumpToPath={onRequestToJumpToPath}
+ />
+ </PageSection>
+ </Page>
+ </>
+ );
+}
+
+function makeid(length: number) {
+ let result = "";
+ const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
+ const charactersLength = characters.length;
+ let counter = 0;
+ while (counter < length) {
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
+ counter += 1;
+ }
+ return result;
+}
diff --git a/packages/dmn-editor/dev-webapp/src/ExternalModels.ts b/packages/dmn-editor/dev-webapp/src/ExternalModels.ts
new file mode 100644
index 00000000000..7b23c229ae0
--- /dev/null
+++ b/packages/dmn-editor/dev-webapp/src/ExternalModels.ts
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+export const sumBkm = `<definitions
+ xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"
+ xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/"
+ xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/"
+ xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/"
+ xmlns:kie="https://kie.org/dmn/extensions/1.0"
+ expressionLanguage="https://www.omg.org/spec/DMN/20211108/FEEL/"
+ typeLanguage="http://www.omg.org/spec/DMN/20211108/FEEL/"
+ namespace="https://kie.org/dmn/_923784BD-CD31-488A-9C31-C1A83C5483C0"
+ id="_0E6F4D88-B955-404B-A31A-72BB7E1E6A77"
+ name="Sum BKM">
+<businessKnowledgeModel name="Sum BKM" id="_3646600D-035F-47B9-8DC6-3FABE844234F">
+ <variable name="New BKM" id="_94BAC9FD-8519-49F9-855A-F4FCBACD2A04" typeRef="number" />
+ <functionDefinition label="Sum BKM" kind="FEEL" typeRef="number">
+ <formalParameter id="_F3A70A69-09FF-417C-8F6C-BD9129231377" name="a" typeRef="number" />
+ <formalParameter id="_E51B1C6E-896B-41C0-B03E-85B3CD7B6655" name="b" typeRef="number" />
+ <literalExpression id="_FA1EE22B-CC6B-499F-95EE-68158A2F233B" label="Expression Name" typeRef="<Undefined>">
+ <text>a + b</text>
+ </literalExpression>
+ </functionDefinition>
+</businessKnowledgeModel>
+<dmndi:DMNDI>
+ <dmndi:DMNDiagram>
+ <dmndi:DMNShape id="_3506A087-AB60-428D-9C75-1E5F5D6F0947" dmnElementRef="_3646600D-035F-47B9-8DC6-3FABE844234F" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="40" y="60" width="160" height="80" />
+ </dmndi:DMNShape>
+ <di:extension>
+ <kie:ComponentsWidthsExtension>
+ <kie:ComponentWidths dmnElementRef="_FA1EE22B-CC6B-499F-95EE-68158A2F233B">
+ <kie:width>190</kie:width>
+ </kie:ComponentWidths>
+ </kie:ComponentsWidthsExtension>
+ </di:extension>
+ </dmndi:DMNDiagram>
+</dmndi:DMNDI>
+</definitions>
+`;
+
+export const sumDiffDs = `<definitions
+ xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"
+ xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/"
+ xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/"
+ xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/"
+ xmlns:kie="https://kie.org/dmn/extensions/1.0"
+ expressionLanguage="https://www.omg.org/spec/DMN/20211108/FEEL/"
+ typeLanguage="http://www.omg.org/spec/DMN/20211108/FEEL/"
+ namespace="https://kie.org/dmn/_D19B0015-2CBD-4BA8-84A9-5F554D84A9E1"
+ id="_F360CECB-5DF2-4546-A7A9-E5ECF0F5A872"
+ name="Sum and Diff DS">
+<decisionService name="Sum and Diff DS" id="_721B7634-7227-42B4-AAA4-17DE60A7A967">
+ <variable name="New Decision Service" id="_A996D4BD-CF69-4CC5-89C0-37CF2BD6BA6E" typeRef="context" />
+ <inputData href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+ <inputData href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+ <outputDecision href="#_1991FB34-1253-4A54-AD3D-89697938DDFA" />
+ <outputDecision href="#_05621ED4-9236-47F1-B93A-164A4527B136" />
+</decisionService>
+<decision name="Sum" id="_05621ED4-9236-47F1-B93A-164A4527B136">
+ <variable name="New Decision" id="_88ECA891-3837-40E6-BCBF-77BF24B26FD0" typeRef="number" />
+ <informationRequirement id="_81BD49F4-E279-48A4-AC71-89CE92EEDE9C">
+ <requiredInput href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+ </informationRequirement>
+ <informationRequirement id="_115B4C89-EBA8-4136-A70E-9D303D8E92C5">
+ <requiredInput href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+ </informationRequirement>
+ <literalExpression id="_2812E0EA-FD32-480F-89CD-D0FE5FA02172" label="Sum" typeRef="<Undefined>">
+ <text>a + b</text>
+ </literalExpression>
+</decision>
+<inputData name="a" id="_18FAE913-2B2A-479D-A53A-14A2D57C46E4">
+ <variable name="New Input Data" id="_250DB850-97F5-45C8-AFBB-207218BDAF7E" typeRef="number" />
+</inputData>
+<inputData name="b" id="_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1">
+ <variable name="New Input Data" id="_0FD3E491-93E4-4AC1-AB46-19A6C6A3E4F1" typeRef="number" />
+</inputData>
+<decision name="Diff" id="_1991FB34-1253-4A54-AD3D-89697938DDFA">
+ <variable name="New Decision" id="_47AD6FB1-1892-4E27-B46D-0AF95B18602E" typeRef="number" />
+ <informationRequirement id="_5CA8EA11-FDFF-410A-AB4F-AA7ACB9F7FDC">
+ <requiredInput href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+ </informationRequirement>
+ <informationRequirement id="_D9E5FB0F-1A8C-4733-BBAB-E4A55113F806">
+ <requiredInput href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+ </informationRequirement>
+ <literalExpression id="_C6BBFC2E-695F-4668-8A0E-D175FE7302C7" label="Diff" typeRef="<Undefined>">
+ <text>a - b</text>
+ </literalExpression>
+</decision>
+<itemDefinition id="_842F4E16-C9A2-47D4-A221-081673B98C2D" name="SumDiffContext" isCollection="false">
+ <itemComponent id="_4882D4FB-2146-4198-8640-33B951B893A7" name="Sum" isCollection="false">
+ <typeRef>number</typeRef>
+ </itemComponent>
+ <itemComponent id="_3EF27B7D-3378-429E-B6DB-B856F5EB0AE7" name="Diff" isCollection="false">
+ <typeRef>number</typeRef>
+ </itemComponent>
+</itemDefinition>
+<dmndi:DMNDI>
+ <dmndi:DMNDiagram>
+ <dmndi:DMNShape id="_495CB0A7-017A-4A2F-A4D7-3133C82708E0" dmnElementRef="_721B7634-7227-42B4-AAA4-17DE60A7A967" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="80" y="120" width="520" height="320" />
+ <dmndi:DMNDecisionServiceDividerLine>
+ <di:waypoint x="80" y="280" />
+ <di:waypoint x="500" y="280" />
+ </dmndi:DMNDecisionServiceDividerLine>
+ </dmndi:DMNShape>
+ <dmndi:DMNShape id="_80C42026-FF56-44C6-84F9-F7A03686F5E8" dmnElementRef="_05621ED4-9236-47F1-B93A-164A4527B136" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="140" y="180" width="160" height="80" />
+ </dmndi:DMNShape>
+ <dmndi:DMNShape id="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" dmnElementRef="_18FAE913-2B2A-479D-A53A-14A2D57C46E4" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="80" y="480" width="160" height="80" />
+ </dmndi:DMNShape>
+ <dmndi:DMNShape id="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" dmnElementRef="_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="440" y="480" width="160" height="80" />
+ </dmndi:DMNShape>
+ <dmndi:DMNEdge id="_768C5D6E-9A41-4AA3-921C-A545E8F11597" dmnElementRef="_81BD49F4-E279-48A4-AC71-89CE92EEDE9C" sourceElement="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" targetElement="_80C42026-FF56-44C6-84F9-F7A03686F5E8">
+ <di:waypoint x="160" y="520" />
+ <di:waypoint x="220" y="260" />
+ </dmndi:DMNEdge>
+ <dmndi:DMNEdge id="_79E2E532-8D84-40C9-91DA-07EA606798E5" dmnElementRef="_115B4C89-EBA8-4136-A70E-9D303D8E92C5" sourceElement="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" targetElement="_80C42026-FF56-44C6-84F9-F7A03686F5E8">
+ <di:waypoint x="520" y="520" />
+ <di:waypoint x="220" y="260" />
+ </dmndi:DMNEdge>
+ <dmndi:DMNShape id="_1553EB6C-2BE8-4BC3-8972-A87308B98C86" dmnElementRef="_1991FB34-1253-4A54-AD3D-89697938DDFA" isCollapsed="false" isListedInputData="false">
+ <dc:Bounds x="380" y="180" width="160" height="80" />
+ </dmndi:DMNShape>
+ <dmndi:DMNEdge id="_C6979483-DBBA-4AC0-AB28-E12EFEF08654" dmnElementRef="_5CA8EA11-FDFF-410A-AB4F-AA7ACB9F7FDC" sourceElement="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" targetElement="_1553EB6C-2BE8-4BC3-8972-A87308B98C86">
+ <di:waypoint x="160" y="520" />
+ <di:waypoint x="460" y="260" />
+ </dmndi:DMNEdge>
+ <dmndi:DMNEdge id="_378C5213-084B-4A1D-ADCC-CEFE41F7E9FC" dmnElementRef="_D9E5FB0F-1A8C-4733-BBAB-E4A55113F806" sourceElement="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" targetElement="_1553EB6C-2BE8-4BC3-8972-A87308B98C86">
+ <di:waypoint x="520" y="520" />
+ <di:waypoint x="460" y="260" />
+ </dmndi:DMNEdge>
+ <di:extension>
+ <kie:ComponentsWidthsExtension>
+ <kie:ComponentWidths dmnElementRef="_2812E0EA-FD32-480F-89CD-D0FE5FA02172">
+ <kie:width>190</kie:width>
+ </kie:ComponentWidths>
+ <kie:ComponentWidths dmnElementRef="_C6BBFC2E-695F-4668-8A0E-D175FE7302C7">
+ <kie:width>190</kie:width>
+ </kie:ComponentWidths>
+ </kie:ComponentsWidthsExtension>
+ </di:extension>
+ </dmndi:DMNDiagram>
+</dmndi:DMNDI>
+</definitions>
+`;
+// Copied from kogito-examples/kogito-quarkus-examples/dmn-pmml-quarkus-example/src/main/resources
+export const testTreePmml = `<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xmlns="http://www.dmg.org/PMML-4_2">
+<Header>
+ <Application name="Drools-PMML" version="7.0.0-SNAPSHOT" />
+</Header>
+
+<DataDictionary numberOfFields="3">
+ <DataField name="temperature" dataType="double" optype="continuous" />
+ <DataField name="humidity" dataType="double" optype="continuous" />
+ <DataField name="decision" dataType="string" optype="categorical">
+ <Value value="sunglasses" />
+ <Value value="umbrella" />
+ <Value value="nothing" />
+ </DataField>
+</DataDictionary>
+
+<TreeModel modelName="DecisionTree" functionName="classification">
+ <MiningSchema>
+ <MiningField name="temperature" usageType="active" />
+ <MiningField name="humidity" usageType="active" />
+ <MiningField name="decision" usageType="predicted" />
+ </MiningSchema>
+ <Output>
+ <OutputField name="weatherdecision" targetField="decision" />
+ </Output>
+
+ <Node score="nothing" id="1">
+ <True />
+ <Node score="sunglasses" id="2">
+ <CompoundPredicate booleanOperator="and">
+ <SimplePredicate field="temperature" operator="greaterThan" value="25" />
+ <SimplePredicate field="humidity" operator="lessOrEqual" value="20" />
+ </CompoundPredicate>
+ </Node>
+ <Node score="umbrella" id="3">
+ <SimplePredicate field="humidity" operator="greaterThan" value="50" />
+ </Node>
+ <Node score="nothing" id="4">
+ <True />
+ </Node>
+ </Node>
+</TreeModel>
+</PMML>
+`;
diff --git a/packages/dashbuilder-editor/tests/jest.setup.ts b/packages/dmn-editor/dev-webapp/src/index.css
similarity index 86%
copy from packages/dashbuilder-editor/tests/jest.setup.ts
copy to packages/dmn-editor/dev-webapp/src/index.css
index f23267ef470..3322a4fd9e0 100644
--- a/packages/dashbuilder-editor/tests/jest.setup.ts
+++ b/packages/dmn-editor/dev-webapp/src/index.css
@@ -17,7 +17,19 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+* {
+ box-sizing: border-box;
+}
-enableAllPlugins();
+html {
+ height: 100vh;
+ margin: 0;
+}
+
+body {
+ margin: 0;
+}
+
+#dev-webapp {
+ height: 100%;
+}
diff --git a/packages/pmml-editor/tests/jest.setup.ts b/packages/dmn-editor/dev-webapp/src/index.tsx
similarity index 79%
copy from packages/pmml-editor/tests/jest.setup.ts
copy to packages/dmn-editor/dev-webapp/src/index.tsx
index f23267ef470..11e8d5416df 100644
--- a/packages/pmml-editor/tests/jest.setup.ts
+++ b/packages/dmn-editor/dev-webapp/src/index.tsx
@@ -17,7 +17,10 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+import * as React from "react";
+import * as ReactDOM from "react-dom";
-enableAllPlugins();
+import { DevWebApp } from "./DevWebApp";
+import "./index.css";
+
+ReactDOM.render(<DevWebApp />, document.getElementById("dev-webapp"));
diff --git a/packages/dmn-editor/dev-webapp/static/dmn-logo.jpg b/packages/dmn-editor/dev-webapp/static/dmn-logo.jpg
new file mode 100644
index 00000000000..7eb4e817850
Binary files /dev/null and b/packages/dmn-editor/dev-webapp/static/dmn-logo.jpg differ
diff --git a/packages/dmn-editor/dev-webapp/static/favicon.ico b/packages/dmn-editor/dev-webapp/static/favicon.ico
new file mode 100644
index 00000000000..c310c539a22
Binary files /dev/null and b/packages/dmn-editor/dev-webapp/static/favicon.ico differ
diff --git a/packages/dmn-editor/dev-webapp/static/index.html b/packages/dmn-editor/dev-webapp/static/index.html
new file mode 100644
index 00000000000..d9175dac04a
--- /dev/null
+++ b/packages/dmn-editor/dev-webapp/static/index.html
@@ -0,0 +1,40 @@
+<!--
+ ~ 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.
+ -->
+
+<!DOCTYPE html>
+<html lang="en-US">
+ <head>
+ <meta charset="utf-8" />
+ <title>DMN Editor - Dev webapp</title>
+ <meta id="appName" name="application-name" content="DMN Editor" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <link rel="icon" type="image/svg+xml" href="./favicon.ico" />
+ <!-- Issue workaround for React v16. -->
+ <script>
+ // See https://github.com/facebook/react/issues/20829#issuecomment-802088260
+ if (!crossOriginIsolated) SharedArrayBuffer = ArrayBuffer;
+ </script>
+ </head>
+
+ <body>
+ <noscript>Enabling JavaScript is required to run this app.</noscript>
+ <div id="dev-webapp" style="height: 100vh"></div>
+ <script src="index.js"></script>
+ </body>
+</html>
diff --git a/packages/dmn-editor/dev-webapp/tsconfig.json b/packages/dmn-editor/dev-webapp/tsconfig.json
new file mode 100644
index 00000000000..5ef2b24fdc9
--- /dev/null
+++ b/packages/dmn-editor/dev-webapp/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "esModuleInterop": true,
+ "lib": ["DOM.Iterable", "es6", "dom", "es2018.promise", "es2019", "esnext"]
+ }
+}
diff --git a/packages/pmml-vscode-extension/webpack.config.js b/packages/dmn-editor/dev-webapp/webpack.config.js
similarity index 56%
copy from packages/pmml-vscode-extension/webpack.config.js
copy to packages/dmn-editor/dev-webapp/webpack.config.js
index 41d2d4e8c35..2da55806e3d 100644
--- a/packages/pmml-vscode-extension/webpack.config.js
+++ b/packages/dmn-editor/dev-webapp/webpack.config.js
@@ -17,43 +17,28 @@
* under the License.
*/
-const patternflyBase = require("@kie-tools-core/patternfly-base");
+const path = require("path");
+const CopyPlugin = require("copy-webpack-plugin");
const { merge } = require("webpack-merge");
const common = require("@kie-tools-core/webpack-base/webpack.common.config");
+const patternflyBase = require("@kie-tools-core/patternfly-base");
+const { env } = require("../env");
+const buildEnv = env;
-const commonConfig = (env) =>
+module.exports = (env) =>
merge(common(env), {
- output: {
- library: "PmmlEditor",
- libraryTarget: "umd",
- umdNamedDefine: true,
- globalObject: "this",
- },
- externals: {
- vscode: "commonjs vscode",
- },
- });
-
-module.exports = async (env) => [
- merge(commonConfig(env), {
- target: "web",
+ mode: "development",
entry: {
- "extension/extension": "./src/extension/extension.ts",
+ index: path.resolve(__dirname, "./src/index.tsx"),
},
- }),
- merge(commonConfig(env), {
- target: "web",
- entry: {
- "webview/PmmlEditorEnvelopeApp": "./src/webview/PmmlEditorEnvelopeApp.ts",
- },
- resolve: {
- alias: {
- // `react-monaco-editor` points to the `monaco-editor` package by default, therefore doesn't use our minified
- // version. To solve that, we fool webpack, saying that every import for Monaco directly should actually point to
- // `@kiegroup/monaco-editor`. This way, everything works as expected.
- "monaco-editor/esm/vs/editor/editor.api": require.resolve("@kie-tools-core/monaco-editor"),
- },
+ output: {
+ path: path.resolve(__dirname, "../dist-dev-webapp"),
},
+ plugins: [
+ new CopyPlugin({
+ patterns: [{ from: path.resolve(__dirname, "./static"), to: "./" }],
+ }),
+ ],
module: {
rules: [
{
@@ -63,5 +48,14 @@ module.exports = async (env) => [
...patternflyBase.webpackModuleRules,
],
},
- }),
-];
+ devServer: {
+ historyApiFallback: true,
+ compress: true,
+ port: buildEnv.dmnEditor.dev.port,
+ open: false,
+ hot: true,
+ client: {
+ overlay: true,
+ },
+ },
+ });
diff --git a/packages/dashbuilder-viewer/tests/jest.setup.ts b/packages/dmn-editor/env/index.js
similarity index 73%
copy from packages/dashbuilder-viewer/tests/jest.setup.ts
copy to packages/dmn-editor/env/index.js
index f23267ef470..567cab7c0d7 100644
--- a/packages/dashbuilder-viewer/tests/jest.setup.ts
+++ b/packages/dmn-editor/env/index.js
@@ -17,7 +17,17 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");
-enableAllPlugins();
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+ vars: varsWithName({}),
+ get env() {
+ return {
+ dmnEditor: {
+ dev: {
+ port: 3001,
+ },
+ },
+ };
+ },
+});
diff --git a/packages/boxed-expression-component/src/api/BeeGwtService.ts b/packages/dmn-editor/jest.config.js
similarity index 57%
copy from packages/boxed-expression-component/src/api/BeeGwtService.ts
copy to packages/dmn-editor/jest.config.js
index efd0df23e14..5a7cac2f7d1 100644
--- a/packages/boxed-expression-component/src/api/BeeGwtService.ts
+++ b/packages/dmn-editor/jest.config.js
@@ -17,13 +17,21 @@
* under the License.
*/
-import { ExpressionDefinition } from "./ExpressionDefinition";
-
-/**
- * This interface defines all the API methods which BoxedExpressionEditor component can use to dialog with GWT Layer
- */
-export interface BeeGwtService {
- getDefaultExpressionDefinition(logicType: string, dataType: string): ExpressionDefinition;
- openDataTypePage: () => void; // Just open the data types tab
- selectObject: (uuid?: string) => void; // Changes the Properties panel
-}
+module.exports = {
+ globals: {
+ "ts-jest": {
+ tsconfig: "<rootDir>/tsconfig.json",
+ },
+ },
+ reporters: ["default", ["jest-junit", { outputFile: "./dist-tests/junit-report.xml" }]],
+ moduleDirectories: ["node_modules"],
+ moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
+ testRegex: "/tests/.*\\.test\\.(jsx?|tsx?)$",
+ transform: {
+ "^.+\\.jsx?$": ["babel-jest", { presets: [["@babel/env", { targets: { node: "current" } }], "@babel/react"] }],
+ "^.+\\.tsx?$": "ts-jest",
+ },
+ moduleNameMapper: {
+ "\\.(css|less|sass|scss)$": "<rootDir>/tests/__mocks__/styleMock.js",
+ },
+};
diff --git a/packages/boxed-expression-component/package.json b/packages/dmn-editor/package.json
similarity index 54%
copy from packages/boxed-expression-component/package.json
copy to packages/dmn-editor/package.json
index 8053019d6be..db8f700bcdc 100644
--- a/packages/boxed-expression-component/package.json
+++ b/packages/dmn-editor/package.json
@@ -1,79 +1,87 @@
{
- "name": "@kie-tools/boxed-expression-component",
+ "name": "@kie-tools/dmn-editor",
"version": "0.0.0",
- "description": "The Boxed Expression editor component provides the possibility to edit the decision logic for decisions and BKMs nodes",
+ "description": "",
"license": "Apache-2.0",
"keywords": [],
+ "homepage": "https://github.com/kiegroup/kie-tools",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/kiegroup/kie-tools.git"
+ },
+ "bugs": {
+ "url": "https://github.com/kiegroup/kie-tools/issues"
+ },
+ "files": [
+ "dist",
+ "src"
+ ],
"scripts": {
"build:dev": "rimraf dist && pnpm copy:css && tsc -p tsconfig.json",
- "build:prod": "rimraf dist && pnpm copy:css && pnpm lint && tsc -p tsconfig.json && pnpm test && pnpm test:e2e",
- "build:storybook": "storybook build -o dist-storybook",
+ "build:dev-webapp": "rimraf ./dist-dev && webpack -c ./dev-webapp/webpack.config.js --env prod",
+ "build:prod": "rimraf dist && pnpm copy:css && pnpm lint && tsc -p tsconfig.json && pnpm test && pnpm test:it",
"copy:css": "copyfiles -u 1 \"src/**/*.{sass,scss,css}\" dist/",
- "deploy": "gh-pages -d dist-dev",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then \"kie-tools--eslint ./src\"",
- "start": "pnpm storybook-base --storybookArgs=\"dev -p $(build-env boxedExpressionComponent.storybook.port) --no-open\"",
+ "start": "webpack serve -c ./dev-webapp/webpack.config.js --host 0.0.0.0 --env dev",
"test": "run-script-if --ignore-errors \"$(build-env tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest --silent --verbose --passWithNoTests\"",
- "test:e2e": "run-script-if --ignore-errors \"$(build-env endToEndTests.ignoreFailures)\" --bool \"$(build-env endToEndTests.run)\" --then \"pnpm rimraf ./dist-e2e\" \"pnpm test:e2e:run\"",
- "test:e2e:open": "pnpm exec playwright show-report dist-e2e-tests/reports",
- "test:e2e:run": "pnpm exec playwright test"
+ "test:it": "echo 'No IT tests to run at this moment.'"
},
"dependencies": {
"@kie-tools-core/i18n": "workspace:*",
"@kie-tools-core/monaco-editor": "workspace:*",
"@kie-tools-core/operating-system": "workspace:*",
"@kie-tools-core/patternfly-base": "workspace:*",
+ "@kie-tools-core/react-hooks": "workspace:*",
+ "@kie-tools-core/switch-expression-ts": "workspace:*",
+ "@kie-tools/boxed-expression-component": "workspace:*",
"@kie-tools/dmn-feel-antlr4-parser": "workspace:*",
+ "@kie-tools/dmn-marshaller": "workspace:*",
"@kie-tools/feel-input-component": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
+ "@kie-tools/pmml-editor-marshaller": "workspace:*",
+ "@kie-tools/xml-parser-ts": "workspace:*",
"@patternfly/react-core": "^4.276.6",
"@patternfly/react-icons": "^4.93.6",
"@patternfly/react-styles": "^4.92.6",
- "@patternfly/react-table": "^4.112.39",
- "lodash": "^4.17.21",
- "papaparse": "^5.3.2",
+ "d3-drag": "^3.0.0",
+ "d3-selection": "^3.0.0",
+ "immer": "^10.0.3",
+ "moment": "^2.29.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "react-id-generator": "^3.0.1",
- "react-resizable": "^1.11.0",
- "react-table": "^7.6.2",
- "uuid": "^8.3.2"
+ "react-error-boundary": "^4.0.11",
+ "reactflow": "^11.8.3",
+ "uuid": "^8.3.2",
+ "zustand": "^4.4.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-react": "^7.16.0",
- "@babel/preset-typescript": "^7.22.5",
- "@jest/globals": "^26.6.2",
"@kie-tools-core/webpack-base": "workspace:*",
"@kie-tools/eslint": "workspace:*",
- "@kie-tools/playwright-base": "workspace:*",
"@kie-tools/root-env": "workspace:*",
- "@kie-tools/storybook-base": "workspace:*",
"@kie-tools/tsconfig": "workspace:*",
- "@playwright/test": "^1.38.1",
- "@storybook/addon-links": "^7.3.2",
- "@storybook/blocks": "^7.3.2",
- "@storybook/manager-api": "^7.3.2",
- "@storybook/preview-api": "^7.3.2",
- "@storybook/react": "^7.3.2",
- "@storybook/react-webpack5": "^7.3.2",
+ "@testing-library/jest-dom": "^5.16.1",
+ "@testing-library/react": "^11.2.6",
+ "@types/d3-drag": "^3.0.3",
+ "@types/d3-selection": "^3.0.6",
+ "@types/jest": "^26.0.23",
+ "@types/jest-when": "^2.7.4",
"@types/lodash": "^4.14.168",
- "@types/papaparse": "^5.3.2",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
- "@types/react-resizable": "^1.7.2",
- "@types/react-table": "^7.0.25",
+ "@types/testing-library__jest-dom": "^5.9.1",
+ "@types/testing-library__react": "^9.1.2",
"@types/uuid": "^8.3.0",
"copy-webpack-plugin": "^11.0.0",
"copyfiles": "^2.4.1",
"file-loader": "^6.2.0",
- "gh-pages": "^3.2.3",
"jest": "^26.6.3",
"jest-junit": "^14.0.0",
"jest-when": "^3.5.0",
- "react-json-view": "^1.21.3",
"rimraf": "^3.0.2",
- "storybook": "^7.3.2",
+ "start-server-and-test": "^1.12.1",
"ts-jest": "^26.5.6",
"typescript": "^4.6.2",
"webpack": "^5.88.2",
diff --git a/packages/dmn-editor/src/Dmn15Spec.ts b/packages/dmn-editor/src/Dmn15Spec.ts
new file mode 100644
index 00000000000..4d14fd2b0d9
--- /dev/null
+++ b/packages/dmn-editor/src/Dmn15Spec.ts
@@ -0,0 +1,104 @@
+/*
+ * 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 { ns as dmn10ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_0/ts-gen/meta";
+import { ns as dmn11ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_1/ts-gen/meta";
+import { ns as dmn12ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_2/ts-gen/meta";
+import { ns as dmn13ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_3/ts-gen/meta";
+import { ns as dmn14ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_4/ts-gen/meta";
+import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
+
+// Those two below are defined by the spec. See S-FEEL grammar. Rule 22: "name".
+const feelNameStart =
+ /^[?A-Z_a-z\uC0-\uD6\uD8-\uF6\uF8-\u2FF\u370-\u37D\u37F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF].*$/;
+const feelNamePart =
+ // ------------------------------------------------------------------------------------------------------ same as nameStart ------------------------------- ----------name part------------ --extra--
+ /^.[?A-Z_a-z\uC0-\uD6\uD8-\uF6\uF8-\u2FF\u370-\u37D\u37F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF\uB7\d\u0300-\u036F\u203F-\u2040.+-/*’\s^]*$/;
+
+// This is not part of the spec.
+const forbiddenEndingChars = /^.*[.:+-/*\s^]$/; // Although they're fine by the Spec, they can seriously complicate FEEL expressions readability.
+
+export type UniqueNameIndex = Map<string, string>;
+
+export const DMN15_SPEC = {
+ namedElement: {
+ isValidName: (id: string, name: string | undefined, allUniqueNames: UniqueNameIndex): boolean => {
+ return (
+ !!name?.trim() && // Names need to be non-empty.
+ !!name.match(feelNameStart) &&
+ !!name.match(feelNamePart) &&
+ !name?.trim().match(forbiddenEndingChars) &&
+ (!allUniqueNames.get(name?.trim()) || allUniqueNames.get(name?.trim()) === id) // All names need to be unique.
+ );
+ },
+ },
+ expressionLanguage: { default: `https://www.omg.org/spec/DMN/20230324/FEEL/` },
+ typeLanguage: { default: `https://www.omg.org/spec/DMN/20230324/FEEL/` },
+ IMPORT: {
+ name: {
+ isValid: (id: string, name: string, allUniqueNames: UniqueNameIndex) => {
+ // Empty strings are allowed for imports, so that imported elements can be used without a prefix.
+ // Source: https://www.omg.org/spec/DMN/1.5/Beta1/PDF. PDF page 40, document page 32. Section "6.3.3 Import Metamodel".
+ return name === "" || DMN15_SPEC.namedElement.isValidName(id, name, allUniqueNames);
+ },
+ },
+ },
+ BOXED: {
+ DECISION_TABLE: {
+ PreferredOrientation: { default: "Rule-as-Row" },
+ HitPolicy: { default: "UNIQUE" },
+ },
+ FUNCTION: {
+ kind: { default: "FEEL" },
+ JAVA: {
+ classFieldName: "class",
+ methodSignatureFieldName: "method signature",
+ },
+ PMML: {
+ documentFieldName: "document",
+ modelFieldName: "model",
+ },
+ },
+ },
+ ITEM_DEFINITIONS: {
+ isCollection: { default: "false" },
+ },
+ ANNOTATIONS: {
+ format: { default: "text/plain" },
+ },
+ ASSOCIATIONS: {
+ direction: { default: "None" },
+ },
+ SHAPE: {
+ isCollapsed: {
+ default: "false",
+ },
+ },
+};
+
+export const allDmnImportNamespaces = new Set([
+ dmn10ns.get("")!,
+ dmn11ns.get("")!,
+ dmn12ns.get("")!,
+ dmn13ns.get("")!,
+ dmn14ns.get("")!,
+ dmn15ns.get("")!,
+]);
+
+export const KIE_DMN_UNKNOWN_NAMESPACE = "https://kie.org/dmn/unknown";
diff --git a/packages/dmn-editor/src/DmnEditor.css b/packages/dmn-editor/src/DmnEditor.css
new file mode 100644
index 00000000000..43d6b7e42c1
--- /dev/null
+++ b/packages/dmn-editor/src/DmnEditor.css
@@ -0,0 +1,1022 @@
+/* (begin) global */
+.kie-dmn-editor--root {
+ height: 100%;
+}
+
+.kie-dmn-editor--diagram-container {
+ height: 100%;
+ position: relative;
+}
+
+.kie-dmn-editor--bee-container {
+ position: relative;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ user-select: none;
+ padding-left: 16px;
+}
+/* (end) global */
+
+/* (begin) diagram empty state */
+.kie-dmn-editor--diagram-empty-state {
+ border: 1px solid lightgray;
+ backdrop-filter: blur(4px);
+ background: rgb(255, 255, 255, 60%);
+ border-radius: 16px;
+ padding: 16px;
+ pointer-events: all;
+ box-shadow: 0 0 60px 20px #e1e1e1;
+}
+/* (end) diagram empty state */
+
+/* (begin) nodes */
+.kie-dmn-editor--node {
+ height: 100%;
+ width: 100%;
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ word-break: break-word;
+ overflow: hidden;
+ -webkit-line-clamp: 2; /* number of lines to show */
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ text-align: center;
+ position: absolute;
+ z-index: 10;
+ top: 0;
+ left: 0;
+ overflow: visible;
+}
+.kie-dmn-editor--node:focus {
+ outline: none;
+}
+.kie-dmn-editor--node.dimmed,
+.kie-dmn-editor--node-shape.dimmed {
+ opacity: 0.3;
+ pointer-events: none;
+}
+.kie-dmn-editor--node-shape {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 1;
+}
+.kie-dmn-editor--text-annotation-node {
+ text-align: left;
+ display: block;
+}
+
+.kie-dmn-editor--unknown-node {
+ color: red;
+}
+/* (end) nodes */
+
+/* (begin) decisionService and group nodes */
+/* DECISION SERVICES AND GROUPS HAVE A SPECIFIC SELECTION MECHANISM TO ALLOW EDITING EDGES INSIDE THEM */
+.kie-dmn-editor--node-decisionService-visibleRect {
+ pointer-events: none;
+}
+
+.kie-dmn-editor--node-containerNodeInteractionRect,
+.kie-dmn-editor--node-decisionService-interactionDividerLine {
+ pointer-events: stroke !important;
+ opacity: 0;
+ /* ⬇ Uncomment for debugging purposes:*/
+ /* stroke: purple;
+ opacity: 0.2; */
+}
+.kie-dmn-editor--node-decisionService-interactionDividerLine:not(.readonly):hover {
+ cursor: row-resize;
+}
+
+.react-flow__node-node_group,
+.react-flow__node-node_decisionService {
+ pointer-events: none !important;
+ background: transparent;
+ box-shadow: none !important;
+}
+.react-flow__node-node_group:not(.selected) .kie-dmn-editor--node-shape,
+.react-flow__node-node_decisionService:not(.selected) .kie-dmn-editor--node-shape {
+ filter: none !important;
+}
+.react-flow__node-node_decisionService .kie-dmn-editor--outgoing-stuff-node-panel,
+.react-flow__node-node_group .kie-dmn-editor--outgoing-stuff-node-panel,
+.react-flow__node-node_decisionService .kie-dmn-editor--editable-node-name-input span,
+.react-flow__node-node_group .kie-dmn-editor--editable-node-name-input span,
+.react-flow__node-node_decisionService .kie-dmn-editor--info-node-panel,
+.react-flow__node-node_group .kie-dmn-editor--info-node-panel,
+.react-flow__node-node_decisionService .kie-dmn-editor--data-type-node-panel,
+.react-flow__node-node_group .kie-dmn-editor--data-type-node-panel,
+.react-flow__node-node_decisionService .react-flow__resize-control div,
+.react-flow__node-node_group .react-flow__resize-control div {
+ pointer-events: all !important;
+}
+.kie-dmn-editor--decision-service-node {
+ position: relative;
+}
+.react-flow__node-node_decisionService.selected .kie-dmn-editor--decision-service-collapsed-button {
+ border-color: #006ba4 !important;
+}
+.kie-dmn-editor--decision-service-node .kie-dmn-editor--decision-service-collapsed-button {
+ border: 3px;
+ border-style: solid;
+ border-color: black;
+ font-weight: bold;
+ position: absolute;
+ width: 24px;
+ height: 25px;
+ font-size: 24px;
+ text-align: center;
+ bottom: 4px;
+ line-height: 21px;
+}
+.react-flow__node-node_decisionService .kie-dmn-editor--node-shape .kie-dmn-editor--decision-service-label {
+ font-family: system-ui;
+ font-size: 0.6em;
+ letter-spacing: 8px;
+ fill: #a9a9a9;
+}
+/* (end) decisionService and group nodes */
+
+/* (begin) external nodes */
+.kie-dmn-editor--node.external {
+ text-decoration: underline;
+}
+/* (end) external node */
+
+/* (begin) textAnnotation, and unknown nodes */
+.react-flow__node-node_unknown.selected:before,
+.react-flow__node-node_textAnnotation.selected:before {
+ content: "";
+ display: block;
+ position: absolute;
+ pointer-events: none;
+ border-radius: 6px;
+ top: -10px;
+ left: -10px;
+ width: calc(100% + 20px);
+ height: calc(100% + 20px);
+ backdrop-filter: blur(8px);
+}
+.react-flow__node-node_textAnnotation.selected:before {
+ border: 1px dashed #006ba4;
+ background-color: rgb(161 222 255 / 20%); /* Very slightly blue hue */
+}
+.react-flow__node-node_unknown.selected:before {
+ border: 1px dashed #a40000;
+ background-color: rgb(255 161 161 / 20%); /* Very slightly red hue */
+}
+/* (end) textAnnotation, and unknown nodes */
+
+/* (begin) palette */
+.kie-dmn-editor--drd-selector-popover .pf-c-popover__body {
+ padding: 0;
+}
+.kie-dmn-editor--drd-selector {
+ padding: 3px 8px 3px 16px;
+ border-radius: 99999px;
+ background: white;
+ border: 1px solid black;
+ display: flex;
+ align-items: center;
+}
+.kie-dmn-editor--drd-selector input {
+ overflow: hidden;
+ text-wrap: nowrap;
+ text-overflow: ellipsis;
+ max-width: 300px;
+ min-width: 50px;
+}
+.kie-dmn-editor--drd-selector:hover {
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+ filter: brightness(95%);
+}
+.kie-dmn-editor--drd-selector button {
+ border: 0;
+ padding: 4px 16px;
+ border-radius: 8px;
+ background: white;
+}
+.kie-dmn-editor--drd-selector button:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--drd-selector button:active {
+ filter: brightness(90%);
+}
+.kie-dmn-editor--drd-list button {
+ padding: 8px 16px;
+ margin: 4px 0;
+ margin-right: 16px;
+ border-radius: 12px;
+ text-align: left;
+ background: white;
+ border-radius: 8px;
+ border: 0;
+ max-width: 300px;
+ width: 100%;
+ overflow: hidden;
+ text-wrap: nowrap;
+ text-overflow: ellipsis;
+}
+.kie-dmn-editor--drd-list button.active {
+ color: #0067cc;
+ filter: brightness(95%);
+}
+.kie-dmn-editor--drd-list button:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--drd-list button:active {
+ filter: brightness(90%);
+}
+.kie-dmn-editor--palette {
+ width: 42px;
+ background: #fff;
+ border-radius: 40px;
+ border: 1px solid black;
+}
+.kie-dmn-editor--palette:hover {
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+}
+
+.kie-dmn-editor--palette.pulse {
+ animation: pulse 3s infinite;
+}
+
+@keyframes pulse {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.3);
+ }
+
+ 70% {
+ box-shadow: 0 0 20px 20px rgba(0, 0, 0, 0);
+ }
+
+ 100% {
+ box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0);
+ }
+}
+
+.kie-dmn-editor--palette-button {
+ margin: 0;
+ margin-bottom: 8px;
+ padding: 0;
+ width: 40px;
+ height: 40px;
+ max-width: 40px;
+ border-radius: 40px;
+ border: 0;
+ background: white;
+}
+.kie-dmn-editor--palette-button:hover {
+ filter: brightness(95%);
+ cursor: grab;
+}
+.kie-dmn-editor--palette-button:active {
+ filter: brightness(90%);
+ cursor: grabbing;
+}
+/* (end) palette */
+
+/* (begin) properties panel toggle */
+
+.kie-dmn-editor--properties-panel-toggle {
+ width: 42px;
+ background: #fff;
+ border-radius: 40px;
+ border: 1px solid black;
+}
+.kie-dmn-editor--properties-panel-toggle:hover {
+ box-shadow: -4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--properties-panel-toggle-button {
+ margin: 0;
+ width: 40px;
+ height: 40px;
+ max-width: 40px;
+ border-radius: 40px;
+ border: 0;
+ background: white;
+}
+.kie-dmn-editor--properties-panel-toggle-button:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--properties-panel-toggle-button:active {
+ filter: brightness(90%);
+}
+/* (end) properties panel toggle */
+
+/* (begin) version popover */
+.kie-dmn-editor--version-popover .pf-c-popover__body {
+ padding: 0;
+}
+/* (end) version popover */
+
+/* (begin) overlays panel toggle */
+.kie-dmn-editor--overlay-panel-popover .pf-c-popover__body {
+ padding: 0;
+}
+.kie-dmn-editor--overlays-panel-toggle {
+ margin-right: 16px;
+ width: 42px;
+ background: #fff;
+ border-radius: 40px;
+ border: 1px solid black;
+}
+.kie-dmn-editor--overlays-panel-toggle:hover {
+ box-shadow: -4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--overlays-panel-toggle-button {
+ margin: 0;
+ width: 40px;
+ height: 40px;
+ max-width: 40px;
+ border-radius: 40px;
+ border: 0;
+ background: white;
+}
+.kie-dmn-editor--overlays-panel-toggle-button:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--overlays-panel-toggle-button:active {
+ filter: brightness(90%);
+}
+
+.kie-dmn-editor--snap-slider .pf-c-slider__value > input {
+ max-width: 60px;
+ min-width: 60px;
+ width: 60px;
+}
+/* (end) overlays panel toggle */
+
+/* (begin) drg/external nodes panel toggle */
+.kie-dmn-editor--drg-panel-toggle {
+ margin-right: 16px;
+ width: 42px;
+ background: #fff;
+ border-radius: 40px;
+ border: 1px solid black;
+}
+.kie-dmn-editor--external-nodes-panel-toggle:hover,
+.kie-dmn-editor--drg-panel-toggle:hover {
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--external-nodes-panel-toggle-button,
+.kie-dmn-editor--drg-panel-toggle-button {
+ margin: 0;
+ width: 40px;
+ height: 40px;
+ max-width: 40px;
+ border-radius: 40px;
+ border: 0;
+ background: white;
+}
+.kie-dmn-editor--external-nodes-panel-toggle-button:hover,
+.kie-dmn-editor--drg-panel-toggle-button:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--external-nodes-panel-toggle-button:active,
+.kie-dmn-editor--drg-panel-toggle-button:active {
+ filter: brightness(90%);
+}
+.kie-dmn-editor--external-nodes-panel-toggle-button.active,
+.kie-dmn-editor--drg-panel-toggle-button.active {
+ color: #006ba4;
+}
+.kie-dmn-editor--palette-nodes-popover {
+ position: absolute;
+ top: 0;
+ left: 58px;
+ overflow: auto;
+ box-shadow: 0px 5px 10px 0px lightgray;
+ background: white;
+ width: 400px;
+}
+.kie-dmn-editor--external-nodes-panel-toggle {
+ margin-right: 16px;
+ width: 42px;
+ background: #fff;
+ border-radius: 40px;
+ border: 1px solid black;
+}
+.kie-dmn-editor--external-nodes-panel-toggle-button svg {
+ transform: scale(1, -1); /* Flip the 'migration icon' vertically, to point to the Diagram */
+}
+
+/* (end) drg/external nodes panel toggle */
+
+/* nodes */
+.kie-dmn-editor--outgoing-stuff-node-panel {
+ position: absolute;
+ left: calc(100% - 10px); /* - 1px to make sure it is directly connected to the node */
+ top: 0;
+ padding-left: 15px;
+ height: max(40%, 80px);
+ align-content: flex-start;
+}
+.kie-dmn-editor--outgoing-stuff-node-panel > div {
+ display: flex;
+ margin: 0 0 4px 0;
+ background: #fff;
+ border-radius: 24px;
+ border: 1px solid black;
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--outgoing-stuff-node-panel > div > div {
+ color: black;
+ margin: 0;
+ padding: 0;
+ width: 34px;
+ height: 34px;
+ max-width: 34px;
+ border-radius: 34px;
+ background: #fff;
+ border: 0;
+ cursor: pointer;
+ display: flex;
+ font-weight: bold;
+ align-items: center;
+ justify-content: center;
+}
+.kie-dmn-editor--outgoing-stuff-node-panel > div > div:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--outgoing-stuff-node-panel > div > div:active {
+ filter: brightness(90%);
+}
+
+/* (begin) node handles */
+/* To make sure connection lines are steadly glued to the
+handles, we make their indicators be ::before elements. The handle
+itself is a 0px by 0px div, as connection lines can move freely when
+the cursor is inside it. By making it adimensional, that never happens. */
+.kie-dmn-editor--node-handle.connecting::before {
+ content: "";
+ position: absolute;
+ background: #0388ce;
+ border-radius: 100%;
+ border: 1px solid black;
+ pointer-events: none;
+ width: 20px;
+ height: 20px;
+ top: -10px;
+ left: -10px;
+}
+.kie-dmn-editor--node-handle:not(.connecting)::before {
+ content: "";
+ position: absolute;
+ background: #0388ce;
+ border-radius: 100%;
+ border: 1px solid black;
+ pointer-events: none;
+ width: 14px;
+ height: 14px;
+ top: -7px;
+ left: -7px;
+}
+.kie-dmn-editor--node-handle {
+ /* These 0px are is by design. See explanation above. */
+ width: 0px;
+ min-width: 0px;
+ height: 0px;
+ min-height: 0px;
+ border: 0;
+ z-index: 20;
+}
+.kie-dmn-editor--node-handle.top {
+ top: 0;
+ left: 50%;
+}
+.kie-dmn-editor--node-handle.right {
+ top: 50%;
+ right: 0;
+}
+.kie-dmn-editor--node-handle.bottom {
+ bottom: 0;
+ left: 50%;
+}
+.kie-dmn-editor--node-handle.left {
+ top: 50%;
+ left: 0;
+}
+.kie-dmn-editor--node-handle.center {
+ top: 50%;
+ left: 50%;
+}
+/* (end) node handles */
+
+/* (begin) node panels */
+
+/* data type selector on inputData, decision, bkm, and decisionService nodes */
+.kie-dmn-editor--data-type-node-panel {
+ position: absolute;
+ top: -46px;
+ padding-bottom: 10px;
+ display: flex;
+ align-items: end;
+ zoom: 0.8;
+}
+.kie-dmn-editor--data-type-node-panel .kie-dmn-editor--data-type-jump-to-definition {
+ padding-left: 4px;
+ padding-right: 4px;
+}
+/* Customizing some patternfly components is hard... */
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type > div:first-of-type > div:first-of-type > button,
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type > div:first-of-type > div:first-of-type input,
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type > div:first-of-type > div:first-of-type,
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type > div:first-of-type,
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type > button,
+.kie-dmn-editor--data-type-node-panel > div > div:first-of-type,
+.kie-dmn-editor--data-type-node-panel > div {
+ border-radius: 99999px;
+ outline: none;
+}
+.kie-dmn-editor--data-type-node-panel > div {
+ padding-left: 12px;
+ border: 1.25px solid black;
+ background: white;
+ box-shadow: 5px 5px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--data-type-node-panel .pf-c-select__menu.pf-m-static {
+ text-align: left;
+ z-index: 999999;
+}
+.kie-dmn-editor--data-type-node-panel span {
+ height: 19px;
+}
+.kie-dmn-editor--data-type-node-panel .pf-c-button.pf-c-select__toggle-button.pf-m-plain {
+ margin-left: 24px;
+}
+.kie-dmn-editor--data-type-node-panel .pf-c-button.pf-m-control::after,
+.kie-dmn-editor--data-type-node-panel .pf-c-select__toggle.pf-m-typeahead::before {
+ border: 0;
+}
+.kie-dmn-editor--data-type-node-panel > div:hover {
+ backdrop-filter: brightness(95%);
+}
+.kie-dmn-editor--data-type-node-panel > div:active {
+ backdrop-filter: brightness(90%);
+}
+/* edit button on decision and bkm nodes */
+.kie-dmn-editor--edit-expression-node-panel {
+ position: absolute;
+ padding: 4px 8px;
+ bottom: -16px;
+ font-size: 0.7em;
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+ cursor: pointer;
+ background: white;
+ color: black;
+}
+.kie-dmn-editor--edit-expression-node-panel > .pf-c-label__content::before {
+ border: 1px solid black;
+}
+.kie-dmn-editor--edit-expression-node-panel:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--edit-expression-node-panel:active {
+ filter: brightness(90%);
+}
+.kie-dmn-editor--tabs ~ section {
+ overflow: auto;
+ height: calc(100% - 40px);
+}
+/* info button on all nodes */
+.kie-dmn-editor--info-node-panel {
+ position: absolute;
+ top: 0;
+ right: calc(100% + 4px - 21px);
+ padding-right: 21px;
+ height: max(25%, 40px);
+}
+.kie-dmn-editor--info-label {
+ padding: 4px 5px;
+ height: 19px;
+ cursor: pointer;
+ background: white;
+ color: black;
+ font-weight: bold;
+ box-shadow: 4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--info-label > .pf-c-label__content::before {
+ border: 1px solid black;
+}
+.kie-dmn-editor--info-label:hover {
+ filter: brightness(95%);
+}
+.kie-dmn-editor--info-label:active {
+ filter: brightness(90%);
+}
+/* (end) node panels */
+
+/* back button on boxed expression */
+.kie-dmn-editor--boxed-expression-back {
+ cursor: pointer;
+ background: white;
+ margin-left: -1px;
+ height: 40px;
+ width: 192px;
+ justify-content: center;
+}
+.kie-dmn-editor--boxed-expression-back > .pf-c-label__content::before {
+ border: 1px solid black;
+}
+.kie-dmn-editor--boxed-expression-back:hover {
+ filter: brightness(95%);
+ box-shadow: 2px 3px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--boxed-expression-back:active {
+ filter: brightness(90%);
+}
+
+/* (begin) edges with waypoints */
+.kie-dmn-editor--edge.dimmed {
+ opacity: 0.3;
+ pointer-events: none;
+}
+circle.kie-dmn-editor--diagram-edge-waypoint {
+ fill: black;
+ stroke-width: 8;
+ stroke: #006ba4;
+}
+circle.kie-dmn-editor--diagram-edge-waypoint:active,
+circle.kie-dmn-editor--diagram-edge-waypoint:hover {
+ stroke-width: 16;
+ cursor: grab;
+}
+.react-flow__edge.selected .kie-dmn-editor--edge-waypoint-potential,
+.react-flow__edge:not(.selected) .kie-dmn-editor--edge-waypoint-potential {
+ fill: #4d809b96;
+}
+.kie-dmn-editor--edge-waypoint-potential {
+ pointer-events: none;
+}
+/* (end) edges with waypoints */
+
+/* (begin) misc */
+.kie-dmn-editor--round-svg-container {
+ pointer-events: none;
+ width: 100%;
+ height: 100%;
+}
+.kie-dmn-editor--sticky-top-glass-header {
+ position: sticky;
+ top: 0;
+ left: 0;
+ z-index: 9999;
+ background: rgb(255, 255, 255, 60%);
+ backdrop-filter: blur(4px);
+ border-bottom: 1px solid lightgray;
+}
+.kie-dmn-editor--boxed-expression-header {
+ padding: 16px;
+}
+.kie-dmn-editor--data-type-panel-header {
+ padding: 0 16px 0 16px;
+ align-items: center !important;
+}
+.kie-dmn-editor--data-type-panel-header-nested-or-external {
+ height: 120px;
+ align-items: flex-end !important;
+ padding: 0 16px 0 16px;
+}
+/* (end) misc */
+
+/* (begin) external nodes */
+.kie-dmn-editor--external-nodes-section:not(:last-child) {
+ margin-bottom: 16px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid lightgray;
+}
+.kie-dmn-editor--external-nodes-section-title {
+ margin-bottom: 6px;
+}
+.kie-dmn-editor--external-nodes-list-item {
+ border-radius: 999px;
+ background: white;
+}
+.kie-dmn-editor--external-nodes-list-item:hover {
+ filter: brightness(95%);
+ cursor: grab;
+}
+.kie-dmn-editor--external-nodes-list-item:active {
+ filter: brightness(90%);
+ cursor: grabbing;
+}
+/* (end) external nodes */
+
+/* (begin) data type label */
+.kie-dmn-editor--data-type-label {
+ font-style: italic;
+ font-size: smaller;
+ color: #1b515f;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+/* (end) data type label */
+
+/* (begin) data types */
+.kie-dmn-editor--data-types-filter {
+ padding: 16px;
+}
+.kie-dmn-editor--data-types-filter input {
+ flex-grow: 1;
+}
+.kie-dmn-editor--data-types-nav {
+ padding-left: 16px;
+}
+.kie-dmn-editor--data-types-nav-item:first-child {
+ margin-top: 16px;
+}
+.kie-dmn-editor--data-types-nav-item {
+ display: flex;
+ align-items: baseline;
+ padding: 0 16px;
+ margin: 8px 0;
+ margin-right: 16px;
+ border-radius: 12px;
+ cursor: pointer;
+}
+.kie-dmn-editor--data-types-title {
+ flex-grow: 1;
+ font-size: 2em;
+}
+.kie-dmn-editor--data-types-title div,
+.kie-dmn-editor--data-types-title div input {
+ width: 100%;
+}
+.kie-dmn-editor--data-types-nav-item.active {
+ color: #0067cc;
+ backdrop-filter: brightness(95%);
+}
+.kie-dmn-editor--data-types-nav-item:hover {
+ backdrop-filter: brightness(90%);
+}
+.kie-dmn-editor--data-types-nav-item:focus {
+ backdrop-filter: brightness(80%);
+}
+.kie-dmn-editor--data-type-parents button {
+ padding: 6px !important;
+ margin-right: 36px !important;
+}
+.kie-dmn-editor--data-type-parents button:last-child::after {
+ content: "↴";
+ margin-top: 8px;
+}
+.kie-dmn-editor--data-type-parents button::after {
+ content: ">";
+ margin: 0;
+ font-size: 24px;
+ position: absolute;
+ padding: 8px;
+ pointer-events: none;
+ right: 0px;
+ width: calc(100% + 30px);
+ height: 100%;
+ text-align: right;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+}
+.kie-dmn-editor--data-type-properties-table--empty-state {
+ margin: 8px 24px 0 0;
+ padding: 24px;
+ background: #eee;
+ border-radius: 24px;
+ text-align: center;
+}
+.kie-dmn-editor--data-type-properties-table td,
+th {
+ padding: 12px;
+}
+.kie-dmn-editor--data-type-properties-table {
+ position: relative;
+ overflow: hidden;
+}
+.kie-dmn-editor--data-type-properties-table tr {
+ border-bottom: 1px solid lightgray;
+ position: relative;
+}
+/* Hover effect */
+.kie-dmn-editor--data-type-properties-table tbody tr:hover::after {
+ content: "";
+ position: absolute;
+ left: 0;
+ width: 6px;
+ height: 100%;
+ background: #0067cc;
+}
+/* Gradients for depth illusion */
+.kie-dmn-editor--data-type-properties-table .first-nested-at-level {
+ background: linear-gradient(to bottom, rgb(0, 0, 0, 0.07) 0, transparent 12px, transparent 100%);
+}
+.kie-dmn-editor--data-type-properties-table .last-nested-at-level {
+ background: linear-gradient(to top, rgb(0, 0, 0, 0.07) 0, transparent 12px, transparent 100%);
+}
+.kie-dmn-editor--data-type-properties-table .first-nested-at-level.last-nested-at-level {
+ background: linear-gradient(to bottom, rgb(0, 0, 0, 0.07) 0, transparent 12px, transparent 100%),
+ linear-gradient(to top, rgb(0, 0, 0, 0.07) 0, transparent 12px, transparent 100%);
+}
+.kie-dmn-editor--data-type-properties-table .pf-m-typeahead {
+ background: rgb(255, 255, 255, 0.7); /* Let */
+}
+.kie-dmn-editor--type-ref-selector-invalid-value input {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
+/* (end) data types */
+
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ⬇ (begin) react-flow theming ⬇ */
+/* ******************************* */
+
+/* edge selection / hover */
+.react-flow__edge > .kie-dmn-editor--edge {
+ pointer-events: none;
+}
+.react-flow__edge.selected > .kie-dmn-editor--edge {
+ fill: #006ba4 !important;
+ stroke: #006ba4 !important;
+ stroke-width: 3px !important;
+ filter: drop-shadow(2px 2px 2px #006ba477);
+}
+.react-flow__edge.selected .react-flow__edge-interaction.normal {
+ cursor: crosshair;
+}
+.react-flow__edge.selected .react-flow__edge-interaction.dragging-waypoint,
+.react-flow__edge.selected
+ .react-flow__edge-interaction.dragging-waypoint
+ ~ .kie-dmn-editor--diagram-edge-waypoints
+ circle {
+ cursor: grabbing;
+}
+.react-flow__edge:not(.selected) .kie-dmn-editor--edge:hover,
+.react-flow__edge:not(.selected) .react-flow__edge-interaction:hover + .kie-dmn-editor--edge {
+ stroke-width: 2px !important;
+}
+
+/* nodes selection / hover */
+.react-flow__node:not(.selected):hover > .kie-dmn-editor--node-shape.normal {
+ filter: drop-shadow(2px 2px 2px rgb(127, 127, 127));
+}
+.react-flow__node.selected {
+ color: #006ba4 !important;
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target-invalid ~ .kie-dmn-editor--node,
+.react-flow__node
+ > .kie-dmn-editor--node-shape.drop-target-invalid
+ ~ .kie-dmn-editor--node
+ .kie-dmn-editor--decision-service-collapsed-button {
+ border-color: red !important;
+ color: red !important;
+ opacity: 0.4;
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target-invalid {
+ border-color: red !important;
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target-invalid > g * {
+ stroke: rgba(255, 0, 0, 0.2) !important;
+ fill: rgba(164, 0, 0, 0.1) !important;
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target ~ .kie-dmn-editor--node {
+ color: #006ba4 !important;
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target,
+.react-flow__node.selected > .kie-dmn-editor--node-shape.normal {
+ border-color: #006ba4 !important;
+ filter: drop-shadow(2px 2px 2px #006ba477);
+}
+.react-flow__node > .kie-dmn-editor--node-shape.drop-target > g * {
+ stroke: #006ba4 !important;
+ fill: rgba(0, 107, 164, 0.1) !important;
+}
+
+.react-flow__node.selected:not(.react-flow__node-node_unknown) > .kie-dmn-editor--node-shape > g * {
+ stroke: #006ba4 !important;
+}
+
+/* hierarchy view */
+
+.react-flow__node.hierarchy.up::after,
+.react-flow__node.hierarchy.down::after {
+ content: "";
+ width: calc(100% + 20px);
+ height: calc(100% + 20px);
+ position: absolute;
+ top: -10px;
+ left: -10px;
+ border-radius: 24px;
+}
+.react-flow__node.hierarchy.up::after {
+ background-color: rgba(0, 131, 164, 0.15);
+}
+.react-flow__node.hierarchy.down::after {
+ background-color: rgb(0 1 128 / 10%);
+}
+.react-flow__edge.hierarchy.up .react-flow__edge-interaction {
+ stroke: rgba(0, 131, 164, 0.15);
+}
+.react-flow__edge.hierarchy.down .react-flow__edge-interaction {
+ stroke: rgb(0 1 128 / 10%);
+}
+
+/* selection rect */
+.react-flow__nodesselection-rect {
+ display: none;
+}
+
+/* controls */
+.react-flow__controls {
+ border-radius: 20px;
+ border: 1px solid black;
+ background: white;
+ margin-bottom: 24px;
+}
+.react-flow__controls:hover {
+ box-shadow: -4px -4px 2px 0px rgb(127 127 127);
+}
+.react-flow__controls > button {
+ border-radius: 20px;
+}
+.react-flow__controls > button:hover {
+ filter: brightness(95%);
+}
+.react-flow__controls > button:active {
+ filter: brightness(90%);
+}
+.react-flow__controls {
+ border-radius: 1000px;
+}
+.react-flow__controls-button {
+ width: 30px;
+ height: 30px;
+ border: 0;
+ border-radius: 1000px;
+}
+.react-flow__resize-control {
+ z-index: 0;
+}
+
+/* This is the rectangle that renders when dragging to select nodes. It shouldn't have any interaction with the mouse, as it messes hoverInfo for nodes. */
+.react-flow__selection.react-flow__container {
+ pointer-events: none;
+}
+
+/* This is the rectangle that renders when dragging to select nodes. It shouldn't have any interaction with the mouse, as it messes hoverInfo for nodes. */
+.react-flow__connectionline {
+ z-index: 10000;
+}
+
+/* edge updaters */
+.react-flow__edgeupdater {
+ z-index: 9000;
+ fill: white;
+ stroke: #006ba4;
+ stroke-width: 2px;
+ cursor: grab;
+}
+.react-flow__edge:not(.selected:hover) .react-flow__edgeupdater,
+.react-flow__edgeupdater.hidden {
+ opacity: 0;
+ pointer-events: none;
+}
+.react-flow__pane.selection {
+ cursor: crosshair;
+}
+/* attribution*/
+.react-flow__attribution {
+ margin-right: 7px;
+}
+/* ⬆ (end) react-flow theming ⬆ */
+
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ******************************* */
+/* ⬇ (begin) pf4 overrides ⬇ */
+/* ******************************* */
+.pf-c-popover {
+ max-width: unset;
+}
+
+.pf-c-truncate,
+.pf-c-truncate__start {
+ min-width: 0 !important;
+}
+
+.pf-c-select__menu {
+ margin-top: 1px;
+}
+/* ⬆ (end) pf4 overrides ⬆ */
diff --git a/packages/dmn-editor/src/DmnEditor.tsx b/packages/dmn-editor/src/DmnEditor.tsx
new file mode 100644
index 00000000000..1617b78c1e7
--- /dev/null
+++ b/packages/dmn-editor/src/DmnEditor.tsx
@@ -0,0 +1,348 @@
+import "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import { useCallback, useEffect, useImperativeHandle, useRef, useState, useMemo } from "react";
+import { Drawer, DrawerContent, DrawerContentBody } from "@patternfly/react-core/dist/js/components/Drawer";
+import { Tab, TabTitleIcon, TabTitleText, Tabs } from "@patternfly/react-core/dist/js/components/Tabs";
+import { FileIcon } from "@patternfly/react-icons/dist/js/icons/file-icon";
+import { InfrastructureIcon } from "@patternfly/react-icons/dist/js/icons/infrastructure-icon";
+import { PficonTemplateIcon } from "@patternfly/react-icons/dist/js/icons/pficon-template-icon";
+import { BoxedExpression } from "./boxedExpressions/BoxedExpression";
+import { DataTypes } from "./dataTypes/DataTypes";
+import { Diagram } from "./diagram/Diagram";
+import { DmnVersionLabel } from "./diagram/DmnVersionLabel";
+import { IncludedModels } from "./includedModels/IncludedModels";
+import { DiagramPropertiesPanel } from "./propertiesPanel/DiagramPropertiesPanel";
+import {
+ DmnEditorStoreApiContext,
+ DmnEditorTab,
+ StoreApiType,
+ createDmnEditorStore,
+ defaultStaticState,
+ useDmnEditorStore,
+ useDmnEditorStoreApi,
+} from "./store/Store";
+import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
+import { Label } from "@patternfly/react-core/dist/js/components/Label";
+import { BeePropertiesPanel } from "./propertiesPanel/BeePropertiesPanel";
+import { DmnEditorDerivedStoreContextProvider, useDmnEditorDerivedStore } from "./store/DerivedStore";
+import { DmnEditorContextProvider, useDmnEditor } from "./DmnEditorContext";
+import { DmnEditorExternalModelsContextProvider } from "./includedModels/DmnEditorDependenciesContext";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
+import { DmnEditorErrorFallback } from "./DmnEditorErrorFallback";
+import { DmnLatestModel, AllDmnMarshallers } from "@kie-tools/dmn-marshaller";
+import { PMML } from "@kie-tools/pmml-editor-marshaller";
+import { original } from "immer";
+
+import "@kie-tools/dmn-marshaller/dist/kie-extensions"; // This is here because of the KIE Extension for DMN.
+import "./DmnEditor.css"; // Leave it for last, as this overrides some of the PF and RF styles.
+
+const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;
+
+export type DmnEditorRef = {
+ reset: (mode: DmnLatestModel) => void;
+};
+
+export type EvaluationResults = Record<string, any>;
+export type ValidationMessages = Record<string, any>;
+export type OnDmnModelChange = (model: DmnLatestModel) => void;
+
+export type OnRequestToJumpToPath = (relativePath: string) => void;
+export type OnRequestToResolvePath = (relativePath: string) => string;
+export type OnRequestExternalModelsAvailableToInclude = () => Promise<string[]>;
+export type OnRequestExternalModelByPath = (relativePath: string) => Promise<ExternalModel | null>;
+export type ExternalModelsIndex = Record<string, ExternalModel | undefined>;
+export type ExternalModel = ({ type: "dmn" } & ExternalDmn) | ({ type: "pmml" } & ExternalPmml);
+
+export type ExternalDmnsIndex = Map<string, ExternalDmn>;
+export type ExternalDmn = { model: DmnLatestModel; relativePath: string; svg: string };
+
+export type ExternalPmmlsIndex = Map<string, ExternalPmml>;
+export type ExternalPmml = { model: PMML; relativePath: string };
+
+export type DmnEditorProps = {
+ /**
+ * The DMN itself.
+ */
+ model: DmnLatestModel;
+ /**
+ * The original version of `model` before upgrading to `latest`.
+ */
+ originalVersion?: AllDmnMarshallers["version"];
+ /**
+ * Called when a change occurs on `model`, so the controlled flow of the component can be done.
+ */
+ onModelChange?: OnDmnModelChange;
+ /**
+ * Called when the contents of a specific available model is necessary. Used by the "Included models" tab.
+ */
+ onRequestExternalModelByPath?: OnRequestExternalModelByPath;
+ /**
+ * Called when the list of paths of available models to be included is needed. Used by the "Included models" tab.
+ */
+ onRequestExternalModelsAvailableToInclude?: OnRequestExternalModelsAvailableToInclude;
+ /**
+ * When the DMN represented by `model` ("This DMN") contains `import`ed models, this prop needs to map their contents by namespace.
+ * The DMN model won't be correctly rendered if an included model is not found on this object.
+ */
+ externalModelsByNamespace?: ExternalModelsIndex;
+ /**
+ * To show information about execution results directly on the DMN diagram and/or Boxed Expression Editor, use this prop.
+ */
+ evaluationResults?: EvaluationResults;
+ /**
+ * To show information about validation messages directly on the DMN diagram and/or Boxed Expression Editor, use this prop.
+ */
+ validationMessages?: ValidationMessages;
+ /**
+ * The name of context in which this instance of DMN Editor is running. For example, if this DMN Editor instance
+ * is displaying a model from a project called "My project", you could use `externalContextName={"My project"}`
+ */
+ externalContextName?: string;
+ /**
+ * Describe the context in which this instance of DMN Editor is running. For example, if this DMN Editor instance
+ * is displaying a model from a project called "My project", you could use
+ * `externalContextDescription={'All models (DMN and PMML) of "My project" are available.'}`
+ */
+ externalContextDescription?: string;
+ /**
+ * A link that will take users to an issue tracker so they can report problems they find on the DMN Editor.
+ * This is shown on the ErrorBoundary fallback component, when an uncaught error happens.
+ */
+ issueTrackerHref?: string;
+ /**
+ * When users want to jump to another file, this method is called, allowing the controller of this component decide what to do.
+ * Links are only rendered if this is provided. Otherwise, paths will be rendered as text.
+ */
+ onRequestToJumpToPath?: OnRequestToJumpToPath;
+ /**
+ * All paths inside the DMN Editor are relative. To be able to resolve them and display them as absolute paths, this function is called.
+ * If undefined, the relative paths will be displayed.
+ */
+ onRequestToResolvePath?: OnRequestToResolvePath;
+};
+
+export const DmnEditorInternal = ({
+ model,
+ originalVersion,
+ onModelChange,
+ forwardRef,
+}: DmnEditorProps & { forwardRef?: React.Ref<DmnEditorRef> }) => {
+ const { boxedExpressionEditor, dmn, navigation, dispatch, diagram } = useDmnEditorStore((s) => s);
+
+ const dmnEditorStoreApi = useDmnEditorStoreApi();
+ const { isDiagramEditingInProgress } = useDmnEditorDerivedStore();
+ const { dmnModelBeforeEditingRef, dmnEditorRootElementRef } = useDmnEditor();
+
+ // Allow imperativelly controlling the Editor.
+ useImperativeHandle(
+ forwardRef,
+ () => ({
+ reset: (model) => dispatch.dmn.reset(model),
+ }),
+ [dispatch.dmn]
+ );
+
+ // Make sure the DMN Editor reacts to props changing.
+ useEffectAfterFirstRender(() => {
+ dmnEditorStoreApi.setState((state) => {
+ // Avoid unecessary state updates
+ if (model === original(state.dmn.model)) {
+ return;
+ }
+ state.dmn.model = model;
+ dmnModelBeforeEditingRef.current = model;
+ });
+ }, [dmnEditorStoreApi, dispatch.dmn, model]);
+
+ useStateAsItWasBeforeConditionBecameTrue(
+ dmn.model,
+ isDiagramEditingInProgress,
+ useCallback((prev) => (dmnModelBeforeEditingRef.current = prev), [dmnModelBeforeEditingRef])
+ );
+
+ // Only notify changes when dragging/resizing operations are not happening.
+ useEffectAfterFirstRender(() => {
+ if (isDiagramEditingInProgress) {
+ return;
+ }
+
+ const timeout = setTimeout(() => {
+ // Ignore changes made outside... If the controller of the component
+ // changed its props, it knows it already, we don't need to call "onModelChange" again.
+ if (model === dmn.model) {
+ return;
+ }
+
+ console.debug("DMN EDITOR: Model changed!");
+ onModelChange?.(dmn.model);
+ }, ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS);
+
+ return () => {
+ clearTimeout(timeout);
+ };
+ }, [isDiagramEditingInProgress, onModelChange, dmn.model]);
+
+ const onTabChanged = useCallback(
+ (e, tab) => {
+ dmnEditorStoreApi.setState((state) => {
+ state.navigation.tab = tab;
+ if (tab === DmnEditorTab.DATA_TYPES) {
+ // Keep the last selected if any. Default to first on list.
+ state.dataTypesEditor.activeItemDefinitionId =
+ state.dataTypesEditor.activeItemDefinitionId ?? state.dmn.model.definitions.itemDefinition?.[0]?.["@_id"];
+ }
+ });
+ },
+ [dmnEditorStoreApi]
+ );
+
+ const diagramContainerRef = useRef<HTMLDivElement>(null);
+ const beeContainerRef = useRef<HTMLDivElement>(null);
+
+ const tabTitle = useMemo(() => {
+ return {
+ editor: (
+ <>
+ <TabTitleIcon>
+ <PficonTemplateIcon />
+ </TabTitleIcon>
+ <TabTitleText>Editor</TabTitleText>
+ </>
+ ),
+ dataTypes: (
+ <>
+ <TabTitleIcon>
+ <InfrastructureIcon />
+ </TabTitleIcon>
+ <TabTitleText>
+ Data types
+ <Label style={{ padding: "0 12px" }}>{dmn.model.definitions.itemDefinition?.length ?? 0}</Label>
+ </TabTitleText>
+ </>
+ ),
+ includedModels: (
+ <>
+ <TabTitleIcon>
+ <FileIcon />
+ </TabTitleIcon>
+ <TabTitleText>
+ Included models
+ <Label style={{ padding: "0 12px" }}>{dmn.model.definitions.import?.length ?? 0}</Label>
+ </TabTitleText>
+ </>
+ ),
+ };
+ }, [dmn.model.definitions.import?.length, dmn.model.definitions.itemDefinition?.length]);
+
+ const diagramPropertiesPanel = useMemo(() => <DiagramPropertiesPanel />, []);
+ const beePropertiesPanel = useMemo(() => <BeePropertiesPanel />, []);
+
+ return (
+ <div ref={dmnEditorRootElementRef} className={"kie-dmn-editor--root"}>
+ <Tabs
+ isFilled={true}
+ activeKey={navigation.tab}
+ onSelect={onTabChanged}
+ role={"region"}
+ className={"kie-dmn-editor--tabs"}
+ >
+ <Tab eventKey={DmnEditorTab.EDITOR} title={tabTitle.editor}>
+ {navigation.tab === DmnEditorTab.EDITOR && (
+ <>
+ {!boxedExpressionEditor.activeDrgElementId && (
+ <Drawer isExpanded={diagram.propertiesPanel.isOpen} isInline={true} position={"right"}>
+ <DrawerContent panelContent={diagramPropertiesPanel}>
+ <DrawerContentBody>
+ <div className={"kie-dmn-editor--diagram-container"} ref={diagramContainerRef}>
+ {originalVersion && <DmnVersionLabel version={originalVersion} />}
+ <Diagram container={diagramContainerRef} />
+ </div>
+ </DrawerContentBody>
+ </DrawerContent>
+ </Drawer>
+ )}
+ {boxedExpressionEditor.activeDrgElementId && (
+ <Drawer isExpanded={boxedExpressionEditor.propertiesPanel.isOpen} isInline={true} position={"right"}>
+ <DrawerContent panelContent={beePropertiesPanel}>
+ <DrawerContentBody>
+ <div className={"kie-dmn-editor--bee-container"} ref={beeContainerRef}>
+ <BoxedExpression container={beeContainerRef} />
+ </div>
+ </DrawerContentBody>
+ </DrawerContent>
+ </Drawer>
+ )}
+ </>
+ )}
+ </Tab>
+
+ <Tab eventKey={DmnEditorTab.DATA_TYPES} title={tabTitle.dataTypes}>
+ {navigation.tab === DmnEditorTab.DATA_TYPES && <DataTypes />}
+ </Tab>
+
+ <Tab eventKey={DmnEditorTab.INCLUDED_MODELS} title={tabTitle.includedModels}>
+ {navigation.tab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
+ </Tab>
+ </Tabs>
+ </div>
+ );
+};
+
+export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref<DmnEditorRef>) => {
+ const storeRef = React.useRef<StoreApiType>(createDmnEditorStore(props.model));
+
+ const resetState: ErrorBoundaryPropsWithFallback["onReset"] = useCallback(({ args }) => {
+ storeRef.current?.setState((state) => {
+ state.diagram = defaultStaticState().diagram;
+ state.dmn.model = args[0];
+ });
+ }, []);
+
+ return (
+ <DmnEditorContextProvider {...props}>
+ <ErrorBoundary FallbackComponent={DmnEditorErrorFallback} onReset={resetState}>
+ <DmnEditorExternalModelsContextProvider {...props}>
+ <DmnEditorStoreApiContext.Provider value={storeRef.current}>
+ <DmnEditorDerivedStoreContextProvider>
+ <DmnEditorInternal forwardRef={ref} {...props} />
+ </DmnEditorDerivedStoreContextProvider>
+ </DmnEditorStoreApiContext.Provider>
+ </DmnEditorExternalModelsContextProvider>
+ </ErrorBoundary>
+ </DmnEditorContextProvider>
+ );
+});
+
+export function usePrevious<T>(value: T) {
+ const [current, setCurrent] = useState<T>(value);
+ const [previous, setPrevious] = useState<T>(value);
+
+ if (value !== current) {
+ setPrevious(current);
+ setCurrent(value);
+ }
+
+ return previous;
+}
+
+/**
+ *
+ * @param state The state to save when condition is true
+ * @param condition Boolean that, when becomes true, sets the ref with the previous value of the first parameter -- `state`.
+ * @param ref The ref that stores the value
+ * @returns The ref that was given as the 3rd parameter.
+ */
+export function useStateAsItWasBeforeConditionBecameTrue<T>(state: T, condition: boolean, set: (prev: T) => void) {
+ const previous = usePrevious(state);
+
+ useEffect(() => {
+ if (condition) {
+ console.debug("HOOK: `useStateBeforeCondition` --> ASSIGN");
+ set(previous);
+ }
+ // !!!! EXCEPTIONAL CASE: Ignore "previous" changes on purpose, as we only want to save the last state before `condition` became true.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [condition, set]);
+}
diff --git a/packages/dmn-editor/src/DmnEditorContext.tsx b/packages/dmn-editor/src/DmnEditorContext.tsx
new file mode 100644
index 00000000000..21c8e4bf4bc
--- /dev/null
+++ b/packages/dmn-editor/src/DmnEditorContext.tsx
@@ -0,0 +1,78 @@
+/*
+ * 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 { useContext, useMemo, useRef } from "react";
+import { DmnEditorProps } from "./DmnEditor";
+import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
+
+export type DmnEditorContextProviderProps = Pick<
+ DmnEditorProps,
+ | "externalContextDescription"
+ | "externalContextName"
+ | "issueTrackerHref"
+ | "model"
+ | "onRequestToJumpToPath"
+ | "onRequestToResolvePath"
+>;
+
+export type DmnModelBeforeEditing = DmnLatestModel;
+
+export type DmnEditorContextType = Pick<
+ DmnEditorContextProviderProps,
+ | "externalContextDescription"
+ | "externalContextName"
+ | "issueTrackerHref"
+ | "onRequestToJumpToPath"
+ | "onRequestToResolvePath"
+> & {
+ dmnModelBeforeEditingRef: React.MutableRefObject<DmnModelBeforeEditing>;
+ dmnEditorRootElementRef: React.RefObject<HTMLDivElement>;
+};
+
+const DmnEditorContext = React.createContext<DmnEditorContextType>({} as any);
+
+export function useDmnEditor() {
+ return useContext(DmnEditorContext);
+}
+
+export function DmnEditorContextProvider(props: React.PropsWithChildren<DmnEditorContextProviderProps>) {
+ const dmnModelBeforeEditingRef = useRef<DmnModelBeforeEditing>(props.model);
+ const dmnEditorRootElementRef = useRef<HTMLDivElement>(null);
+
+ const value = useMemo<DmnEditorContextType>(
+ () => ({
+ dmnModelBeforeEditingRef,
+ dmnEditorRootElementRef,
+ externalContextDescription: props.externalContextDescription,
+ externalContextName: props.externalContextName,
+ issueTrackerHref: props.issueTrackerHref,
+ onRequestToJumpToPath: props.onRequestToJumpToPath,
+ onRequestToResolvePath: props.onRequestToResolvePath,
+ }),
+ [
+ props.externalContextDescription,
+ props.externalContextName,
+ props.issueTrackerHref,
+ props.onRequestToJumpToPath,
+ props.onRequestToResolvePath,
+ ]
+ );
+ return <DmnEditorContext.Provider value={value}>{props.children}</DmnEditorContext.Provider>;
+}
diff --git a/packages/dmn-editor/src/DmnEditorErrorFallback.tsx b/packages/dmn-editor/src/DmnEditorErrorFallback.tsx
new file mode 100644
index 00000000000..3b18a217643
--- /dev/null
+++ b/packages/dmn-editor/src/DmnEditorErrorFallback.tsx
@@ -0,0 +1,94 @@
+/*
+ * 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 { useDmnEditor } from "./DmnEditorContext";
+import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
+import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+import {
+ EmptyState,
+ EmptyStateBody,
+ EmptyStateIcon,
+ EmptyStatePrimary,
+} from "@patternfly/react-core/dist/js/components/EmptyState";
+import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
+import { FallbackProps } from "react-error-boundary";
+import { ClipboardCopy, ClipboardCopyVariant } from "@patternfly/react-core/dist/js/components/ClipboardCopy";
+import { ExternalLinkAltIcon } from "@patternfly/react-icons/dist/js/icons/external-link-alt-icon";
+import { useCallback, useEffect } from "react";
+
+export function DmnEditorErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
+ const { dmnModelBeforeEditingRef, issueTrackerHref } = useDmnEditor();
+
+ const resetToLastWorkingState = useCallback(() => {
+ resetErrorBoundary(dmnModelBeforeEditingRef.current);
+ }, [dmnModelBeforeEditingRef, resetErrorBoundary]);
+
+ useEffect(() => {
+ console.error(error);
+ }, [error]);
+
+ return (
+ <Flex justifyContent={{ default: "justifyContentCenter" }} style={{ marginTop: "100px" }}>
+ <EmptyState style={{ maxWidth: "1280px" }}>
+ <EmptyStateIcon icon={() => <div style={{ fontSize: "3em" }}>😕</div>} />
+ <Title size={"lg"} headingLevel={"h4"}>
+ An unexpected error happened
+ </Title>
+ <EmptyStateBody>
+ This is a bug. Please consider reporting it so the DMN Editor can continue improving. See the details below.
+ </EmptyStateBody>
+ <br />
+ <ClipboardCopy
+ isReadOnly={true}
+ isExpanded={false}
+ hoverTip={"Copy"}
+ clickTip={"Copied"}
+ variant={ClipboardCopyVariant.expansion}
+ style={{ textAlign: "left", whiteSpace: "pre-wrap", fontFamily: "monospace" }}
+ >
+ {JSON.stringify(
+ {
+ name: error.name,
+ message: error.message,
+ cause: error.cause,
+ stack: error.stack,
+ },
+ null,
+ 2
+ ).replaceAll("\\n", "\n")}
+ </ClipboardCopy>
+ <br />
+ <EmptyStatePrimary>
+ <Button variant={ButtonVariant.link} onClick={resetToLastWorkingState}>
+ Try undoing last action
+ </Button>
+ {issueTrackerHref && (
+ <a href={issueTrackerHref} target={"_blank"}>
+ <Button variant={ButtonVariant.link} icon={<ExternalLinkAltIcon />}>
+ File an issue...
+ </Button>
+ </a>
+ )}
+ </EmptyStatePrimary>
+ </EmptyState>
+ </Flex>
+ );
+}
diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx b/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx
new file mode 100644
index 00000000000..8ca343f7368
--- /dev/null
+++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx
@@ -0,0 +1,501 @@
+/*
+ * 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 RF from "reactflow";
+import {
+ BeeGwtService,
+ DmnBuiltInDataType,
+ DmnDataType,
+ ExpressionDefinition,
+ ExpressionDefinitionLogicType,
+ PmmlParam,
+ generateUuid,
+} from "@kie-tools/boxed-expression-component/dist/api";
+import { BoxedExpressionEditor } from "@kie-tools/boxed-expression-component/dist/expressions";
+import { Label } from "@patternfly/react-core/dist/js/components/Label";
+import * as React from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
+import { updateExpression } from "../mutations/updateExpression";
+import { DmnEditorTab, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { dmnToBee, getUndefinedExpressionDefinition } from "./dmnToBee";
+import { getDefaultExpressionDefinitionByLogicType } from "./getDefaultExpressionDefinitionByLogicType";
+import {
+ DMN15__tBusinessKnowledgeModel,
+ DMN15__tDecision,
+ DMN15__tItemDefinition,
+} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import {
+ EmptyState,
+ EmptyStateBody,
+ EmptyStateIcon,
+ EmptyStatePrimary,
+} from "@patternfly/react-core/dist/js/components/EmptyState";
+import { Button } from "@patternfly/react-core/dist/js/components/Button";
+import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { ErrorCircleOIcon } from "@patternfly/react-icons/dist/js/icons/error-circle-o-icon";
+import { InfoIcon } from "@patternfly/react-icons/dist/js/icons/info-icon";
+import { builtInFeelTypes } from "../dataTypes/BuiltInFeelTypes";
+import { useDmnEditorDerivedStore } from "../store/DerivedStore";
+import { isStruct } from "../dataTypes/DataTypeSpec";
+import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
+import { DataTypeIndex } from "../dataTypes/DataTypes";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { getNodeTypeFromDmnObject } from "../diagram/maths/DmnMaths";
+import { NodeIcon } from "../icons/Icons";
+import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
+import { PMMLDocumentData } from "@kie-tools/pmml-editor-marshaller/dist/api";
+import { PMMLModelData } from "@kie-tools/pmml-editor-marshaller/dist/api/PMMLModelData";
+import {
+ AnomalyDetectionModel,
+ AssociationModel,
+ BaselineModel,
+ BayesianNetworkModel,
+ ClusteringModel,
+ GaussianProcessModel,
+ GeneralRegressionModel,
+ MiningModel,
+ Model,
+ NaiveBayesModel,
+ NearestNeighborModel,
+ NeuralNetwork,
+ PMML,
+ RegressionModel,
+ RuleSetModel,
+ Scorecard,
+ SequenceModel,
+ SupportVectorMachineModel,
+ TextModel,
+ TimeSeriesModel,
+ TreeModel,
+} from "@kie-tools/pmml-editor-marshaller/dist/marshaller/model/pmml4_4";
+import { PMMLFieldData } from "@kie-tools/pmml-editor-marshaller/dist/api/PMMLFieldData";
+import { getDefaultColumnWidth } from "./getDefaultColumnWidth";
+import { FeelVariables } from "@kie-tools/dmn-feel-antlr4-parser";
+import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
+import { ArrowRightIcon } from "@patternfly/react-icons/dist/js/icons/arrow-right-icon";
+
+export function BoxedExpression({ container }: { container: React.RefObject<HTMLElement> }) {
+ const thisDmn = useDmnEditorStore((s) => s.dmn);
+ const diagram = useDmnEditorStore((s) => s.diagram);
+ const dispatch = useDmnEditorStore((s) => s.dispatch);
+ const boxedExpressionEditor = useDmnEditorStore((s) => s.boxedExpressionEditor);
+ const { externalDmnsByNamespace } = useDmnEditorDerivedStore();
+ const dmnEditorStoreApi = useDmnEditorStoreApi();
+
+ const feelVariables = useMemo(() => {
+ const externalModels = new Map<string, DmnLatestModel>();
+
+ for (const [key, externalDmn] of externalDmnsByNamespace) {
+ externalModels.set(key, externalDmn.model);
+ }
+
+ return new FeelVariables(thisDmn.model.definitions, externalModels);
+ }, [externalDmnsByNamespace, thisDmn.model.definitions]);
+
+ const widthsById = useMemo(() => {
+ return (
+ thisDmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[diagram.drdIndex]["di:extension"]?.[
+ "kie:ComponentsWidthsExtension"
+ ]?.["kie:ComponentWidths"] ?? []
+ ).reduce((acc, c) => {
+ if (c["@_dmnElementRef"] === undefined) {
+ return acc;
+ } else {
+ return acc.set(
+ c["@_dmnElementRef"],
+ (c["kie:width"] ?? []).map((vv) => vv.__$$text)
+ );
+ }
+ }, new Map<string, number[]>());
+ }, [diagram.drdIndex, thisDmn.model.definitions]);
+
+ const expression = useMemo(() => {
+ if (!boxedExpressionEditor.activeDrgElementId) {
+ return undefined;
+ }
+
+ const drgElementIndex = (thisDmn.model.definitions.drgElement ?? []).findIndex(
+ (e) => e["@_id"] === boxedExpressionEditor.activeDrgElementId
+ );
+ if (drgElementIndex < 0) {
+ return undefined;
+ }
+
+ const drgElement = thisDmn.model.definitions.drgElement![drgElementIndex];
+ if (!(drgElement.__$$element === "decision" || drgElement.__$$element === "businessKnowledgeModel")) {
+ return undefined;
+ }
+
+ return {
+ beeExpression: drgElementToBoxedExpression(widthsById, drgElement),
+ drgElementIndex,
+ drgElement,
+ drgElementType: drgElement.__$$element,
+ };
+ }, [boxedExpressionEditor.activeDrgElementId, thisDmn.model.definitions.drgElement, widthsById]);
+
+ const [lastValidExpression, setLastValidExpression] = useState<typeof expression>(undefined);
+ useEffect(() => {
+ if (expression) {
+ setLastValidExpression(expression);
+ }
+ }, [expression, setLastValidExpression]);
+
+ const setExpression: React.Dispatch<React.SetStateAction<ExpressionDefinition>> = useCallback(
+ (expressionAction) => {
+ dmnEditorStoreApi.setState((state) => {
+ const newExpression =
+ typeof expressionAction === "function"
+ ? expressionAction(expression?.beeExpression ?? getUndefinedExpressionDefinition())
+ : expressionAction;
+
+ updateExpression({
+ definitions: state.dmn.model.definitions,
+ drdIndex: diagram.drdIndex,
+ expression: newExpression,
+ drgElementIndex: expression?.drgElementIndex ?? 0,
+ });
+ });
+ },
+ [diagram.drdIndex, dmnEditorStoreApi, expression?.beeExpression, expression?.drgElementIndex]
+ );
+
+ const isResetSupportedOnRootExpression = useMemo(() => {
+ return expression?.drgElementType === "decision"; // BKMs are ALWAYS functions, and can't be reset.
+ }, [expression?.drgElementType]);
+
+ ////
+
+ const { dataTypesTree, allTopLevelDataTypesByFeelName, nodesById, importsByNamespace, externalPmmlsByNamespace } =
+ useDmnEditorDerivedStore();
+
+ const dataTypes = useMemo<DmnDataType[]>(() => {
+ const customDataTypes = dataTypesTree.map((d) => ({
+ isCustom: true,
+ typeRef: d.itemDefinition.typeRef?.__$$text ?? "",
+ name: d.feelName,
+ }));
+
+ return [...builtInFeelTypes, ...customDataTypes];
+ }, [dataTypesTree]);
+
+ const pmmlParams = useMemo<PmmlParam[]>(() => {
+ return [...externalPmmlsByNamespace.entries()].flatMap(([namespace, pmml]) => {
+ const documentData = getPmmlDocumentData(pmml.model);
+ const _import = importsByNamespace.get(namespace);
+ if (!_import) {
+ return [];
+ }
+
+ return {
+ document: _import["@_name"],
+ modelsFromDocument: documentData.models.map((m) => ({
+ model: m.modelName,
+ parametersFromModel: m.fields.map((f) => ({
+ id: generateUuid(),
+ name: f.fieldName,
+ dataType: undefined as any,
+ })),
+ })),
+ };
+ });
+ }, [importsByNamespace, externalPmmlsByNamespace]);
+
+ const beeGwtService = useMemo<BeeGwtService>(() => {
+ return {
+ getDefaultExpressionDefinition(
+ logicType: string,
+ typeRef: string | undefined,
+ isRoot?: boolean
+ ): ExpressionDefinition {
+ return getDefaultExpressionDefinitionByLogicType({
+ logicType: logicType as ExpressionDefinitionLogicType,
+ typeRef: typeRef ?? DmnBuiltInDataType.Undefined,
+ expressionHolderName: expression?.drgElement?.["@_name"],
+ allTopLevelDataTypesByFeelName,
+ getDefaultColumnWidth,
+ getInputs: () => {
+ if (!isRoot || expression?.drgElement.__$$element !== "decision") {
+ return undefined;
+ } else {
+ return determineInputsForDecision(expression?.drgElement, allTopLevelDataTypesByFeelName, nodesById);
+ }
+ },
+ });
+ },
+ selectObject(uuid) {
+ dmnEditorStoreApi.setState((state) => {
+ state.boxedExpressionEditor.selectedObjectId = uuid;
+ });
+ },
+ openDataTypePage() {
+ dmnEditorStoreApi.setState((state) => {
+ state.navigation.tab = DmnEditorTab.DATA_TYPES;
+ });
+ },
+ };
+ }, [allTopLevelDataTypesByFeelName, dmnEditorStoreApi, expression?.drgElement, nodesById]);
+
+ ////
+
+ const Icon = expression ? NodeIcon(getNodeTypeFromDmnObject(expression.drgElement)) : () => <></>;
+
+ return (
+ <>
+ <>
+ <Flex
+ className={"kie-dmn-editor--sticky-top-glass-header kie-dmn-editor--boxed-expression-header"}
+ justifyContent={{ default: "justifyContentSpaceBetween" }}
+ alignItems={{ default: "alignItemsCenter" }}
+ direction={{ default: "row" }}
+ >
+ <FlexItem>
+ <Label
+ className={"kie-dmn-editor--boxed-expression-back"}
+ onClick={() => {
+ dmnEditorStoreApi.setState((state) => {
+ dispatch.boxedExpressionEditor.close(state);
+ });
+ }}
+ >
+ <ArrowRightIcon style={{ transform: "scale(-1, -1)", marginRight: "12px" }} />
+ <p>Back to Diagram</p>
+ </Label>
+ </FlexItem>
+ <FlexItem>
+ <Flex
+ flexWrap={{ default: "nowrap" }}
+ justifyContent={{ default: "justifyContentSpaceBetween" }}
+ alignItems={{ default: "alignItemsCenter" }}
+ >
+ <FlexItem>
+ <div style={{ height: "40px", width: "40px" }}>
+ <Icon />
+ </div>
+ </FlexItem>
+ <FlexItem>
+ <TextContent>
+ <Text component={TextVariants.h2}>{expression?.drgElement["@_name"]}</Text>
+ </TextContent>
+ </FlexItem>
+ <FlexItem style={{ width: "105px" }} />
+ </Flex>
+ </FlexItem>
+
+ <aside
+ className={"kie-dmn-editor--properties-panel-toggle"}
+ style={{ visibility: boxedExpressionEditor.propertiesPanel.isOpen ? "hidden" : undefined }}
+ >
+ <button
+ className={"kie-dmn-editor--properties-panel-toggle-button"}
+ onClick={() => {
+ dmnEditorStoreApi.setState((state) => {
+ state.boxedExpressionEditor.propertiesPanel.isOpen =
+ !state.boxedExpressionEditor.propertiesPanel.isOpen;
+ });
+ }}
+ >
+ <InfoIcon size={"sm"} />
+ </button>
+ </aside>
+ </Flex>
+ {!expression && (
+ <>
+ <EmptyState>
+ <EmptyStateIcon icon={ErrorCircleOIcon} />
+ <Title size="lg" headingLevel="h4">
+ {`Expression with ID '${boxedExpressionEditor.activeDrgElementId}' doesn't exist.`}
+ </Title>
+ <EmptyStateBody>
+ This happens when the DMN file is modified externally while the expression was open here.
+ </EmptyStateBody>
+ <EmptyStatePrimary>
+ <Button
+ variant="link"
+ onClick={() => {
+ dmnEditorStoreApi.setState((state) => {
+ dispatch.boxedExpressionEditor.close(state);
+ });
+ }}
+ >
+ Go back to the Diagram
+ </Button>
+ </EmptyStatePrimary>
+ </EmptyState>
+ </>
+ )}
+ {expression && (
+ <div style={{ flexGrow: 1 }}>
+ <BoxedExpressionEditor
+ beeGwtService={beeGwtService}
+ pmmlParams={pmmlParams}
+ isResetSupportedOnRootExpression={isResetSupportedOnRootExpression}
+ decisionNodeId={boxedExpressionEditor.activeDrgElementId!}
+ expressionDefinition={expression.beeExpression}
+ setExpressionDefinition={setExpression}
+ dataTypes={dataTypes}
+ scrollableParentRef={container}
+ variables={feelVariables}
+ />
+ </div>
+ )}
+ </>
+ </>
+ );
+}
+
+function drgElementToBoxedExpression(
+ widthsById: Map<string, number[]>,
+ expressionHolder:
+ | (DMN15__tDecision & { __$$element: "decision" })
+ | (DMN15__tBusinessKnowledgeModel & { __$$element: "businessKnowledgeModel" })
+): ExpressionDefinition {
+ if (expressionHolder.__$$element === "businessKnowledgeModel") {
+ return {
+ ...dmnToBee(widthsById, {
+ expression: {
+ __$$element: "functionDefinition",
+ ...expressionHolder.encapsulatedLogic,
+ },
+ }),
+ dataType: (expressionHolder.variable?.["@_typeRef"] ??
+ expressionHolder.encapsulatedLogic?.["@_typeRef"] ??
+ DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ name: expressionHolder["@_name"],
+ };
+ } else if (expressionHolder.__$$element === "decision") {
+ return {
+ ...dmnToBee(widthsById, expressionHolder),
+ dataType: (expressionHolder.variable?.["@_typeRef"] ??
+ expressionHolder.expression?.["@_typeRef"] ??
+ DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ name: expressionHolder["@_name"],
+ };
+ } else {
+ throw new Error(
+ `Unknown __$$element of expressionHolder that has an expression '${(expressionHolder as any).__$$element}'.`
+ );
+ }
+}
+
+function determineInputsForDecision(
+ decision: DMN15__tDecision,
+ allTopLevelDataTypesByFeelName: DataTypeIndex,
+ nodesById: Map<string, RF.Node<DmnDiagramNodeData>>
+) {
+ try {
+ const ret = (decision.informationRequirement ?? []).flatMap((s) => {
+ const dmnObject = nodesById.get((s.requiredDecision?.["@_href"] ?? s.requiredInput?.["@_href"])!)!.data.dmnObject;
+ if (!(dmnObject?.__$$element === "inputData" || dmnObject?.__$$element === "decision")) {
+ throw new Error(
+ "DMN EDITOR: Information requirement can't ever point to anything other than an InputData or a Decision"
+ );
+ }
+
+ const dataType = allTopLevelDataTypesByFeelName.get(dmnObject.variable!["@_typeRef"]!);
+ return dataType && isStruct(dataType.itemDefinition)
+ ? (dataType.itemDefinition.itemComponent ?? []).flatMap((ic) =>
+ flattenComponents(ic, dmnObject.variable!["@_name"])
+ )
+ : [
+ {
+ name: dmnObject.variable!["@_name"]!,
+ typeRef: dmnObject.variable?.["@_typeRef"],
+ },
+ ];
+ });
+
+ if (ret.length === 0) {
+ return undefined;
+ }
+
+ return ret;
+ } catch (e) {
+ console.error(`DMN EDITOR: Error suggesting imports for root expression on '${decision["@_name"]}'.`, e);
+ return undefined;
+ }
+}
+function flattenComponents(
+ itemDefinition: DMN15__tItemDefinition,
+ acc: string
+): { name: string; typeRef: string | undefined }[] {
+ if (!isStruct(itemDefinition)) {
+ return [
+ {
+ name: `${acc}.${itemDefinition["@_name"]!}`,
+ typeRef: itemDefinition.typeRef?.__$$text,
+ },
+ ];
+ }
+
+ return (itemDefinition.itemComponent ?? []).flatMap((ic) => {
+ return flattenComponents(ic, `${acc}.${itemDefinition["@_name"]!}`);
+ });
+}
+
+export function getPmmlDocumentData(pmml: PMML): PMMLDocumentData {
+ const models: PMMLModelData[] = [];
+ const document = new PMMLDocumentData(models);
+
+ if (pmml.models) {
+ pmml.models.forEach((model) => {
+ const modelData = retrieveModelData(model);
+ if (modelData) {
+ models.push(modelData);
+ }
+ });
+ }
+ return document;
+}
+
+export function retrieveModelData(model: Model): PMMLModelData | undefined {
+ const modelsTypes = [
+ AnomalyDetectionModel,
+ AssociationModel,
+ BayesianNetworkModel,
+ BaselineModel,
+ ClusteringModel,
+ GaussianProcessModel,
+ GeneralRegressionModel,
+ MiningModel,
+ NaiveBayesModel,
+ NearestNeighborModel,
+ NeuralNetwork,
+ RegressionModel,
+ RuleSetModel,
+ SequenceModel,
+ Scorecard,
+ SupportVectorMachineModel,
+ TextModel,
+ TimeSeriesModel,
+ TreeModel,
+ ];
+ let modelData;
+
+ for (const type of modelsTypes) {
+ if (model instanceof type) {
+ const modelFields = model.MiningSchema.MiningField.map(
+ (field) => new PMMLFieldData(field.name.toString(), field.usageType)
+ );
+ modelData = new PMMLModelData(model.modelName == null ? "" : model.modelName, modelFields);
+ }
+ }
+
+ return modelData;
+}
diff --git a/packages/dmn-editor/src/boxedExpressions/beeToDmn.tsx b/packages/dmn-editor/src/boxedExpressions/beeToDmn.tsx
new file mode 100644
index 00000000000..d85ef4fe9d4
--- /dev/null
+++ b/packages/dmn-editor/src/boxedExpressions/beeToDmn.tsx
@@ -0,0 +1,248 @@
+import {
+ DecisionTableExpressionDefinitionBuiltInAggregation,
+ ExpressionDefinition,
+ ExpressionDefinitionLogicType,
+} from "@kie-tools/boxed-expression-component/dist/api";
+import { DMN15__tDecision } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DMN15_SPEC } from "../Dmn15Spec";
+import {
+ BEE_TABLE_ROW_INDEX_COLUMN_WIDTH,
+ DECISION_TABLE_ANNOTATION_MIN_WIDTH,
+ DECISION_TABLE_INPUT_MIN_WIDTH,
+ DECISION_TABLE_OUTPUT_MIN_WIDTH,
+ JAVA_FUNCTION_EXPRESSION_VALUES_MIN_WIDTH,
+} from "@kie-tools/boxed-expression-component/dist/resizing/WidthConstants";
+
+/** Converts an ExpressionDefinition to a DMN JSON. This convertion is
+ * necessary for historical reasons, as the Boxed Expression Editor was
+ * created prior to the DMN Editor, needing to declare its own model. */
+export function beeToDmn(
+ expression: ExpressionDefinition,
+ __widths: Map<string, number[]>
+): DMN15__tDecision["expression"] {
+ switch (expression.logicType) {
+ case ExpressionDefinitionLogicType.Undefined:
+ return undefined;
+ case ExpressionDefinitionLogicType.Context:
+ return {
+ __$$element: "context",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ contextEntry: [
+ ...expression.contextEntries.map((e) => {
+ __widths.set(expression.id, expression.entryInfoWidth ? [expression.entryInfoWidth] : []);
+ return {
+ "@_id": e.entryInfo.id,
+ expression: beeToDmn(e.entryExpression, __widths)!,
+ variable: {
+ "@_name": e.entryInfo.name,
+ "@_typeRef": e.entryInfo.dataType,
+ },
+ };
+ }),
+ ...(expression.result
+ ? [
+ {
+ "@_id": expression.result.id,
+ expression: beeToDmn(expression.result, __widths)!,
+ },
+ ]
+ : []),
+ ],
+ };
+ case ExpressionDefinitionLogicType.DecisionTable:
+ __widths.set(expression.id, [BEE_TABLE_ROW_INDEX_COLUMN_WIDTH]);
+ return {
+ __$$element: "decisionTable",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ "@_hitPolicy": expression.hitPolicy,
+ "@_aggregation": (() => {
+ switch (expression.aggregation) {
+ case DecisionTableExpressionDefinitionBuiltInAggregation["<None>"]:
+ return undefined;
+ case DecisionTableExpressionDefinitionBuiltInAggregation.SUM:
+ return "SUM";
+ case DecisionTableExpressionDefinitionBuiltInAggregation.COUNT:
+ return "COUNT";
+ case DecisionTableExpressionDefinitionBuiltInAggregation.MIN:
+ return "MIN";
+ case DecisionTableExpressionDefinitionBuiltInAggregation.MAX:
+ return "MAX";
+ }
+ })(),
+ input: (expression.input ?? []).map((s) => {
+ __widths.set(expression.id, [
+ ...(__widths.get(expression.id) ?? []),
+ s.width ?? DECISION_TABLE_INPUT_MIN_WIDTH,
+ ]);
+ return {
+ "@_id": s.id,
+ inputExpression: {
+ "@_id": s.idLiteralExpression,
+ "@_typeRef": s.dataType,
+ text: { __$$text: s.name }, // This is really bad... `s.name` is actually an expression. Will be addressed by https://github.com/apache/incubator-kie-issues/issues/455
+ },
+ };
+ }),
+ output: (expression.output ?? []).map((o) => {
+ __widths.set(expression.id, [
+ ...(__widths.get(expression.id) ?? []),
+ o.width ?? DECISION_TABLE_OUTPUT_MIN_WIDTH,
+ ]);
+ return {
+ "@_id": o.id,
+ "@_name": o.name,
+ "@_typeRef": o.dataType,
+ };
+ }),
+ annotation: (expression.annotations ?? []).map((a) => {
+ __widths.set(expression.id, [
+ ...(__widths.get(expression.id) ?? []),
+ a.width ?? DECISION_TABLE_ANNOTATION_MIN_WIDTH,
+ ]);
+ return {
+ "@_name": a.name,
+ };
+ }),
+ rule: (expression.rules ?? []).map((r) => {
+ return {
+ "@_id": r.id,
+ inputEntry: r.inputEntries.map((i) => ({ "@_id": i.id, text: { __$$text: i.content } })),
+ outputEntry: r.outputEntries.map((s) => ({ "@_id": s.id, text: { __$$text: s.content } })),
+ annotationEntry: r.annotationEntries.map((a) => ({ text: { __$$text: a } })),
+ };
+ }),
+ };
+ case ExpressionDefinitionLogicType.Function:
+ return {
+ __$$element: "functionDefinition",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_kind": expression.functionKind,
+ "@_typeRef": expression.dataType,
+ formalParameter: expression.formalParameters.map((p) => ({
+ "@_id": p.id,
+ "@_name": p.name,
+ "@_typeRef": p.dataType,
+ })),
+ expression:
+ expression.functionKind === "FEEL"
+ ? beeToDmn(expression.expression, __widths)
+ : expression.functionKind === "Java"
+ ? (() => {
+ __widths.set(expression.id, [
+ BEE_TABLE_ROW_INDEX_COLUMN_WIDTH,
+ expression.classAndMethodNamesWidth ?? JAVA_FUNCTION_EXPRESSION_VALUES_MIN_WIDTH,
+ ]);
+ return {
+ __$$element: "context",
+ contextEntry: [
+ {
+ "@_id": expression.classFieldId,
+ expression: { __$$element: "literalExpression", text: { __$$text: expression.className! } },
+ variable: { "@_name": DMN15_SPEC.BOXED.FUNCTION.JAVA.classFieldName },
+ },
+ {
+ "@_id": expression.methodFieldId,
+ expression: { __$$element: "literalExpression", text: { __$$text: expression.methodName! } },
+ variable: { "@_name": DMN15_SPEC.BOXED.FUNCTION.JAVA.methodSignatureFieldName },
+ },
+ ],
+ };
+ })()
+ : expression.functionKind === "PMML"
+ ? (() => {
+ return {
+ __$$element: "context",
+ contextEntry: [
+ {
+ "@_id": expression.documentFieldId,
+ expression: { __$$element: "literalExpression", text: { __$$text: expression.document! } },
+ variable: { "@_name": DMN15_SPEC.BOXED.FUNCTION.PMML.documentFieldName },
+ },
+ {
+ "@_id": expression.modelFieldId,
+ expression: { __$$element: "literalExpression", text: { __$$text: expression.model! } },
+ variable: { "@_name": DMN15_SPEC.BOXED.FUNCTION.PMML.modelFieldName },
+ },
+ ],
+ };
+ })()
+ : (() => {
+ throw new Error(`Unknown Function kind '${(expression as any).functionKind}'.`);
+ })(),
+ };
+ case ExpressionDefinitionLogicType.Invocation:
+ return {
+ __$$element: "invocation",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ expression: {
+ __$$element: "literalExpression",
+ "@_id": expression.invokedFunction.id,
+ text: { __$$text: expression.invokedFunction.name },
+ },
+ binding: expression.bindingEntries.map((e) => {
+ __widths.set(expression.id, expression.entryInfoWidth ? [expression.entryInfoWidth] : []);
+ return {
+ "@_id": e.entryInfo.id,
+ expression: beeToDmn(e.entryExpression, __widths)!,
+ parameter: {
+ "@_name": e.entryInfo.name,
+ "@_typeRef": e.entryInfo.dataType,
+ },
+ };
+ }),
+ };
+ case ExpressionDefinitionLogicType.List:
+ __widths.set(expression.id, [BEE_TABLE_ROW_INDEX_COLUMN_WIDTH]);
+ return {
+ __$$element: "list",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ expression: expression.items.map((i) => beeToDmn(i, __widths)!),
+ };
+ case ExpressionDefinitionLogicType.Literal:
+ __widths.set(expression.id, expression.width ? [expression.width] : []);
+ return {
+ __$$element: "literalExpression",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ text: { __$$text: expression.content! },
+ };
+ case ExpressionDefinitionLogicType.Relation:
+ __widths.set(expression.id, [BEE_TABLE_ROW_INDEX_COLUMN_WIDTH]);
+ return {
+ __$$element: "relation",
+ "@_id": expression.id,
+ "@_label": expression.name,
+ "@_typeRef": expression.dataType,
+ row: (expression.rows ?? []).map((r) => {
+ return {
+ "@_id": r.id,
+ expression: r.cells.map((cell) => ({
+ __$$element: "literalExpression",
+ text: { __$$text: cell.content },
+ id: cell.id,
+ })),
+ };
+ }),
+ column: (expression.columns ?? []).map((c) => {
+ __widths.set(expression.id, [...(__widths.get(expression.id) ?? []), ...(c.width ? [c.width] : [])]);
+ return {
+ "@_id": c.id,
+ "@_name": c.name,
+ "@_typeRef": c.dataType,
+ };
+ }),
+ };
+ default:
+ throw new Error(`Unknown logicType for expression: '${(expression as any).logicType}'`);
+ }
+}
diff --git a/packages/dmn-editor/src/boxedExpressions/dmnToBee.tsx b/packages/dmn-editor/src/boxedExpressions/dmnToBee.tsx
new file mode 100644
index 00000000000..1ad71f7deda
--- /dev/null
+++ b/packages/dmn-editor/src/boxedExpressions/dmnToBee.tsx
@@ -0,0 +1,257 @@
+import {
+ ContextExpressionDefinitionEntry,
+ DecisionTableExpressionDefinitionBuiltInAggregation,
+ DecisionTableExpressionDefinitionHitPolicy,
+ DmnBuiltInDataType,
+ ExpressionDefinition,
+ ExpressionDefinitionLogicType,
+ FunctionExpressionDefinitionKind,
+ generateUuid,
+} from "@kie-tools/boxed-expression-component/dist/api";
+import {
+ DMN15__tContext,
+ DMN15__tLiteralExpression,
+} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DMN15_SPEC } from "../Dmn15Spec";
+import { AllExpressions } from "../dataTypes/DataTypeSpec";
+
+/** Converts a DMN JSON to an ExpressionDefinition. This convertion is
+ * necessary for historical reasons, as the Boxed Expression Editor was
+ * created prior to the DMN Editor, needing to declare its own model. */
+export function dmnToBee(
+ widthsById: Map<string, number[]>,
+ expressionHolder: { expression?: AllExpressions } | undefined,
+ typeRef?: string
+): ExpressionDefinition {
+ if (!expressionHolder?.expression) {
+ return { ...getUndefinedExpressionDefinition(), ...(typeRef ? { dataType: typeRef as DmnBuiltInDataType } : {}) };
+ }
+
+ const expr = expressionHolder.expression;
+
+ if (expr.__$$element === "literalExpression") {
+ return {
+ id: expr["@_id"]!,
+ name: expr["@_label"],
+ logicType: ExpressionDefinitionLogicType.Literal,
+ dataType: (expr["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ content: expr.text?.__$$text,
+ width: widthsById.get(expr["@_id"]!)?.[0],
+ };
+ } else if (expr.__$$element === "decisionTable") {
+ return {
+ id: expr["@_id"]!,
+ name: expr["@_label"],
+ logicType: ExpressionDefinitionLogicType.DecisionTable,
+ dataType: (expr["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ aggregation: expr["@_aggregation"]
+ ? DecisionTableExpressionDefinitionBuiltInAggregation[expr["@_aggregation"]]
+ : DecisionTableExpressionDefinitionBuiltInAggregation["<None>"],
+ hitPolicy:
+ (expr["@_hitPolicy"] as DecisionTableExpressionDefinitionHitPolicy) ??
+ DMN15_SPEC.BOXED.DECISION_TABLE.HitPolicy.default,
+ input: (expr.input ?? []).map((input, i) => ({
+ idLiteralExpression: input.inputExpression["@_id"]!,
+ id: input["@_id"]!,
+ name: input["@_label"] ?? input.inputExpression["@_label"] ?? input.inputExpression.text?.__$$text ?? "",
+ dataType: (input.inputExpression["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ width: widthsById.get(expr["@_id"]!)?.[1 + i],
+ })),
+ output: (expr.output ?? []).map((output, i) => ({
+ id: output["@_id"]!,
+ name: output["@_label"] ?? output["@_name"] ?? "",
+ dataType: (output["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ width: widthsById.get(expr["@_id"]!)?.[1 + (expr.input ?? []).length + i],
+ })),
+ annotations: (expr.annotation ?? []).map((a, i) => ({
+ name: a["@_name"] ?? "",
+ width: widthsById.get(expr["@_id"]!)?.[1 + (expr.input ?? []).length + (expr.output ?? []).length + i],
+ })),
+ rules: (expr.rule ?? []).map((r) => ({
+ id: r["@_id"]!,
+ inputEntries: (r.inputEntry ?? []).map((i) => ({ id: i["@_id"]!, content: i.text?.__$$text ?? "" })),
+ outputEntries: (r.outputEntry ?? []).map((o) => ({ id: o["@_id"]!, content: o.text?.__$$text ?? "" })),
+ annotationEntries: (r.annotationEntry ?? []).map((a) => a.text?.__$$text ?? ""),
+ })),
+ };
+ } else if (expr.__$$element === "relation") {
+ return {
+ id: expr["@_id"]!,
+ name: expr["@_label"],
+ logicType: ExpressionDefinitionLogicType.Relation,
+ dataType: (expr["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ rows: (expr.row ?? []).map((row) => ({
+ id: row["@_id"]!,
+ // Assuming only literalExpressions are supported. Any other type of expression won't work for Relations.
+ cells: ((row.expression as DMN15__tLiteralExpression[]) ?? []).map((s) => ({
+ id: s["@_id"]!,
+ content: s.text?.__$$text ?? "",
+ })),
+ })),
+ columns: (expr.column ?? []).map((c, i) => ({
+ id: c["@_id"]!,
+ name: c["@_label"] ?? c["@_name"] ?? "",
+ dataType: (c["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ width: widthsById.get(expr["@_id"]!)?.[1 + i],
+ })),
+ };
+ } else if (expr.__$$element === "context") {
+ const { contextEntries, result } = (expr.contextEntry ?? []).reduce(
+ (acc, e) => {
+ if (!e.variable) {
+ acc.result = dmnToBee(widthsById, e, expr["@_typeRef"]);
+ } else {
+ acc.contextEntries.push({
+ entryInfo: {
+ id: e.variable?.["@_id"] ?? e["@_id"]!,
+ name: e.variable?.["@_label"] ?? e.variable?.["@_name"] ?? e["@_label"]!,
+ dataType: (e.variable?.["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ },
+ entryExpression: dmnToBee(
+ widthsById,
+ e,
+ (e.variable?.["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType
+ ),
+ });
+ }
+
+ return acc;
+ },
+ { contextEntries: [], result: getUndefinedExpressionDefinition() } as {
+ contextEntries: ContextExpressionDefinitionEntry[];
+ result: ExpressionDefinition;
+ }
+ );
+
+ return {
+ id: expr["@_id"]!,
+ dataType: expr["@_typeRef"] as DmnBuiltInDataType,
+ logicType: ExpressionDefinitionLogicType.Context as const,
+ name: expr["@_label"],
+ entryInfoWidth: widthsById.get(expr["@_id"] ?? "")?.[0],
+ result,
+ contextEntries,
+ };
+ } else if (expr.__$$element === "invocation") {
+ // From the spec:
+ //
+ // An Invocation contains a calledFunction, an Expression, which must evaluate to a function. Most
+ // commonly, it is a LiteralExpression naming a BusinessKnowledgeModel.
+ //
+ // Source: https://www.omg.org/spec/DMN/1.4/PDF. PDF page 71, document page 57. Section "7.3.6 Invocation metamodel".
+ const calledFunction = expr.expression! as DMN15__tLiteralExpression;
+
+ return {
+ id: expr["@_id"]!,
+ dataType: (expr["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ logicType: ExpressionDefinitionLogicType.Invocation as const,
+ name: expr["@_label"],
+ entryInfoWidth: widthsById.get(expr["@_id"] ?? "")?.[0],
+ invokedFunction: {
+ id: calledFunction["@_id"]!,
+ name: calledFunction.text?.__$$text ?? "",
+ },
+ bindingEntries: (expr.binding ?? []).map((b) => ({
+ entryInfo: {
+ id: b.parameter["@_id"]!,
+ name: b.parameter["@_name"],
+ dataType: (b.parameter["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ },
+ entryExpression: dmnToBee(
+ widthsById,
+ b,
+ (b.parameter["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType
+ ),
+ })),
+ };
+ } else if (expr.__$$element === "functionDefinition") {
+ const basic = {
+ id: expr["@_id"]!,
+ name: expr["@_label"],
+ dataType: expr["@_typeRef"] as DmnBuiltInDataType,
+ logicType: ExpressionDefinitionLogicType.Function as const,
+ formalParameters: (expr.formalParameter ?? []).map((p) => ({
+ id: p["@_id"]!,
+ name: p["@_name"]!,
+ dataType: (p["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ })),
+ };
+
+ const kind = expr["@_kind"] ?? DMN15_SPEC.BOXED.FUNCTION.kind.default;
+ switch (kind) {
+ case "FEEL": {
+ return {
+ ...basic,
+ functionKind: FunctionExpressionDefinitionKind.Feel,
+ expression: dmnToBee(widthsById, expr),
+ };
+ }
+ case "Java": {
+ // From the spec:
+ //
+ // For FEEL functions, denoted by Kind FEEL or by omission of Kind, the Body SHALL be a FEEL expression
+ // that references the parameters. For externally defined functions denoted by Kind Java, the Body SHALL be a
+ // context as described in 10.3.2.13.3 and the form of the mapping information SHALL be the java form. For
+ // externally defined functions denoted by Kind PMML, the Body SHALL be a context as described in 10.3.2.13.3
+ // and the form of the mapping information SHALL be the pmml form.
+ //
+ // Source: https://www.omg.org/spec/DMN/1.4/PDF, PDF page 106, document page 92. Section "10.2.1.7 Boxed Function".
+ const c = expr.expression! as DMN15__tContext;
+ const clazz = c.contextEntry?.find(
+ ({ variable }) => variable?.["@_name"] === DMN15_SPEC.BOXED.FUNCTION.JAVA.classFieldName
+ );
+ const method = c.contextEntry?.find(
+ ({ variable }) => variable?.["@_name"] === DMN15_SPEC.BOXED.FUNCTION.JAVA.methodSignatureFieldName
+ );
+
+ return {
+ ...basic,
+ functionKind: FunctionExpressionDefinitionKind.Java,
+ className: (clazz?.expression as DMN15__tLiteralExpression | undefined)?.text?.__$$text,
+ classFieldId: clazz?.expression?.["@_id"],
+ methodName: (method?.expression as DMN15__tLiteralExpression | undefined)?.text?.__$$text,
+ methodFieldId: method?.expression?.["@_id"],
+ classAndMethodNamesWidth: widthsById.get(expr["@_id"] ?? "")?.[1],
+ };
+ }
+ case "PMML": {
+ // Special case, defined by the spec, where the implementation is a context expression with two fields.
+ const c = expr.expression as DMN15__tContext;
+ const document = c.contextEntry?.find(
+ ({ variable }) => variable?.["@_name"] === DMN15_SPEC.BOXED.FUNCTION.PMML.documentFieldName
+ );
+ const model = c.contextEntry?.find(
+ ({ variable }) => variable?.["@_name"] === DMN15_SPEC.BOXED.FUNCTION.PMML.modelFieldName
+ );
+ return {
+ ...basic,
+ functionKind: FunctionExpressionDefinitionKind.Pmml,
+ document: (document?.expression as DMN15__tLiteralExpression | undefined)?.text?.__$$text.replaceAll(`"`, ``), // Sometimes this is stored as a FEEL string. We don't need the quotes to show in the screen.
+ documentFieldId: document?.expression?.["@_id"],
+ model: (model?.expression as DMN15__tLiteralExpression | undefined)?.text?.__$$text.replaceAll(`"`, ``), // Sometimes this is stored as a FEEL string. We don't need the quotes to show in the screen.
+ modelFieldId: model?.expression?.["@_id"],
+ };
+ }
+ default:
+ throw new Error(`Unknown function expression kind '${expr["@_kind"]}'`);
+ }
+ } else if (expr.__$$element === "list") {
+ return {
+ id: expr["@_id"]!,
+ name: expr["@_label"],
+ dataType: (expr["@_typeRef"] ?? DmnBuiltInDataType.Undefined) as unknown as DmnBuiltInDataType,
+ logicType: ExpressionDefinitionLogicType.List as const,
+ items: (expr.expression ?? []).map((e) => dmnToBee(widthsById, { expression: e }, expr["@_typeRef"])),
+ };
+ } else {
+ return getUndefinedExpressionDefinition();
+ }
+}
+
+export function getUndefinedExpressionDefinition(): ExpressionDefinition {
+ return {
+ id: generateUuid(),
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ dataType: DmnBuiltInDataType.Undefined,
+ };
+}
diff --git a/packages/online-editor/src/settings/SettingsButton.tsx b/packages/dmn-editor/src/boxedExpressions/getDefaultColumnWidth.tsx
similarity index 55%
copy from packages/online-editor/src/settings/SettingsButton.tsx
copy to packages/dmn-editor/src/boxedExpressions/getDefaultColumnWidth.tsx
index 185721e189f..bebeab34d8f 100644
--- a/packages/online-editor/src/settings/SettingsButton.tsx
+++ b/packages/dmn-editor/src/boxedExpressions/getDefaultColumnWidth.tsx
@@ -17,21 +17,17 @@
* under the License.
*/
-import * as React from "react";
-import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
-import { CogIcon } from "@patternfly/react-icons/dist/js/icons/cog-icon";
-import { useSettingsDispatch } from "./SettingsContext";
+import { getTextWidth } from "@kie-tools/boxed-expression-component/dist/resizing/WidthsToFitData";
+import { DEFAULT_MIN_WIDTH } from "@kie-tools/boxed-expression-component/dist/resizing/WidthConstants";
-export function SettingsButton() {
- const settingsDispatch = useSettingsDispatch();
+export function getDefaultColumnWidth({ name, typeRef }: { name: string; typeRef: string | undefined }): number {
return (
- <Button
- variant={ButtonVariant.plain}
- onClick={() => settingsDispatch.open()}
- aria-label="Settings"
- className={"kie-tools--masthead-hoverable-dark"}
- >
- <CogIcon />
- </Button>
+ 8 * 2 + // Copied from ContextEntry info `getWidthToFit`
+ 2 + // Copied from ContextEntry info `getWidthToFit`
+ Math.max(
+ DEFAULT_MIN_WIDTH,
+ getTextWidth(name, "700 11.2px Menlo, monospace"),
+ getTextWidth(`(${typeRef ?? ""})`, "700 11.6667px RedHatText, Overpass, overpass, helvetica, arial, sans-serif")
+ )
);
}
diff --git a/packages/dmn-editor/src/boxedExpressions/getDefaultExpressionDefinitionByLogicType.tsx b/packages/dmn-editor/src/boxedExpressions/getDefaultExpressionDefinitionByLogicType.tsx
new file mode 100644
index 00000000000..e54db28f835
--- /dev/null
+++ b/packages/dmn-editor/src/boxedExpressions/getDefaultExpressionDefinitionByLogicType.tsx
@@ -0,0 +1,311 @@
+/*
+ * 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 {
+ ContextExpressionDefinition,
+ DecisionTableExpressionDefinition,
+ DecisionTableExpressionDefinitionBuiltInAggregation,
+ DecisionTableExpressionDefinitionHitPolicy,
+ DmnBuiltInDataType,
+ ExpressionDefinition,
+ ExpressionDefinitionLogicType,
+ FunctionExpressionDefinition,
+ FunctionExpressionDefinitionKind,
+ InvocationExpressionDefinition,
+ ListExpressionDefinition,
+ LiteralExpressionDefinition,
+ RelationExpressionDefinition,
+ generateUuid,
+} from "@kie-tools/boxed-expression-component/dist/api";
+import {
+ LITERAL_EXPRESSION_MIN_WIDTH,
+ CONTEXT_ENTRY_INFO_MIN_WIDTH,
+ DECISION_TABLE_INPUT_DEFAULT_WIDTH,
+ DECISION_TABLE_OUTPUT_DEFAULT_WIDTH,
+ DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH,
+ RELATION_EXPRESSION_COLUMN_DEFAULT_WIDTH,
+} from "@kie-tools/boxed-expression-component/dist/resizing/WidthConstants";
+import {
+ DECISION_TABLE_INPUT_DEFAULT_VALUE,
+ DECISION_TABLE_OUTPUT_DEFAULT_VALUE,
+} from "@kie-tools/boxed-expression-component/dist/expressions/DecisionTableExpression";
+import {
+ INVOCATION_EXPRESSION_DEFAULT_PARAMETER_NAME,
+ INVOCATION_EXPRESSION_DEFAULT_PARAMETER_DATA_TYPE,
+ INVOCATION_EXPRESSION_DEFAULT_PARAMETER_LOGIC_TYPE,
+} from "@kie-tools/boxed-expression-component/dist/expressions/InvocationExpression";
+import { RELATION_EXPRESSION_DEFAULT_VALUE } from "@kie-tools/boxed-expression-component/dist/expressions/RelationExpression";
+import { DataTypeIndex } from "../dataTypes/DataTypes";
+import { isStruct } from "../dataTypes/DataTypeSpec";
+
+export function getDefaultExpressionDefinitionByLogicType({
+ logicType,
+ typeRef,
+ allTopLevelDataTypesByFeelName,
+ expressionHolderName,
+ getInputs,
+ getDefaultColumnWidth,
+}: {
+ logicType: ExpressionDefinitionLogicType;
+ typeRef: string;
+ expressionHolderName?: string;
+ allTopLevelDataTypesByFeelName: DataTypeIndex;
+ getInputs?: () => { name: string; typeRef: string | undefined }[] | undefined;
+ getDefaultColumnWidth?: (args: { name: string; typeRef: string | undefined }) => number | undefined;
+}): ExpressionDefinition {
+ const dataType = allTopLevelDataTypesByFeelName.get(typeRef);
+
+ if (logicType === ExpressionDefinitionLogicType.Literal) {
+ const literalExpression: LiteralExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ width: LITERAL_EXPRESSION_MIN_WIDTH,
+ };
+ return literalExpression;
+ }
+ //
+ else if (logicType === ExpressionDefinitionLogicType.Function) {
+ const functionExpression: FunctionExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ functionKind: FunctionExpressionDefinitionKind.Feel,
+ formalParameters: [],
+ expression: {
+ id: generateUuid(),
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ dataType: DmnBuiltInDataType.Undefined,
+ },
+ };
+ return functionExpression;
+ }
+ //
+ else if (logicType === ExpressionDefinitionLogicType.Context) {
+ let maxWidthBasedOnEntryNames = CONTEXT_ENTRY_INFO_MIN_WIDTH;
+
+ const contextEntries: ContextExpressionDefinition["contextEntries"] =
+ !dataType || !isStruct(dataType.itemDefinition)
+ ? [
+ {
+ entryInfo: {
+ id: generateUuid(),
+ name: "ContextEntry-1",
+ dataType: DmnBuiltInDataType.Undefined,
+ },
+ entryExpression: {
+ id: generateUuid(),
+ name: "ContextEntry-1",
+ dataType: DmnBuiltInDataType.Undefined,
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ },
+ },
+ ]
+ : (dataType.itemDefinition.itemComponent ?? []).map((ic) => {
+ const name = ic["@_name"];
+ const typeRef = isStruct(ic)
+ ? DmnBuiltInDataType.Any
+ : (ic.typeRef?.__$$text as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined;
+ maxWidthBasedOnEntryNames = Math.max(
+ maxWidthBasedOnEntryNames,
+ getDefaultColumnWidth?.({ name, typeRef }) ?? CONTEXT_ENTRY_INFO_MIN_WIDTH
+ );
+ return {
+ entryInfo: {
+ id: generateUuid(),
+ name,
+ dataType: typeRef,
+ },
+ entryExpression: {
+ id: generateUuid(),
+ name,
+ dataType: typeRef,
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ },
+ };
+ });
+
+ const contextExpression: ContextExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ entryInfoWidth: maxWidthBasedOnEntryNames,
+ result: {
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ dataType: DmnBuiltInDataType.Undefined,
+ id: generateUuid(),
+ },
+ contextEntries,
+ };
+ return contextExpression;
+ } else if (logicType === ExpressionDefinitionLogicType.List) {
+ const listExpression: ListExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ items: [
+ {
+ id: generateUuid(),
+ logicType: ExpressionDefinitionLogicType.Undefined,
+ dataType: DmnBuiltInDataType.Undefined,
+ },
+ ],
+ };
+ return listExpression;
+ } else if (logicType === ExpressionDefinitionLogicType.Invocation) {
+ const invocationExpression: InvocationExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ entryInfoWidth: CONTEXT_ENTRY_INFO_MIN_WIDTH,
+ bindingEntries: [
+ {
+ entryInfo: {
+ id: generateUuid(),
+ name: INVOCATION_EXPRESSION_DEFAULT_PARAMETER_NAME,
+ dataType: INVOCATION_EXPRESSION_DEFAULT_PARAMETER_DATA_TYPE,
+ },
+ entryExpression: {
+ id: generateUuid(),
+ name: INVOCATION_EXPRESSION_DEFAULT_PARAMETER_NAME,
+ dataType: INVOCATION_EXPRESSION_DEFAULT_PARAMETER_DATA_TYPE,
+ logicType: INVOCATION_EXPRESSION_DEFAULT_PARAMETER_LOGIC_TYPE,
+ },
+ },
+ ],
+ invokedFunction: {
+ id: generateUuid(),
+ name: "FUNCTION NAME",
+ },
+ };
+ return invocationExpression;
+ } else if (logicType === ExpressionDefinitionLogicType.Relation) {
+ const relationExpression: RelationExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ rows: [
+ {
+ id: generateUuid(),
+ cells: [{ id: generateUuid(), content: RELATION_EXPRESSION_DEFAULT_VALUE }],
+ },
+ ],
+ columns:
+ !dataType || !isStruct(dataType.itemDefinition)
+ ? [
+ {
+ id: generateUuid(),
+ name: dataType?.itemDefinition["@_name"] ?? "column-1",
+ dataType: (dataType?.feelName as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined,
+ width: RELATION_EXPRESSION_COLUMN_DEFAULT_WIDTH,
+ },
+ ]
+ : (dataType.itemDefinition.itemComponent ?? []).map((ic) => {
+ const name = ic["@_name"];
+ const typeRef = isStruct(ic)
+ ? DmnBuiltInDataType.Any
+ : (ic.typeRef?.__$$text as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined;
+ return {
+ id: generateUuid(),
+ name,
+ dataType: typeRef,
+ width: getDefaultColumnWidth?.({ name, typeRef }) ?? RELATION_EXPRESSION_COLUMN_DEFAULT_WIDTH,
+ };
+ }),
+ };
+ return relationExpression;
+ } else if (logicType === ExpressionDefinitionLogicType.DecisionTable) {
+ const singleOutputColumn = {
+ name: expressionHolderName || "Output 1",
+ typeRef: (dataType?.feelName as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined,
+ };
+ const singleInputColumn = {
+ name: "Input 1",
+ typeRef: DmnBuiltInDataType.Undefined,
+ };
+
+ const input = getInputs?.()?.map((input) => {
+ return {
+ id: generateUuid(),
+ idLiteralExpression: generateUuid(),
+ name: input.name, // This is actually a FEEL expression! Will be addressed as part of https://github.com/apache/incubator-kie-issues/issues/455
+ dataType: (input.typeRef as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined,
+ width: getDefaultColumnWidth?.(input) ?? DECISION_TABLE_INPUT_DEFAULT_WIDTH,
+ };
+ }) ?? [
+ {
+ id: generateUuid(),
+ idLiteralExpression: generateUuid(),
+ name: singleInputColumn.name,
+ dataType: singleInputColumn.typeRef,
+ width: getDefaultColumnWidth?.(singleInputColumn) ?? DECISION_TABLE_INPUT_DEFAULT_WIDTH,
+ },
+ ];
+
+ const output =
+ !dataType || !isStruct(dataType.itemDefinition)
+ ? [
+ {
+ id: generateUuid(),
+ name: singleOutputColumn.name,
+ dataType: singleOutputColumn.typeRef,
+ width: getDefaultColumnWidth?.(singleOutputColumn) ?? DECISION_TABLE_OUTPUT_DEFAULT_WIDTH,
+ },
+ ]
+ : (dataType.itemDefinition.itemComponent ?? []).map((ic) => {
+ const name = ic["@_name"];
+ const typeRef = isStruct(ic)
+ ? DmnBuiltInDataType.Any
+ : (ic.typeRef?.__$$text as DmnBuiltInDataType) ?? DmnBuiltInDataType.Undefined;
+ return {
+ id: generateUuid(),
+ name,
+ dataType: typeRef,
+ width: getDefaultColumnWidth?.({ name, typeRef }) ?? DECISION_TABLE_OUTPUT_DEFAULT_WIDTH,
+ };
+ });
+
+ const decisionTableExpression: DecisionTableExpressionDefinition = {
+ id: generateUuid(),
+ dataType: typeRef as DmnBuiltInDataType,
+ logicType,
+ hitPolicy: DecisionTableExpressionDefinitionHitPolicy.Unique,
+ aggregation: DecisionTableExpressionDefinitionBuiltInAggregation["<None>"],
+ input,
+ output,
+ annotations: [
+ {
+ name: "Annotations",
+ width: DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH,
+ },
+ ],
+ rules: [
+ {
+ id: generateUuid(),
+ inputEntries: input.map(() => ({ id: generateUuid(), content: DECISION_TABLE_INPUT_DEFAULT_VALUE })),
+ outputEntries: output.map(() => ({ id: generateUuid(), content: DECISION_TABLE_OUTPUT_DEFAULT_VALUE })),
+ annotationEntries: ["// Your annotations here"],
+ },
+ ],
+ };
+ return decisionTableExpression;
+ } else {
+ throw new Error(`No default expression available for ${logicType}`);
+ }
+}
diff --git a/packages/dmn-editor/src/clipboard/Clipboard.ts b/packages/dmn-editor/src/clipboard/Clipboard.ts
new file mode 100644
index 00000000000..b1b1e7e87d7
--- /dev/null
+++ b/packages/dmn-editor/src/clipboard/Clipboard.ts
@@ -0,0 +1,246 @@
+/*
+ * 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 {
+ DMN15__tDecision,
+ DMN15__tDecisionService,
+ DMN15__tDefinitions,
+ DMN15__tItemDefinition,
+ DMNDI15__DMNEdge,
+ DMNDI15__DMNShape,
+} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { Unpacked } from "../tsExt/tsExt";
+import * as RF from "reactflow";
+import { State } from "../store/Store";
+import { NodeNature, nodeNatures } from "../mutations/NodeNature";
+import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
+import { NodeType } from "../diagram/connections/graphStructure";
+import { DmnDiagramEdgeData } from "../diagram/edges/Edges";
+import { KIE, Namespaced } from "@kie-tools/dmn-marshaller/dist/kie-extensions";
+import { KIE__tComponentWidths } from "@kie-tools/dmn-marshaller/dist/schemas/kie-1_0/ts-gen/types";
+import { DataType } from "../dataTypes/DataTypes";
+import { parseXmlHref } from "../xml/xmlHrefs";
+import { getNewDmnIdRandomizer } from "../idRandomizer/dmnIdRandomizer";
+
+export const DMN_EDITOR_DIAGRAM_CLIPBOARD_MIME_TYPE = "application/json+kie-dmn-editor--diagram" as const;
+export const DMN_EDITOR_BOXED_EXPRESSION_CLIPBOARD_MIME_TYPE =
+ "application/json+kie-dmn-editor--boxed-expression" as const;
+export const DMN_EDITOR_DATA_TYPES_CLIPBOARD_MIME_TYPE = "application/json+kie-dmn-editor--data-types" as const;
+
+export type DmnEditorDataTypesClipboard = {
+ mimeType: typeof DMN_EDITOR_DATA_TYPES_CLIPBOARD_MIME_TYPE;
+ namespaceWhereClipboardWasCreatedFrom: string;
+ namespace: string;
+ itemDefinitions: DMN15__tItemDefinition[];
+};
+
+export type DmnEditorDiagramClipboard = {
+ mimeType: typeof DMN_EDITOR_DIAGRAM_CLIPBOARD_MIME_TYPE;
+ namespaceWhereClipboardWasCreatedFrom: string;
+ drgElements: NonNullable<Unpacked<DMN15__tDefinitions["drgElement"]>>[];
+ artifacts: NonNullable<Unpacked<DMN15__tDefinitions["artifact"]>>[];
+ widths: Namespaced<KIE, KIE__tComponentWidths>[];
+ shapes: DMNDI15__DMNShape[];
+ edges: DMNDI15__DMNEdge[];
+};
+
+export function buildClipboardFromDiagram(rfState: RF.ReactFlowState, dmnEditorState: State) {
+ const copiedEdgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
+ const copiedNodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
+ const danglingEdgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
+
+ const nodesById = rfState
+ .getNodes()
+ .reduce((acc, n) => acc.set(n.id, n), new Map<string, RF.Node<DmnDiagramNodeData>>());
+
+ const selectedNodesById = rfState
+ .getNodes()
+ .reduce((acc, n) => (n.selected ? acc.set(n.id, n) : acc), new Map<string, RF.Node<DmnDiagramNodeData>>());
+
+ const clipboard = [...selectedNodesById.values()].reduce<DmnEditorDiagramClipboard>(
+ (acc, _node: RF.Node<DmnDiagramNodeData>) => {
+ function accNode(node: RF.Node<DmnDiagramNodeData>) {
+ const nodeNature = nodeNatures[node.type as NodeType];
+
+ // Groups and TextAnnotations.. Associations are treated after.
+ if (nodeNature === NodeNature.ARTIFACT) {
+ acc.artifacts.unshift(node.data.dmnObject as any);
+ }
+ // DRG Elements
+ else if (nodeNature === NodeNature.DRG_ELEMENT) {
+ if (_node.data.dmnObjectQName.prefix) {
+ // External node. Will not go in the Clipboard.
+ return;
+ }
+
+ const dmnObject = JSON.parse(JSON.stringify(node.data.dmnObject)) as DMN15__tDecision; // Casting to `DMN15__tDecision` because it has all requirement types.
+
+ // This is going to get repopulated when this data is pasted somewhere.
+ if (node.data.dmnObject?.__$$element === "decisionService") {
+ (dmnObject as DMN15__tDecisionService).inputData = [];
+ (dmnObject as DMN15__tDecisionService).inputDecision = [];
+ }
+
+ if (dmnObject.authorityRequirement) {
+ dmnObject.authorityRequirement = dmnObject.authorityRequirement.filter(
+ (s) =>
+ (s.requiredInput &&
+ selectedNodesById.has(s.requiredInput["@_href"]) &&
+ !selectedNodesById.get(s.requiredInput["@_href"])?.data?.dmnObjectQName.prefix) ||
+ (s.requiredDecision &&
+ selectedNodesById.has(s.requiredDecision["@_href"]) &&
+ !selectedNodesById.get(s.requiredDecision["@_href"])?.data?.dmnObjectQName.prefix) ||
+ (s.requiredAuthority &&
+ selectedNodesById.has(s.requiredAuthority["@_href"]) &&
+ !selectedNodesById.get(s.requiredAuthority["@_href"])?.data?.dmnObjectQName.prefix)
+ );
+ }
+
+ if (dmnObject.knowledgeRequirement) {
+ dmnObject.knowledgeRequirement = dmnObject.knowledgeRequirement.filter(
+ (s) =>
+ selectedNodesById.has(s.requiredKnowledge["@_href"]) &&
+ !selectedNodesById.get(s.requiredKnowledge["@_href"])?.data?.dmnObjectQName.prefix
+ );
+ }
+
+ if (dmnObject.informationRequirement) {
+ dmnObject.informationRequirement = dmnObject.informationRequirement.filter(
+ (s) =>
+ (s.requiredInput &&
+ selectedNodesById.has(s.requiredInput["@_href"]) &&
+ !selectedNodesById.get(s.requiredInput["@_href"])?.data?.dmnObjectQName.prefix) ||
+ (s.requiredDecision &&
+ selectedNodesById.has(s.requiredDecision["@_href"]) &&
+ !selectedNodesById.get(s.requiredDecision["@_href"])?.data?.dmnObjectQName.prefix)
+ );
+ }
+ acc.drgElements.unshift(dmnObject as any);
+ } else if (nodeNature === NodeNature.UNKNOWN) {
+ // Ignore.
+ } else {
+ throw new Error(`Unknwon node nature '${nodeNature}'`);
+ }
+
+ copiedNodesById.set(node.id, node);
+
+ const { index, ...dmnShape } = node.data.shape;
+ acc.shapes.push(dmnShape);
+ }
+
+ if (!_node.selected) {
+ return acc;
+ }
+
+ // When a Decision Service is selected, we treat all its contained Decisions as if they were too, making them part of the cut/copy/paste operations.
+ if (_node.data.dmnObject?.__$$element === "decisionService") {
+ for (const decision of [
+ ...(_node.data.dmnObject.outputDecision ?? []),
+ ...(_node.data.dmnObject.encapsulatedDecision ?? []),
+ ]) {
+ if (parseXmlHref(decision["@_href"]).namespace) {
+ continue; // External decision relative to this DMN. Will not go in the Clipboard.
+ }
+
+ const decisionNode = nodesById.get(decision["@_href"]);
+ if (!decisionNode) {
+ // Decision Service has a reference to an unknown Decision. Ignoring.
+ continue;
+ }
+
+ accNode(decisionNode);
+ }
+ }
+
+ accNode(_node);
+
+ return acc;
+ },
+ {
+ mimeType: DMN_EDITOR_DIAGRAM_CLIPBOARD_MIME_TYPE,
+ namespaceWhereClipboardWasCreatedFrom: dmnEditorState.dmn.model.definitions["@_namespace"],
+ widths: [],
+ drgElements: [],
+ artifacts: [],
+ shapes: [],
+ edges: [],
+ }
+ );
+
+ const idsOnDrgElementTrees = getNewDmnIdRandomizer()
+ .ack({ json: clipboard.drgElements, type: "DMN15__tDefinitions", attr: "drgElement" })
+ .getOriginalIds();
+
+ clipboard.widths = (
+ dmnEditorState.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[dmnEditorState.diagram.drdIndex][
+ "di:extension"
+ ]?.["kie:ComponentsWidthsExtension"]?.["kie:ComponentWidths"] ?? []
+ ).filter((w: KIE__tComponentWidths) => idsOnDrgElementTrees.has(w["@_dmnElementRef"]!));
+
+ const artifacts = dmnEditorState.dmn.model.definitions.artifact ?? [];
+
+ clipboard.edges = rfState.edges.flatMap((edge: RF.Edge<DmnDiagramEdgeData>) => {
+ if (copiedNodesById.has(edge.source) && !copiedNodesById.has(edge.target)) {
+ danglingEdgesById.set(edge.id, edge); // Edges that point to nodes that are not part of the clipboard need to be removed when 'cut' is executed.
+ }
+
+ if (copiedNodesById.has(edge.source) && copiedNodesById.has(edge.target)) {
+ if (!edge.data?.dmnEdge) {
+ return [];
+ }
+
+ copiedEdgesById.set(edge.id, edge);
+ const { index, ...dmnEdge } = edge.data!.dmnEdge!;
+ if (edge.data?.dmnObject.requirementType === "association") {
+ clipboard.artifacts.push(artifacts[edge.data.dmnObject.index]);
+ }
+ return dmnEdge ?? [];
+ } else {
+ return [];
+ }
+ });
+
+ return { clipboard, copiedEdgesById, copiedNodesById, danglingEdgesById };
+}
+
+export function buildClipboardFromDataType(dataType: DataType, thisDmnsNamespace: string): DmnEditorDataTypesClipboard {
+ return {
+ namespaceWhereClipboardWasCreatedFrom: thisDmnsNamespace,
+ namespace: dataType.namespace,
+ mimeType: DMN_EDITOR_DATA_TYPES_CLIPBOARD_MIME_TYPE,
+ itemDefinitions: [dataType.itemDefinition],
+ };
+}
+
+export function getClipboard<T extends { mimeType: string }>(text: string, mimeType: string): T | undefined {
+ let potentialClipboard: T | undefined;
+ try {
+ potentialClipboard = JSON.parse(text);
+ } catch (e) {
+ console.debug("DMN DIAGRAM: Ignoring pasted content. Not a valid JSON.");
+ return undefined;
+ }
+
+ if (!potentialClipboard || potentialClipboard.mimeType !== mimeType) {
+ console.debug("DMN DIAGRAM: Ignoring pasted content. MIME type doesn't match.");
+ return undefined;
+ }
+
+ return potentialClipboard;
+}
diff --git a/packages/pmml-editor/tests/jest.setup.ts b/packages/dmn-editor/src/dataTypes/BuiltInFeelTypes.ts
similarity index 64%
copy from packages/pmml-editor/tests/jest.setup.ts
copy to packages/dmn-editor/src/dataTypes/BuiltInFeelTypes.ts
index f23267ef470..689fa1df116 100644
--- a/packages/pmml-editor/tests/jest.setup.ts
+++ b/packages/dmn-editor/src/dataTypes/BuiltInFeelTypes.ts
@@ -17,7 +17,13 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+import { DmnDataType } from "@kie-tools/boxed-expression-component/dist/api";
+import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api/DmnBuiltInDataType";
-enableAllPlugins();
+export const builtInFeelTypes: DmnDataType[] = Object.values(DmnBuiltInDataType).map((feelType) => ({
+ isCustom: false,
+ typeRef: feelType,
+ name: feelType,
+}));
+
+export const builtInFeelTypeNames = new Set<string>(Object.values(DmnBuiltInDataType));
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.css b/packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.css
new file mode 100644
index 00000000000..475a9c948dd
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.css
@@ -0,0 +1,17 @@
+.kie-dmn-editor--constraint-input {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-invalid input {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
+
+.kie-dmn-editor--constraint-invalid {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
diff --git a/packages/pmml-editor/tests/jest.setup.ts b/packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.ts
similarity index 65%
copy from packages/pmml-editor/tests/jest.setup.ts
copy to packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.ts
index f23267ef470..7d2cbccf0f3 100644
--- a/packages/pmml-editor/tests/jest.setup.ts
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/Constraint.ts
@@ -17,7 +17,20 @@
* under the License.
*/
-import "@testing-library/jest-dom";
-import { enableAllPlugins } from "immer";
+import React from "react";
-enableAllPlugins();
+export interface ConstraintProps {
+ id: string;
+ placeholder?: string;
+ type: "text" | "number";
+ value: string;
+ onChange: (newValue: string) => void;
+ onBlur?: () => void;
+ isDisabled?: boolean;
+ autoFocus?: boolean;
+ focusOwner?: string;
+ setFocusOwner?: (id: string) => void;
+ style?: React.CSSProperties;
+ isValid: boolean;
+ onKeyDown: (e: React.KeyboardEvent) => void;
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.css b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.css
new file mode 100644
index 00000000000..03306d6b02e
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.css
@@ -0,0 +1,23 @@
+.kie-dmn-editor--constraint-date button::after {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-date > div > div > button {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent !important;
+}
+
+.kie-dmn-editor--constraint-date > div > div {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-date-invalid > div > div > input {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
diff --git a/packages/online-editor/src/settings/SettingsButton.tsx b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
similarity index 58%
copy from packages/online-editor/src/settings/SettingsButton.tsx
copy to packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
index 185721e189f..e4cb2e573e9 100644
--- a/packages/online-editor/src/settings/SettingsButton.tsx
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
@@ -18,20 +18,22 @@
*/
import * as React from "react";
-import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
-import { CogIcon } from "@patternfly/react-icons/dist/js/icons/cog-icon";
-import { useSettingsDispatch } from "./SettingsContext";
+import { DatePicker } from "@patternfly/react-core/dist/js/components/DatePicker";
+import "./Constraint.css";
+import "./ConstraintDate.css";
+import { ConstraintProps } from "./Constraint";
-export function SettingsButton() {
- const settingsDispatch = useSettingsDispatch();
+export function ConstraintDate({ value, onChange, isValid }: ConstraintProps) {
return (
- <Button
- variant={ButtonVariant.plain}
- onClick={() => settingsDispatch.open()}
- aria-label="Settings"
- className={"kie-tools--masthead-hoverable-dark"}
- >
- <CogIcon />
- </Button>
+ <>
+ <DatePicker
+ className={`kie-dmn-editor--constraint-date kie-dmn-editor--constraint-input ${
+ isValid ? "" : "kie-dmn-editor--constraint-date-invalid"
+ }`}
+ inputProps={{ className: "kie-dmn-editor--constraint-input" }}
+ value={value}
+ onChange={(e, value) => onChange(value)}
+ />
+ </>
);
}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.css b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.css
new file mode 100644
index 00000000000..c1b9f733bfa
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.css
@@ -0,0 +1,14 @@
+.kie-dmn-editor--constraint-date-time {
+ display: flex;
+ flex-direction: row;
+}
+
+.kie-dmn-editor--constraint-date-time-timezone {
+ width: 120px;
+}
+
+.kie-dmn-editor--constraint-date-time-timezone-invalid > button {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.tsx b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.tsx
new file mode 100644
index 00000000000..08e4f3dfda5
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTime.tsx
@@ -0,0 +1,67 @@
+/*
+ * 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 } from "react";
+import "./ConstraintDateTime.css";
+import { ConstraintProps } from "./Constraint";
+import { ConstraintTime } from "./ConstraintTime";
+import { ConstraintDate } from "./ConstraintDate";
+
+export function ConstraintDateTime({ value, onChange, isValid, ...props }: ConstraintProps) {
+ const date = useMemo(() => value.split("T")?.[0] ?? "", [value]);
+ const time = useMemo(() => value.split("T")?.[1] ?? "", [value]);
+
+ const onInternalChange = useCallback(
+ (args: { date?: string; time?: string }) => {
+ const newDate = args.date ?? date;
+ const newTime = args.time ?? time;
+ if (newDate !== "" && newTime === "") {
+ onChange(`${newDate}`);
+ }
+ if (newDate !== "" && newTime !== "") {
+ onChange(`${newDate}T${newTime}`);
+ }
+ },
+ [date, onChange, time]
+ );
+
+ const onChangeDate = useCallback(
+ (value: string) => {
+ onInternalChange({ date: value });
+ },
+ [onInternalChange]
+ );
+
+ const onChangeTime = useCallback(
+ (value: string) => {
+ onInternalChange({ time: value });
+ },
+ [onInternalChange]
+ );
+
+ return (
+ <>
+ <div className={"kie-dmn-editor--constraint-date-time"}>
+ <ConstraintDate {...props} value={date} onChange={onChangeDate} isValid={isValid} />
+ <ConstraintTime {...props} value={time} onChange={onChangeTime} isValid={isValid} />
+ </div>
+ </>
+ );
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTimeDuration.tsx b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTimeDuration.tsx
new file mode 100644
index 00000000000..8b9c5dd41be
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDateTimeDuration.tsx
@@ -0,0 +1,211 @@
+/*
+ * 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 { useMemo, useCallback, useEffect } from "react";
+import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
+import "./Constraint.css";
+import { ConstraintProps } from "./Constraint";
+
+export const REGEX_DATE_TIME_DURATION = /^P(?!$)((-)?\d+D)?(T(?=(-)?\d)((-)?\d+H)?((-)?\d+M)?((-)?\d+S)?)?$/;
+
+export function ConstraintDateTimeDuration({
+ id,
+ value,
+ onChange,
+ focusOwner,
+ setFocusOwner,
+ isValid,
+ isDisabled,
+}: ConstraintProps) {
+ const days = useMemo<string>(() => getDaysDuration(value), [value]);
+ const hours = useMemo<string>(() => getHoursDuration(value), [value]);
+ const minutes = useMemo<string>(() => getMinutesDuration(value), [value]);
+ const seconds = useMemo<string>(() => getSecondsDuration(value), [value]);
+
+ // It should run on the first render;
+ useEffect(() => {
+ if (focusOwner) {
+ document.getElementById(focusOwner)?.focus();
+ }
+ }, [focusOwner]);
+
+ const onInternalChange = useCallback(
+ (args: { days?: string; hours?: string; minutes?: string; seconds?: string }) => {
+ const d = args.days ?? days ? (args.days ?? days) + "D" : "";
+ const h = args.hours ?? hours ? (args.hours ?? hours) + "H" : "";
+ const m = args.minutes ?? minutes ? (args.minutes ?? minutes) + "M" : "";
+ const s = args.seconds ?? seconds ? (args.seconds ?? seconds) + "S" : "";
+ const t = h || m || s ? "T" : "";
+ const p = d || h || m || s ? "P" : "";
+ onChange(`${p}${d}${t}${h}${m}${s}`);
+ },
+ [days, hours, minutes, onChange, seconds]
+ );
+
+ const onDaysChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ days: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ const onHoursChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ hours: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ const onMinutesChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ minutes: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ const onSecondsChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ seconds: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ return (
+ <>
+ <div style={{ display: "flex", flexDirection: "row" }}>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>D:</p>
+ <TextInput
+ id={`${id}-constraint-days`}
+ type={"number"}
+ placeholder={"Days"}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={days}
+ onChange={onDaysChange}
+ isDisabled={isDisabled}
+ autoFocus={true}
+ />
+ </div>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>H:</p>
+ <TextInput
+ id={`${id}-constraint-hours`}
+ type={"number"}
+ placeholder={"Hours"}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={hours}
+ onChange={onHoursChange}
+ isDisabled={isDisabled}
+ />
+ </div>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>M:</p>
+ <TextInput
+ id={`${id}-constraint-minutes`}
+ type={"number"}
+ placeholder={"Minutes"}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={minutes}
+ onChange={onMinutesChange}
+ isDisabled={isDisabled}
+ />
+ </div>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>S:</p>
+ <TextInput
+ id={`${id}-constraint-seconds`}
+ type={"number"}
+ placeholder={"Seconds"}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={seconds}
+ onChange={onSecondsChange}
+ isDisabled={isDisabled}
+ />
+ </div>
+ </div>
+ </>
+ );
+}
+
+function getDaysDuration(value: string) {
+ if (!value.includes("D")) {
+ return "";
+ }
+ const days = value.replace("P", "").split("D")[0];
+ if (days.length >= 1) {
+ return !isNaN(parseInt(days)) ? days : "";
+ }
+ return "";
+}
+
+function getHoursDuration(value: string) {
+ if (!value.includes("T") || !value.includes("H")) {
+ return "";
+ }
+ let hours = value.replace("P", "").replace("T", "").split("H")[0];
+ if (hours.includes("D")) {
+ hours = hours.split("D")[1];
+ }
+ if (hours.length >= 1) {
+ return !isNaN(parseInt(hours)) ? hours : "";
+ }
+ return "";
+}
+
+function getMinutesDuration(value: string) {
+ if (!value.includes("T") || !value.includes("M")) {
+ return "";
+ }
+ let hours = value.replace("P", "").replace("T", "").split("M")[0];
+ if (hours.includes("D")) {
+ hours = hours.split("D")[1];
+ }
+ if (hours.includes("H")) {
+ hours = hours.split("H")[1];
+ }
+ if (hours.length >= 1) {
+ return !isNaN(parseInt(hours)) ? hours : "";
+ }
+ return "";
+}
+
+function getSecondsDuration(value: string) {
+ if (!value.includes("T") || !value.includes("S")) {
+ return "";
+ }
+ let hours = value.replace("P", "").replace("T", "").split("S")[0];
+ if (hours.includes("D")) {
+ hours = hours.split("D")[1];
+ }
+ if (hours.includes("H")) {
+ hours = hours.split("H")[1];
+ }
+ if (hours.includes("M")) {
+ hours = hours.split("M")[1];
+ }
+ if (hours.length >= 1) {
+ return !isNaN(parseInt(hours)) ? hours : "";
+ }
+ return "";
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.css b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.css
new file mode 100644
index 00000000000..7090420fc0a
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.css
@@ -0,0 +1,33 @@
+.kie-dmn-editor--constraint-time button::after {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-time > div > div > button {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent !important;
+}
+
+.kie-dmn-editor--constraint-time > div > div {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-time-timezone {
+ width: 120px;
+}
+
+.kie-dmn-editor--constraint-time-timezone > button {
+ outline: none;
+ border-color: transparent;
+ background-color: transparent;
+}
+
+.kie-dmn-editor--constraint-time-timezone-invalid > button {
+ color: red;
+ text-decoration: red dotted underline;
+ text-underline-position: under;
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
new file mode 100644
index 00000000000..346b3eb4a82
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
@@ -0,0 +1,158 @@
+/*
+ * 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, useRef, useState } from "react";
+import { TimePicker } from "@patternfly/react-core/dist/js/components/TimePicker";
+import "./Constraint.css";
+import "./ConstraintTime.css";
+import { ConstraintProps } from "./Constraint";
+import { Select, SelectOption, SelectVariant } from "@patternfly/react-core/dist/js/components/Select";
+import { useDmnEditor } from "../../DmnEditorContext";
+import { useInViewSelect } from "../../responsiveness/useInViewSelect";
+
+// Time zone list from https://www.timeanddate.com/time/zones/
+const UTC_POSITEVE_TIMEZONES = [
+ "+00:00",
+ "+01:00",
+ "+02:00",
+ "+03:00",
+ "+03:30",
+ "+04:00",
+ "+04:30",
+ "+05:00",
+ "+05:30",
+ "+05:45",
+ "+06:00",
+ "+06:30",
+ "+07:00",
+ "+08:00",
+ "+08:30",
+ "+08:45",
+ "+09:00",
+ "+09:30",
+ "+10:00",
+ "+10:30",
+ "+11:00",
+ "+12:00",
+ "+12:45",
+ "+13:00",
+ "+13:45",
+ "+14:00",
+];
+
+const UTC_NEGATIVE_TIMEZONES = [
+ "-12:00",
+ "-11:00",
+ "-10:00",
+ "-09:30",
+ "-09:00",
+ "-08:00",
+ "-07:00",
+ "-06:00",
+ "-05:00",
+ "-04:00",
+ "-03:30",
+ "-03:00",
+ "-02:30",
+ "-02:00",
+ "-01:00",
+];
+
+export function ConstraintTime({ value, onChange, isValid }: ConstraintProps) {
+ const time = useMemo(() => {
+ return value.includes("+") ? value.split("+")[0] : value.split("-")[0];
+ }, [value]);
+ const timezone = useMemo<string>(() => {
+ return value.includes("+")
+ ? `+${value.split("+")[1]}`
+ : value.includes("-")
+ ? `-${value.split("-")[1]}`
+ : UTC_POSITEVE_TIMEZONES[0];
+ }, [value]);
+ const [isSelectTimezoneOpen, setSelectTimezoneOpen] = useState(false);
+ const { dmnEditorRootElementRef } = useDmnEditor();
+ const toggleRef = useRef<HTMLButtonElement>(null);
+ const inViewTimezoneSelect = useInViewSelect(dmnEditorRootElementRef, toggleRef);
+
+ const onInternalChange = useCallback(
+ (args: { time?: string; timezone?: string }) => {
+ const newTime = args.time ?? time;
+ const newTimezone = args.timezone ?? timezone;
+ if (newTime !== "" && newTimezone !== "") {
+ onChange(`${newTime}${newTimezone}`);
+ }
+ },
+ [onChange, time, timezone]
+ );
+
+ const onChangeTime = useCallback(
+ (value: string) => {
+ onInternalChange({ time: value });
+ },
+ [onInternalChange]
+ );
+
+ const onSelectTimezone = useCallback(
+ (e, value) => {
+ onInternalChange({ timezone: value.toString() });
+ },
+ [onInternalChange]
+ );
+
+ return (
+ <div>
+ <TimePicker
+ is24Hour={true}
+ className={`kie-dmn-editor--constraint-time kie-dmn-editor--constraint-input ${
+ isValid ? "" : "kie-dmn-editor--constraint-invalid"
+ }`}
+ inputProps={{ className: "kie-dmn-editor--constraint-input" }}
+ time={time}
+ onChange={(e, value, hour, minute, seconds, isValid) => {
+ if (isValid) {
+ onChangeTime(value);
+ }
+ }}
+ includeSeconds={true}
+ />
+ <Select
+ toggleRef={toggleRef}
+ className={`kie-dmn-editor--constraint-time-timezone ${
+ isValid ? "" : "kie-dmn-editor--constraint-time-timezone-invalid"
+ }`}
+ variant={SelectVariant.single}
+ placeholderText="Select timezone"
+ aria-label="Select timezone"
+ onToggle={(isExpanded) => setSelectTimezoneOpen(isExpanded)}
+ onSelect={onSelectTimezone}
+ selections={timezone}
+ isOpen={isSelectTimezoneOpen}
+ isDisabled={false}
+ isPlain={true}
+ maxHeight={inViewTimezoneSelect.maxHeight}
+ direction={inViewTimezoneSelect.direction}
+ >
+ {[...UTC_NEGATIVE_TIMEZONES, ...UTC_POSITEVE_TIMEZONES].map((timezone) => (
+ <SelectOption key={timezone} value={timezone} />
+ ))}
+ </Select>
+ </div>
+ );
+}
diff --git a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintYearsMonthsDuration.tsx b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintYearsMonthsDuration.tsx
new file mode 100644
index 00000000000..06bbfb73034
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintYearsMonthsDuration.tsx
@@ -0,0 +1,133 @@
+/*
+ * 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, useEffect } from "react";
+import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
+import "./Constraint.css";
+import { ConstraintProps } from "./Constraint";
+
+export const REGEX_YEARS_MONTH_DURATION = /^P(?!$)((-)?\d+Y)?((-)?\d+M)?$/;
+
+export function ConstraintYearsMonthsDuration({
+ id,
+ value,
+ onChange,
+ focusOwner,
+ setFocusOwner,
+ isValid,
+ isDisabled,
+}: ConstraintProps) {
+ const years = useMemo<string>(() => getYearsDuration(value), [value]);
+ const months = useMemo<string>(() => getMonthsDuration(value), [value]);
+
+ // It should run on the first render;
+ useEffect(() => {
+ if (focusOwner) {
+ document.getElementById(focusOwner)?.focus();
+ }
+ }, [focusOwner]);
+
+ const onInternalChange = useCallback(
+ (args: { years?: string; months?: string }) => {
+ const y = args.years ?? years ? (args.years ?? years) + "Y" : "";
+ const m = args.months ?? months ? (args.months ?? months) + "M" : "";
+ const p = y || m ? "P" : "";
+ onChange(`${p}${y}${m}`);
+ },
+ [months, onChange, years]
+ );
+
+ const onYearsChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ years: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ const onMonthsChange = useCallback(
+ (newValue: string, e: React.FormEvent<HTMLInputElement>) => {
+ onInternalChange({ months: newValue });
+ setFocusOwner?.(e.currentTarget.id);
+ },
+ [onInternalChange, setFocusOwner]
+ );
+
+ return (
+ <>
+ <div style={{ display: "flex", flexDirection: "row" }}>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>Y:</p>
+ <TextInput
+ id={`${id}-constraint-years`}
+ type={"number"}
+ placeholder={"Years"}
+ style={{ flex: "1 1 0px" }}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={years}
+ onChange={onYearsChange}
+ autoFocus={true}
+ isDisabled={isDisabled}
+ />
+ </div>
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
+ <p>M:</p>
+ <TextInput
+ id={`${id}-constraint-months`}
+ type={"number"}
+ placeholder={"Months"}
+ style={{ flex: "1 1 0px" }}
+ className={`kie-dmn-editor--constraint-input ${isValid ? "" : "kie-dmn-editor--constraint-invalid"}`}
+ value={months}
+ onChange={onMonthsChange}
+ isDisabled={isDisabled}
+ />
+ </div>
+ </div>
+ </>
+ );
+}
+
+function getYearsDuration(value: string) {
+ if (!value.includes("Y")) {
+ return "";
+ }
+ const years = value.replace("P", "").split("Y")[0];
+ if (years.length >= 1) {
+ return !isNaN(parseInt(years)) ? years : "";
+ }
+ return "";
+}
+
+function getMonthsDuration(value: string) {
+ if (!value.includes("M")) {
+ return "";
+ }
+ let months = value.replace("P", "").split("M")[0];
+ // if has year, remove it
+ if (value.includes("Y")) {
+ months = months.split("Y")[1];
+ }
+ // checks if has a value, and if its a number
+ if (months.length >= 1) {
+ return !isNaN(parseInt(months)) ? months : "";
+ }
+ return "";
+}
diff --git a/packages/dmn-editor/src/dataTypes/Constraints.tsx b/packages/dmn-editor/src/dataTypes/Constraints.tsx
new file mode 100644
index 00000000000..7c00834f0de
--- /dev/null
+++ b/packages/dmn-editor/src/dataTypes/Constraints.tsx
@@ -0,0 +1,517 @@
+/*
+ * 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 { useMemo, useCallback, useRef, useState, useLayoutEffect } from "react";
+import { ConstraintsExpression } from "./ConstraintsExpression";
+import { DMN15__tItemDefinition } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DmnBuiltInDataType, generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { ConstraintsEnum, isEnum } from "./ConstraintsEnum";
+import { ConstraintsRange, isRange } from "./ConstraintsRange";
+import { KIE__tConstraintType } from "@kie-tools/dmn-marshaller/dist/schemas/kie-1_0/ts-gen/types";
+import { EditItemDefinition } from "./DataTypes";
+import { ToggleGroup, ToggleGroupItem } from "@patternfly/react-core/dist/js/components/ToggleGroup";
+import { canHaveConstraints, constrainableBuiltInFeelTypes } from "./DataTypeSpec";
+import moment from "moment";
+import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
+import { ConstraintDate } from "./ConstraintComponents/ConstraintDate";
+import { ConstraintDateTime } from "./ConstraintComponents/ConstraintDateTime";
+import {
+ ConstraintDateTimeDuration,
+ REGEX_DATE_TIME_DURATION,
+} from "./ConstraintComponents/ConstraintDateTimeDuration";
+import { ConstraintTime } from "./ConstraintComponents/ConstraintTime";
+import {
+ ConstraintYearsMonthsDuration,
+ REGEX_YEARS_MONTH_DURATION,
+} from "./ConstraintComponents/ConstraintYearsMonthsDuration";
+import { invalidInlineFeelNameStyle } from "../feel/InlineFeelNameInput";
+import { ConstraintProps } from "./ConstraintComponents/Constraint";
+
+export type TypeHelper = {
+ check: (value: string) => boolean;
+ parse: (value: string) => any;
+ transform: (value: string) => string;
+ recover: (value?: string) => string | undefined;
+ component: (props: any) => React.ReactNode | undefined;
+};
+
+export interface ConstraintComponentProps {
+ isReadonly: boolean;
+ value?: string;
+ expressionValue?: string;
+ type: DmnBuiltInDataType;
+ typeHelper: TypeHelper;
+ onSave: (value?: string) => void;
+ isDisabled: boolean;
+}
+
+enum ConstraintsType {
+ ENUMERATION = "Enumeration",
+ EXPRESSION = "Expression",
+ RANGE = "Range",
+ NONE = "None",
+}
+
+export const constraintTypeHelper = (typeRef: DmnBuiltInDataType): TypeHelper => {
+ return {
+ // check if the value has the correct type
+ check: (value: string) => {
+ const recoveredValue = constraintTypeHelper(typeRef).recover(value);
+ switch (typeRef) {
+ case DmnBuiltInDataType.Any:
... 28909 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org