diff --git a/README.md b/README.md index df3dc6f0a74..5d41dc7ffd7 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ The Apache KIE Tools project contains several applications. To develop each one 1. After you've successfully built the project following the instructions above, open the `packages/kie-editors-dev-vscode-extension` folder on VS Code. Use a new VS Code window so that the `packages/kie-editors-dev-vscode-extension` folder shows up as root in the VS Code explorer. 2. From there, you can Run the extension or the end-to-end tests by using the `Debug` menu/section. You can also use the respective shortcuts (F5 to start debugging, for instance). -3. **NOTE:** To run the VS Code extension in development mode, you need `webpack` and `webpack-cli` to be globally installed on NPM. Normally you can do that with `npm install -g webpack@^5.88.2 webpack-cli@^4.10.0`, but `sudo` may be required depending on your installation. +3. **NOTE:** To run the VS Code extension in development mode, you need `webpack` and `webpack-cli` to be globally installed on NPM. Normally you can do that with `npm install -g webpack@^5.92.1 webpack-cli@^4.10.0`, but `sudo` may be required depending on your installation. 4. **Remember!** If you make changes to any package other than `packages/kie-editors-dev-vscode-extension`, you have to manually rebuild them before relaunching the extension on VS Code. #### VS Code Extension (Serverless Workflow Editor) diff --git a/examples/base64png-editor-chrome-extension/package.json b/examples/base64png-editor-chrome-extension/package.json index eeab5bc3347..08129d5c413 100644 --- a/examples/base64png-editor-chrome-extension/package.json +++ b/examples/base64png-editor-chrome-extension/package.json @@ -33,7 +33,7 @@ "copy-webpack-plugin": "^11.0.0", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0", diff --git a/examples/base64png-editor-vscode-extension/package.json b/examples/base64png-editor-vscode-extension/package.json index 4beb32b86f7..cdbd9ee73c2 100644 --- a/examples/base64png-editor-vscode-extension/package.json +++ b/examples/base64png-editor-vscode-extension/package.json @@ -38,7 +38,7 @@ "@vscode/vsce": "^2.22.0", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/examples/dmn-editor-standalone-examples/README.md b/examples/dmn-editor-standalone-examples/README.md new file mode 100644 index 00000000000..039c312e3d8 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/README.md @@ -0,0 +1,75 @@ + + +## DMN Editor Standalone Examples + +A series of examples on how to use the DMN Editor Standalone in different applications. + +### Examples + +- [State Control]("src/stateControl/index.ts"): Shows how to leverage the Editor API to undo/redo changes to a decision, get its contents and download an SVG of the diagram. +- [Read Only]("src/readOnly/index.ts"): Loads the editor in "Read Only" mode, where a decision can be displayed and navigated but not changed. +- [With Included Models]("src/withIncludedModels/index.ts"): Displays how Decisions can be imported into other Decisions as "Included Models", using the `resources` parameter from the DMN Editor. + +### Build + +To build the examples, execute one of the following commands on the root folder of the project: + +```shell script +KIE_TOOLS_BUILD__buildExamples=true pnpm -F @kie-tools-examples/dmn-editor-standalone-examples... build:dev +KIE_TOOLS_BUILD__buildExamples=true pnpm -F @kie-tools-examples/dmn-editor-standalone-examples... build:prod +``` + +### Run + +To start the examples application, execute the following command on the root folder of the project: + +```shell script +pnpm -F @kie-tools-examples/dmn-editor-standalone-examples start +``` + +Open http://localhost:9102 to see the list of files bundled by webpack, then choose an example: + +- State Control: http://localhost:9102/state_control.html +- Read Only: http://localhost:9102/read_only.html +- With Included Models: http://localhost:9102/with_included_models.html + +--- + +Apache KIE (incubating) is an effort undergoing incubation at The Apache Software +Foundation (ASF), sponsored by the name of Apache Incubator. Incubation is +required of all newly accepted projects until a further review indicates that +the infrastructure, communications, and decision making process have stabilized +in a manner consistent with other successful ASF projects. While incubation +status is not necessarily a reflection of the completeness or stability of the +code, it does indicate that the project has yet to be fully endorsed by the ASF. + +Some of the incubating project’s releases may not be fully compliant with ASF +policy. For example, releases may have incomplete or un-reviewed licensing +conditions. What follows is a list of known issues the project is currently +aware of (note that this list, by definition, is likely to be incomplete): + +- Hibernate, an LGPL project, is being used. Hibernate is in the process of + relicensing to ASL v2 +- Some files, particularly test files, and those not supporting comments, may + be missing the ASF Licensing Header + +If you are planning to incorporate this work into your product/project, please +be aware that you will need to conduct a thorough licensing review to determine +the overall implications of including this work. For the current status of this +project through the Apache Incubator visit: +https://incubator.apache.org/projects/kie.html diff --git a/examples/dmn-editor-standalone-examples/env/index.js b/examples/dmn-editor-standalone-examples/env/index.js new file mode 100644 index 00000000000..d0530a1d5ff --- /dev/null +++ b/examples/dmn-editor-standalone-examples/env/index.js @@ -0,0 +1,31 @@ +/* + * 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. + */ + +const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env"); + +module.exports = composeEnv([require("@kie-tools/root-env/env")], { + vars: varsWithName({}), + get env() { + return { + dmnEditorStandaloneExamples: { + port: 9102, + }, + }; + }, +}); diff --git a/examples/dmn-editor-standalone-examples/package.json b/examples/dmn-editor-standalone-examples/package.json new file mode 100644 index 00000000000..479bb384c27 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/package.json @@ -0,0 +1,45 @@ +{ + "private": true, + "name": "@kie-tools-examples/dmn-editor-standalone-examples", + "version": "0.0.0", + "description": "", + "license": "Apache-2.0", + "homepage": "https://github.com/apache/incubator-kie-tools", + "repository": { + "type": "git", + "url": "https://github.com/apache/incubator-kie-tools.git" + }, + "bugs": { + "url": "https://github.com/apache/incubator-kie-tools/issues" + }, + "scripts": { + "build:dev": "rimraf dist && webpack --env dev", + "build:prod": "rimraf dist && webpack --env prod", + "start": "webpack serve --host 0.0.0.0 --env dev" + }, + "dependencies": { + "@kie-tools/dmn-editor-standalone": "workspace:*" + }, + "devDependencies": { + "@kie-tools-core/webpack-base": "workspace:*", + "@kie-tools/root-env": "workspace:*", + "@kie-tools/tsconfig": "workspace:*", + "copy-webpack-plugin": "^11.0.0", + "html-webpack-plugin": "^5.3.2", + "process": "^0.11.10", + "raw-loader": "^4.0.2", + "rimraf": "^3.0.2", + "typescript": "^5.5.3", + "webpack": "^5.92.1", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0" + }, + "kieTools": { + "requiredPreinstalledCliCommands": [ + "java", + "mvn" + ] + } +} diff --git a/examples/dmn-editor-standalone-examples/src/fileLoader.ts b/examples/dmn-editor-standalone-examples/src/fileLoader.ts new file mode 100644 index 00000000000..1dcd0920f3a --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/fileLoader.ts @@ -0,0 +1,32 @@ +/* + * 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 { DmnEditorStandaloneApi } from "@kie-tools/dmn-editor-standalone/dist"; + +export function loadFile(fileName: string) { + return fetch(`/static/models/${fileName}`).then((value) => value.text()); +} + +export function initFileLoader(files: Array, editor: DmnEditorStandaloneApi) { + files.map((fileName) => { + document.getElementById(fileName)?.addEventListener("click", () => { + loadFile(fileName).then((fileContent) => editor.setContent(fileName, fileContent)); + }); + }); +} diff --git a/examples/dmn-editor-standalone-examples/src/readOnly/index.html b/examples/dmn-editor-standalone-examples/src/readOnly/index.html new file mode 100644 index 00000000000..f72922efd6e --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/readOnly/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + +
+ + diff --git a/examples/dmn-editor-standalone-examples/src/readOnly/index.ts b/examples/dmn-editor-standalone-examples/src/readOnly/index.ts new file mode 100644 index 00000000000..ff6cdf0e905 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/readOnly/index.ts @@ -0,0 +1,43 @@ +/* + * 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 DmnEditor from "@kie-tools/dmn-editor-standalone/dist"; +import { loadFile } from "../fileLoader"; + +document.addEventListener("DOMContentLoaded", function () { + loadEditor(); +}); + +function loadEditor() { + // Loads the DMN Editor in the `
` element. + // Initializes with an existing file called `loan-pre-qualification.dmn` on the root of the + // workspace. + // The `loadFile` function loads the file from the /static/models directory and returns + // a Promise that resolves into a string. + // The `readOnly` flag changes the editor, locking all changes to the model, making it + // useful for displaying diagrams without editing the Decision. + const editor = DmnEditor.open({ + container: document.getElementById("dmn-editor-container")!, + initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "loan-pre-qualification.dmn", + initialContent: loadFile("loan-pre-qualification.dmn"), + readOnly: true, + }); + + console.log({ editor }); +} diff --git a/examples/dmn-editor-standalone-examples/src/stateControl/index.html b/examples/dmn-editor-standalone-examples/src/stateControl/index.html new file mode 100644 index 00000000000..d769644f5a6 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/stateControl/index.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+
+
+ Load DMN: + + + + +
+
+
+ + diff --git a/examples/dmn-editor-standalone-examples/src/stateControl/index.ts b/examples/dmn-editor-standalone-examples/src/stateControl/index.ts new file mode 100644 index 00000000000..ce8682e8252 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/stateControl/index.ts @@ -0,0 +1,96 @@ +/* + * 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 DmnEditor from "@kie-tools/dmn-editor-standalone/dist"; +import { initFileLoader } from "../fileLoader"; + +document.addEventListener("DOMContentLoaded", function () { + loadEditor(); +}); + +function loadEditor() { + // Loads the DMN Editor in the `
` element. + // Initializes with an empty file called `newModel.dmn` on the root of the + // workspace. + const editor = DmnEditor.open({ + container: document.getElementById("dmn-editor-container")!, + initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "newModel.dmn", + initialContent: Promise.resolve(``), + readOnly: false, + }); + + // Undo button: Calls the `undo` method from the Editor API. + // Will undo the last action (moving a node, renaming a node, adding an edge, etc). + document.getElementById("undo")?.addEventListener("click", () => { + editor.undo(); + }); + + // Undo button: Calls the `redo` method from the Editor API. + // Useful after an undo, will redo the last action undone action. + document.getElementById("redo")?.addEventListener("click", () => { + editor.redo(); + }); + + // Download button: Calls the `getContent` method from the Editor API + // and then starts a download of a .dmn file with the string contents + // of the underlying XML for the current Decision. + // In the end, marks the content as saved via `markAsSaved`. + document.getElementById("download")?.addEventListener("click", () => { + editor.getContent().then((content) => { + const elem = window.document.createElement("a"); + elem.href = "data:text/plain;charset=utf-8," + encodeURIComponent(content); + elem.download = "model.dmn"; + document.body.appendChild(elem); + elem.click(); + document.body.removeChild(elem); + editor.markAsSaved(); + }); + }); + + // Download button: Calls the `getPreview` method from the Editor API + // and then starts a download of a .svg file with the diagram generated + // for the current Decision. + document.getElementById("downloadSvg")?.addEventListener("click", () => { + editor.getPreview().then((svgContent) => { + if (!svgContent) { + return; + } + const elem = window.document.createElement("a"); + elem.href = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgContent); + elem.download = "model.svg"; + document.body.appendChild(elem); + elem.click(); + document.body.removeChild(elem); + }); + }); + + // Listens to the `contentChange` notification. + // Useful for checking if a model has changed and needs to be saved, for example. + editor.subscribeToContentChanges((isDirty) => { + if (isDirty) { + document.getElementById("unsavedChanges")?.classList.remove("hidden"); + } else { + document.getElementById("unsavedChanges")?.classList.add("hidden"); + } + }); + + initFileLoader(["empty.dmn", "empty-drd.dmn", "find-employees.dmn", "loan-pre-qualification.dmn"], editor); + + console.log({ editor }); +} diff --git a/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.html b/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.html new file mode 100644 index 00000000000..f72922efd6e --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + +
+ + diff --git a/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.ts b/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.ts new file mode 100644 index 00000000000..0489488ff2b --- /dev/null +++ b/examples/dmn-editor-standalone-examples/src/withIncludedModels/index.ts @@ -0,0 +1,59 @@ +/* + * 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 DmnEditor from "@kie-tools/dmn-editor-standalone/dist"; +import { DmnEditorStandaloneResource } from "@kie-tools/dmn-editor-standalone/dist"; +import { loadFile } from "../fileLoader"; + +document.addEventListener("DOMContentLoaded", function () { + loadEditor(); +}); + +function loadEditor() { + // Loads the DMN Editor in the `
` element. + // Initializes with an existing file called `can-drive.dmn` on the root of the + // workspace. + // The `loadFile` function loads files from the /static/models directory and returns + // a Promise that resolves into a string. + // In this case resources are added alongside the main content and can be used as + // an included model. + // The paths are important here! Since path2/loan-pre-qualification.dmn is in a + // different parent path than the main content (path1/can-drive.dmn), it won't be availabe + // to be used as an included model. + // Examples: + // | Path | Available | + // | ------------------------------ | --------- | + // | path1/test/myModel.dmn | ✓ | + // | myTypes.dmn | x | + // | path2/model.dmn | x | + // | path1/sample.dm | ✓ | + // | ------------------------------ | --------- | + const editor = DmnEditor.open({ + container: document.getElementById("dmn-editor-container")!, + initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "path1/can-drive.dmn", + initialContent: loadFile("can-drive.dmn"), + resources: new Map([ + ["path1/can-drive-types.dmn", { contentType: "text", content: loadFile("can-drive-types.dmn") }], + ["path2/loan-pre-qualification.dmn", { contentType: "text", content: loadFile("loan-pre-qualification.dmn") }], + ]), + readOnly: false, + }); + + console.log({ editor }); +} diff --git a/examples/dmn-editor-standalone-examples/static/models/can-drive-types.dmn b/examples/dmn-editor-standalone-examples/static/models/can-drive-types.dmn new file mode 100644 index 00000000000..63b05475423 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/can-drive-types.dmn @@ -0,0 +1,55 @@ + + + + + Country + + + number + + + boolean + + + + string + + "Brazil", "USA", "England" + + + diff --git a/examples/dmn-editor-standalone-examples/static/models/can-drive.dmn b/examples/dmn-editor-standalone-examples/static/models/can-drive.dmn new file mode 100644 index 00000000000..984a24a1d5a --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/can-drive.dmn @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + Person.Age + + + + + Person.Country + + + "Brazil", "US", "England" + + + + + + + >= 18 + + + "Brazil" + + + true + + + + + + + + < 18 + + + "Brazil" + + + false + + + + + + + + >= 17 + + + "England" + + + true + + + + + + + + < 17 + + + "England" + + + false + + + + + + + + >= 16 + + + "USA" + + + true + + + + + + + + < 16 + + + "USA" + + + false + + + + + + + + + + + + + 60 + 118 + 118 + 240 + + + 50 + 100 + 100 + 100 + 100 + + + + + + + + + + + + + + + + diff --git a/examples/dmn-editor-standalone-examples/static/models/empty-drd.dmn b/examples/dmn-editor-standalone-examples/static/models/empty-drd.dmn new file mode 100644 index 00000000000..460371390fe --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/empty-drd.dmn @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/dmn-editor-standalone-examples/static/models/empty.dmn b/examples/dmn-editor-standalone-examples/static/models/empty.dmn new file mode 100644 index 00000000000..d405c98d1ec --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/empty.dmn @@ -0,0 +1,20 @@ + + + + + + diff --git a/examples/dmn-editor-standalone-examples/static/models/find-employees.dmn b/examples/dmn-editor-standalone-examples/static/models/find-employees.dmn new file mode 100644 index 00000000000..669fee27cbd --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/find-employees.dmn @@ -0,0 +1,374 @@ + + + + + + + number + + [1..9999] + + + + tKnowledges + + + tDept + + + string + + + + string + + "Sales", "Engineering", "Management" + + + + tEmployee + + + string + + "Git", "Java", "Scrum", "TypeScript" + + + + tKnowledge + + + + + + + + + + + + + employees[item.Dept = dept] + + + + + + for e in Employees by return +if (list contains(e.Knowledges, knowledge)) +then e +else null + + + + + for e in Employees with Knowledge[item != null] return e + + + + + + + + + + + + + + + + 32 + + + "Jane Doe" + + + "Management" + + + ["Scrum", "Git"] + + + + + 555 + + + "John Doe" + + + "Engineering" + + + ["TypeScript", "Java", "Git"] + + + + + 4567 + + + "Richard Roe" + + + "Sales" + + + ["Scrum"] + + + + + 612 + + + "Foo Bar" + + + "Engineering" + + + ["TypeScript", "Git"] + + + + + + + + + + + + + + + + + + + + + + Find employee by knowledge + + + + + Employees + + + + + + Knowledge + + + + + + Dept + + + + + + + + + + + + + + + + + + 50 + 204 + 281 + + + 281 + + + 281 + + + 281 + + + 50 + 555 + + + 50 + 100 + 156 + 150 + 252 + + + + + + + + + + + + + + + + + + + 50 + 120 + 100 + + + + 100 + + + 100 + + + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/dmn-editor-standalone-examples/static/models/loan-pre-qualification.dmn b/examples/dmn-editor-standalone-examples/static/models/loan-pre-qualification.dmn new file mode 100644 index 00000000000..85b41de564b --- /dev/null +++ b/examples/dmn-editor-standalone-examples/static/models/loan-pre-qualification.dmn @@ -0,0 +1,840 @@ + + + + + + Product_Type + + + number + + + number + + + number + + + + string + + "M","D","S" + + + + + number + + + Marital_Status + + + string + + "Unemployed","Employed","Self-employed","Student" + + + + boolean + + + + number + + + number + + + number + + + number + + + number + + + + + + Risk_Category + + + number + + + + + string + + + number + + + + string + + "Ineligible","Eligible" + + + + string + + "Decline","Bureau","Through" + + + + string + + "Full","Mini","None" + + + + string + + "Standard Loan","Special Loan" + + + + string + + "High","Medium","Low","Very Low","Decline" + + + + string + + "Poor","Bad","Fair","Good","Excellent" + + + + string + + "Insufficient","Sufficient" + + + + string + + "Sufficient","Insufficient" + + + + string + + "Not Qualified","Qualified" + + + + + number + + [300..850] + + + + + + string + + "Qualified","Not Qualified" + + + + string + + + + + + + + + + + + 0.36 + + + + + + + + + + + + + + + + + + + + + + + + PITI + + + + + (Requested Product.Amount * ((Requested Product.Rate/100)/12)) / (1-(1/(1+(Requested Product.Rate/100)/12) * -Requested Product.Term)) + + + + + + Applicant Data.Monthly.Tax + + + + + + Applicant Data.Monthly.Insurance + + + + + + Applicant Data.Monthly.Income + + + + + + + if Client PITI <= Lender Acceptable PITI() + then "Sufficient" + else "Insufficient" + + + + + + + + + + + + + + (pmt+tax+insurance) / income + + + + + + + + + + + + + + + + + + + + + + + + + DTI + + + + + Applicant Data.Monthly.Repayments + Applicant Data.Monthly.Expenses + + + + + + Applicant Data.Monthly.Income + + + + + + + if Client DTI <= Lender Acceptable DTI() + then "Sufficient" + else "Insufficient" + + + + + + + + + + + + + + Credit Score.FICO + + + + + + + >= 750 + + + "Excellent" + + + + + + + + [700..750) + + + "Good" + + + + + + + + [650..700) + + + "Fair" + + + + + + + + [600..650) + + + "Poor" + + + + + + + + < 600 + + + "Bad" + + + + + + + + + + + + + + + + + + + + + + + Credit Score Rating + + + + + Back End Ratio + + + + + Front End Ratio + + + + + + + + "Poor", "Bad" + + + - + + + - + + + "Not Qualified" + + + "Credit Score too low." + + + + + + + + - + + + "Insufficient" + + + "Sufficient" + + + "Not Qualified" + + + "Debt to income ratio is too high." + + + + + + + + - + + + "Sufficient" + + + "Insufficient" + + + "Not Qualified" + + + "Mortgage payment to income ratio is too high." + + + + + + + + - + + + "Insufficient" + + + "Insufficient" + + + "Not Qualified" + + + "Debt to income ratio is too high AND mortgage payment to income ratio is too high." + + + + + + + + "Fair", "Good", "Excellent" + + + "Sufficient" + + + "Sufficient" + + + "Qualified" + + + "The borrower has been successfully prequalified for the requested loan." + + + + + + + + + + + + + + + + + + + d/i + + + + + + + + + 0.28 + + + + + + + + + 209 + + + 50 + 209 + + + 50 + 100 + 1280 + + + 50 + 100 + 1110 + + + + 1110 + + + 1110 + + + 1110 + + + 1110 + + + 1280 + + + 300 + + + 50 + 300 + + + 50 + 100 + 802 + + + 50 + 100 + 632 + + + + 632 + + + 632 + + + 802 + + + 50 + 224 + 226 + 335 + + + 50 + 233 + 130 + 136 + 135 + 681 + 100 + + + 150 + + + 50 + 150 + + + 228 + + + 50 + 228 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/dmn-editor-standalone-examples/tsconfig.json b/examples/dmn-editor-standalone-examples/tsconfig.json new file mode 100644 index 00000000000..6eaa9245ccf --- /dev/null +++ b/examples/dmn-editor-standalone-examples/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@kie-tools/tsconfig/tsconfig.esm.json", + "compilerOptions": { + "esModuleInterop": true, + "jsx": "react-jsx", + // Skip declarations, they are bundled manually in another step + "declarationMap": false, + "declaration": false + } +} diff --git a/examples/dmn-editor-standalone-examples/webpack.config.js b/examples/dmn-editor-standalone-examples/webpack.config.js new file mode 100644 index 00000000000..f6dead2bfa1 --- /dev/null +++ b/examples/dmn-editor-standalone-examples/webpack.config.js @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const { merge } = require("webpack-merge"); +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const common = require("@kie-tools-core/webpack-base/webpack.common.config"); +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { ProvidePlugin } = require("webpack"); +const { env } = require("./env"); +const buildEnv = env; + +module.exports = (env) => + merge(common(env), { + output: { + path: path.join(__dirname, "dist"), + filename: "[name].js", + }, + entry: { + state_control: "./src/stateControl/index.ts", + read_only: "./src/readOnly/index.ts", + with_included_models: "./src/withIncludedModels/index.ts", + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: "state_control.html", + template: "./src/stateControl/index.html", + chunks: ["state_control"], + minify: false, + }), + new HtmlWebpackPlugin({ + filename: "read_only.html", + template: "./src/readOnly/index.html", + chunks: ["read_only"], + minify: false, + }), + new HtmlWebpackPlugin({ + filename: "with_included_models.html", + template: "./src/withIncludedModels/index.html", + chunks: ["with_included_models"], + minify: false, + }), + new ProvidePlugin({ + process: require.resolve("process/browser.js"), + Buffer: ["buffer", "Buffer"], + }), + new CopyWebpackPlugin({ + patterns: [{ from: "./static", to: "static" }], + }), + ], + devServer: { + static: [{ directory: path.join(__dirname, "./dist") }], + compress: true, + https: false, + port: buildEnv.dmnEditorStandaloneExamples.port, + client: { + overlay: false, + }, + }, + }); diff --git a/examples/ping-pong-view-angular/package.json b/examples/ping-pong-view-angular/package.json index 2a40e5e30a2..a3f6532c905 100644 --- a/examples/ping-pong-view-angular/package.json +++ b/examples/ping-pong-view-angular/package.json @@ -46,6 +46,7 @@ "@kie-tools/root-env": "workspace:*", "@kie-tools/tsconfig": "workspace:*", "rimraf": "^3.0.2", - "typescript": "^5.5.3" + "typescript": "^5.5.3", + "webpack": "^5.92.1" } } diff --git a/examples/todo-list-view-vscode-extension/package.json b/examples/todo-list-view-vscode-extension/package.json index a18638a0fba..f94483d86b3 100644 --- a/examples/todo-list-view-vscode-extension/package.json +++ b/examples/todo-list-view-vscode-extension/package.json @@ -36,7 +36,7 @@ "@vscode/vsce": "^2.22.0", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/examples/uniforms-patternfly/package.json b/examples/uniforms-patternfly/package.json index 68b1c45581f..9b643bf55e5 100644 --- a/examples/uniforms-patternfly/package.json +++ b/examples/uniforms-patternfly/package.json @@ -36,7 +36,7 @@ "react-router-dom": "^5.3.4", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/examples/webapp/package.json b/examples/webapp/package.json index 0a7d0f55ce0..19d3a076b0a 100644 --- a/examples/webapp/package.json +++ b/examples/webapp/package.json @@ -46,7 +46,7 @@ "react-router-dom": "^5.3.4", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/backend/package.json b/packages/backend/package.json index 6ea0e377b44..792009c6f83 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -26,7 +26,7 @@ "@kie-tools-core/i18n": "workspace:*", "@kie-tools-core/notifications": "workspace:*", "@kie-tools-core/workspace": "workspace:*", - "axios": "^1.6.8", + "axios": "^1.7.4", "fast-xml-parser": "^4.4.1", "portfinder": "^1.0.32", "semver": "^7.5.4", diff --git a/packages/boxed-expression-component/package.json b/packages/boxed-expression-component/package.json index d17ad505396..44e84bdec63 100644 --- a/packages/boxed-expression-component/package.json +++ b/packages/boxed-expression-component/package.json @@ -80,7 +80,7 @@ "storybook": "^7.3.2", "ts-jest": "^29.1.5", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/boxed-expression-component/src/BoxedExpressionEditor.tsx b/packages/boxed-expression-component/src/BoxedExpressionEditor.tsx index 24034cc378b..920e4110257 100644 --- a/packages/boxed-expression-component/src/BoxedExpressionEditor.tsx +++ b/packages/boxed-expression-component/src/BoxedExpressionEditor.tsx @@ -55,6 +55,8 @@ export interface BoxedExpressionEditorProps { isResetSupportedOnRootExpression?: boolean; /** The Data Types available */ dataTypes: DmnDataType[]; + /** ReadOnly mode flag */ + isReadOnly?: boolean; /** PMML models available to use on Boxed PMML Function */ pmmlDocuments?: PmmlDocument[]; /** The containing HTMLElement which is scrollable */ @@ -67,6 +69,7 @@ export interface BoxedExpressionEditorProps { export function BoxedExpressionEditor({ dataTypes, + isReadOnly, expressionHolderId, expressionHolderName, expressionHolderTypeRef, @@ -97,6 +100,7 @@ export function BoxedExpressionEditor({ expression={expression} onExpressionChange={onExpressionChange} onWidthsChange={onWidthsChange} + isReadOnly={isReadOnly} dataTypes={dataTypes} pmmlDocuments={pmmlDocuments} onRequestFeelVariables={onRequestFeelVariables} diff --git a/packages/boxed-expression-component/src/BoxedExpressionEditorContext.tsx b/packages/boxed-expression-component/src/BoxedExpressionEditorContext.tsx index 3260a7ae14c..ce879f8808c 100644 --- a/packages/boxed-expression-component/src/BoxedExpressionEditorContext.tsx +++ b/packages/boxed-expression-component/src/BoxedExpressionEditorContext.tsx @@ -33,6 +33,7 @@ export interface BoxedExpressionEditorContextType { expressionHolderId: string; pmmlDocuments?: PmmlDocument[]; dataTypes: DmnDataType[]; + isReadOnly?: boolean; // State currentlyOpenContextMenu: string | undefined; @@ -68,6 +69,7 @@ export function BoxedExpressionEditorContextProvider({ onExpressionChange, onWidthsChange, dataTypes, + isReadOnly, expressionHolderId, beeGwtService, children, @@ -110,6 +112,7 @@ export function BoxedExpressionEditorContextProvider({ // props expressionHolderId, dataTypes, + isReadOnly, pmmlDocuments, //state // FIXME: Move to a separate context (https://github.com/apache/incubator-kie-issues/issues/168) diff --git a/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.css b/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.css index 8b74a7e7703..f155ce33106 100644 --- a/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.css +++ b/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.css @@ -6,18 +6,18 @@ * 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. + * under the License. */ -.pf-c-popover__content > .pf-c-button { +.popover-menu-selector .pf-c-popover__content > .pf-c-button { display: none; } diff --git a/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.tsx b/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.tsx index 2be8a510813..fb03105edb8 100644 --- a/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.tsx +++ b/packages/boxed-expression-component/src/contextMenu/PopoverMenu/PopoverMenu.tsx @@ -152,6 +152,7 @@ export const PopoverMenu = React.forwardRef( = ({ data, rowIndex, columnIndex, onExpressionWithVariableUpdated }) => { const ref = React.useRef(null); - + const { isReadOnly } = useBoxedExpressionEditor(); const { expression, variable, index } = data[rowIndex]; const onVariableUpdated = useCallback( @@ -110,33 +110,44 @@ export const ExpressionVariableCell: React.FunctionComponent< } }, [beeGwtService, variable, isActive]); + const cellContent = useMemo( + () => ( +
+

+ {variable["@_name"]} +

+

+ ({variable["@_typeRef"] ?? DmnBuiltInDataType.Undefined}) +

+
+ ), + [variable] + ); + return (
- -
-

- {variable["@_name"]} -

-

- ({variable["@_typeRef"] ?? DmnBuiltInDataType.Undefined}) -

-
-
+ {isReadOnly ? ( + cellContent + ) : ( + + {cellContent} + + )}
); diff --git a/packages/boxed-expression-component/src/expressions/ConditionalExpression/ConditionalExpression.tsx b/packages/boxed-expression-component/src/expressions/ConditionalExpression/ConditionalExpression.tsx index b0c678ad55e..ab9871d81e8 100644 --- a/packages/boxed-expression-component/src/expressions/ConditionalExpression/ConditionalExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/ConditionalExpression/ConditionalExpression.tsx @@ -62,7 +62,7 @@ export function ConditionalExpression({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression } = useBoxedExpressionEditorDispatch(); const tableRows = useMemo(() => { @@ -228,8 +228,10 @@ export function ConditionalExpression({ return ( -
+
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={id} headerLevelCountForAppendingRowIndexColumn={1} diff --git a/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx b/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx index 5fa7a92c96a..ef7ff4641f3 100644 --- a/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/ContextExpression/ContextExpression.tsx @@ -68,7 +68,7 @@ export function ContextExpression({ }) { const { i18n } = useBoxedExpressionEditorI18n(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const id = contextExpression["@_id"]!; @@ -460,6 +460,8 @@ export function ContextExpression({
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={id} headerLevelCountForAppendingRowIndexColumn={1} diff --git a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx index afcf3bbcf0e..e22e1da0ce0 100644 --- a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/DecisionTableExpression.tsx @@ -109,7 +109,7 @@ export function DecisionTableExpression({ isNested: boolean; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); const id = decisionTableExpression["@_id"]!; @@ -647,9 +647,10 @@ export function DecisionTableExpression({ selectedBuiltInAggregator={getAggregationKey(decisionTableExpression["@_aggregation"])} onHitPolicySelected={onHitPolicySelect} onBuiltInAggregatorSelected={onBuiltInAggregatorSelect} + isReadOnly={isReadOnly ?? false} /> ), - [decisionTableExpression, getAggregationKey, onBuiltInAggregatorSelect, onHitPolicySelect] + [decisionTableExpression, getAggregationKey, isReadOnly, onBuiltInAggregatorSelect, onHitPolicySelect] ); const onRowAdded = useCallback( @@ -1047,6 +1048,8 @@ export function DecisionTableExpression({ return (
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ isPivoting ? ResizerStopBehavior.SET_WIDTH_ALWAYS : ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER } diff --git a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/HitPolicySelector.tsx b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/HitPolicySelector.tsx index e73376f7c66..53d4d8d97f4 100644 --- a/packages/boxed-expression-component/src/expressions/DecisionTableExpression/HitPolicySelector.tsx +++ b/packages/boxed-expression-component/src/expressions/DecisionTableExpression/HitPolicySelector.tsx @@ -41,6 +41,8 @@ export interface HitPolicySelectorProps { onHitPolicySelected: (hitPolicy: string) => void; /** Callback invoked when built-in aggregator selection changes */ onBuiltInAggregatorSelected: (builtInAggregator: string) => void; + /** If the hit policy is readonly or not*/ + isReadOnly: boolean; } export const HIT_POLICIES_THAT_SUPPORT_AGGREGATION = ["COLLECT"]; @@ -50,6 +52,7 @@ export function HitPolicySelector({ onHitPolicySelected, selectedBuiltInAggregator, selectedHitPolicy, + isReadOnly, }: HitPolicySelectorProps) { const { i18n } = useBoxedExpressionEditorI18n(); const { editorRef } = useBoxedExpressionEditor(); @@ -140,7 +143,18 @@ export function HitPolicySelector({ setVisibleHelpAggregatorFunction((previousHelp) => (previousHelp !== help ? help : "")); }, []); - return ( + const hitPolicyCell = useMemo(() => { + return ( +
+ {!builtInAggregatorEnabled && `${_.first(selectedHitPolicy)}`} + {builtInAggregatorEnabled && `${_.first(selectedHitPolicy)}${selectedBuiltInAggregator}`} +
+ ); + }, [builtInAggregatorEnabled, selectedBuiltInAggregator, selectedHitPolicy]); + + return isReadOnly ? ( + hitPolicyCell + ) : ( { setVisibleHelpAggregatorFunction(""); @@ -211,10 +225,7 @@ export function HitPolicySelector({
} > -
- {!builtInAggregatorEnabled && `${_.first(selectedHitPolicy)}`} - {builtInAggregatorEnabled && `${_.first(selectedHitPolicy)}${selectedBuiltInAggregator}`} -
+ {hitPolicyCell} ); } diff --git a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector.tsx b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector.tsx index 063106b6281..6a2e1a052ca 100644 --- a/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector.tsx +++ b/packages/boxed-expression-component/src/expressions/ExpressionDefinitionRoot/ExpressionDefinitionLogicTypeSelector.tsx @@ -93,7 +93,7 @@ export function ExpressionDefinitionLogicTypeSelector({ [isNested] ); const { i18n } = useBoxedExpressionEditorI18n(); - const { setCurrentlyOpenContextMenu, widthsById, scrollableParentRef } = useBoxedExpressionEditor(); + const { setCurrentlyOpenContextMenu, widthsById, scrollableParentRef, isReadOnly } = useBoxedExpressionEditor(); const [isOpen, setOpen] = useState(false); const [position, setPosition] = useState({ x: 0, y: 0 }); @@ -212,8 +212,8 @@ export function ExpressionDefinitionLogicTypeSelector({ const selectExpressionMenuContainerRef = React.useRef(null); const shouldRenderSelectExpressionContextMenu = useMemo(() => { - return isOpen && !expression; - }, [isOpen, expression]); + return !isReadOnly && isOpen && !expression; + }, [isReadOnly, isOpen, expression]); const hide = useCallback((e: MouseEvent) => { if (e.target != selectExpressionMenuContainerRef.current) { @@ -412,7 +412,7 @@ export function ExpressionDefinitionLogicTypeSelector({ const contextMenuItems = useMemo(() => { return ( - {isResetSupported && ( + {!isReadOnly && isResetSupported && ( <> {i18n.terms.copy} - {isResetSupported && ( + {!isReadOnly && isResetSupported && ( )} - - -
- } - > - {i18n.terms.paste} - + + {!isReadOnly && ( + + +
+ } + > + {i18n.terms.paste} + + )} ); }, [ @@ -472,6 +475,7 @@ export function ExpressionDefinitionLogicTypeSelector({ pasteExpression, resetLogicType, isResetSupported, + isReadOnly, ]); const [isDropdownOpen, setDropdownOpen] = useState(false); diff --git a/packages/boxed-expression-component/src/expressions/FilterExpression/FilterExpressionComponent.tsx b/packages/boxed-expression-component/src/expressions/FilterExpression/FilterExpressionComponent.tsx index 0a3d0e908f5..0ab60b7b5e8 100644 --- a/packages/boxed-expression-component/src/expressions/FilterExpression/FilterExpressionComponent.tsx +++ b/packages/boxed-expression-component/src/expressions/FilterExpression/FilterExpressionComponent.tsx @@ -58,7 +58,7 @@ export function FilterExpressionComponent({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression } = useBoxedExpressionEditorDispatch(); const beeTableColumns = useMemo[]>(() => { @@ -167,6 +167,8 @@ export function FilterExpressionComponent({ return ( + isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} onColumnResizingWidthChange={onColumnResizingWidthChange} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={filterExpression["@_id"]} diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx index 53cab86a1b6..2fa6dfb2bbe 100644 --- a/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/FeelFunctionExpression.tsx @@ -71,10 +71,13 @@ export function FeelFunctionExpression({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); - const parametersColumnHeader = useFunctionExpressionParametersColumnHeader(functionExpression.formalParameter); + const parametersColumnHeader = useFunctionExpressionParametersColumnHeader( + functionExpression.formalParameter, + isReadOnly ?? false + ); const parametersId = useMemo( () => (functionExpression["@_id"] ? `${functionExpression["@_id"]}-parameters` : "parameters"), [functionExpression] @@ -204,6 +207,7 @@ export function FeelFunctionExpression({
+ isReadOnly={isReadOnly} onColumnResizingWidthChange={onColumnResizingWidthChange} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} operationConfig={beeTableOperationConfig} diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionExpression.tsx index 41d8fae4a23..a7d5fa29bf2 100644 --- a/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionExpression.tsx @@ -73,6 +73,7 @@ export function FunctionExpression({ export function useFunctionExpressionControllerCell(functionKind: Normalized) { const { setExpression } = useBoxedExpressionEditorDispatch(); + const { isReadOnly } = useBoxedExpressionEditor(); const onFunctionKindSelect = useCallback( (kind: Normalized) => { @@ -134,50 +135,65 @@ export function useFunctionExpressionControllerCell(functionKind: Normalized , - [functionKind, onFunctionKindSelect] + () => ( + + ), + [functionKind, isReadOnly, onFunctionKindSelect] ); } export function useFunctionExpressionParametersColumnHeader( - formalParameters: Normalized + formalParameters: Normalized, + isReadOnly: boolean ) { const { i18n } = useBoxedExpressionEditorI18n(); const { editorRef } = useBoxedExpressionEditor(); - return useMemo( + const expressionParametersContent = useMemo( () => ( +
+

+ {_.isEmpty(formalParameters) ? ( + i18n.editParameters + ) : ( + <> + {"("} + {(formalParameters ?? []).map((parameter, i) => ( + + {parameter["@_name"]} + {": "} + + ({parameter["@_typeRef"] ?? DmnBuiltInDataType.Undefined}) + + {i < (formalParameters ?? []).length - 1 && {", "}} + + ))} + {")"} + + )} +

+
+ ), + [formalParameters, i18n.editParameters] + ); + + return useMemo(() => { + return isReadOnly ? ( + expressionParametersContent + ) : ( editorRef.current!} className="parameters-editor-popover" minWidth="400px" body={} > -
-

- {_.isEmpty(formalParameters) ? ( - i18n.editParameters - ) : ( - <> - {"("} - {(formalParameters ?? []).map((parameter, i) => ( - - {parameter["@_name"]} - {": "} - - ({parameter["@_typeRef"] ?? DmnBuiltInDataType.Undefined}) - - {i < (formalParameters ?? []).length - 1 && {", "}} - - ))} - {")"} - - )} -

-
+ {expressionParametersContent}
- ), - [formalParameters, i18n.editParameters, editorRef] - ); + ); + }, [isReadOnly, expressionParametersContent, formalParameters, editorRef]); } diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionKindSelector.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionKindSelector.tsx index 585020e7b5e..9d60253a627 100644 --- a/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionKindSelector.tsx +++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/FunctionKindSelector.tsx @@ -21,7 +21,7 @@ import { PopoverMenu } from "../../contextMenu/PopoverMenu"; import { PopoverPosition } from "@patternfly/react-core/dist/js/components/Popover"; import _ from "lodash"; import * as React from "react"; -import { useCallback } from "react"; +import { useCallback, useMemo } from "react"; import { useBoxedExpressionEditor } from "../../BoxedExpressionEditorContext"; import { MenuItemWithHelp } from "../../contextMenu/MenuWithHelp"; import { Menu } from "@patternfly/react-core/dist/js/components/Menu/Menu"; @@ -35,11 +35,14 @@ export interface FunctionKindSelectorProps { selectedFunctionKind: DMN15__tFunctionKind; /** Callback invoked when function kind selection changes */ onFunctionKindSelect: (functionKind: DMN15__tFunctionKind) => void; + /** If should only display function kind */ + isReadOnly?: boolean; } export const FunctionKindSelector: React.FunctionComponent = ({ selectedFunctionKind, onFunctionKindSelect, + isReadOnly, }) => { const { editorRef } = useBoxedExpressionEditor(); @@ -70,6 +73,15 @@ export const FunctionKindSelector: React.FunctionComponent (previousHelp !== help ? help : "")); }, []); + const displaySelectedFunctionKind = useMemo( + () =>
{_.first(selectedFunctionKind)}
, + [selectedFunctionKind] + ); + + if (isReadOnly) { + return displaySelectedFunctionKind; + } + return ( setVisibleHelp("")} @@ -95,7 +107,7 @@ export const FunctionKindSelector: React.FunctionComponent )} > -
{_.first(selectedFunctionKind)}
+ {displaySelectedFunctionKind}
); }; diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx index a06db0ec962..5f2b882f6a8 100644 --- a/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/JavaFunctionExpression.tsx @@ -75,7 +75,7 @@ export function JavaFunctionExpression({ isNested: boolean; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); const getClassContextEntry = useCallback((c: Normalized) => { @@ -120,7 +120,10 @@ export function JavaFunctionExpression({ [getClassAndMethodNamesWidth, id, setWidthsById] ); - const parametersColumnHeader = useFunctionExpressionParametersColumnHeader(functionExpression.formalParameter); + const parametersColumnHeader = useFunctionExpressionParametersColumnHeader( + functionExpression.formalParameter, + isReadOnly ?? false + ); const parametersId = useMemo( () => (functionExpression["@_id"] ? `${functionExpression["@_id"]}-parameters` : "parameters"), [functionExpression] @@ -387,6 +390,7 @@ export function JavaFunctionExpression({
forwardRef={beeTableRef} + isReadOnly={isReadOnly} onColumnResizingWidthChange={onColumnResizingWidthChange} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} operationConfig={beeTableOperationConfig} diff --git a/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx b/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx index 1d5c9770eb5..4534c9e258d 100644 --- a/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/FunctionExpression/PmmlFunctionExpression.tsx @@ -75,10 +75,13 @@ export function PmmlFunctionExpression({ isNested: boolean; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId } = useBoxedExpressionEditor(); + const { expressionHolderId, isReadOnly } = useBoxedExpressionEditor(); const { setExpression } = useBoxedExpressionEditorDispatch(); - const parametersColumnHeader = useFunctionExpressionParametersColumnHeader(functionExpression.formalParameter); + const parametersColumnHeader = useFunctionExpressionParametersColumnHeader( + functionExpression.formalParameter, + isReadOnly ?? false + ); const parametersId = useMemo( () => (functionExpression["@_id"] ? `${functionExpression["@_id"]}-parameters` : "parameters"), [functionExpression] @@ -264,6 +267,7 @@ export function PmmlFunctionExpression({
forwardRef={beeTableRef} + isReadOnly={isReadOnly} onColumnResizingWidthChange={onColumnResizingWidthChange} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} operationConfig={beeTableOperationConfig} diff --git a/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx b/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx index eee61d6a6f2..f66e3d61a97 100644 --- a/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/InvocationExpression/InvocationExpression.tsx @@ -69,7 +69,7 @@ export function InvocationExpression({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); const id = invocationExpression["@_id"]!; @@ -455,6 +455,8 @@ export function InvocationExpression({
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={id} headerLevelCountForAppendingRowIndexColumn={2} diff --git a/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionComponent.tsx b/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionComponent.tsx index be7e22911a1..9791885ccf6 100644 --- a/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionComponent.tsx +++ b/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionComponent.tsx @@ -68,7 +68,7 @@ export function IteratorExpressionComponent({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression } = useBoxedExpressionEditorDispatch(); const id = expression["@_id"]!; @@ -310,6 +310,8 @@ export function IteratorExpressionComponent({
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} forwardRef={beeTableRef} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={id} diff --git a/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionVariableCell.tsx b/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionVariableCell.tsx index 6caa6dcd680..8bf8add74bb 100644 --- a/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionVariableCell.tsx +++ b/packages/boxed-expression-component/src/expressions/IteratorExpression/IteratorExpressionVariableCell.tsx @@ -43,7 +43,7 @@ export function IteratorExpressionVariableCell({ }: IteratorExpressionVariableCellProps) { const { setExpression } = useBoxedExpressionEditorDispatch(); const { isActive } = useBeeTableSelectableCellRef(rowIndex ?? 0, columnIndex ?? 0, undefined); - const { beeGwtService } = useBoxedExpressionEditor(); + const { beeGwtService, isReadOnly } = useBoxedExpressionEditor(); // Selecting the context result cell should be the parent data type useEffect(() => { @@ -78,6 +78,7 @@ export function IteratorExpressionVariableCell({ setActiveCellEditing={(value) => { beeTableRef.current?.setActiveCellEditing(value); }} + isReadOnly={isReadOnly ?? false} />
); diff --git a/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx b/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx index 8806d19e2b8..f352159ba26 100644 --- a/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/ListExpression/ListExpression.tsx @@ -59,7 +59,7 @@ export function ListExpression({ }) { const { i18n } = useBoxedExpressionEditorI18n(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); /// ////////////////////////////////////////////////////// /// ///////////// RESIZING WIDTHS //////////////////////// @@ -278,6 +278,8 @@ export function ListExpression({
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} onColumnResizingWidthChange={onColumnResizingWidthChange} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={listExpression["@_id"]} diff --git a/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx b/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx index e807a58b21d..10458c7e1be 100644 --- a/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/LiteralExpression/LiteralExpression.tsx @@ -53,7 +53,7 @@ export function LiteralExpression({ isNested: boolean; }) { const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); - const { expressionHolderId, widthsById } = useBoxedExpressionEditor(); + const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const id = literalExpression["@_id"]!; @@ -212,8 +212,10 @@ export function LiteralExpression({ return (
-
{`=`}
+
{`=`}
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} forwardRef={beeTableRef} getRowKey={getRowKey} diff --git a/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx b/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx index 7f3271f5319..68d81dcbaed 100644 --- a/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx +++ b/packages/boxed-expression-component/src/expressions/RelationExpression/RelationExpression.tsx @@ -60,7 +60,7 @@ export function RelationExpression({ parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); - const { widthsById, expressionHolderId } = useBoxedExpressionEditor(); + const { widthsById, expressionHolderId, isReadOnly } = useBoxedExpressionEditor(); const { setExpression, setWidthsById } = useBoxedExpressionEditorDispatch(); const id = relationExpression["@_id"]!; @@ -495,6 +495,8 @@ export function RelationExpression({ return (
+ isReadOnly={isReadOnly} + isEditableHeader={!isReadOnly} resizerStopBehavior={ isPivoting ? ResizerStopBehavior.SET_WIDTH_ALWAYS : ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER } diff --git a/packages/boxed-expression-component/src/resizing/Hooks.tsx b/packages/boxed-expression-component/src/resizing/Hooks.tsx index 106b09020fa..4231fccdf65 100644 --- a/packages/boxed-expression-component/src/resizing/Hooks.tsx +++ b/packages/boxed-expression-component/src/resizing/Hooks.tsx @@ -68,7 +68,11 @@ export function useNestedExpressionResizingWidthValue( return Math.max( nestedExpressionContainerResizingWidthValue - fixedColumnResizingWidth.value - extraWidth, - ...nestedExpressions.map((e) => getExpressionResizingWidth(e, new Map(), widthsById)), + ...nestedExpressions.map( + (e) => + getExpressionResizingWidth(e, new Map(), widthsById) + + (nestedExpressionsExtraWidths?.get(e?.["@_id"] ?? "") ?? 0) + ), nestedExpressionMinWidth ); }, [ diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx index f20cf71d4f4..6bd456c9f80 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx @@ -445,7 +445,7 @@ export function BeeTableInternal({ // DELETE - if (NavigationKeysUtils.isDelete(e.key) || NavigationKeysUtils.isBackspace(e.key)) { + if (!isReadOnly && (NavigationKeysUtils.isDelete(e.key) || NavigationKeysUtils.isBackspace(e.key))) { e.stopPropagation(); e.preventDefault(); erase(); @@ -466,17 +466,18 @@ export function BeeTableInternal({ e.preventDefault(); copy(); } - if (!e.shiftKey && complementaryKey && e.key.toLowerCase() === "x") { - e.stopPropagation(); - e.preventDefault(); - cut(); - } - if (!e.shiftKey && complementaryKey && e.key.toLowerCase() === "v") { - e.stopPropagation(); - e.preventDefault(); - paste(); + if (!isReadOnly) { + if (!e.shiftKey && complementaryKey && e.key.toLowerCase() === "x") { + e.stopPropagation(); + e.preventDefault(); + cut(); + } + if (!e.shiftKey && complementaryKey && e.key.toLowerCase() === "v") { + e.stopPropagation(); + e.preventDefault(); + paste(); + } } - // SELECT ALL if (!e.shiftKey && complementaryKey && e.key.toLowerCase() === "a") { e.stopPropagation(); @@ -516,6 +517,7 @@ export function BeeTableInternal({ copy, cut, paste, + isReadOnly, ] ); @@ -638,12 +640,13 @@ export function BeeTableInternal({ onHeaderKeyUp={onHeaderKeyUp} lastColumnMinWidth={lastColumnMinWidth} setActiveCellEditing={setActiveCellEditing} + isReadOnly={isReadOnly} /> rowWrapper={rowWrapper} resizerStopBehavior={resizerStopBehavior} shouldRenderRowIndexColumn={shouldRenderRowIndexColumn} - shouldShowRowsInlineControls={shouldShowRowsInlineControls} + shouldShowRowsInlineControls={!isReadOnly && shouldShowRowsInlineControls} getColumnKey={onGetColumnKey} getRowKey={onGetRowKey} headerVisibility={headerVisibility} @@ -653,6 +656,7 @@ export function BeeTableInternal({ onDataCellClick={onDataCellClick} onDataCellKeyUp={onDataCellKeyUp} lastColumnMinWidth={lastColumnMinWidth} + isReadOnly={isReadOnly} /> ({ onColumnAdded={onColumnAdded2} onColumnDeleted={onColumnDeleted2} onRowReset={onRowReset} + isReadOnly={isReadOnly} />
); diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx index 8a70da00d6d..a704f2c7c32 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableBody.tsx @@ -53,6 +53,8 @@ export interface BeeTableBodyProps { lastColumnMinWidth?: number; rowWrapper?: React.FunctionComponent>; + + isReadOnly: boolean; } export function BeeTableBody({ @@ -69,6 +71,7 @@ export function BeeTableBody({ resizerStopBehavior, lastColumnMinWidth, rowWrapper, + isReadOnly, }: BeeTableBodyProps) { const renderRow = useCallback( (row: ReactTable.Row, rowIndex: number) => { @@ -100,6 +103,7 @@ export function BeeTableBody({ lastColumnMinWidth={ cellIndex === reactTableInstance.allColumns.length - 1 ? lastColumnMinWidth : undefined } + isReadOnly={isReadOnly} /> )} @@ -136,6 +140,7 @@ export function BeeTableBody({ onDataCellKeyUp, onRowAdded, lastColumnMinWidth, + isReadOnly, ] ); @@ -168,6 +173,7 @@ export function BeeTableBody({ isLastColumn={false} isEmptyCell={true} resizerStopBehavior={resizerStopBehavior} + isReadOnly={isReadOnly} /> )} @@ -188,6 +194,7 @@ export function BeeTableBody({ isEmptyCell={false} resizerStopBehavior={resizerStopBehavior} lastColumnMinWidth={columnIndex === additionalRow.length - 1 ? lastColumnMinWidth : undefined} + isReadOnly={isReadOnly} > {elem} diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx index 0e9909320f5..ed742cf2927 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx @@ -36,6 +36,7 @@ import { BeeTableContextMenuAllowedOperationsConditions, BeeTableOperation, BeeTableOperationConfig, + BeeTableOperationGroup, InsertRowColumnsDirection, } from "../../api"; import { useCustomContextMenuHandler } from "../../contextMenu"; @@ -75,6 +76,7 @@ export interface BeeTableContextMenuHandlerProps { insertDirection: InsertRowColumnsDirection; }) => void; onColumnDeleted?: (args: { columnIndex: number; groupType: string | undefined }) => void; + isReadOnly: boolean; } /** The maximum numbers of rows or columns that can be inserted from the Insert menu. */ @@ -94,6 +96,7 @@ export function BeeTableContextMenuHandler({ onRowReset, onColumnAdded, onColumnDeleted, + isReadOnly, }: BeeTableContextMenuHandlerProps) { const { i18n } = useBoxedExpressionEditorI18n(); const { setCurrentlyOpenContextMenu } = useBoxedExpressionEditor(); @@ -209,20 +212,6 @@ export function BeeTableContextMenuHandler({ } }, [activeCell, columns]); - const operationGroups = useMemo(() => { - if (!activeCell) { - return []; - } - if (_.isArray(operationConfig)) { - return operationConfig; - } - return (operationConfig ?? {})[column?.groupType || ""]; - }, [activeCell, column?.groupType, operationConfig]); - - const allOperations = useMemo(() => { - return operationGroups.flatMap(({ items }) => items); - }, [operationGroups]); - const operationLabel = useCallback( (operation: BeeTableOperation) => { switch (operation) { @@ -261,6 +250,33 @@ export function BeeTableContextMenuHandler({ [i18n] ); + const operationGroups = useMemo(() => { + if (!activeCell) { + return []; + } + if (isReadOnly) { + const operationGroup: BeeTableOperationGroup = { + group: "", + items: [ + { + name: operationLabel(BeeTableOperation.SelectionCopy), + type: BeeTableOperation.SelectionCopy, + }, + ], + }; + + return [operationGroup]; + } + if (_.isArray(operationConfig)) { + return operationConfig; + } + return (operationConfig ?? {})[column?.groupType || ""]; + }, [activeCell, column?.groupType, isReadOnly, operationConfig, operationLabel]); + + const allOperations = useMemo(() => { + return operationGroups.flatMap(({ items }) => items); + }, [operationGroups]); + const operationIcon = useCallback((operation: BeeTableOperation) => { switch (operation) { case BeeTableOperation.ColumnInsertLeft: diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableEditableCellContent.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableEditableCellContent.tsx index a5114819883..372f2578249 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableEditableCellContent.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableEditableCellContent.tsx @@ -188,12 +188,12 @@ export function BeeTableEditableCellContent({ } // This is used to start editing a cell without being in edit mode. - if (isActive && !isEditing && isEditModeTriggeringKey(e)) { + if (!isReadOnly && isActive && !isEditing && isEditModeTriggeringKey(e)) { setEditingValue(""); setEditing(true); } }, - [isActive, isEditing, setEditing] + [isActive, isEditing, isReadOnly, setEditing] ); return ( diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx index 9a9856aa01a..6b8da177426 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableHeader.tsx @@ -82,6 +82,8 @@ export interface BeeTableHeaderProps { resizerStopBehavior: ResizerStopBehavior; lastColumnMinWidth?: number; setActiveCellEditing: (isEditing: boolean) => void; + + isReadOnly: boolean; } export function BeeTableHeader({ @@ -100,6 +102,7 @@ export function BeeTableHeader({ resizerStopBehavior, lastColumnMinWidth, setActiveCellEditing, + isReadOnly, }: BeeTableHeaderProps) { const getColumnLabel: (groupType: string) => string | undefined = useCallback( (groupType) => { @@ -154,7 +157,8 @@ export function BeeTableHeader({ className={classNames} groupType={column.groupType} isLastLevelColumn={(column.columns?.length ?? 0) <= 0} - shouldShowColumnsInlineControls={shouldShowRowsInlineControls} + shouldShowColumnsInlineControls={!isReadOnly && shouldShowRowsInlineControls} + isReadOnly={isReadOnly} >
{column.label} @@ -162,7 +166,7 @@ export function BeeTableHeader({ ); }, - [getColumnKey, shouldShowRowsInlineControls] + [getColumnKey, isReadOnly, shouldShowRowsInlineControls] ); const renderColumn = useCallback< @@ -192,6 +196,7 @@ export function BeeTableHeader({ rowSpan={rowSpan} shouldRenderRowIndexColumn={shouldRenderRowIndexColumn} isEditableHeader={isEditableHeader} + isReadOnly={isReadOnly} shouldShowColumnsInlineControls={shouldShowRowsInlineControls} getColumnKey={getColumnKey} getColumnLabel={getColumnLabel} @@ -230,7 +235,7 @@ export function BeeTableHeader({ > {column.headerCellElement ? ( column.headerCellElement - ) : column.isInlineEditable ? ( + ) : column.isInlineEditable && !isReadOnly ? ( ({ columnIndex )({ "@_label": value, "@_typeRef": column.dataType }); }} + isReadOnly={isReadOnly} /> ) : (

({ lastColumnMinWidth, setActiveCellEditing, onExpressionHeaderUpdated, + isReadOnly, ] ); diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx index 30b6248c46d..b9a0a71da04 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTd.tsx @@ -48,6 +48,7 @@ export interface BeeTableTdProps { lastColumnMinWidth?: number; onDataCellClick?: (columnID: string) => void; onDataCellKeyUp?: (columnID: string) => void; + isReadOnly: boolean; } export type HoverInfo = @@ -71,6 +72,7 @@ export function BeeTableTd({ lastColumnMinWidth, onDataCellClick, onDataCellKeyUp, + isReadOnly, }: BeeTableTdProps) { const [isResizing, setResizing] = useState(false); const [hoverInfo, setHoverInfo] = useState({ isHovered: false }); @@ -227,9 +229,9 @@ export function BeeTableTd({ ({ <> {tdContent} - {shouldRenderResizer && ( + {!isReadOnly && shouldRenderResizer && ( ({ )} - {hoverInfo.isHovered && shouldRenderInlineButtons && onRowAdded && shouldShowRowsInlineControls && ( -

+ {!isReadOnly && + hoverInfo.isHovered && + shouldRenderInlineButtons && + onRowAdded && + shouldShowRowsInlineControls && (
e.stopPropagation()} - onDoubleClick={(e) => e.stopPropagation()} - onClick={onAddRowButtonClick} - className={"add-row-button"} - style={addRowButtonStyle} + style={{ + display: "flex", + justifyContent: "center", + }} > - +
e.stopPropagation()} + onDoubleClick={(e) => e.stopPropagation()} + onClick={onAddRowButtonClick} + className={"add-row-button"} + style={addRowButtonStyle} + > + +
-
- )} + )} ); diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTdForAdditionalRow.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTdForAdditionalRow.tsx index 1e772f28e36..db862f1644b 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTdForAdditionalRow.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTdForAdditionalRow.tsx @@ -35,6 +35,7 @@ export interface BeeTableTdForAdditionalRowProps { resizerStopBehavior: ResizerStopBehavior; column: ReactTable.ColumnInstance; lastColumnMinWidth?: number; + isReadOnly: boolean; } export function BeeTableTdForAdditionalRow({ @@ -46,6 +47,7 @@ export function BeeTableTdForAdditionalRow({ isLastColumn, resizerStopBehavior, lastColumnMinWidth, + isReadOnly, }: BeeTableTdForAdditionalRowProps) { const tdRef = useRef(null); @@ -81,7 +83,7 @@ export function BeeTableTdForAdditionalRow({ > {children} - {!column.isWidthConstant && ( + {!column.isWidthConstant && !isReadOnly && ( { column: ReactTable.ColumnInstance; shouldShowColumnsInlineControls: boolean; forwardRef?: React.RefObject; + isReadOnly: boolean; } export type HoverInfo = @@ -78,6 +79,7 @@ export function BeeTableTh({ column, isLastLevelColumn, shouldShowColumnsInlineControls: shouldShowRowsInlineControls, + isReadOnly, }: React.PropsWithChildren>) { const [hoverInfo, setHoverInfo] = useState({ isHovered: false }); @@ -193,15 +195,15 @@ export function BeeTableTh({ style={{ ...thProps.style, display: "table-cell" }} ref={thRef} onMouseDown={onMouseDown} - onDoubleClick={onDoubleClick} + onDoubleClick={isReadOnly ? undefined : onDoubleClick} onClick={onClick} - onKeyUp={onHeaderKeyUp} + onKeyUp={isReadOnly ? undefined : onHeaderKeyUp} className={`${className} ${cssClasses}`} tabIndex={-1} data-testid={`kie-tools--bee--table-header-${column.groupType ?? "undefined"}`} > {children} - {hoverInfo.isHovered && onColumnAdded && isLastLevelColumn && shouldShowRowsInlineControls && ( + {!isReadOnly && hoverInfo.isHovered && onColumnAdded && isLastLevelColumn && shouldShowRowsInlineControls && (
e.stopPropagation()} onDoubleClick={(e) => e.stopPropagation()} diff --git a/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx b/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx index c7cbeff5fb1..b74592eddb2 100644 --- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx +++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableThResizable.tsx @@ -55,6 +55,7 @@ export interface BeeTableThResizableProps { onGetWidthToFitData: () => number; forwardRef?: React.RefObject; shouldRenderRowIndexColumn: boolean; + isReadOnly: boolean; } export function BeeTableThResizable({ @@ -76,6 +77,7 @@ export function BeeTableThResizable({ lastColumnMinWidth, onGetWidthToFitData, forwardRef, + isReadOnly, }: BeeTableThResizableProps) { const columnKey = useMemo(() => getColumnKey(column), [column, getColumnKey]); @@ -178,6 +180,7 @@ export function BeeTableThResizable({ forwardRef={forwardRef} className={cssClasses} + isReadOnly={isReadOnly} thProps={{ ...column.getHeaderProps(), style: { @@ -204,7 +207,7 @@ export function BeeTableThResizable({ column={column} >
- {column.dataType && isEditableHeader ? ( + {!isReadOnly && column.dataType && isEditableHeader ? ( ({ )}
{/* resizingWidth. I.e., Exact-sized columns. */} - {!column.isWidthConstant && + {!isReadOnly && + !column.isWidthConstant && column.width && resizingWidth && (hoverInfo.isHovered || (resizingWidth?.isPivoting && isResizing)) && ( @@ -236,7 +240,8 @@ export function BeeTableThResizable({ {/* fillingResizingWidth. I.e., Flexible or parent columns. */} {getFlatListOfSubColumns(column).some((c) => !(c.isWidthConstant ?? false)) && (isFlexbileColumn(column) || isParentColumn(column)) && - (hoverInfo.isHovered || (fillingResizingWidth?.isPivoting && isResizing)) && ( + (hoverInfo.isHovered || (fillingResizingWidth?.isPivoting && isResizing)) && + !isReadOnly && ( void; rowIndex: number; columnIndex: number; + isReadOnly: boolean; } export const InlineEditableTextInput: React.FunctionComponent = ({ @@ -38,6 +39,7 @@ export const InlineEditableTextInput: React.FunctionComponent { const { i18n } = useBoxedExpressionEditorI18n(); const inputRef = useRef(null); @@ -91,11 +93,11 @@ export const InlineEditableTextInput: React.FunctionComponent {value || i18n.enterText}

diff --git a/packages/boxed-expression-component/stories/boxedExpressionStoriesWrapper.tsx b/packages/boxed-expression-component/stories/boxedExpressionStoriesWrapper.tsx index 191d112f5cb..92276209843 100644 --- a/packages/boxed-expression-component/stories/boxedExpressionStoriesWrapper.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressionStoriesWrapper.tsx @@ -181,6 +181,7 @@ export function BoxedExpressionEditorStory(props?: Partial + +# Boxed Conditional Expression + +The Boxed Conditional expression was implemented as an alternative way of defining FEEL expressions `if [condition satisfied] then [something] else [something else]` diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Conditional/Conditional.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Conditional/Conditional.stories.tsx new file mode 100644 index 00000000000..c4315e4d878 --- /dev/null +++ b/packages/boxed-expression-component/stories/boxedExpressions/Conditional/Conditional.stories.tsx @@ -0,0 +1,216 @@ +/* + * 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 { Meta, StoryObj } from "@storybook/react"; +import { BoxedExpressionEditor, BoxedExpressionEditorProps } from "../../../src/BoxedExpressionEditor"; +import { BoxedExpressionEditorStory, BoxedExpressionEditorStoryArgs } from "../../boxedExpressionStoriesWrapper"; +import { generateUuid } from "../../../src/api"; +import { Base as EmptyExpression } from "../../misc/Empty/EmptyExpression.stories"; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +const meta: Meta = { + title: "Boxed Expressions/Conditional", + component: BoxedExpressionEditor, + includeStories: /^[A-Z]/, +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args +export const Base: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "conditional", + "@_id": generateUuid(), + "@_label": "Expression Name", + if: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + then: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + else: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + }, + }, +}; + +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "conditional", + "@_id": generateUuid(), + "@_label": "Expression Name", + if: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + then: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + else: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + }, + isReadOnly: true, + }, +}; + +export const MonthlyFee: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "conditional", + "@_id": "_D98FB35A-C6A5-4BA7-AD38-176D56A31983", + "@_label": "MonthlyFee", + "@_typeRef": "number", + if: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + text: { __$$text: 'ProductType = "STANDARD LOAN"' }, + }, + }, + then: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + text: { __$$text: "20" }, + }, + }, + else: { + "@_id": generateUuid(), + expression: { + __$$element: "conditional", + "@_id": generateUuid(), + if: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": "_D98FB35A-C6A5-4BA7-AD38-176D56A31983", + text: { __$$text: 'ProductType = "SPECIAL OFFERING"' }, + }, + }, + then: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + text: { __$$text: "25" }, + }, + }, + else: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + text: { __$$text: "null" }, + }, + }, + }, + }, + }, + widthsById: { + "_D98FB35A-C6A5-4BA7-AD38-176D56A31983": [300], + }, + }, +}; + +export const Nested: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "context", + "@_id": generateUuid(), + "@_label": "Expression Name", + contextEntry: [ + { + "@_id": generateUuid(), + variable: { + "@_id": generateUuid(), + "@_name": "ContextEntry-1", + }, + expression: { + __$$element: "conditional", + "@_id": generateUuid(), + "@_label": "Expression Name", + if: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + then: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + else: { + "@_id": generateUuid(), + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + }, + }, + }, + }, + ], + }, + }, +}; diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Context/Context.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Context/Context.stories.tsx index ce061fe14e8..286796a7523 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Context/Context.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Context/Context.stories.tsx @@ -61,6 +61,38 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "context", + "@_id": "_35255561-88FA-4A78-9C3F-61855213EE0F", + "@_label": "Expression Name", + "@_typeRef": undefined, + contextEntry: [ + { + "@_id": generateUuid(), + variable: { + "@_id": generateUuid(), + "@_name": "ContextEntry-1", + "@_typeRef": undefined, + }, + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "readonly text" }, + }, + }, + ], + }, + isResetSupportedOnRootExpression: true, + widthsById: { "_35255561-88FA-4A78-9C3F-61855213EE0F": [CONTEXT_ENTRY_VARIABLE_MIN_WIDTH] }, + isReadOnly: true, + }, +}; + export const InstallmentCalculation: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/DecisionTable/DecisionTable.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/DecisionTable/DecisionTable.stories.tsx index cb1d5ed7715..0a8d78dfc98 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/DecisionTable/DecisionTable.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/DecisionTable/DecisionTable.stories.tsx @@ -103,6 +103,66 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "decisionTable", + "@_id": "_92929AE6-3BB5-4217-B66E-07614680971D", + "@_label": "Expression Name", + "@_hitPolicy": "UNIQUE", + input: [ + { + "@_id": generateUuid(), + inputExpression: { + "@_id": generateUuid(), + text: { __$$text: "input-1" }, + "@_typeRef": undefined, + }, + }, + ], + output: [ + { + "@_id": generateUuid(), + "@_label": "output-1", + "@_typeRef": undefined, + }, + ], + annotation: [ + { + "@_name": "Annotations", + }, + ], + rule: [ + { + "@_id": generateUuid(), + inputEntry: [{ "@_id": generateUuid(), text: { __$$text: DECISION_TABLE_INPUT_DEFAULT_VALUE } }], + outputEntry: [ + { + "@_id": generateUuid(), + text: { __$$text: DECISION_TABLE_OUTPUT_DEFAULT_VALUE }, + }, + ], + annotationEntry: [{ text: { __$$text: "// Your annotations here" } }], + }, + ], + }, + widthsById: { + "_92929AE6-3BB5-4217-B66E-07614680971D": [ + BEE_TABLE_ROW_INDEX_COLUMN_WIDTH, + DECISION_TABLE_INPUT_DEFAULT_WIDTH, + DECISION_TABLE_OUTPUT_DEFAULT_WIDTH, + DECISION_TABLE_ANNOTATION_DEFAULT_WIDTH, + ], + }, + + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const Discount: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Every/Every.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Every/Every.stories.tsx index aacf921ce5c..4af9b469900 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Every/Every.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Every/Every.stories.tsx @@ -54,3 +54,34 @@ export const Base: Story = { }, }, }; + +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "every", + "@_id": generateUuid(), + "@_label": "Expression Name", + in: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "['read', 'only']" }, + }, + }, + satisfies: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "readOnlyTest(itemReadOnly)" }, + }, + }, + "@_iteratorVariable": "itemReadOnly", + }, + isReadOnly: true, + }, +}; diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Filter/Filter.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Filter/Filter.stories.tsx index 7174f71cbf0..655600513c9 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Filter/Filter.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Filter/Filter.stories.tsx @@ -55,6 +55,36 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "filter", + "@_id": generateUuid(), + "@_label": "Expression Name", + in: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "['read', 'only']" }, + }, + }, + match: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "readOnlyTest(itemReadOnly)" }, + }, + }, + }, + isReadOnly: true, + }, +}; + export const RebookedFlights: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/For/For.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/For/For.stories.tsx index 9a6f56b1839..898f34f8d3d 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/For/For.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/For/For.stories.tsx @@ -54,3 +54,34 @@ export const Base: Story = { }, }, }; + +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "for", + "@_id": generateUuid(), + "@_label": "Expression Name", + in: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "['read', 'only']" }, + }, + }, + return: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "readOnlyTest(itemReadOnly)" }, + }, + }, + "@_iteratorVariable": "itemReadOnly", + }, + isReadOnly: true, + }, +}; diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Function/Function.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Function/Function.stories.tsx index b7cf246f555..466041e2409 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Function/Function.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Function/Function.stories.tsx @@ -48,6 +48,22 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "functionDefinition", + "@_id": generateUuid(), + "@_label": "Expression Name", + "@_kind": BoxedFunctionKind.Feel, + }, + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const InstallmentCalculation: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Invocation/Invocation.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Invocation/Invocation.stories.tsx index 612d913559f..7a83ffae49b 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Invocation/Invocation.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Invocation/Invocation.stories.tsx @@ -62,6 +62,39 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "invocation", + "@_id": generateUuid(), + "@_label": "Expression Name", + binding: [ + { + parameter: { + "@_id": generateUuid(), + "@_name": INVOCATION_EXPRESSION_DEFAULT_PARAMETER_NAME, + }, + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "read only" }, + }, + }, + ], + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "FUNCTION NAME" }, + }, + }, + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const MonthlyInstallment: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/List/List.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/List/List.stories.tsx index 2e86ea6cadc..c19f64c69c2 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/List/List.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/List/List.stories.tsx @@ -48,6 +48,22 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "list", + "@_id": generateUuid(), + "@_label": "Expression Name", + expression: [{ __$$element: "literalExpression", "@_id": generateUuid(), text: { __$$text: "read only" } }], + }, + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const AgeGroups: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Literal/Literal.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Literal/Literal.stories.tsx index 54fb6249b35..1e30af74482 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Literal/Literal.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Literal/Literal.stories.tsx @@ -47,6 +47,21 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "literalExpression", + "@_id": generateUuid(), + "@_label": "Expression Name", + }, + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const CanDrive: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Relation/Relation.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Relation/Relation.stories.tsx index 540bf330536..c1b2627cba6 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Relation/Relation.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Relation/Relation.stories.tsx @@ -66,6 +66,39 @@ export const Base: Story = { }, }; +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "relation", + "@_id": generateUuid(), + "@_label": "Expression Name", + column: [ + { + "@_id": generateUuid(), + "@_name": "column-1", + }, + ], + row: [ + { + "@_id": generateUuid(), + expression: [ + { + __$$element: "literalExpression", + "@_id": generateUuid(), + text: { __$$text: RELATION_EXPRESSION_DEFAULT_VALUE }, + }, + ], + }, + ], + }, + isResetSupportedOnRootExpression: true, + isReadOnly: true, + }, +}; + export const People: Story = { render: (args) => BoxedExpressionEditorStory(), parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, diff --git a/packages/boxed-expression-component/stories/boxedExpressions/Some/Some.stories.tsx b/packages/boxed-expression-component/stories/boxedExpressions/Some/Some.stories.tsx index 7c78217b389..914a196958d 100644 --- a/packages/boxed-expression-component/stories/boxedExpressions/Some/Some.stories.tsx +++ b/packages/boxed-expression-component/stories/boxedExpressions/Some/Some.stories.tsx @@ -54,3 +54,34 @@ export const Base: Story = { }, }, }; + +export const Readonly: Story = { + render: (args) => BoxedExpressionEditorStory(), + parameters: { exclude: ["dataTypes", "beeGwtService", "pmmlDocuments"] }, + args: { + ...EmptyExpression.args, + expression: { + __$$element: "some", + "@_id": generateUuid(), + "@_label": "Expression Name", + in: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "['read', 'only']" }, + }, + }, + satisfies: { + "@_id": generateUuid(), + expression: { + "@_id": generateUuid(), + __$$element: "literalExpression", + text: { __$$text: "readOnlyTest(itemReadOnly)" }, + }, + }, + "@_iteratorVariable": "itemReadOnly", + }, + isReadOnly: true, + }, +}; diff --git a/packages/boxed-expression-component/stories/dev/WebApp.stories.tsx b/packages/boxed-expression-component/stories/dev/WebApp.stories.tsx index fa98da41221..575019f1b54 100644 --- a/packages/boxed-expression-component/stories/dev/WebApp.stories.tsx +++ b/packages/boxed-expression-component/stories/dev/WebApp.stories.tsx @@ -197,6 +197,7 @@ export const WebApp: Story = { widthsById: { control: "object" }, }, args: { + isReadOnly: false, expressionHolderId: undefined, // Needs to be here to be displayed. expression: undefined, // Needs to be here to be displayed. widthsById: {}, // Needs to be here to be displayed. diff --git a/packages/boxed-expression-component/tests-e2e/__fixtures__/monaco.ts b/packages/boxed-expression-component/tests-e2e/__fixtures__/monaco.ts index 8ccabcba9f5..10b149aedba 100644 --- a/packages/boxed-expression-component/tests-e2e/__fixtures__/monaco.ts +++ b/packages/boxed-expression-component/tests-e2e/__fixtures__/monaco.ts @@ -44,4 +44,24 @@ export class Monaco { await this.page.keyboard.press("Home"); await this.page.keyboard.press("Enter"); } + + public async canFill(args: { monacoParentLocator: Locator | Page; nth?: number }) { + if (args.nth !== undefined) { + await args.monacoParentLocator.getByTestId("monaco-container").nth(args.nth).dblclick(); + } else { + await args.monacoParentLocator.getByTestId("monaco-container").dblclick(); + } + + if (await this.page.getByLabel("Editor content;Press Alt+F1 for Accessibility Options.").isVisible()) { + return true; + } + + // Try to fill by typing instead of double-click + if (args.nth !== undefined) { + await args.monacoParentLocator.getByTestId("monaco-container").nth(args.nth).press("KeyA"); + } else { + await args.monacoParentLocator.getByTestId("monaco-container").press("KeyA"); + } + return await this.page.getByLabel("Editor content;Press Alt+F1 for Accessibility Options.").isVisible(); + } } diff --git a/packages/boxed-expression-component/tests-e2e/__fixtures__/stories.ts b/packages/boxed-expression-component/tests-e2e/__fixtures__/stories.ts index b8219799152..d5286b9de27 100644 --- a/packages/boxed-expression-component/tests-e2e/__fixtures__/stories.ts +++ b/packages/boxed-expression-component/tests-e2e/__fixtures__/stories.ts @@ -34,47 +34,53 @@ export class Stories { return `iframe.html?id=${iframeId}&viewMode=story`; } - public async openBoxedContext(type: BoxedExpressionTypes | "installment-calculation" | "customer" = "base") { + public async openBoxedContext( + type: BoxedExpressionTypes | "readonly" | "installment-calculation" | "customer" = "base" + ) { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-context--${type}`)}` ?? ""); } - public async openDecisionTable(type: BoxedExpressionTypes | "discount" | "undefined-widths" = "base") { + public async openDecisionTable(type: BoxedExpressionTypes | "readonly" | "discount" | "undefined-widths" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-decision-table--${type}`)}` ?? ""); } - public async openBoxedFunction(type: BoxedExpressionTypes | "installment-calculation" = "base") { + public async openBoxedFunction(type: BoxedExpressionTypes | "readonly" | "installment-calculation" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-function--${type}`)}` ?? ""); } - public async openBoxedInvocation(type: BoxedExpressionTypes | "monthly-installment" = "base") { + public async openBoxedInvocation(type: BoxedExpressionTypes | "readonly" | "monthly-installment" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-invocation--${type}`)}` ?? ""); } - public async openBoxedList(type: BoxedExpressionTypes | "age-groups" = "base") { + public async openBoxedList(type: BoxedExpressionTypes | "readonly" | "age-groups" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-list--${type}`)}` ?? ""); } - public async openBoxedLiteral(type: BoxedExpressionTypes | "can-drive" = "base") { + public async openBoxedLiteral(type: BoxedExpressionTypes | "readonly" | "can-drive" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-literal--${type}`)}` ?? ""); } - public async openRelation(type: BoxedExpressionTypes | "bigger" | "people" = "base") { + public async openRelation(type: BoxedExpressionTypes | "readonly" | "bigger" | "people" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-relation--${type}`)}` ?? ""); } - public async openBoxedFilter(type: BoxedExpressionTypes | "rebooked-flights" = "base") { + public async openBoxedFilter(type: BoxedExpressionTypes | "readonly" | "rebooked-flights" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-filter--${type}`)}` ?? ""); } - public async openBoxedEvery(type: BoxedExpressionTypes = "base") { + public async openBoxedEvery(type: BoxedExpressionTypes | "readonly" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-every--${type}`)}` ?? ""); } - public async openBoxedSome(type: BoxedExpressionTypes = "base") { + public async openBoxedSome(type: BoxedExpressionTypes | "readonly" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-some--${type}`)}` ?? ""); } - public async openBoxedFor(type: BoxedExpressionTypes = "base") { + public async openBoxedFor(type: BoxedExpressionTypes | "readonly" = "base") { await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-for--${type}`)}` ?? ""); } + + public async openBoxedConditional(type: BoxedExpressionTypes | "readonly" = "base") { + await this.page.goto(`${this.baseURL}/${this.getIframeURL(`boxed-expressions-conditional--${type}`)}` ?? ""); + } } diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional--reset-state.png new file mode 100644 index 00000000000..f44c5cba2c9 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png new file mode 100644 index 00000000000..6bd847a9a48 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-monthly-fee.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-monthly-fee.png new file mode 100644 index 00000000000..386d6ec164d Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-monthly-fee.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png new file mode 100644 index 00000000000..13d3414cdf5 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png new file mode 100644 index 00000000000..45dbeb75840 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional.png new file mode 100644 index 00000000000..9a7177e73fb Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/conditional/nested-boxed-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png new file mode 100644 index 00000000000..da201654066 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-context.png new file mode 100644 index 00000000000..e89e1c18936 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png new file mode 100644 index 00000000000..01c469c4a3f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-every.png new file mode 100644 index 00000000000..de3115675f7 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-filter.png new file mode 100644 index 00000000000..244ba5c2f68 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-for.png new file mode 100644 index 00000000000..d67f02b34e8 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-function.png new file mode 100644 index 00000000000..8ec765362b1 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png new file mode 100644 index 00000000000..decc7fdb64c Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-list.png new file mode 100644 index 00000000000..9e3473b810f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-some.png new file mode 100644 index 00000000000..b025d33dc6e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/boxedExpressions/filter/boxed-filter-aligned-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-else.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-else.png new file mode 100644 index 00000000000..38cb57b29dd Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-else.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-if.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-if.png new file mode 100644 index 00000000000..1709529fd6e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-if.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-root.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-root.png new file mode 100644 index 00000000000..7370f195731 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-root.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-then.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-then.png new file mode 100644 index 00000000000..8f29758822e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-conditionald-resized-using-then.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-conditional.png new file mode 100644 index 00000000000..8f0adf4a203 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-context.png new file mode 100644 index 00000000000..7ab6e547e1f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-decision-table.png new file mode 100644 index 00000000000..3bd2a7e9429 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-every.png new file mode 100644 index 00000000000..351f8a8609a Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-filter.png new file mode 100644 index 00000000000..8b44270a338 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-for.png new file mode 100644 index 00000000000..02114a380fc Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-function.png new file mode 100644 index 00000000000..566347d7dcd Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-invocation.png new file mode 100644 index 00000000000..e345694fe79 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-list.png new file mode 100644 index 00000000000..d4ecfb82b09 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-some.png new file mode 100644 index 00000000000..8668cbac705 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/Google-Chrome/features/resizing/boxed-filter-resized-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional--reset-state.png new file mode 100644 index 00000000000..7bde9eb7624 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png new file mode 100644 index 00000000000..13013a99c4c Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-copy-and-paste-recursively.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-monthly-fee.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-monthly-fee.png new file mode 100644 index 00000000000..c7ddc016eb9 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-monthly-fee.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png new file mode 100644 index 00000000000..7192f369de9 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png new file mode 100644 index 00000000000..30ce064cdce Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional.png new file mode 100644 index 00000000000..b51cdfc3f50 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/conditional/nested-boxed-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png new file mode 100644 index 00000000000..d0f9e97b9e5 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-context.png new file mode 100644 index 00000000000..e89e1c18936 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png new file mode 100644 index 00000000000..01c469c4a3f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-every.png new file mode 100644 index 00000000000..38a805cad8e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-filter.png new file mode 100644 index 00000000000..244ba5c2f68 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-for.png new file mode 100644 index 00000000000..309baf04d79 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-function.png new file mode 100644 index 00000000000..8ec765362b1 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png new file mode 100644 index 00000000000..c13cd988a97 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-list.png new file mode 100644 index 00000000000..545a6965f91 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-some.png new file mode 100644 index 00000000000..b025d33dc6e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/boxedExpressions/filter/boxed-filter-aligned-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-else.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-else.png new file mode 100644 index 00000000000..80be3408ba7 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-else.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-if.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-if.png new file mode 100644 index 00000000000..44b3452127b Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-if.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-root.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-root.png new file mode 100644 index 00000000000..0207f0f7bce Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-root.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-then.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-then.png new file mode 100644 index 00000000000..0d0f642c594 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-conditionald-resized-using-then.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-conditional.png new file mode 100644 index 00000000000..8f0adf4a203 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-context.png new file mode 100644 index 00000000000..7ab6e547e1f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-decision-table.png new file mode 100644 index 00000000000..3bd2a7e9429 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-every.png new file mode 100644 index 00000000000..351f8a8609a Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-filter.png new file mode 100644 index 00000000000..8b44270a338 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-for.png new file mode 100644 index 00000000000..02114a380fc Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-function.png new file mode 100644 index 00000000000..566347d7dcd Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-invocation.png new file mode 100644 index 00000000000..e345694fe79 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-list.png new file mode 100644 index 00000000000..d4ecfb82b09 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-some.png new file mode 100644 index 00000000000..8668cbac705 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/chromium/features/resizing/boxed-filter-resized-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional--reset-state.png new file mode 100644 index 00000000000..60341110829 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-monthly-fee.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-monthly-fee.png new file mode 100644 index 00000000000..181a4cdda76 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-monthly-fee.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png new file mode 100644 index 00000000000..6598af722c9 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/boxed-conditional-with-nested-other-expressions.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png new file mode 100644 index 00000000000..7253c2a2c5e Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional--reset-state.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional.png new file mode 100644 index 00000000000..12afac56898 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/conditional/nested-boxed-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png new file mode 100644 index 00000000000..3937d89f9dc Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-context.png new file mode 100644 index 00000000000..3fce2cafac6 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png new file mode 100644 index 00000000000..9c4f6642a3f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-every.png new file mode 100644 index 00000000000..a9f4717eb3f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-filter.png new file mode 100644 index 00000000000..1cefd78e2fb Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-for.png new file mode 100644 index 00000000000..770201906b2 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-function.png new file mode 100644 index 00000000000..d5089c19f4f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png new file mode 100644 index 00000000000..f0c50d3a9d4 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-list.png new file mode 100644 index 00000000000..1becb3d21a3 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-some.png new file mode 100644 index 00000000000..1a706d54bb3 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/boxedExpressions/filter/boxed-filter-aligned-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-else.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-else.png new file mode 100644 index 00000000000..4ed1291557f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-else.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-if.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-if.png new file mode 100644 index 00000000000..5f126677cbf Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-if.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-root.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-root.png new file mode 100644 index 00000000000..e8cae2a2c8a Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-root.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-then.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-then.png new file mode 100644 index 00000000000..ced31850116 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-conditionald-resized-using-then.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-conditional.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-conditional.png new file mode 100644 index 00000000000..1b70995dce4 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-conditional.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-context.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-context.png new file mode 100644 index 00000000000..fe0852c8558 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-context.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-decision-table.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-decision-table.png new file mode 100644 index 00000000000..7708ec63c8d Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-decision-table.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-every.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-every.png new file mode 100644 index 00000000000..16cdd8f5c8f Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-every.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-filter.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-filter.png new file mode 100644 index 00000000000..bfc2308b9ef Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-filter.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-for.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-for.png new file mode 100644 index 00000000000..552ad90fee6 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-for.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-function.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-function.png new file mode 100644 index 00000000000..4e830734110 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-function.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-invocation.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-invocation.png new file mode 100644 index 00000000000..6cecc83d8d7 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-invocation.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-list.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-list.png new file mode 100644 index 00000000000..49bf5f4f9fd Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-list.png differ diff --git a/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-some.png b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-some.png new file mode 100644 index 00000000000..d49983a7184 Binary files /dev/null and b/packages/boxed-expression-component/tests-e2e/__screenshots__/webkit/features/resizing/boxed-filter-resized-match-some.png differ diff --git a/packages/boxed-expression-component/tests-e2e/api/expressionContainer.ts b/packages/boxed-expression-component/tests-e2e/api/expressionContainer.ts index 549e11a2e33..22121236cea 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressionContainer.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressionContainer.ts @@ -132,6 +132,10 @@ export class ContextMenu { await this.locator.nth(0).click({ button: "right" }); } + public async availableOptions() { + return this.locator.page().getByTestId("kie-tools--bee--context-menu-container").getByRole("menuitem"); + } + public heading(sectionName: string) { return this.locator.page().getByRole("heading", { name: sectionName }); } @@ -165,10 +169,15 @@ export class ChildExpression { private locator: Locator, monaco: Monaco ) { - this._expression = new ExpressionContainer( - this.locator.getByTestId("kie-tools--bee--expression-container").nth(0), - monaco - ); + this._expression = new ExpressionContainer(this.elementCell, monaco); + } + + public async hover() { + await this.elementCell.hover(); + } + + get elementCell() { + return this.locator.getByTestId("kie-tools--bee--expression-container").nth(0); } get expression() { @@ -176,7 +185,7 @@ export class ChildExpression { } get selectExpressionMenu() { - return new SelectExpressionMenu(this.locator.getByTestId("kie-tools--bee--expression-container").nth(0)); + return new SelectExpressionMenu(this.elementCell); } get contextMenu() { diff --git a/packages/boxed-expression-component/tests-e2e/api/expressionHeader.ts b/packages/boxed-expression-component/tests-e2e/api/expressionHeader.ts index 1d3334cd311..4f0758d4719 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressionHeader.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressionHeader.ts @@ -45,4 +45,8 @@ export class ExpressionHeader { await this.get().click(); await this.page.getByRole("menuitem", { name: "Reset" }).click(); } + + public async availableOptions() { + return this.page.getByRole("menuitem"); + } } diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/contextExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/contextExpressionElement.ts index c3c06e92d00..b6539eab88b 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/contextExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/contextExpressionElement.ts @@ -104,4 +104,12 @@ export class ContextExpressionEntry { get variable() { return new NameAndDataTypeCell(this.locator.getByRole("cell").nth(0)); } + + public async getPopoverMenu() { + return this.locator.page().getByTestId("kie-tools--bee--expression-popover-menu"); + } + + get elementCell() { + return this.childExpression.elementCell; + } } diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/decisionTableExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/decisionTableExpressionElement.ts index d8872f4723a..2ce6a761d49 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/decisionTableExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/decisionTableExpressionElement.ts @@ -311,6 +311,10 @@ export class HitTableSelector { export class HitTableMenu { constructor(private locator: Locator) {} + public async availableOptions() { + return this.locator.page().getByTestId("kie-tools--bee--hit-policy-header").getByRole("menuitem"); + } + public option(optionName: string) { return this.locator.page().getByTestId("kie-tools--bee--hit-policy-header").getByRole("menuitem", { name: optionName, diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/invocationExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/invocationExpressionElement.ts index 71a186cc2ba..4e52faeca56 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/invocationExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/invocationExpressionElement.ts @@ -32,6 +32,10 @@ export class InvocationExpressionElement { return new InvocationParameter(this.locator.getByTestId(`kie-tools--bee--expression-row-${index}`), this.monaco); } + get invokedFunctionNameCell() { + return this.locator.getByTestId(`kie-tools--bee--table-header-invokedFunctionName`); + } + get expressionHeaderCell() { return new NameAndDataTypeCell(this.locator.getByRole("columnheader")); } @@ -100,4 +104,8 @@ class InvocationParameter { get descriptionCell() { return new NameAndDataTypeCell(this.locator.getByTestId(`kie-tools--bee--expression-column-1`).nth(0)); } + + get elementCell() { + return this.expressionElement.elementCell; + } } diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/listExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/listExpressionElement.ts index 646d99d4836..05ef0b46f32 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/listExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/listExpressionElement.ts @@ -76,6 +76,10 @@ export class Row { return this.childExpression.expression; } + get elementCell() { + return this.childExpression.elementCell; + } + get selectExpressionMenu() { return this.childExpression.selectExpressionMenu; } diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/literalExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/literalExpressionElement.ts index 2429c5c6e7e..7dee6f7783f 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/literalExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/literalExpressionElement.ts @@ -20,7 +20,7 @@ import { Locator, Page } from "@playwright/test"; import { Monaco } from "../../__fixtures__/monaco"; import { NameAndDataTypeCell } from "../nameAndDataTypeCell"; -import { ExpressionCell } from "../expressionContainer"; +import { ContextMenu, ExpressionCell } from "../expressionContainer"; export class LiteralExpressionElement { constructor( @@ -32,6 +32,10 @@ export class LiteralExpressionElement { await this.monaco.fill({ monacoParentLocator: this.locator, nth: 0, content: expression }); } + public async canFill() { + return await this.monaco.canFill({ monacoParentLocator: this.locator, nth: 0 }); + } + get content() { return this.locator.getByRole("cell").nth(0); } @@ -40,6 +44,10 @@ export class LiteralExpressionElement { return new ExpressionCell(this.locator.getByRole("cell").nth(0), this.monaco); } + get equalsSignContextMenu() { + return new ContextMenu(this.locator.getByTestId("kie-tools--equals-sign")); + } + get expressionHeaderCell() { return new NameAndDataTypeCell(this.locator.getByRole("columnheader")); } diff --git a/packages/boxed-expression-component/tests-e2e/api/expressions/relationExpressionElement.ts b/packages/boxed-expression-component/tests-e2e/api/expressions/relationExpressionElement.ts index 297d9092f30..655858941f4 100644 --- a/packages/boxed-expression-component/tests-e2e/api/expressions/relationExpressionElement.ts +++ b/packages/boxed-expression-component/tests-e2e/api/expressions/relationExpressionElement.ts @@ -28,11 +28,11 @@ export class RelationExpressionElement { private monaco: Monaco ) {} - public cellAt(param: { column: number; row: number }) { + public cellAt(coordinate: { column: number; row: number }) { return new ExpressionCell( this.locator - .getByTestId(`kie-tools--bee--expression-row-${param.row - 1}`) - .getByTestId(`kie-tools--bee--expression-column-${param.column}`), + .getByTestId(`kie-tools--bee--expression-row-${coordinate.row - 1}`) + .getByTestId(`kie-tools--bee--expression-column-${coordinate.column}`), this.monaco ); } @@ -119,4 +119,9 @@ export class RelationExpressionElement { .locator("svg") .click(); } + + public getColumnHeaderAtIndex(index: number) { + // index+1 because we're ignoring the expression header cell + return this.locator.getByRole("columnheader").nth(index + 1); + } } diff --git a/packages/boxed-expression-component/tests-e2e/api/nameAndDataTypeCell.ts b/packages/boxed-expression-component/tests-e2e/api/nameAndDataTypeCell.ts index fbae08acd35..b693bdfe7c6 100644 --- a/packages/boxed-expression-component/tests-e2e/api/nameAndDataTypeCell.ts +++ b/packages/boxed-expression-component/tests-e2e/api/nameAndDataTypeCell.ts @@ -27,6 +27,10 @@ export class NameAndDataTypeCell { await this.locator.nth(0).click(); } + public async getPopoverMenu() { + return this.locator.page().getByTestId("kie-tools--bee--expression-popover-menu"); + } + public async setName(params: { name: string; close: boolean }) { await this.locator.getByRole("textbox").fill(params.name); if (params.close) { diff --git a/packages/boxed-expression-component/tests-e2e/boxedExpressions/conditional/populate.spec.ts b/packages/boxed-expression-component/tests-e2e/boxedExpressions/conditional/populate.spec.ts new file mode 100644 index 00000000000..7ed29672ffd --- /dev/null +++ b/packages/boxed-expression-component/tests-e2e/boxedExpressions/conditional/populate.spec.ts @@ -0,0 +1,169 @@ +/* + * 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 _ from "lodash"; +import { test, expect } from "../../__fixtures__/base"; + +test.describe("Populate Boxed Conditional", () => { + test("should rename a Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + await bee.expression.asConditional().expressionHeaderCell.open(); + await bee.expression + .asConditional() + .expressionHeaderCell.setName({ name: "Conditional Expression Name", close: true }); + + expect(await bee.expression.asConditional().expressionHeaderCell.content.textContent()).toEqual( + "Conditional Expression Name()" + ); + }); + + test("should change a Conditional data type", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + await bee.expression.asConditional().expressionHeaderCell.open(); + await bee.expression.asConditional().expressionHeaderCell.setDataType({ dataType: "boolean", close: true }); + + await expect(await bee.expression.asConditional().expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + expect(await bee.expression.asConditional().expressionHeaderCell.content.textContent()).toEqual( + "Expression Name(boolean)" + ); + }); + + test("should create the Monthly Fee Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + // HEADER + await bee.expression.asConditional().expressionHeaderCell.open(); + await bee.expression.asConditional().expressionHeaderCell.setName({ name: "MonthlyFee", close: false }); + await bee.expression.asConditional().expressionHeaderCell.setDataType({ dataType: "number", close: true }); + + // IF + await bee.expression.asConditional().if.expression.asLiteral().fill('ProdctType = "STANDARD LOAN"'); + + // THEN + await bee.expression.asConditional().then.expression.asLiteral().fill("20"); + + // ELSE + await bee.expression.asConditional().else.expression.asLiteral().equalsSignContextMenu.open(); + await bee.expression + .asConditional() + .else.expression.asLiteral() + .equalsSignContextMenu.option("Reset") + .nth(0) + .click(); + await bee.expression.asConditional().else.selectExpressionMenu.selectConditional(); + await bee.expression.asConditional().else.expression.asConditional().if.selectExpressionMenu.selectLiteral(); + await bee.expression + .asConditional() + .else.expression.asConditional() + .if.expression.asLiteral() + .fill('ProdctType = "SPECIAL OFFERING"'); + await bee.expression.asConditional().else.expression.asConditional().then.selectExpressionMenu.selectLiteral(); + await bee.expression.asConditional().else.expression.asConditional().then.expression.asLiteral().fill("25"); + await bee.expression.asConditional().else.expression.asConditional().else.selectExpressionMenu.selectLiteral(); + await bee.expression.asConditional().else.expression.asConditional().else.expression.asLiteral().fill("null"); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditional-monthly-fee.png"); + }); + + test("should create a nested Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + await bee.expression.header.reset(); + await bee.selectExpressionMenu.selectContext(); + await bee.expression.asContext().entry(0).selectExpressionMenu.selectConditional(); + + await bee.expression.asContext().entry(0).expression.asConditional().if.selectExpressionMenu.selectLiteral(); + await bee.expression.asContext().entry(0).expression.asConditional().if.expression.asLiteral().fill("1 > 0"); + + await bee.expression.asContext().entry(0).expression.asConditional().then.selectExpressionMenu.selectLiteral(); + await bee.expression.asContext().entry(0).expression.asConditional().then.expression.asLiteral().fill("always"); + + await bee.expression.asContext().entry(0).expression.asConditional().else.selectExpressionMenu.selectLiteral(); + await bee.expression.asContext().entry(0).expression.asConditional().else.expression.asLiteral().fill("never"); + + await expect(bee.getContainer()).toHaveScreenshot("nested-boxed-conditional.png"); + }); + + test("should combine other expressions with the Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + await bee.expression.asConditional().if.expression.asLiteral().equalsSignContextMenu.open(); + await bee.expression.asConditional().if.expression.asLiteral().equalsSignContextMenu.option("Reset").nth(0).click(); + await bee.expression.asConditional().if.selectExpressionMenu.selectContext(); + + await bee.expression.asConditional().then.expression.asLiteral().equalsSignContextMenu.open(); + await bee.expression + .asConditional() + .then.expression.asLiteral() + .equalsSignContextMenu.option("Reset") + .nth(0) + .click(); + await bee.expression.asConditional().then.selectExpressionMenu.selectDecisionTable(); + + await bee.expression.asConditional().else.expression.asLiteral().equalsSignContextMenu.open(); + await bee.expression + .asConditional() + .else.expression.asLiteral() + .equalsSignContextMenu.option("Reset") + .nth(0) + .click(); + await bee.expression.asConditional().else.selectExpressionMenu.selectSome(); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditional-with-nested-other-expressions.png"); + }); + + test("should reset a Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional(); + + await bee.expression.header.reset(); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditional--reset-state.png"); + }); + + test("should reset a nested Conditional", async ({ bee, stories }) => { + await stories.openBoxedConditional("nested"); + + await bee.expression.asContext().entry(0).expression.header.reset(); + + await expect(bee.getContainer()).toHaveScreenshot("nested-boxed-conditional--reset-state.png"); + }); + + test("should copy and paste Conditional", async ({ bee, browserName, context, stories }) => { + test.skip( + browserName === "webkit", + "Playwright Webkit doesn't support clipboard permissions: https://github.com/microsoft/playwright/issues/13037" + ); + + await context.grantPermissions(["clipboard-read", "clipboard-write"]); + + await stories.openBoxedConditional(); + + // Copy the root of the expression + await bee.expression.header.copy(); + + // Paste it recursively as 'if' expression + await bee.expression.asConditional().if.expression.asLiteral().equalsSignContextMenu.open(); + await bee.expression.asConditional().if.expression.asLiteral().equalsSignContextMenu.option("Paste").nth(0).click(); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditional-copy-and-paste-recursively.png"); + }); +}); diff --git a/packages/boxed-expression-component/tests-e2e/boxedExpressions/filter/filterExpression.spec.ts b/packages/boxed-expression-component/tests-e2e/boxedExpressions/filter/filterExpression.spec.ts index cf742918f75..0490d1ef39a 100644 --- a/packages/boxed-expression-component/tests-e2e/boxedExpressions/filter/filterExpression.spec.ts +++ b/packages/boxed-expression-component/tests-e2e/boxedExpressions/filter/filterExpression.spec.ts @@ -108,4 +108,171 @@ test.describe("Create Boxed Filter", () => { expect((await jsonModel.getFilterExpression()).in["@_id"]).not.toBeUndefined(); expect((await jsonModel.getFilterExpression()).match["@_id"]).not.toBeUndefined(); }); + + test.describe("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell", () => { + // We're testing the expressions known to be wider than the default Filter Expression width, not all expressions + test.beforeEach(async ({ stories, browserName, clipboard }) => { + await stories.openBoxedFilter("base"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Context Expression", async ({ + bee, + page, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectContext(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-context.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Decision Table", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectDecisionTable(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-decision-table.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - List", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectList(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-list.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Invocation", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectInvocation(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-invocation.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Function", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFunction(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-function.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Conditional", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectConditional(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-conditional.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - For", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFor(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-for.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Every", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectEvery(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-every.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Some", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectSome(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-some.png"); + }); + + test("should correctly fill the 'in' cell when the 'match' cell is larger than the 'in' cell - Filter", async ({ + bee, + jsonModel, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFilter(); + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-aligned-match-filter.png"); + }); + }); }); diff --git a/packages/boxed-expression-component/tests-e2e/features/readonly/readonly.spec.ts b/packages/boxed-expression-component/tests-e2e/features/readonly/readonly.spec.ts new file mode 100644 index 00000000000..16d607f59c2 --- /dev/null +++ b/packages/boxed-expression-component/tests-e2e/features/readonly/readonly.spec.ts @@ -0,0 +1,314 @@ +/* + * 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 { test, expect } from "../../__fixtures__/base"; + +test.describe("Read Only Mode", () => { + test("Literal expression", async ({ stories, bee, page }) => { + await stories.openBoxedLiteral("readonly"); + const literalExpression = bee.expression.asLiteral(); + + expect(await literalExpression.canFill()).toBeFalsy(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + // Can change name/data type? + await literalExpression.expressionHeaderCell.open(); + await expect(await literalExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + }); + + test("Relation expression", async ({ stories, bee, page }) => { + await stories.openRelation("readonly"); + const relationExpression = bee.expression.asRelation(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + // Can change name/data type? + await relationExpression.expressionHeaderCell.open(); + await expect(await relationExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + // Can add rows? + await relationExpression.cellAt({ column: 0, row: 1 }).content.hover(); + await expect(relationExpression.cellAt({ column: 0, row: 1 }).content.locator("svg")).not.toBeAttached(); + + // Can add columns? + await relationExpression.getColumnHeaderAtIndex(0).hover(); + await expect(relationExpression.getColumnHeaderAtIndex(0).locator("svg")).not.toBeAttached(); + }); + + test("Context expression", async ({ stories, bee, page }) => { + await stories.openBoxedContext("readonly"); + const contextExpression = bee.expression.asContext(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + // Can change name/data type? + await contextExpression.expressionHeaderCell.open(); + await expect(await contextExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + // Can add entry? + await contextExpression.entry(0).variable.content.hover(); + await expect(contextExpression.entry(0).variable.content.locator("svg")).not.toBeAttached(); + + // Can change entry name/datatype? + await contextExpression.entry(0).variable.open(); + await expect(await contextExpression.entry(0).getPopoverMenu()).not.toBeAttached(); + + // Can change entry expression? + expect(await contextExpression.entry(0).expression.asLiteral().canFill()).toBeFalsy(); + + // Can reset, cut, paste in entry expression? + await contextExpression.entry(0).expression.contextMenu.open(); + await expect(await contextExpression.entry(0).expression.contextMenu.availableOptions()).toHaveCount(1); + await expect(await contextExpression.entry(0).expression.contextMenu.availableOptions()).toContainText("Copy"); + await expect(await contextExpression.entry(0).expression.contextMenu.availableOptions()).not.toContainText("Reset"); + await expect(await contextExpression.entry(0).expression.contextMenu.availableOptions()).not.toContainText("Cut"); + await expect(await contextExpression.entry(0).expression.contextMenu.availableOptions()).not.toContainText("Paste"); + }); + + test("Decision Table expression", async ({ stories, bee, page }) => { + await stories.openDecisionTable("readonly"); + const decisionTableExpression = bee.expression.asDecisionTable(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + // Hit table menu + await decisionTableExpression.hitTableSelector.cell.click(); + await expect(await decisionTableExpression.hitTableSelector.menu.availableOptions()).not.toBeAttached(); + + // Can add input? + await decisionTableExpression.inputHeaderAt(0).content.hover(); + await expect(decisionTableExpression.inputHeaderAt(0).content.locator("svg")).not.toBeAttached(); + + // Can add output? + await decisionTableExpression.outputHeaderAt(0).content.hover(); + await expect(decisionTableExpression.outputHeaderAt(0).content.locator("svg")).not.toBeAttached(); + + // Can add annotation? + await decisionTableExpression.annotationHeaderAt(0).content.hover(); + await expect(decisionTableExpression.annotationHeaderAt(0).content.locator("svg")).not.toBeAttached(); + + // Can change input? + await decisionTableExpression.inputHeaderAt(0).open(); + await expect(await decisionTableExpression.inputHeaderAt(0).getPopoverMenu()).not.toBeAttached(); + + // Can change output? + await decisionTableExpression.outputHeaderAt(0).open(); + await expect(await decisionTableExpression.outputHeaderAt(0).getPopoverMenu()).not.toBeAttached(); + + // Can change name/data type? + await decisionTableExpression.expressionHeaderCell.open(); + await expect(await decisionTableExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + // Can add rows? + await decisionTableExpression.cellAt({ row: 1, column: 1 }).content.hover(); + await expect(decisionTableExpression.cellAt({ row: 1, column: 1 }).content.locator("svg")).not.toBeAttached(); + }); + + test("List expression", async ({ stories, bee, page }) => { + await stories.openBoxedList("readonly"); + const listExpression = bee.expression.asList(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await listExpression.expressionHeaderCell.open(); + await expect(await listExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + // Can add rows? + await listExpression.row(0).cell.content.hover(); + await expect(listExpression.row(0).cell.content.locator("svg")).not.toBeAttached(); + + // Can change list expression? + expect(await listExpression.row(0).expression.asLiteral().canFill()).toBeFalsy(); + }); + + test("Invocation expression", async ({ stories, bee, page }) => { + await stories.openBoxedInvocation("readonly"); + const invocationExpression = bee.expression.asInvocation(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await invocationExpression.expressionHeaderCell.open(); + await expect(await invocationExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + // Can add rows? + await invocationExpression.parameter(0).descriptionCell.content.hover(); + await expect(invocationExpression.parameter(0).descriptionCell.content.locator("svg")).not.toBeAttached(); + + // Can change invocation name? + await invocationExpression.invokedFunctionNameCell.click(); + await expect(invocationExpression.invokedFunctionNameCell.getByRole("textbox")).not.toBeAttached(); + + // Can change list expression? + expect(await invocationExpression.parameter(0).expression.asLiteral().canFill()).toBeFalsy(); + + // Can reset, cut, paste in entry expression? + await invocationExpression.parameter(0).expression.contextMenu.open(); + await expect(await invocationExpression.parameter(0).expression.contextMenu.availableOptions()).toHaveCount(1); + await expect(await invocationExpression.parameter(0).expression.contextMenu.availableOptions()).toContainText( + "Copy" + ); + await expect(await invocationExpression.parameter(0).expression.contextMenu.availableOptions()).not.toContainText( + "Reset" + ); + await expect(await invocationExpression.parameter(0).expression.contextMenu.availableOptions()).not.toContainText( + "Cut" + ); + await expect(await invocationExpression.parameter(0).expression.contextMenu.availableOptions()).not.toContainText( + "Paste" + ); + }); + + test("Conditional expression", async ({ stories, bee, page }) => { + await stories.openBoxedConditional("readonly"); + const conditionalExpression = bee.expression.asConditional(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await conditionalExpression.expressionHeaderCell.open(); + await expect(await conditionalExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + expect(await conditionalExpression.if.expression.asLiteral().canFill()).toBeFalsy(); + expect(await conditionalExpression.then.expression.asLiteral().canFill()).toBeFalsy(); + expect(await conditionalExpression.else.expression.asLiteral().canFill()).toBeFalsy(); + }); + + test("For expression", async ({ stories, bee, page }) => { + await stories.openBoxedFor("readonly"); + const forExpression = bee.expression.asFor(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await forExpression.expressionHeaderCell.open(); + await expect(await forExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + await forExpression.variable.content.click(); + await expect(forExpression.variable.content.getByRole("textbox")).not.toBeAttached(); + expect(await forExpression.in.expression.asLiteral().canFill()).toBeFalsy(); + expect(await forExpression.return.expression.asLiteral().canFill()).toBeFalsy(); + }); + + test("Every expression", async ({ stories, bee, page }) => { + await stories.openBoxedEvery("readonly"); + const everyExpression = bee.expression.asEvery(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await everyExpression.expressionHeaderCell.open(); + await expect(await everyExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + await everyExpression.variable.content.click(); + await expect(everyExpression.variable.content.getByRole("textbox")).not.toBeAttached(); + expect(await everyExpression.in.expression.asLiteral().canFill()).toBeFalsy(); + expect(await everyExpression.satisfies.expression.asLiteral().canFill()).toBeFalsy(); + }); + + test("Some expression", async ({ stories, bee, page }) => { + await stories.openBoxedSome("readonly"); + const someExpression = bee.expression.asSome(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await someExpression.expressionHeaderCell.open(); + await expect(await someExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + await someExpression.variable.content.click(); + await expect(someExpression.variable.content.getByRole("textbox")).not.toBeAttached(); + expect(await someExpression.in.expression.asLiteral().canFill()).toBeFalsy(); + expect(await someExpression.satisfies.expression.asLiteral().canFill()).toBeFalsy(); + }); + + test("Filter expression", async ({ stories, bee, page }) => { + await stories.openBoxedFilter("readonly"); + const filterExpression = bee.expression.asFilter(); + + await bee.expression.header.get().click(); + await expect(await bee.expression.header.availableOptions()).toHaveCount(1); + await expect(await bee.expression.header.availableOptions()).toContainText("Copy"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Reset"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Cut"); + await expect(await bee.expression.header.availableOptions()).not.toContainText("Paste"); + await page.keyboard.press("Escape"); + + await filterExpression.expressionHeaderCell.open(); + await expect(await filterExpression.expressionHeaderCell.getPopoverMenu()).not.toBeAttached(); + + expect(await filterExpression.in.expression.asLiteral().canFill()).toBeFalsy(); + expect(await filterExpression.match.expression.asLiteral().canFill()).toBeFalsy(); + }); +}); 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 c46a5ef64ea..9e72f472613 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 @@ -17,7 +17,7 @@ * under the License. */ -import { test, expect } from "../../__fixtures__/base"; +import { expect, test } from "../../__fixtures__/base"; import { TestAnnotations } from "@kie-tools/playwright-base/annotations"; import { WidthConstants } from "../../__fixtures__/jsonModel"; @@ -1008,5 +1008,311 @@ test.describe("Resizing", () => { await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-nested-resized-using-match.png"); }); + + test("should correct resize the 'in' cell when the 'match' is resized - Context", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + test.info().annotations.push({ + type: TestAnnotations.REGRESSION, + description: "https://github.com/apache/incubator-kie-issues/issues/1147", + }); + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectContext(); + await filterExpression.match.expression.asContext().entry(0).selectExpressionMenu.selectLiteral(); + await resizing.resizeCell( + filterExpression.match.expression.asContext().entry(0).elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-context.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Decision Table", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectDecisionTable(); + + await resizing.resizeCell( + filterExpression.match.expression.asDecisionTable().cellAt({ row: 1, column: 1 }).content, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-decision-table.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - List", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectList(); + await filterExpression.match.expression.asList().row(0).selectExpressionMenu.selectLiteral(); + await resizing.resizeCell( + filterExpression.match.expression.asList().row(0).elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-list.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Invocation", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectInvocation(); + + await filterExpression.match.expression.asInvocation().parameter(0).selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asInvocation().parameter(0).elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-invocation.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Function", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFunction(); + + await filterExpression.match.expression.asFunction().entry(0).selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asFunction().entry(0).elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-function.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - For", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFor(); + + await filterExpression.match.expression.asFor().in.selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asFor().in.elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-for.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Conditional", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectConditional(); + + await filterExpression.match.expression.asConditional().if.selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asConditional().if.elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-conditional.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Every", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectEvery(); + + await filterExpression.match.expression.asEvery().in.selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asEvery().in.elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-every.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Some", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectSome(); + + await filterExpression.match.expression.asSome().in.selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asSome().in.elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-some.png"); + }); + + test("should correct resize the 'in' cell when the 'match' is resized - Filter", async ({ + bee, + monaco, + page, + resizing, + stories, + }) => { + await stories.openBoxedFilter(); + const filterExpression = bee.expression.asFilter(); + await filterExpression.match.selectExpressionMenu.selectFilter(); + + await filterExpression.match.expression.asFilter().match.selectExpressionMenu.selectLiteral(); + + await resizing.resizeCell( + filterExpression.match.expression.asFilter().match.elementCell, + { x: 0, y: 0 }, + { x: 150, y: 0 } + ); + + // We're hovering the 'in' to make the width difference to the 'match' more clear + await filterExpression.in.hover(); + await expect(bee.getContainer()).toHaveScreenshot("boxed-filter-resized-match-filter.png"); + }); + }); + + test.describe("Conditional expression", async () => { + test("should resize a Conditional", async ({ bee, resizing, stories }) => { + await stories.openBoxedConditional(); + + await resizing.resizeCell( + bee.expression.asConditional().expressionHeaderCell.content, + { x: 0, y: 0 }, + { x: 250, y: 0 } + ); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditionald-resized-using-root.png"); + }); + + test("should resize a Conditional - if", async ({ bee, monaco, page, resizing, stories }) => { + await stories.openBoxedConditional(); + + await monaco.fill({ + monacoParentLocator: page, + nth: 0, + content: "some pretty long text that will not fit the 'if' box", + }); + + await resizing.resizeCell( + bee.expression.asConditional().if.expression.asLiteral().content, + { x: 0, y: 0 }, + { x: 250, y: 0 } + ); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditionald-resized-using-if.png"); + }); + + test("should resize a Conditional - then", async ({ bee, monaco, page, resizing, stories }) => { + await stories.openBoxedConditional(); + + await monaco.fill({ + monacoParentLocator: page, + nth: 1, + content: "some pretty long text that will not fit the 'then' box", + }); + + await resizing.resizeCell( + bee.expression.asConditional().then.expression.asLiteral().content, + { x: 0, y: 0 }, + { x: 250, y: 0 } + ); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditionald-resized-using-then.png"); + }); + + test("should resize a Conditional - else", async ({ bee, monaco, page, resizing, stories }) => { + await stories.openBoxedConditional(); + + await monaco.fill({ + monacoParentLocator: page, + nth: 2, + content: "some pretty long text that will not fit the 'else' box", + }); + + await resizing.resizeCell( + bee.expression.asConditional().else.expression.asLiteral().content, + { x: 0, y: 0 }, + { x: 250, y: 0 } + ); + + await expect(bee.getContainer()).toHaveScreenshot("boxed-conditionald-resized-using-else.png"); + }); }); }); diff --git a/packages/boxed-expression-component/tests/__mocks__/monacoMock.js b/packages/boxed-expression-component/tests/__mocks__/monacoMock.js deleted file mode 100644 index a1fa4fbe465..00000000000 --- a/packages/boxed-expression-component/tests/__mocks__/monacoMock.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -const languages = []; -let value = "new value"; -let onDidBlurEditorText; - -module.exports = { - languages: { - registeredLanguages: [], - register: (language) => { - languages.push(language); - }, - getLanguages: () => { - return languages; - }, - setMonarchTokensProvider: (_name, _tokens) => {}, - registerCompletionItemProvider: (_name, _provider) => {}, - CompletionItemKind: { - Keyword: "Keyword", - Function: "Function", - }, - CompletionItemInsertTextRule: { - InsertAsSnippet: "InsertAsSnippet", - }, - }, - editor: { - defineTheme: (_name, _theme) => {}, - colorize: () => ({ - then: (fn) => fn(), - }), - create: (element, _config) => { - element.innerHTML = ""; - return { - dispose: () => {}, - getValue: () => value, - setValue: (newValue) => { - if (newValue.includes("")) { - onDidBlurEditorText(newValue); - } - }, - setPosition: (_v) => {}, - focus: () => {}, - onDidChangeModelContent: () => {}, - onDidBlurEditorText: (fn) => (onDidBlurEditorText = fn), - onKeyDown: () => {}, - }; - }, - }, -}; diff --git a/packages/boxed-expression-component/tests/keysUtils/NavigationKeysUtils.test.ts b/packages/boxed-expression-component/tests/keysUtils/NavigationKeysUtils.test.ts deleted file mode 100644 index 5026ecb1f8c..00000000000 --- a/packages/boxed-expression-component/tests/keysUtils/NavigationKeysUtils.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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 { NavigationKeysUtils } from "@kie-tools/boxed-expression-component/dist/keysUtils/keyUtils"; - -const notAKey = "NotAKey"; -const testDescription = "With input key: '%s', should return '%s'"; - -describe("NavigationKeysUtils", () => { - describe("isEscape", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["escapex", false], - ["escape", true], - ["Escape", true], - ["ESCAPE", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isEsc(key!)).toBe(expected); - }); - }); - - describe("isAltGraph", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["altgraphx", false], - ["altgraph", true], - ["AltGraph", true], - ["ALTGRAPH", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isAltGraph(key!)).toBe(expected); - }); - }); - - describe("isArrowDown", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["arrowdownx", false], - ["arrowdown", true], - ["ArrowDown", true], - ["ARROWDOWN", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isArrowDown(key!)).toBe(expected); - }); - }); - - describe("isArrowLeft", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["arrowleftx", false], - ["arrowleft", true], - ["ArrowLeft", true], - ["ARROWLEFT", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isArrowLeft(key!)).toBe(expected); - }); - }); - - describe("isArrowRight", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["arrowrightx", false], - ["arrowright", true], - ["ArrowRight", true], - ["ARROWRIGHT", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isArrowRight(key!)).toBe(expected); - }); - }); - - describe("isArrowUp", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["arrowupx", false], - ["arrowup", true], - ["ArrowUp", true], - ["ARROWUP", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isArrowUp(key!)).toBe(expected); - }); - }); - - describe("isAnyArrow", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["enter", false], - ["arrowupx", false], - ["arrowup", true], - ["arrowleft", true], - ["ArrowUp", true], - ["ARROWRIGHT", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isAnyArrow(key!)).toBe(expected); - }); - }); - - describe("isEnter", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["enterx", false], - ["enter", true], - ["Enter", true], - ["ENTER", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isEnter(key!)).toBe(expected); - }); - }); - - describe("isTab", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["tabx", false], - ["tab", true], - ["Tab", true], - ["TAB", true], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isTab(key!)).toBe(expected); - }); - }); - - describe("isFX", () => { - test.each([ - [undefined, false], - ["", false], - [notAKey, false], - ["F1x", false], - ["f1", true], - ["F1", true], - ["F12", true], - ["F120", false], - ])(testDescription, (key, expected) => { - expect(NavigationKeysUtils.isFunctionKey(key!)).toBe(expected); - }); - }); -}); diff --git a/packages/bpmn-vscode-extension/package.json b/packages/bpmn-vscode-extension/package.json index 20e2d65cb74..48400e50396 100644 --- a/packages/bpmn-vscode-extension/package.json +++ b/packages/bpmn-vscode-extension/package.json @@ -45,7 +45,7 @@ "copy-webpack-plugin": "^11.0.0", "process": "^0.11.10", "rimraf": "^3.0.2", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/chrome-extension-pack-kogito-kie-editors/package.json b/packages/chrome-extension-pack-kogito-kie-editors/package.json index 7bd978b3c00..6030fcbd441 100644 --- a/packages/chrome-extension-pack-kogito-kie-editors/package.json +++ b/packages/chrome-extension-pack-kogito-kie-editors/package.json @@ -57,7 +57,7 @@ "start-server-and-test": "^2.0.3", "ts-jest": "^29.1.5", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0", diff --git a/packages/chrome-extension-serverless-workflow-editor/package.json b/packages/chrome-extension-serverless-workflow-editor/package.json index 003d780d3c0..06c85c0881b 100644 --- a/packages/chrome-extension-serverless-workflow-editor/package.json +++ b/packages/chrome-extension-serverless-workflow-editor/package.json @@ -60,7 +60,7 @@ "typescript": "^5.5.3", "vscode-languageserver-textdocument": "^1.0.4", "vscode-languageserver-types": "^3.16.0", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0", diff --git a/packages/cors-proxy/package.json b/packages/cors-proxy/package.json index ab940523999..4a51561146e 100644 --- a/packages/cors-proxy/package.json +++ b/packages/cors-proxy/package.json @@ -50,7 +50,7 @@ "run-script-os": "^1.1.6", "ts-jest": "^29.1.5", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-merge": "^5.9.0" } diff --git a/packages/dashbuilder-component-assembler/package.json b/packages/dashbuilder-component-assembler/package.json index 824cbc94434..8524321ba93 100644 --- a/packages/dashbuilder-component-assembler/package.json +++ b/packages/dashbuilder-component-assembler/package.json @@ -36,7 +36,7 @@ "copy-webpack-plugin": "^11.0.0", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-echarts/package.json b/packages/dashbuilder-component-echarts/package.json index 87505eda23b..6c12f83918a 100644 --- a/packages/dashbuilder-component-echarts/package.json +++ b/packages/dashbuilder-component-echarts/package.json @@ -42,7 +42,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-map/package.json b/packages/dashbuilder-component-map/package.json index 7044adf9135..3df60281448 100644 --- a/packages/dashbuilder-component-map/package.json +++ b/packages/dashbuilder-component-map/package.json @@ -46,7 +46,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-svg-heatmap/package.json b/packages/dashbuilder-component-svg-heatmap/package.json index b2f017e5e40..586be3f3452 100644 --- a/packages/dashbuilder-component-svg-heatmap/package.json +++ b/packages/dashbuilder-component-svg-heatmap/package.json @@ -43,7 +43,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-table/package.json b/packages/dashbuilder-component-table/package.json index d55c118f4d6..3f3f6cf69bf 100644 --- a/packages/dashbuilder-component-table/package.json +++ b/packages/dashbuilder-component-table/package.json @@ -45,7 +45,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-timeseries/package.json b/packages/dashbuilder-component-timeseries/package.json index 43d0a52097f..8970bb02d55 100644 --- a/packages/dashbuilder-component-timeseries/package.json +++ b/packages/dashbuilder-component-timeseries/package.json @@ -42,7 +42,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-uniforms/package.json b/packages/dashbuilder-component-uniforms/package.json index d5d9670f348..ff410e5e442 100644 --- a/packages/dashbuilder-component-uniforms/package.json +++ b/packages/dashbuilder-component-uniforms/package.json @@ -48,7 +48,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-component-victory-charts/package.json b/packages/dashbuilder-component-victory-charts/package.json index bad138496c8..05756f7275c 100644 --- a/packages/dashbuilder-component-victory-charts/package.json +++ b/packages/dashbuilder-component-victory-charts/package.json @@ -49,7 +49,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-editor/package.json b/packages/dashbuilder-editor/package.json index a6313916229..4eac6a727d7 100644 --- a/packages/dashbuilder-editor/package.json +++ b/packages/dashbuilder-editor/package.json @@ -65,7 +65,7 @@ "start-server-and-test": "^2.0.3", "typescript": "^5.5.3", "vscode-json-languageservice": "^4.2.1", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-viewer-deployment-webapp/package.json b/packages/dashbuilder-viewer-deployment-webapp/package.json index 35f0542fc1e..82656db978f 100644 --- a/packages/dashbuilder-viewer-deployment-webapp/package.json +++ b/packages/dashbuilder-viewer-deployment-webapp/package.json @@ -54,7 +54,7 @@ "html-webpack-plugin": "^5.3.2", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dashbuilder-viewer/package.json b/packages/dashbuilder-viewer/package.json index 17330dd3288..7c848d5142f 100644 --- a/packages/dashbuilder-viewer/package.json +++ b/packages/dashbuilder-viewer/package.json @@ -55,7 +55,7 @@ "start-server-and-test": "^2.0.3", "typescript": "^5.5.3", "vscode-json-languageservice": "^4.2.1", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dev-deployment-dmn-form-webapp/package.json b/packages/dev-deployment-dmn-form-webapp/package.json index 03ef39f0464..8036a264f34 100644 --- a/packages/dev-deployment-dmn-form-webapp/package.json +++ b/packages/dev-deployment-dmn-form-webapp/package.json @@ -72,7 +72,7 @@ "ts-jest": "^29.1.5", "ts-node": "^10.9.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx b/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx index 411287583be..0af0ec31460 100644 --- a/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx +++ b/packages/dmn-editor-envelope/src/DmnEditorFactory.tsx @@ -93,6 +93,7 @@ export class DmnEditorInterface implements Editor { workspaceRootAbsolutePosixPath={ this.initArgs.workspaceRootAbsolutePosixPath ?? DEFAULT_WORKSPACE_ROOT_ABSOLUTE_POSIX_PATH } + isReadOnly={this.initArgs.isReadOnly} /> ); } @@ -103,10 +104,12 @@ function DmnEditorRootWrapper({ envelopeContext, exposing, workspaceRootAbsolutePosixPath, + isReadOnly, }: { envelopeContext?: KogitoEditorEnvelopeContextType; exposing: (s: DmnEditorRoot) => void; workspaceRootAbsolutePosixPath: string; + isReadOnly: boolean; }) { const onNewEdit = useCallback( (workspaceEdit: WorkspaceEdit) => { @@ -151,6 +154,7 @@ function DmnEditorRootWrapper({ } workspaceRootAbsolutePosixPath={workspaceRootAbsolutePosixPath} keyboardShortcutsService={envelopeContext?.services.keyboardShortcuts} + isReadOnly={isReadOnly} /> ); } diff --git a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx index 2cb5e5dafd7..c6741d3cc3c 100644 --- a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx +++ b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx @@ -65,6 +65,7 @@ export type DmnEditorRootProps = { onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot: WorkspaceChannelApi["kogitoWorkspace_openFile"]; workspaceRootAbsolutePosixPath: string; keyboardShortcutsService: KeyboardShortcutsService | undefined; + isReadOnly: boolean; }; export type DmnEditorRootState = { @@ -73,7 +74,7 @@ export type DmnEditorRootState = { pointer: number; openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined; externalModelsByNamespace: DmnEditor.ExternalModelsIndex; - readonly: boolean; + isReadOnly: boolean; externalModelsManagerDoneBootstraping: boolean; keyboardShortcutsRegisterIds: number[]; keyboardShortcutsRegistred: boolean; @@ -95,7 +96,7 @@ export class DmnEditorRoot extends React.Component }; +export type DmnEditorStandaloneResource = { contentType: "text" | "binary"; content: Promise }; export class DmnEditorStandaloneChannelApiImpl implements KogitoEditorChannelApi { constructor( @@ -102,7 +102,9 @@ export class DmnEditorStandaloneChannelApiImpl implements KogitoEditorChannelApi return new ResourceContent( request.normalizedPosixPathRelativeToTheWorkspaceRoot, await resource.content, - resource.contentType + // We need to typecast because ContentType is not exported + // and TS complains when trying to match strings with enums + resource.contentType as ContentType ); } diff --git a/packages/dmn-editor-standalone/src/DmnEditorStandaloneEnvelopeServer.ts b/packages/dmn-editor-standalone/src/DmnEditorStandaloneEnvelopeServer.ts index 8b7ea1a0cfb..eae8bc87fa1 100644 --- a/packages/dmn-editor-standalone/src/DmnEditorStandaloneEnvelopeServer.ts +++ b/packages/dmn-editor-standalone/src/DmnEditorStandaloneEnvelopeServer.ts @@ -41,7 +41,7 @@ export const createEnvelopeServer = (iframe: HTMLIFrameElement, readOnly?: boole resourcesPathPrefix: "", fileExtension: "dmn", initialLocale: "en-US", - isReadOnly: readOnly ?? true, + isReadOnly: readOnly ?? false, channel: ChannelType.STANDALONE, workspaceRootAbsolutePosixPath: DEFAULT_WORKSPACE_ROOT_ABSOLUTE_POSIX_PATH, } diff --git a/packages/dmn-editor-standalone/src/index.ts b/packages/dmn-editor-standalone/src/index.ts index fd4cdb0c9db..44486327b46 100644 --- a/packages/dmn-editor-standalone/src/index.ts +++ b/packages/dmn-editor-standalone/src/index.ts @@ -17,6 +17,9 @@ * under the License. */ +// eslint-disable-next-line @typescript-eslint/triple-slash-reference +/// // Required for bundling types + import dmnEnvelopeJs from "../dist/envelope.js"; import { StateControl } from "@kie-tools-core/editor/dist/channel"; import { DmnEditorStandaloneChannelApiImpl, DmnEditorStandaloneResource } from "./DmnEditorStandaloneChannelApiImpl"; diff --git a/packages/dmn-editor-standalone/stories/DevWebApp.stories.tsx b/packages/dmn-editor-standalone/stories/DevWebApp.stories.tsx index 499ff9c06ce..c2b6ec0e2d5 100644 --- a/packages/dmn-editor-standalone/stories/DevWebApp.stories.tsx +++ b/packages/dmn-editor-standalone/stories/DevWebApp.stories.tsx @@ -19,11 +19,12 @@ import * as React from "react"; import type { Meta, StoryObj } from "@storybook/react"; -import { useRef, useState, useEffect, useCallback } from "react"; +import { useArgs } from "@storybook/preview-api"; +import { useRef, useState, useEffect, useCallback, useMemo } from "react"; import "@patternfly/react-core/dist/styles/base.css"; import { Page, PageSection } from "@patternfly/react-core/dist/js/components/Page"; import * as DmnEditor from "../dist/index"; -import { DmnEditorStandaloneApi } from "../dist/DmnEditorStandaloneApi"; +import { DmnEditorStandaloneApi } from "../dist/index"; import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex/Flex"; import { FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex/FlexItem"; import { Text, TextVariants } from "@patternfly/react-core/dist/js/components/Text"; @@ -56,29 +57,37 @@ export type DevWebAppProps = { origin: string; }; -function DevWebApp(props: DevWebAppProps) { +function DevWebApp(props?: Partial) { const [editCount, setEditCount] = useState(0); + const [args, updateArgs] = useArgs(); const editorRef = useRef(null); const editorContainerRef = useRef(null); const downloadRef = useRef(null); const [isDroppingFile, setIsDroppingFile] = useState(false); + const resources = useMemo(() => { + const inputResources = props?.resources ?? args.resources; + + return inputResources + ? new Map( + inputResources.map(([key, value]) => [ + key, + { contentType: value.contentType, content: Promise.resolve(value.content) }, + ]) + ) + : undefined; + }, [args.resources, props?.resources]); + useEffect(() => { const editor = DmnEditor.open({ container: editorContainerRef.current!, initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: - props.initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot, - initialContent: Promise.resolve(props.initialContent), - readOnly: props.readOnly, - resources: props.resources - ? new Map( - props.resources.map(([key, value]) => [ - key, - { contentType: value.contentType, content: Promise.resolve(value.content) }, - ]) - ) - : undefined, - origin: props.origin ?? "*", + props?.initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot ?? + args.initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot, + initialContent: Promise.resolve(props?.initialContent ?? args.initialContent), + readOnly: props?.readOnly ?? args.readOnly, + resources: resources, + origin: props?.origin ?? args.origin ?? "*", }); editor.subscribeToContentChanges(() => setEditCount((currentCount) => currentCount + 1)); @@ -97,7 +106,7 @@ function DevWebApp(props: DevWebAppProps) { editor.close(); setEditCount(0); }; - }, [props]); + }, [args, props, resources]); const onUndo = useCallback(() => { setEditCount((currentCount) => { @@ -249,7 +258,7 @@ type Story = StoryObj; // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const WebApp: Story = { - render: (args) => DevWebApp(args), + render: (args) => DevWebApp(), args: { initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "path1/subpath/newModel1.dmn", initialContent: "", diff --git a/packages/dmn-editor-standalone/stories/LoanPreQualification.stories.tsx b/packages/dmn-editor-standalone/stories/LoanPreQualification.stories.tsx new file mode 100644 index 00000000000..b35ee368976 --- /dev/null +++ b/packages/dmn-editor-standalone/stories/LoanPreQualification.stories.tsx @@ -0,0 +1,885 @@ +/* + * 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 type { Meta, StoryObj } from "@storybook/react"; +import "@patternfly/react-core/dist/styles/base.css"; +import { WebApp, DevWebAppProps } from "./DevWebApp.stories"; + +const loanPreQualificationDmn = ` + + + + + Product_Type + + + number + + + number + + + number + + + + string + + "M","D","S" + + + + + number + + + Marital_Status + + + string + + "Unemployed","Employed","Self-employed","Student" + + + + boolean + + + + number + + + number + + + number + + + number + + + number + + + + + + Risk_Category + + + number + + + + + string + + + number + + + + string + + "Ineligible","Eligible" + + + + string + + "Decline","Bureau","Through" + + + + string + + "Full","Mini","None" + + + + string + + "Standard Loan","Special Loan" + + + + string + + "High","Medium","Low","Very Low","Decline" + + + + string + + "Poor","Bad","Fair","Good","Excellent" + + + + string + + "Insufficient","Sufficient" + + + + string + + "Sufficient","Insufficient" + + + + string + + "Not Qualified","Qualified" + + + + + number + + [300..850] + + + + + + string + + "Qualified","Not Qualified" + + + + string + + + + + + + + + + + + 0.36 + + + + + + + + + + + + + + + + + + + + + + + + PITI + + + + + (Requested Product.Amount * ((Requested Product.Rate/100)/12)) / (1-(1/(1+(Requested Product.Rate/100)/12) * -Requested Product.Term)) + + + + + + Applicant Data.Monthly.Tax + + + + + + Applicant Data.Monthly.Insurance + + + + + + Applicant Data.Monthly.Income + + + + + + + if Client PITI <= Lender Acceptable PITI() + then "Sufficient" + else "Insufficient" + + + + + + + + + + + + + + (pmt+tax+insurance) / income + + + + + + + + + + + + + + + + + + + + + + + + + DTI + + + + + Applicant Data.Monthly.Repayments + Applicant Data.Monthly.Expenses + + + + + + Applicant Data.Monthly.Income + + + + + + + if Client DTI <= Lender Acceptable DTI() + then "Sufficient" + else "Insufficient" + + + + + + + + + + + + + + Credit Score.FICO + + + + + + + >= 750 + + + "Excellent" + + + + + + + + [700..750) + + + "Good" + + + + + + + + [650..700) + + + "Fair" + + + + + + + + [600..650) + + + "Poor" + + + + + + + + < 600 + + + "Bad" + + + + + + + + + + + + + + + + + + + + + + + Credit Score Rating + + + + + Back End Ratio + + + + + Front End Ratio + + + + + + + + "Poor", "Bad" + + + - + + + - + + + "Not Qualified" + + + "Credit Score too low." + + + + + + + + - + + + "Insufficient" + + + "Sufficient" + + + "Not Qualified" + + + "Debt to income ratio is too high." + + + + + + + + - + + + "Sufficient" + + + "Insufficient" + + + "Not Qualified" + + + "Mortgage payment to income ratio is too high." + + + + + + + + - + + + "Insufficient" + + + "Insufficient" + + + "Not Qualified" + + + "Debt to income ratio is too high AND mortgage payment to income ratio is too high." + + + + + + + + "Fair", "Good", "Excellent" + + + "Sufficient" + + + "Sufficient" + + + "Qualified" + + + "The borrower has been successfully prequalified for the requested loan." + + + + + + + + + + + + + + + + + + + d/i + + + + + + + + + 0.28 + + + + + + + + + 209 + + + 50 + 209 + + + 50 + 100 + 1280 + + + 50 + 100 + 1110 + + + + 1110 + + + 1110 + + + 1110 + + + 1110 + + + 1280 + + + 300 + + + 50 + 300 + + + 50 + 100 + 802 + + + 50 + 100 + 632 + + + + 632 + + + 632 + + + 802 + + + 50 + 224 + 226 + 335 + + + 50 + 233 + 130 + 136 + 135 + 681 + 100 + + + 150 + + + 50 + 150 + + + 228 + + + 50 + 228 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta: Meta = { + title: "Dev/Loan Pre Qualification", +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const LoanPreQualification: Story = { + render: WebApp.render, + args: { + initialFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "path1/subpath/newModel1.dmn", + initialContent: loanPreQualificationDmn, + readOnly: false, + resources: [], + origin: "*", + }, +}; diff --git a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/editor.ts b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/editor.ts index f72046ca2f2..5ecc57ef09d 100644 --- a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/editor.ts +++ b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/editor.ts @@ -19,8 +19,7 @@ import { Page, expect } from "@playwright/test"; import { ContentType } from "@kie-tools-core/workspace/dist/api"; -import type { DmnEditorStandaloneApi } from "@kie-tools/dmn-editor-standalone/dist/DmnEditorStandaloneApi"; -import type { open } from "@kie-tools/dmn-editor-standalone/dist"; +import type { open, DmnEditorStandaloneApi } from "@kie-tools/dmn-editor-standalone/dist"; import * as prettier from "prettier"; export enum DefaultNodeName { diff --git a/packages/dmn-editor-standalone/tsconfig.json b/packages/dmn-editor-standalone/tsconfig.json index eda786a5eb1..6eaa9245ccf 100644 --- a/packages/dmn-editor-standalone/tsconfig.json +++ b/packages/dmn-editor-standalone/tsconfig.json @@ -2,6 +2,9 @@ "extends": "@kie-tools/tsconfig/tsconfig.esm.json", "compilerOptions": { "esModuleInterop": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + // Skip declarations, they are bundled manually in another step + "declarationMap": false, + "declaration": false } } diff --git a/packages/dmn-editor/package.json b/packages/dmn-editor/package.json index b1ee3fdf418..48940c12c4f 100644 --- a/packages/dmn-editor/package.json +++ b/packages/dmn-editor/package.json @@ -97,7 +97,7 @@ "start-server-and-test": "^2.0.3", "storybook": "^7.3.2", "typescript": "^5.5.3", - "webpack": "^5.88.2", + "webpack": "^5.92.1", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0" diff --git a/packages/dmn-editor/src/DmnEditor.css b/packages/dmn-editor/src/DmnEditor.css index 6982b7488a1..4e5107f818d 100644 --- a/packages/dmn-editor/src/DmnEditor.css +++ b/packages/dmn-editor/src/DmnEditor.css @@ -274,9 +274,6 @@ 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%); } @@ -606,9 +603,17 @@ the cursor is inside it. By making it adimensional, that never happens. */ transform: scale(0.8); } .kie-dmn-editor--data-type-node-panel .kie-dmn-editor--data-type-jump-to-definition { - padding-left: 4px; - padding-right: 4px; + padding-right: 0px; + background: none; + border: none; + height: auto; + padding-top: 0; + padding-bottom: 0; } +.kie-dmn-editor--data-type-node-panel-readonly .kie-dmn-editor--data-type-jump-to-definition { + padding-right: 6px; +} + /* 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, @@ -620,8 +625,13 @@ the cursor is inside it. By making it adimensional, that never happens. */ border-radius: 99999px; outline: none; } +.kie-dmn-editor--data-type-node-panel .pf-c-select__toggle.pf-m-typeahead { + padding-left: 10px; +} +.kie-dmn-editor--data-type-node-panel .pf-c-select__toggle-wrapper { + padding-left: 10px; +} .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); @@ -908,6 +918,11 @@ th { text-decoration: red dotted underline; text-underline-position: under; } + +.kie-dmn-editor--data-types-container .pf-c-switch__input:disabled:checked ~ .pf-c-switch__toggle { + background-color: var(--pf-global--primary-color--100); + opacity: 50%; +} /* (end) data types */ /* ******************************* */ diff --git a/packages/dmn-editor/src/DmnEditor.tsx b/packages/dmn-editor/src/DmnEditor.tsx index 39871faa1af..7739a0cbf7c 100644 --- a/packages/dmn-editor/src/DmnEditor.tsx +++ b/packages/dmn-editor/src/DmnEditor.tsx @@ -58,6 +58,7 @@ import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial"; 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. import { Commands, CommandsContextProvider, useCommands } from "./commands/CommandsContextProvider"; +import { DmnEditorSettingsContextProvider } from "./settings/DmnEditorSettingsContext"; const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500; @@ -148,6 +149,12 @@ export type DmnEditorProps = { * This is shown on the ErrorBoundary fallback component, when an uncaught error happens. */ issueTrackerHref?: string; + /** + * A flag to enable read-only mode on the DMN Editor. + * When enabled navigation is still possible (e.g. entering the Boxed Expression Editor, Data Types and Included Models), + * but no changes can be made and the model itself is unaltered. + */ + isReadOnly?: boolean; /** * 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. @@ -418,13 +425,15 @@ export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref return ( - - - - - - - + + + + + + + + + ); diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx index 19ca9ee664c..18c7be1da75 100644 --- a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx +++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx @@ -80,10 +80,12 @@ import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext"; import { getDefaultColumnWidth } from "./getDefaultColumnWidth"; import { getDefaultBoxedExpression } from "./getDefaultBoxedExpression"; import { Normalized } from "../normalization/normalize"; +import { useSettings } from "../settings/DmnEditorSettingsContext"; export function BoxedExpressionScreen({ container }: { container: React.RefObject }) { const { externalModelsByNamespace } = useExternalModels(); + const settings = useSettings(); const dmnEditorStoreApi = useDmnEditorStoreApi(); const thisDmn = useDmnEditorStore((s) => s.dmn); @@ -393,6 +395,7 @@ export function BoxedExpressionScreen({ container }: { container: React.RefObjec onRequestFeelVariables={onRequestFeelVariables} widthsById={widthsById} onWidthsChange={onWidthsChange} + isReadOnly={settings.isReadOnly} />
diff --git a/packages/dmn-editor/src/dataTypes/Constraints.tsx b/packages/dmn-editor/src/dataTypes/Constraints.tsx index fe64fc9f95d..9c2bd764d1b 100644 --- a/packages/dmn-editor/src/dataTypes/Constraints.tsx +++ b/packages/dmn-editor/src/dataTypes/Constraints.tsx @@ -62,7 +62,7 @@ export type TypeHelper = { export interface ConstraintComponentProps { id: string; - isReadonly: boolean; + isReadOnly: boolean; value?: string; expressionValue?: string; type: DmnBuiltInDataType; @@ -406,12 +406,12 @@ export function useConstraint({ } export function ConstraintsFromAllowedValuesAttribute({ - isReadonly, + isReadOnly, itemDefinition, editItemDefinition, renderOnPropertiesPanel, }: { - isReadonly: boolean; + isReadOnly: boolean; itemDefinition: Normalized; editItemDefinition: EditItemDefinition; renderOnPropertiesPanel?: boolean; @@ -530,7 +530,7 @@ export function ConstraintsFromAllowedValuesAttribute({ return ( ; editItemDefinition: EditItemDefinition; renderOnPropertiesPanel?: boolean; @@ -674,7 +674,7 @@ export function ConstraintsFromTypeConstraintAttribute({ return (
@@ -814,7 +814,7 @@ export function Constraints({ {internalSelectedConstraint.selectedConstraint === ConstraintsType.ENUMERATION && (
  • onChangeItem(newValue, index)} onRemove={() => onRemove(index)} @@ -140,7 +140,7 @@ export function ConstraintsEnum({ ); }, - [focusOwner, isDisabled, isItemValid, isReadonly, onAdd, onChangeItem, onRemove, typeHelper, valuesUuid] + [focusOwner, isDisabled, isItemValid, isReadOnly, onAdd, onChangeItem, onRemove, typeHelper, valuesUuid] ); return ( @@ -161,12 +161,12 @@ export function ConstraintsEnum({ onDragEnd={onDragEnd} values={enumValues} draggableItem={draggableItem} - isDisabled={isDisabled || isReadonly} + isDisabled={isDisabled || isReadOnly} />
  • - {!(isDisabled || isReadonly) && ( + {!(isDisabled || isReadOnly) && ( <>
    @@ -240,6 +240,7 @@ function EnumElement({ title={"Remove enum value"} ref={removeButtonRef} style={{ opacity: hovered ? "100%" : "0" }} + isDisabled={isDisabled} className={"kie-dmn-editor--documentation-link--row-remove"} variant={"plain"} icon={} diff --git a/packages/dmn-editor/src/dataTypes/ConstraintsExpression.tsx b/packages/dmn-editor/src/dataTypes/ConstraintsExpression.tsx index 1a87017d20a..791facf420c 100644 --- a/packages/dmn-editor/src/dataTypes/ConstraintsExpression.tsx +++ b/packages/dmn-editor/src/dataTypes/ConstraintsExpression.tsx @@ -29,12 +29,12 @@ import { TypeHelper } from "./Constraints"; export function ConstraintsExpression({ id, - isReadonly, + isReadOnly, value, onSave, }: { id: string; - isReadonly: boolean; + isReadOnly: boolean; value?: string; savedValue?: string; type: DmnBuiltInDataType; @@ -68,16 +68,16 @@ export function ConstraintsExpression({ (e) => { // When inside FEEL Input, all keyboard events should be kept inside it. // Exceptions to this strategy are handled on `onFeelKeyDown`. - if (!isReadonly && isEditing) { + if (!isReadOnly && isEditing) { e.stopPropagation(); } // This is used to start editing a cell without being in edit mode. - if (!isReadonly && !isEditing) { + if (!isReadOnly && !isEditing) { setEditing(true); } }, - [isEditing, isReadonly] + [isEditing, isReadOnly] ); const monacoOptions = useMemo( @@ -97,7 +97,7 @@ export function ConstraintsExpression({ // FeelInput doens't react to `onFeelChange` updates // making it necessary to add a key to force a re-render;
    - {isReadonly && ( + {isReadOnly && ( Equivalent FEEL expression: @@ -105,12 +105,12 @@ export function ConstraintsExpression({
    - {isReadonly && + {isReadOnly && (value ? (
    - {!isReadonly && ( + {!isReadOnly && ( }> Check the{" "} diff --git a/packages/dmn-editor/src/dataTypes/ConstraintsRange.tsx b/packages/dmn-editor/src/dataTypes/ConstraintsRange.tsx index 3b7ea1e2b29..e730b7e0d95 100644 --- a/packages/dmn-editor/src/dataTypes/ConstraintsRange.tsx +++ b/packages/dmn-editor/src/dataTypes/ConstraintsRange.tsx @@ -32,7 +32,7 @@ const CONSTRAINT_END_ID = "end"; export function ConstraintsRange({ id, - isReadonly, + isReadOnly, value, expressionValue, type, @@ -210,7 +210,7 @@ export function ConstraintsRange({ >
    diff --git a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx index 965d211f2dc..f10279dd739 100644 --- a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx +++ b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx @@ -34,7 +34,7 @@ import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/a import { Normalized } from "../normalization/normalize"; export function DataTypeName({ - isReadonly, + isReadOnly, itemDefinition, isActive, editMode, @@ -43,7 +43,7 @@ export function DataTypeName({ onGetAllUniqueNames, enableAutoFocusing, }: { - isReadonly: boolean; + isReadOnly: boolean; editMode: "hover" | "double-click"; itemDefinition: Normalized; isActive: boolean; @@ -72,7 +72,7 @@ export function DataTypeName({ const onRenamed = useCallback( (newName) => { - if (isReadonly) { + if (isReadOnly) { return; } @@ -85,7 +85,7 @@ export function DataTypeName({ }); }); }, - [dmnEditorStoreApi, externalModelsByNamespace, isReadonly, itemDefinition] + [dmnEditorStoreApi, externalModelsByNamespace, isReadOnly, itemDefinition] ); const _shouldCommitOnBlur = shouldCommitOnBlur ?? true; // Defaults to true @@ -95,7 +95,7 @@ export function DataTypeName({ {editMode === "hover" && ( { - if (isReadonly) { + if (isReadOnly) { return; } @@ -86,12 +86,12 @@ export function DataTypePanel({ } }); }, - [dataType.itemDefinition, editItemDefinition, isReadonly] + [dataType.itemDefinition, editItemDefinition, isReadOnly] ); const toggleCollection = useCallback( (isChecked: boolean) => { - if (isReadonly) { + if (isReadOnly) { return; } @@ -115,12 +115,12 @@ export function DataTypePanel({ } }); }, - [dataType.itemDefinition, editItemDefinition, isReadonly] + [dataType.itemDefinition, editItemDefinition, isReadOnly] ); const changeTypeRef = useCallback( (typeRef: DmnBuiltInDataType) => { - if (isReadonly) { + if (isReadOnly) { return; } @@ -133,12 +133,12 @@ export function DataTypePanel({ } }); }, - [dataType.itemDefinition, editItemDefinition, isReadonly] + [dataType.itemDefinition, editItemDefinition, isReadOnly] ); const changeDescription = useCallback( (newDescription: string) => { - if (isReadonly) { + if (isReadOnly) { return; } @@ -146,7 +146,7 @@ export function DataTypePanel({ itemDefinition.description = { __$$text: newDescription }; }); }, - [dataType.itemDefinition, editItemDefinition, isReadonly] + [dataType.itemDefinition, editItemDefinition, isReadOnly] ); const parents = useMemo(() => { @@ -164,7 +164,7 @@ export function DataTypePanel({ const addItemComponent = useCallback( (id, how, partial) => { - if (isReadonly) { + if (isReadOnly) { return; } @@ -175,7 +175,7 @@ export function DataTypePanel({ state.focus.consumableId = newItemDefinition["@_id"]; }); }, - [editItemDefinition, isReadonly] + [editItemDefinition, isReadOnly] ); const dmnEditorStoreApi = useDmnEditorStoreApi(); @@ -259,7 +259,7 @@ export function DataTypePanel({ itemDefinition={dataType.itemDefinition} isActive={false} editMode={"hover"} - isReadonly={dataType.namespace !== thisDmnsNamespace} + isReadOnly={isReadOnly || dataType.namespace !== thisDmnsNamespace} onGetAllUniqueNames={() => allUniqueNames} />
    @@ -296,28 +296,30 @@ export function DataTypePanel({ > Copy , - , - {!isReadonly && ( - } - onClick={() => { - if (isReadonly) { - return; - } + {!isReadOnly && ( + <> + + } + onClick={() => { + if (isReadOnly) { + return; + } - editItemDefinition(dataType.itemDefinition["@_id"]!, (_, items) => { - items?.splice(dataType.index, 1); - }); - dmnEditorStoreApi.setState((state) => { - state.dataTypesEditor.activeItemDefinitionId = - dataType.parentId ?? state.dmn.model.definitions.itemDefinition?.[0]?.["@_id"]; - }); - }} - > - Remove - + editItemDefinition(dataType.itemDefinition["@_id"]!, (_, items) => { + items?.splice(dataType.index, 1); + }); + dmnEditorStoreApi.setState((state) => { + state.dataTypesEditor.activeItemDefinitionId = + dataType.parentId ?? state.dmn.model.definitions.itemDefinition?.[0]?.["@_id"]; + }); + }} + > + Remove + + )} , ]} @@ -327,7 +329,7 @@ export function DataTypePanel({ {/* This padding was necessary because PF4 has a @media query that doesn't run inside iframes, for some reason. */}