You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by po...@apache.org on 2023/09/21 14:30:00 UTC
[incubator-kie-tools-temporary-rnd-do-not-use] 08/27: NO-ISSUE: merge main into KOGITO-8015-feature-preview (#1461)
This is an automated email from the ASF dual-hosted git repository.
porcelli pushed a commit to branch KOGITO-8015-feature-preview
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools-temporary-rnd-do-not-use.git
commit 9bc804ea709147694e994ae30f250a390606785d
Author: Fabrizio Antonangeli <fa...@gmail.com>
AuthorDate: Wed Feb 15 10:07:14 2023 +0100
NO-ISSUE: merge main into KOGITO-8015-feature-preview (#1461)
Co-authored-by: Gianluca <gi...@gmail.com>
Co-authored-by: Gianluca <gz...@redhat.com>
Co-authored-by: Wojtek Trocki <wt...@redhat.com>
Co-authored-by: renovate[bot] <29...@users.noreply.github.com>
Co-authored-by: Renovate Bot <bo...@renovateapp.com>
Co-authored-by: Luiz Motta <lu...@gmail.com>
Co-authored-by: Riccardo Forina <rf...@redhat.com>
Co-authored-by: Rachel Yordán <ka...@users.noreply.github.com>
Co-authored-by: Jozef Marko <jo...@redhat.com>
Co-authored-by: Wagner Scholl Lemos <jo...@gmail.com>
Co-authored-by: Kumar Aditya Raj <se...@gmail.com>
Co-authored-by: Thiago Lugli <th...@users.noreply.github.com>
Co-authored-by: Tiago Bento <15...@users.noreply.github.com>
Co-authored-by: Yeser Amer <ya...@redhat.com>
Co-authored-by: Kirill Gaevskii <kg...@redhat.com>
Co-authored-by: Jaime Enriquez <ja...@inodesoft.com>
Co-authored-by: Pere Fernández <pe...@users.noreply.github.com>
---
.github/actions/setup-env/action.yml | 2 +-
README.md | 2 +-
.../uniforms-patternfly/env/index.js | 24 +-
examples/uniforms-patternfly/package.json | 44 +
examples/uniforms-patternfly/src/App.tsx | 55 +
.../uniforms-patternfly/src/CodeBlock.tsx | 27 +-
examples/uniforms-patternfly/src/Form.tsx | 53 +
.../uniforms-patternfly/src/index.tsx | 10 +-
.../uniforms-patternfly/src/schemas/json-schema.ts | 113 ++
.../src/schemas/simple-schema-2.ts | 80 +
examples/uniforms-patternfly/static/index.html | 29 +
examples/uniforms-patternfly/static/logo.png | Bin 0 -> 30305 bytes
.../static/resources/styles.css | 17 +-
examples/uniforms-patternfly/tsconfig.json | 9 +
examples/uniforms-patternfly/webpack.config.js | 49 +
package.json | 4 +-
.../dashbuilder-component-table/static/index.css | 4 +-
.../dashbuilder-component-uniforms/package.json | 6 +-
.../src/Uniforms.tsx | 2 +-
packages/form-dmn/package.json | 6 +-
.../form-dmn/src/uniforms/DmnAutoFieldProvider.tsx | 2 +-
packages/form-dmn/tests/DmnForm.test.tsx | 10 +-
.../tests/__snapshots__/DmnForm.test.tsx.snap | 60 +-
packages/form-generation-tool/package.json | 4 +-
packages/form/package.json | 6 +-
packages/form/src/FormBase.tsx | 4 +-
packages/kn-plugin-workflow/README.md | 2 +-
.../src/devDeployments/DevDeploymentsDropdown.tsx | 4 +-
packages/online-editor/src/index.tsx | 3 -
.../src/workspace/startupBlockers/FsChanged.tsx | 148 --
.../startupBlockers/IncompatibleBrowser.tsx | 3 +-
packages/serverless-logic-web-tools/src/index.tsx | 3 -
.../src/workspace/startupBlockers/FsChanged.tsx | 145 --
.../startupBlockers/IncompatibleBrowser.tsx | 3 +-
.../core/shape/toolbox/items/tooltip/Tooltip.java | 6 +-
.../org/kie/lienzo/client/BasicWiresExample.java | 81 +-
.../java/org/kie/lienzo/client/EventExample.java | 61 +-
.../org/kie/lienzo/client/WiresDockingExample.java | 3 -
.../common/stunner/sw/definition/ModelUtils.java | 1 -
.../stunner/sw/definition/ParallelStateBranch.java | 12 +-
.../common/stunner/sw/definition/State.java | 28 +-
.../common/stunner/sw/definition/Timeout.java | 1 -
.../stunner/sw/marshall/StateMarshalling.java | 8 -
.../stunner/sw/marshall/StateMarshallingTest.java | 5 +-
.../common/stunner/sw/client/ShapeFactory.java | 2 +-
.../sw/client/shapes/CallbackStateShape.java | 58 +
.../common/stunner/sw/client/shapes/EndShape.java | 5 +-
.../stunner/sw/client/shapes/EndShapeView.java | 2 +-
.../stunner/sw/client/shapes/EventStateShape.java | 58 +
.../sw/client/shapes/ForEachStateShape.java | 57 +
.../stunner/sw/client/shapes/InjectStateShape.java | 39 +
.../sw/client/shapes/OperationStateShape.java | 57 +
.../sw/client/shapes/ParallelStateShape.java | 57 +
.../sw/client/shapes/ServerlessWorkflowShape.java | 55 +
...Shape.java => ServerlessWorkflowShapeView.java} | 68 +-
.../stunner/sw/client/shapes/SleepStateShape.java | 53 +
.../stunner/sw/client/shapes/StartShape.java | 5 +-
.../stunner/sw/client/shapes/StartShapeView.java | 2 +-
.../stunner/sw/client/shapes/StateShape.java | 190 ++-
.../stunner/sw/client/shapes/StateShapeView.java | 10 +-
.../stunner/sw/client/shapes/SwitchStateShape.java | 57 +
.../stunner/sw/client/shapes/TransitionView.java | 8 +-
.../stunner/sw/client/shapes/icons/CornerIcon.java | 80 +
.../stunner/sw/client/shapes/icons/IconPath.java | 21 +
.../common/stunner/sw/client/shapes/StateNode.java | 73 +
.../stunner/sw/client/shapes/StateShapeTest.java | 297 +++-
.../common/stunner/sw/client/shapes/StateView.java | 49 +
.../ast/visitor/ASTHeuristicCheckerVisitor.java | 72 +
.../kie-wb-common-dmn-client/pom.xml | 14 +-
.../DecisionTableEditorDefinitionEnricher.java | 2 +-
.../actions/AbstractActionsToolboxView.java | 1 +
.../customproperties/AssociationList.java | 21 +-
.../processes/ProcessConverterDelegate.java | 43 +-
packages/uniforms-bootstrap4-codegen/package.json | 4 +-
.../src/__tests__/_createContext.ts | 12 +-
.../src/uniforms/BootstrapCodeGenContext.tsx | 12 +-
packages/uniforms-patternfly-codegen/package.json | 4 +-
.../src/__tests__/_createContext.ts | 12 +-
.../src/uniforms/CodeGenContext.tsx | 12 +-
packages/uniforms-patternfly/.vscode/launch.json | 29 +
packages/uniforms-patternfly/README.md | 97 ++
.../uniforms-patternfly/__mocks__/styleMock.js | 1 +
.../env/index.js} | 13 +-
packages/uniforms-patternfly/jest.config.js | 34 +
.../package.json | 39 +-
.../src}/AutoField.tsx | 32 +-
packages/uniforms-patternfly/src/AutoFields.tsx | 40 +
.../src/AutoForm.tsx} | 15 +-
packages/uniforms-patternfly/src/BaseForm.tsx | 39 +
packages/uniforms-patternfly/src/BoolField.tsx | 56 +
packages/uniforms-patternfly/src/DateField.tsx | 184 +++
packages/uniforms-patternfly/src/ErrorField.tsx | 47 +
packages/uniforms-patternfly/src/ErrorsField.tsx | 50 +
packages/uniforms-patternfly/src/HiddenField.tsx | 46 +
packages/uniforms-patternfly/src/ListAddField.tsx | 60 +
packages/uniforms-patternfly/src/ListDelField.tsx | 54 +
packages/uniforms-patternfly/src/ListField.tsx | 105 ++
packages/uniforms-patternfly/src/ListItemField.tsx | 48 +
packages/uniforms-patternfly/src/LongTextField.tsx | 60 +
packages/uniforms-patternfly/src/NestField.tsx | 50 +
packages/uniforms-patternfly/src/NumField.tsx | 60 +
packages/uniforms-patternfly/src/QuickForm.tsx | 43 +
packages/uniforms-patternfly/src/RadioField.tsx | 56 +
.../src/SelectCheckboxField.tsx | 67 +
packages/uniforms-patternfly/src/SelectField.tsx | 53 +
.../uniforms-patternfly/src/SelectInputsField.tsx | 133 ++
packages/uniforms-patternfly/src/SubmitField.tsx | 41 +
packages/uniforms-patternfly/src/TextField.tsx | 187 +++
.../src/ValidatedForm.tsx} | 15 +-
.../src/ValidatedQuickForm.tsx} | 8 +-
.../src/__tests__/AutoField.test.tsx | 107 ++
.../src/__tests__/AutoFields.test.tsx | 105 ++
.../src/__tests__/AutoForm.test.tsx} | 12 +-
.../src/__tests__/BaseForm.test.tsx} | 12 +-
.../src/__tests__/BoolField.test.tsx | 108 ++
.../src/__tests__/DateField.test.tsx | 188 +++
.../src/__tests__/ErrorField.test.tsx | 51 +
.../src/__tests__/ErrorsField.test.tsx | 58 +
.../src/__tests__/HiddenField.test.tsx | 131 ++
.../src/__tests__/ListAddField.test.tsx | 56 +
.../src/__tests__/ListDelField.test.tsx | 56 +
.../src/__tests__/ListField.test.tsx | 93 ++
.../src/__tests__/ListItemField.test.tsx | 55 +
.../src/__tests__/LongTextField.test.tsx | 129 ++
.../src/__tests__/NestField.test.tsx | 70 +
.../src/__tests__/NumField.test.tsx | 240 +++
.../src/__tests__/QuickForm.test.tsx} | 12 +-
.../src/__tests__/RadioField.test.tsx | 218 +++
.../src/__tests__/SelectField.test.tsx | 498 ++++++
.../src/__tests__/SubmitField.test.tsx | 40 +
.../src/__tests__/TextField.test.tsx | 357 +++++
.../src/__tests__/ValidateQuickForm.test.tsx} | 12 +-
.../src/__tests__/ValidatedForm.test.tsx} | 12 +-
.../src/__tests__/index.test.ts | 45 +
.../src/__tests__/jest.setup.ts} | 6 +-
.../src/__tests__/test-utils.tsx | 62 +
packages/uniforms-patternfly/src/index.ts | 39 +
packages/uniforms-patternfly/src/wrapField.tsx | 71 +
packages/uniforms-patternfly/tsconfig.cjs.json | 13 +
packages/uniforms-patternfly/tsconfig.esm.json | 13 +
packages/unitables-dmn/package.json | 5 +-
packages/unitables/package.json | 6 +-
packages/unitables/src/uniforms/AutoField.tsx | 2 +-
pnpm-lock.yaml | 1594 +++++++++++++++++---
repo/graph.dot | 15 +-
repo/graph.json | 25 +-
146 files changed, 7972 insertions(+), 957 deletions(-)
diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml
index 9afb7a6b1f..f1bde8db42 100644
--- a/.github/actions/setup-env/action.yml
+++ b/.github/actions/setup-env/action.yml
@@ -25,7 +25,7 @@ runs:
- name: "Setup Node"
uses: actions/setup-node@v2
with:
- node-version: 16.13.2
+ node-version: 18.14.0
- name: "Setup JDK 11"
uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc
diff --git a/README.md b/README.md
index de610ee98a..7ae9f768e4 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ This repository contains tooling applications and libraries for KIE projects.
To start building the KIE Tools project, you're going to need:
-- Node `16` _(To install, follow these instructions: https://nodejs.org/en/download/package-manager/)_
+- Node `18` _(To install, follow these instructions: https://nodejs.org/en/download/package-manager/)_
- pnpm `7.26.3` _(To install, follow these instructions: https://pnpm.io/installation)_
- Maven `3.8.6`
- Java `11`
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java b/examples/uniforms-patternfly/env/index.js
similarity index 56%
copy from packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
copy to examples/uniforms-patternfly/env/index.js
index 06bac41e46..00d6364f4d 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
+++ b/examples/uniforms-patternfly/env/index.js
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package org.kie.workbench.common.stunner.sw.client.shapes;
+const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");
-import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
-
-public class StartShape extends NodeShapeImpl {
-
- public StartShape() {
- super(new StartShapeView().asAbstractShape());
- }
-}
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+ vars: varsWithName({}),
+ get env() {
+ return {
+ exampleUniformsPatternflyPort: {
+ port: 9101,
+ },
+ };
+ },
+});
diff --git a/examples/uniforms-patternfly/package.json b/examples/uniforms-patternfly/package.json
new file mode 100644
index 0000000000..234e211670
--- /dev/null
+++ b/examples/uniforms-patternfly/package.json
@@ -0,0 +1,44 @@
+{
+ "private": true,
+ "name": "@kie-tools-examples/uniforms-patternfly",
+ "version": "0.0.0",
+ "license": "Apache-2.0",
+ "scripts": {
+ "build": "rimraf dist && webpack",
+ "build:dev": "run-script-if --bool \"$(build-env examples.build)\" --then \"pnpm build --env dev\"",
+ "build:prod": "run-script-if --bool \"$(build-env examples.build)\" --then \"pnpm build\"",
+ "start": "webpack serve --host 0.0.0.0 --env dev"
+ },
+ "dependencies": {
+ "@kie-tools-core/patternfly-base": "workspace:*",
+ "@kie-tools/uniforms-patternfly": "workspace:*",
+ "@patternfly/react-core": "^4.157.3",
+ "@patternfly/react-icons": "^4.11.17",
+ "ajv": "^6.12.6",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "simpl-schema": "^1.12.0",
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2",
+ "uniforms-bridge-simple-schema": "^3.10.2",
+ "uniforms-bridge-simple-schema-2": "^3.10.2"
+ },
+ "devDependencies": {
+ "@kie-tools-core/webpack-base": "workspace:*",
+ "@kie-tools/root-env": "workspace:*",
+ "@kie-tools/tsconfig": "workspace:*",
+ "@types/react": "^17.0.6",
+ "@types/react-dom": "^17.0.5",
+ "@types/react-router": "^5.1.14",
+ "@types/react-router-dom": "^5.1.7",
+ "@types/simpl-schema": "^1.12.0",
+ "copy-webpack-plugin": "^11.0.0",
+ "react-router-dom": "^5.2.1",
+ "rimraf": "^3.0.2",
+ "typescript": "^4.4.2",
+ "webpack": "^5.36.2",
+ "webpack-cli": "^4.10.0",
+ "webpack-dev-server": "^4.7.3",
+ "webpack-merge": "^5.8.0"
+ }
+}
\ No newline at end of file
diff --git a/examples/uniforms-patternfly/src/App.tsx b/examples/uniforms-patternfly/src/App.tsx
new file mode 100644
index 0000000000..1edc8c61c0
--- /dev/null
+++ b/examples/uniforms-patternfly/src/App.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import "@patternfly/react-core/dist/styles/base.css";
+import * as React from "react";
+import "../static/resources/styles.css";
+import { useState } from "react";
+import { Brand, Nav, NavItem, NavList, Page, PageHeader } from "@patternfly/react-core";
+import { Form } from "./Form";
+
+export enum SchemaType {
+ JsonSchema,
+ SimpleSchema,
+}
+
+export function App() {
+ const [schemaType, setSchemaType] = useState<SchemaType>(SchemaType.JsonSchema);
+
+ return (
+ <Page
+ header={
+ <PageHeader
+ logo={<Brand src={"logo.png"} alt="Logo" />}
+ topNav={
+ <Nav onSelect={(e) => setSchemaType(e.itemId as SchemaType)} aria-label="Nav" variant="horizontal">
+ <NavList>
+ <NavItem itemId={SchemaType.JsonSchema} isActive={schemaType === SchemaType.JsonSchema}>
+ JSON Schema
+ </NavItem>
+ <NavItem itemId={SchemaType.SimpleSchema} isActive={schemaType === SchemaType.SimpleSchema}>
+ Simple Schema
+ </NavItem>
+ </NavList>
+ </Nav>
+ }
+ />
+ }
+ >
+ <Form schemaType={schemaType} />
+ </Page>
+ );
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java b/examples/uniforms-patternfly/src/CodeBlock.tsx
similarity index 51%
copy from packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
copy to examples/uniforms-patternfly/src/CodeBlock.tsx
index 06bac41e46..d52c96189c 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
+++ b/examples/uniforms-patternfly/src/CodeBlock.tsx
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,13 +14,24 @@
* limitations under the License.
*/
-package org.kie.workbench.common.stunner.sw.client.shapes;
+import * as React from "react";
-import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
+interface Props {
+ model: any;
+}
-public class StartShape extends NodeShapeImpl {
+export function CodeBlock(props: Props) {
+ if (!props.model)
+ return (
+ <>
+ <span></span>
+ </>
+ );
- public StartShape() {
- super(new StartShapeView().asAbstractShape());
- }
+ return (
+ <div style={{ marginBottom: "1em" }}>
+ <h2>Result:</h2>
+ <pre style={{ background: "#eee", padding: "1rem" }}>{JSON.stringify(props.model, null, 2)}</pre>
+ </div>
+ );
}
diff --git a/examples/uniforms-patternfly/src/Form.tsx b/examples/uniforms-patternfly/src/Form.tsx
new file mode 100644
index 0000000000..ac9f495f22
--- /dev/null
+++ b/examples/uniforms-patternfly/src/Form.tsx
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { useState, useMemo } from "react";
+import { SchemaType } from "./App";
+import { bridge as jsonSchema } from "./schemas/json-schema";
+import { bridge as simpleSchema } from "./schemas/simple-schema-2";
+import { CodeBlock } from "./CodeBlock";
+import AutoForm from "@kie-tools/uniforms-patternfly/dist/esm/AutoForm";
+
+interface Props {
+ schemaType: SchemaType;
+}
+
+export function Form(props: Props) {
+ const [model, setModel] = useState<any>(undefined);
+
+ const schema = useMemo(() => {
+ if (props.schemaType === SchemaType.SimpleSchema) {
+ return simpleSchema;
+ }
+ return jsonSchema;
+ }, [props.schemaType]);
+
+ return (
+ <div className={"form--page"}>
+ <div className={"form--container"}>
+ <CodeBlock model={model} />
+ <AutoForm
+ placeholder
+ model={model}
+ schema={schema}
+ onSubmit={(model: any) => setModel(model)}
+ showInlineError
+ />
+ </div>
+ </div>
+ );
+}
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/examples/uniforms-patternfly/src/index.tsx
similarity index 65%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to examples/uniforms-patternfly/src/index.tsx
index 7f7980f259..148f255eab 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/examples/uniforms-patternfly/src/index.tsx
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,4 +14,8 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import { App } from "./App";
+
+ReactDOM.render(<App />, document.getElementById("app"));
diff --git a/examples/uniforms-patternfly/src/schemas/json-schema.ts b/examples/uniforms-patternfly/src/schemas/json-schema.ts
new file mode 100644
index 0000000000..22bd1408ba
--- /dev/null
+++ b/examples/uniforms-patternfly/src/schemas/json-schema.ts
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as Ajv from "ajv";
+import { JSONSchemaBridge } from "uniforms-bridge-json-schema";
+
+const ajv = new Ajv({ allErrors: true, useDefaults: true });
+
+function createValidator(schema: any) {
+ const validator = ajv.compile(schema);
+ return (model: any) => {
+ validator(model);
+ if (validator.errors && validator.errors.length) {
+ throw { details: validator.errors };
+ }
+ };
+}
+
+const schema = {
+ type: "object",
+ properties: {
+ flight: {
+ type: "object",
+ properties: {
+ flightNumber: {
+ type: "string",
+ },
+ seat: {
+ type: "string",
+ },
+ gate: {
+ type: "string",
+ },
+ departure: {
+ type: "string",
+ format: "date-time",
+ },
+ arrival: {
+ type: "string",
+ format: "date-time",
+ },
+ },
+ disabled: true,
+ },
+ hotel: {
+ type: "object",
+ properties: {
+ name: {
+ type: "string",
+ },
+ addresses: {
+ type: "array",
+ items: {
+ $ref: "#/definitions/address",
+ },
+ },
+ phone: {
+ type: "string",
+ },
+ bookingNumber: {
+ type: "string",
+ },
+ room: {
+ type: "string",
+ },
+ numberOfBeds: {
+ placeholder: "Select...",
+ enum: [1, 2, 3],
+ type: "number",
+ },
+ },
+ },
+ },
+ definitions: {
+ address: {
+ type: "object",
+ properties: {
+ street: {
+ type: "string",
+ },
+ city: {
+ type: "string",
+ },
+ zipCode: {
+ type: "string",
+ },
+ country: {
+ placeholder: "Select...",
+ enum: ["Brazil", "Ireland", "USA"],
+ type: "string",
+ },
+ },
+ },
+ },
+ phases: ["complete", "release"],
+};
+
+const schemaValidator = createValidator(schema);
+
+export const bridge = new JSONSchemaBridge(schema, schemaValidator);
diff --git a/examples/uniforms-patternfly/src/schemas/simple-schema-2.ts b/examples/uniforms-patternfly/src/schemas/simple-schema-2.ts
new file mode 100644
index 0000000000..284777d046
--- /dev/null
+++ b/examples/uniforms-patternfly/src/schemas/simple-schema-2.ts
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SimpleSchema2Bridge from "uniforms-bridge-simple-schema-2";
+import SimpleSchema from "simpl-schema";
+
+const schema = new SimpleSchema({
+ date: {
+ type: Date,
+ defaultValue: new Date(),
+ },
+
+ adult: {
+ type: Boolean,
+ },
+
+ size: {
+ type: String,
+ defaultValue: "m",
+ allowedValues: ["xs", "s", "m", "l", "xl"],
+ },
+
+ rating: {
+ type: Number,
+ allowedValues: [1, 2, 3, 4, 5],
+ uniforms: {
+ checkboxes: true,
+ },
+ },
+
+ hello: {
+ type: Object,
+ },
+
+ "hello.something": {
+ type: String,
+ },
+
+ "hello.somethingelse": {
+ type: String,
+ },
+
+ friends: {
+ type: Array,
+ minCount: 1,
+ },
+
+ "friends.$": {
+ type: Object,
+ uniforms: {
+ label: false,
+ },
+ },
+
+ "friends.$.name": {
+ type: String,
+ min: 3,
+ },
+
+ "friends.$.age": {
+ type: Number,
+ min: 0,
+ max: 150,
+ },
+} as any);
+
+export const bridge = new SimpleSchema2Bridge(schema);
diff --git a/examples/uniforms-patternfly/static/index.html b/examples/uniforms-patternfly/static/index.html
new file mode 100644
index 0000000000..bf8755ddf9
--- /dev/null
+++ b/examples/uniforms-patternfly/static/index.html
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright 2020 Red Hat, Inc. and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE html>
+<html lang="en" class="pf-m-redhat-font">
+ <head>
+ <title>Uniforms Patternfly Examples</title>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body>
+ <div id="app" style="height: 100vh"></div>
+ <script src="index.js"></script>
+ </body>
+</html>
diff --git a/examples/uniforms-patternfly/static/logo.png b/examples/uniforms-patternfly/static/logo.png
new file mode 100644
index 0000000000..3691516354
Binary files /dev/null and b/examples/uniforms-patternfly/static/logo.png differ
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/examples/uniforms-patternfly/static/resources/styles.css
similarity index 64%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to examples/uniforms-patternfly/static/resources/styles.css
index 7f7980f259..a45a12fe6a 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/examples/uniforms-patternfly/static/resources/styles.css
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,4 +14,15 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+.form--page {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100vw;
+}
+
+.form--container {
+ width: 60%;
+ background-color: white;
+ padding: 20px;
+}
diff --git a/examples/uniforms-patternfly/tsconfig.json b/examples/uniforms-patternfly/tsconfig.json
new file mode 100644
index 0000000000..12548a6f43
--- /dev/null
+++ b/examples/uniforms-patternfly/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "@kie-tools/tsconfig/tsconfig.json",
+ "compilerOptions": {
+ "declaration": false,
+ "declarationMap": false,
+ "moduleResolution": "node",
+ "target": "es6"
+ }
+}
diff --git a/examples/uniforms-patternfly/webpack.config.js b/examples/uniforms-patternfly/webpack.config.js
new file mode 100644
index 0000000000..4249153f0c
--- /dev/null
+++ b/examples/uniforms-patternfly/webpack.config.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const path = require("path");
+const CopyPlugin = require("copy-webpack-plugin");
+const patternflyBase = require("@kie-tools-core/patternfly-base");
+const common = require("@kie-tools-core/webpack-base/webpack.common.config");
+const { merge } = require("webpack-merge");
+const { env } = require("./env");
+const buildEnv = env;
+
+module.exports = (env) => [
+ merge(common(env), {
+ entry: {
+ index: "./src/index.tsx",
+ },
+ output: {
+ publicPath: "/",
+ },
+ module: {
+ rules: [...patternflyBase.webpackModuleRules],
+ },
+ plugins: [
+ new CopyPlugin({
+ patterns: [{ from: "./static", to: "." }],
+ }),
+ ],
+ devServer: {
+ historyApiFallback: false,
+ static: [{ directory: path.join(__dirname, "./dist") }, { directory: path.join(__dirname, "./static") }],
+ compress: true,
+ port: buildEnv.exampleUniformsPatternflyPort.port,
+ },
+ ignoreWarnings: [/Failed to parse source map/],
+ }),
+];
diff --git a/package.json b/package.json
index 1c1ff4e362..b3f35b0a6d 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
"@kie-tools-scripts/sparse-checkout": "workspace:*",
"@kie-tools-scripts/update-version": "workspace:*",
"@nice-move/prettier-plugin-package-json": "^0.6.1",
- "@types/node": "^15.0.2",
+ "@types/node": "^18.13.0",
"filemanager-webpack-plugin": "^7.0.0",
"husky": "^6.0.0",
"postinstall-postinstall": "^2.1.0",
@@ -31,7 +31,7 @@
"react-dropzone": "^11.4.2"
},
"engines": {
- "node": ">=16",
+ "node": ">=18",
"pnpm": "7.26.3"
},
"pnpm": {
diff --git a/packages/dashbuilder-component-table/static/index.css b/packages/dashbuilder-component-table/static/index.css
index 3661509f9b..b6c2e78cd3 100644
--- a/packages/dashbuilder-component-table/static/index.css
+++ b/packages/dashbuilder-component-table/static/index.css
@@ -42,7 +42,9 @@
--pf-global--BackgroundColor--100: #100c2a !important;
}
-[mode="dark"] .pf-c-options-menu__menu {
+[mode="dark"] .pf-c-options-menu__menu,
+[mode="dark"] .pf-c-pagination__nav,
+[mode="dark"] .pf-c-pagination__total-items {
background-color: #100c2a !important;
color: #eef1fa;
}
diff --git a/packages/dashbuilder-component-uniforms/package.json b/packages/dashbuilder-component-uniforms/package.json
index ebe8499ac6..94b5f30ba3 100644
--- a/packages/dashbuilder-component-uniforms/package.json
+++ b/packages/dashbuilder-component-uniforms/package.json
@@ -24,15 +24,15 @@
"dependencies": {
"@kie-tools-core/patternfly-base": "workspace:*",
"@kie-tools/dashbuilder-component-api": "workspace:*",
+ "@kie-tools/uniforms-patternfly": "workspace:*",
"@patternfly/react-core": "^4.157.3",
"@patternfly/react-table": "^4.27.15",
"ajv": "^6.12.6",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5",
- "uniforms-patternfly": "^4.7.9"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/dashbuilder-component-uniforms/src/Uniforms.tsx b/packages/dashbuilder-component-uniforms/src/Uniforms.tsx
index 10520f1308..55ad7b8017 100644
--- a/packages/dashbuilder-component-uniforms/src/Uniforms.tsx
+++ b/packages/dashbuilder-component-uniforms/src/Uniforms.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { JSONSchemaBridge } from "uniforms-bridge-json-schema";
-import { AutoForm } from "uniforms-patternfly/dist/es6";
+import { AutoForm } from "@kie-tools/uniforms-patternfly/dist/esm";
import * as Ajv from "ajv";
import * as React from "react";
import { useCallback } from "react";
diff --git a/packages/form-dmn/package.json b/packages/form-dmn/package.json
index cd493340ce..dc3e4670f9 100644
--- a/packages/form-dmn/package.json
+++ b/packages/form-dmn/package.json
@@ -29,6 +29,7 @@
"@kie-tools-core/notifications": "workspace:*",
"@kie-tools/form": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
+ "@kie-tools/uniforms-patternfly": "workspace:*",
"@patternfly/react-core": "^4.157.3",
"@patternfly/react-icons": "^4.11.17",
"ajv": "^6.12.6",
@@ -37,9 +38,8 @@
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5",
- "uniforms-patternfly": "^4.7.9"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/form-dmn/src/uniforms/DmnAutoFieldProvider.tsx b/packages/form-dmn/src/uniforms/DmnAutoFieldProvider.tsx
index d34ae060fd..b94d5ac826 100644
--- a/packages/form-dmn/src/uniforms/DmnAutoFieldProvider.tsx
+++ b/packages/form-dmn/src/uniforms/DmnAutoFieldProvider.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { AutoField, AutoFields } from "uniforms-patternfly";
+import { AutoField, AutoFields } from "@kie-tools/uniforms-patternfly/dist/esm";
import { DmnFeelContextField } from "./DmnFeelContextField";
import * as React from "react";
import { FEEL_CONTEXT } from "./DmnFormJsonSchemaBridge";
diff --git a/packages/form-dmn/tests/DmnForm.test.tsx b/packages/form-dmn/tests/DmnForm.test.tsx
index 27a2d6e3a7..47470c10ee 100644
--- a/packages/form-dmn/tests/DmnForm.test.tsx
+++ b/packages/form-dmn/tests/DmnForm.test.tsx
@@ -58,7 +58,7 @@ describe("DmnForm tests", () => {
const { findByTestId } = render(<DmnForm {...newProps} />);
- expect(await findByTestId("base-form")).toMatchSnapshot();
+ expect(await findByTestId("form-base")).toMatchSnapshot();
});
it("should submit the formData", async () => {
@@ -68,7 +68,7 @@ describe("DmnForm tests", () => {
const { findByTestId } = render(<DmnForm {...props} onSubmit={onSubmit} formRef={formRef} formInputs={formData} />);
- expect(await findByTestId("base-form")).toMatchSnapshot();
+ expect(await findByTestId("form-base")).toMatchSnapshot();
await act(async () => {
formRef.current?.submit();
@@ -84,7 +84,7 @@ describe("DmnForm tests", () => {
const { findByTestId } = render(<DmnForm {...props} onSubmit={onSubmit} formRef={formRef} formInputs={formData} />);
- expect(await findByTestId("base-form")).toMatchSnapshot();
+ expect(await findByTestId("form-base")).toMatchSnapshot();
await act(async () => {
formRef.current?.submit();
@@ -102,7 +102,7 @@ describe("DmnForm tests", () => {
<DmnForm {...props} formRef={formRef} onValidate={onValidate} formInputs={formData} />
);
- expect(await findByTestId("base-form")).toMatchSnapshot();
+ expect(await findByTestId("form-base")).toMatchSnapshot();
await act(async () => {
formRef.current?.submit();
@@ -120,7 +120,7 @@ describe("DmnForm tests", () => {
<DmnForm {...props} formRef={formRef} onValidate={onValidate} formInputs={formData} />
);
- expect(await findByTestId("base-form")).toMatchSnapshot();
+ expect(await findByTestId("form-base")).toMatchSnapshot();
await act(async () => {
formRef.current?.submit();
diff --git a/packages/form-dmn/tests/__snapshots__/DmnForm.test.tsx.snap b/packages/form-dmn/tests/__snapshots__/DmnForm.test.tsx.snap
index ad6e340733..03d8a34534 100644
--- a/packages/form-dmn/tests/__snapshots__/DmnForm.test.tsx.snap
+++ b/packages/form-dmn/tests/__snapshots__/DmnForm.test.tsx.snap
@@ -19,15 +19,17 @@ exports[`DmnForm tests should have placeholder 1`] = `
exports[`DmnForm tests should remove require parameter 1`] = `
<div>
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -53,6 +55,7 @@ exports[`DmnForm tests should remove require parameter 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-22"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0007-0001"
name="name"
placeholder=""
@@ -70,15 +73,17 @@ exports[`DmnForm tests should remove require parameter 1`] = `
exports[`DmnForm tests should render the DMN Form 1`] = `
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -104,6 +109,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-1"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0000-0001"
name="name"
placeholder=""
@@ -115,6 +121,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -140,6 +147,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-2"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0000-0003"
name="lastName"
placeholder=""
@@ -151,6 +159,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -176,6 +185,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-3"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0000-0005"
name="daysAndTimeDuration"
placeholder=""
@@ -187,6 +197,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -212,6 +223,7 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-4"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0000-0007"
name="yearsAndMonthDuration"
placeholder=""
@@ -228,15 +240,17 @@ exports[`DmnForm tests should render the DMN Form 1`] = `
exports[`DmnForm tests should submit the formData 1`] = `
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -262,6 +276,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-5"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0001-0001"
name="name"
placeholder=""
@@ -273,6 +288,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -298,6 +314,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-6"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0001-0003"
name="lastName"
placeholder=""
@@ -309,6 +326,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -334,6 +352,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-7"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0001-0005"
name="daysAndTimeDuration"
placeholder=""
@@ -345,6 +364,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -370,6 +390,7 @@ exports[`DmnForm tests should submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-8"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0001-0007"
name="yearsAndMonthDuration"
placeholder=""
@@ -386,15 +407,17 @@ exports[`DmnForm tests should submit the formData 1`] = `
exports[`DmnForm tests should validate the formData - invalid 1`] = `
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -420,6 +443,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-17"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0004-0001"
name="name"
placeholder=""
@@ -431,6 +455,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -456,6 +481,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-18"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0004-0003"
name="lastName"
placeholder=""
@@ -467,6 +493,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -492,6 +519,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-19"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0004-0005"
name="daysAndTimeDuration"
placeholder=""
@@ -509,6 +537,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -534,6 +563,7 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-20"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0004-0007"
name="yearsAndMonthDuration"
placeholder=""
@@ -550,15 +580,17 @@ exports[`DmnForm tests should validate the formData - invalid 1`] = `
exports[`DmnForm tests should validate the formData - success 1`] = `
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -584,6 +616,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-13"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0003-0001"
name="name"
placeholder=""
@@ -595,6 +628,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -620,6 +654,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-14"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0003-0003"
name="lastName"
placeholder=""
@@ -631,6 +666,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -656,6 +692,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-15"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0003-0005"
name="daysAndTimeDuration"
placeholder=""
@@ -667,6 +704,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -692,6 +730,7 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-16"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0003-0007"
name="yearsAndMonthDuration"
placeholder=""
@@ -708,15 +747,17 @@ exports[`DmnForm tests should validate the formData - success 1`] = `
exports[`DmnForm tests shouldn't submit the formData 1`] = `
<div
- data-testid="base-form"
+ data-testid="form-base"
>
<form
class="pf-c-form"
+ data-testid="base-form"
novalidate=""
>
<div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -742,6 +783,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-9"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0002-0001"
name="name"
placeholder=""
@@ -753,6 +795,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -778,6 +821,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-10"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0002-0003"
name="lastName"
placeholder=""
@@ -789,6 +833,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -814,6 +859,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-11"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0002-0005"
name="daysAndTimeDuration"
placeholder=""
@@ -831,6 +877,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
</div>
<div
class="pf-c-form__group"
+ data-testid="wrapper-field"
>
<div
class="pf-c-form__group-label"
@@ -856,6 +903,7 @@ exports[`DmnForm tests shouldn't submit the formData 1`] = `
data-ouia-component-id="OUIA-Generated-TextInputBase-12"
data-ouia-component-type="PF4/TextInput"
data-ouia-safe="true"
+ data-testid="text-field"
id="uniforms-0002-0007"
name="yearsAndMonthDuration"
placeholder=""
diff --git a/packages/form-generation-tool/package.json b/packages/form-generation-tool/package.json
index d61d7b11b6..bc640fd276 100644
--- a/packages/form-generation-tool/package.json
+++ b/packages/form-generation-tool/package.json
@@ -32,8 +32,8 @@
"@kie-tools/uniforms-patternfly-codegen": "workspace:*",
"inquirer": "^8.1.1",
"lodash": "^4.17.21",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/form/package.json b/packages/form/package.json
index bbbf464777..57d5a6236e 100644
--- a/packages/form/package.json
+++ b/packages/form/package.json
@@ -27,6 +27,7 @@
"@kie-tools-core/i18n": "workspace:*",
"@kie-tools-core/notifications": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
+ "@kie-tools/uniforms-patternfly": "workspace:*",
"@patternfly/react-core": "^4.157.3",
"@patternfly/react-icons": "^4.11.17",
"ajv": "^6.12.6",
@@ -35,9 +36,8 @@
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5",
- "uniforms-patternfly": "^4.7.9"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/form/src/FormBase.tsx b/packages/form/src/FormBase.tsx
index f91d3aff19..02fe94c9ca 100644
--- a/packages/form/src/FormBase.tsx
+++ b/packages/form/src/FormBase.tsx
@@ -16,7 +16,7 @@
import { AutoGenerationErrorFormStatus, EmptyFormStatus, FormStatus, ValidatorErrorFormStatus } from "./FormStatus";
import { ErrorBoundary } from "./ErrorBoundary";
-import AutoForm from "uniforms-patternfly/dist/es6/AutoForm";
+import AutoForm from "@kie-tools/uniforms-patternfly/dist/esm/AutoForm";
import * as React from "react";
import { FormI18n } from "./i18n";
import { FormJsonSchemaBridge } from "./uniforms/FormJsonSchemaBridge";
@@ -55,7 +55,7 @@ export function FormBase(props: React.PropsWithChildren<FormBaseProps>) {
)}
{props.formStatus === FormStatus.EMPTY && <EmptyFormStatus i18n={props.i18n} />}
{props.formStatus === FormStatus.WITHOUT_ERROR && (
- <div data-testid={"base-form"}>
+ <div data-testid={"form-base"}>
<ErrorBoundary
ref={props.errorBoundaryRef}
setHasError={props.setFormError}
diff --git a/packages/kn-plugin-workflow/README.md b/packages/kn-plugin-workflow/README.md
index 21bc65ed5e..8ac70a2d76 100644
--- a/packages/kn-plugin-workflow/README.md
+++ b/packages/kn-plugin-workflow/README.md
@@ -10,7 +10,7 @@ All the commands in this section should be performed in the monorepo root.
### Prerequisites
-- Node `>= 16.13.2` _(To install, follow these instructions: https://nodejs.org/en/download/package-manager/)_
+- Node `>= 18.14.0` _(To install, follow these instructions: https://nodejs.org/en/download/package-manager/)_
- pnpm `7.26.3` _(To install, follow these instructions: https://pnpm.io/installation)_
- Go `1.19` _(To install, follow these instructions: https://go.dev/doc/install)_
diff --git a/packages/online-editor/src/devDeployments/DevDeploymentsDropdown.tsx b/packages/online-editor/src/devDeployments/DevDeploymentsDropdown.tsx
index 5b99e47485..1ce7260702 100644
--- a/packages/online-editor/src/devDeployments/DevDeploymentsDropdown.tsx
+++ b/packages/online-editor/src/devDeployments/DevDeploymentsDropdown.tsx
@@ -193,14 +193,14 @@ export function DevDeploymentsDropdown() {
}
} else {
return [
- <>
+ <div key={"empty-deployments"}>
<EmptyState>
<EmptyStateIcon icon={PficonSatelliteIcon} />
<Title headingLevel="h4" size="md" style={{ color: "darkgray" }}>
{`Choose a Cloud provider to see your Dev deployments.`}
</Title>
</EmptyState>
- </>,
+ </div>,
];
}
}, [authSession, deleteAllDeployments, deployments.data, deployments.status, i18n]);
diff --git a/packages/online-editor/src/index.tsx b/packages/online-editor/src/index.tsx
index 6a601443be..706e521e06 100644
--- a/packages/online-editor/src/index.tsx
+++ b/packages/online-editor/src/index.tsx
@@ -20,15 +20,12 @@ import * as ReactDOM from "react-dom";
import { App } from "./App";
import "../static/resources/style.css";
import * as incompatibleBrowser from "./workspace/startupBlockers/IncompatibleBrowser";
-import * as fsChanged from "./workspace/startupBlockers/FsChanged";
async function main() {
const appContainer = document.getElementById("app")!;
if (await incompatibleBrowser.isTrue()) {
ReactDOM.render(<incompatibleBrowser.Component />, appContainer);
- } else if (await fsChanged.isTrue()) {
- ReactDOM.render(<fsChanged.Component />, appContainer);
} else {
ReactDOM.render(<App />, appContainer);
}
diff --git a/packages/online-editor/src/workspace/startupBlockers/FsChanged.tsx b/packages/online-editor/src/workspace/startupBlockers/FsChanged.tsx
deleted file mode 100644
index 980aac6d25..0000000000
--- a/packages/online-editor/src/workspace/startupBlockers/FsChanged.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import * as React from "react";
-import { useState } from "react";
-import { Modal } from "@patternfly/react-core/dist/js/components/Modal";
-import { ModalVariant } from "@patternfly/react-core/dist/esm/components/Modal";
-import { Button } from "@patternfly/react-core/dist/js/components/Button";
-import ExternalLinkSquareAltIcon from "@patternfly/react-icons/dist/esm/icons/external-link-square-alt-icon";
-import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
-import { StartupBlockerTemplate } from "./StartupBlockerTemplate";
-import { KieIcon } from "./KieIcon";
-import { LATEST_VERSION_COMPATIBLE_WITH_LFS } from "./LatestCompatibleVersion";
-
-const OLD_WORKSPACES_IDB_NAME = "workspaces";
-
-export async function isTrue() {
- const dbs = await indexedDB.databases();
- return dbs.map((db) => db.name).indexOf(OLD_WORKSPACES_IDB_NAME) > 0;
-}
-
-export function Component() {
- const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false);
- const [isDeleting, setDeleting] = useState(false);
-
- return (
- <StartupBlockerTemplate>
- <Modal
- variant={ModalVariant.small}
- isOpen={isDeleteConfirmationModalOpen}
- showClose={false}
- titleIconVariant={KieIcon}
- title={"Please confirm deleting everything"}
- actions={[
- <Button
- key="delete-everything"
- variant="primary"
- isLarge={true}
- style={{ width: "50%", backgroundColor: "var(--pf-c-button--m-danger--BackgroundColor)" }}
- isLoading={isDeleting}
- onClick={async () => {
- setDeleting(true);
- await Promise.all(
- (await indexedDB.databases())
- .filter((db) => db.name)
- .map(async (db) => indexedDB.deleteDatabase(db.name!))
- );
- window.location.reload();
- }}
- >
- Delete everything
- <br />
- and start fresh
- </Button>,
- <Button
- key="latest-version"
- variant="tertiary"
- iconPosition="right"
- style={{ width: "50%" }}
- icon={<ExternalLinkSquareAltIcon />}
- isLarge={true}
- onClick={() => {
- window.open(LATEST_VERSION_COMPATIBLE_WITH_LFS);
- }}
- >
- Open latest
- <br />
- compatible version
- </Button>,
- ]}
- >
- <br />
- <TextContent>
- <Text component={TextVariants.h4}>This action cannot be undone.</Text>
- </TextContent>
- <br />
- <hr />
- <br />
- Continuing will delete all models you have saved on this browser. Please certify that your work is already
- persisted somewhere else.
- <br />
- <br />
- {`If you're not sure, proceed to the latest compatible version to push or download your models.`}
- </Modal>
- <Modal
- showClose={false}
- isOpen={!isDeleteConfirmationModalOpen}
- variant={ModalVariant.small}
- title={"Oops!"}
- titleIconVariant={KieIcon}
- actions={[
- <Button
- key="delete-everything"
- variant="primary"
- isLarge={true}
- style={{ width: "50%" }}
- onClick={() => setDeleteConfirmationModalOpen(true)}
- >
- Delete everything
- <br />
- and start fresh
- </Button>,
- <Button
- key="latest-version"
- variant="secondary"
- iconPosition="right"
- style={{ width: "50%" }}
- icon={<ExternalLinkSquareAltIcon />}
- isLarge={true}
- onClick={() => {
- window.open(LATEST_VERSION_COMPATIBLE_WITH_LFS);
- }}
- >
- Open latest
- <br />
- compatible version
- </Button>,
- ]}
- >
- <br />
- <TextContent>
- <Text component={TextVariants.h4}>KIE Sandbox has changed the way it saves your models.</Text>
- </TextContent>
- <br />
- <hr />
- <br />
- {`If you have work that is not saved outside of this browser yet, proceed to the latest compatible version to push or download your models.`}
- <br />
- <br />
- {`If your work is already safe somewhere else, start fresh by deleting the old models.`}
- <br />
- </Modal>
- </StartupBlockerTemplate>
- );
-}
diff --git a/packages/online-editor/src/workspace/startupBlockers/IncompatibleBrowser.tsx b/packages/online-editor/src/workspace/startupBlockers/IncompatibleBrowser.tsx
index 033afe714f..81d95665b3 100644
--- a/packages/online-editor/src/workspace/startupBlockers/IncompatibleBrowser.tsx
+++ b/packages/online-editor/src/workspace/startupBlockers/IncompatibleBrowser.tsx
@@ -22,7 +22,8 @@ import * as Bowser from "bowser";
import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
import { List, ListItem } from "@patternfly/react-core/dist/js/components/List";
import { KieIcon } from "./KieIcon";
-import { LATEST_VERSION_COMPATIBLE_WITH_LFS } from "./LatestCompatibleVersion";
+
+export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.23.0";
const hasNecessaryApis = window["SharedWorker"] && window["BroadcastChannel"];
const isCompatibleBrowser = Bowser.getParser(window.navigator.userAgent).satisfies({
diff --git a/packages/serverless-logic-web-tools/src/index.tsx b/packages/serverless-logic-web-tools/src/index.tsx
index db8f193bdd..27441046d8 100644
--- a/packages/serverless-logic-web-tools/src/index.tsx
+++ b/packages/serverless-logic-web-tools/src/index.tsx
@@ -22,15 +22,12 @@ import { App } from "./App";
import "../static/resources/style.css";
import "../static/resources/application-services.css";
import * as incompatibleBrowser from "./workspace/startupBlockers/IncompatibleBrowser";
-import * as fsChanged from "./workspace/startupBlockers/FsChanged";
async function main() {
const appContainer = document.getElementById("app")!;
if (await incompatibleBrowser.isTrue()) {
ReactDOM.render(<incompatibleBrowser.Component />, appContainer);
- } else if (await fsChanged.isTrue()) {
- ReactDOM.render(<fsChanged.Component />, appContainer);
} else {
ReactDOM.render(<App />, appContainer);
}
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/FsChanged.tsx b/packages/serverless-logic-web-tools/src/workspace/startupBlockers/FsChanged.tsx
deleted file mode 100644
index 29200a6a01..0000000000
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/FsChanged.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import * as React from "react";
-import { useState } from "react";
-import { Modal } from "@patternfly/react-core/dist/js/components/Modal";
-import { ModalVariant } from "@patternfly/react-core/dist/esm/components/Modal";
-import { Button } from "@patternfly/react-core/dist/js/components/Button";
-import ExternalLinkSquareAltIcon from "@patternfly/react-icons/dist/esm/icons/external-link-square-alt-icon";
-import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
-import { StartupBlockerTemplate } from "./StartupBlockerTemplate";
-import { KieIcon } from "./KieIcon";
-import { LATEST_VERSION_COMPATIBLE_WITH_LFS } from "./LatestCompatibleVersion";
-import { APP_NAME } from "../../AppConstants";
-import Dexie from "dexie";
-
-const OLD_WORKSPACES_IDB_NAME = "workspaces";
-
-export async function isTrue() {
- return await Dexie.exists(OLD_WORKSPACES_IDB_NAME);
-}
-
-export function Component() {
- const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false);
- const [isDeleting, setDeleting] = useState(false);
-
- return (
- <StartupBlockerTemplate>
- <Modal
- variant={ModalVariant.medium}
- isOpen={isDeleteConfirmationModalOpen}
- showClose={false}
- titleIconVariant={KieIcon}
- title={"Please confirm deleting everything"}
- actions={[
- <Button
- key="delete-everything"
- variant="primary"
- isLarge={true}
- style={{ width: "50%", backgroundColor: "var(--pf-c-button--m-danger--BackgroundColor)" }}
- isLoading={isDeleting}
- onClick={async () => {
- setDeleting(true);
- await Promise.all((await Dexie.getDatabaseNames()).map(async (dbName) => Dexie.delete(dbName)));
- window.location.reload();
- }}
- >
- Delete everything
- <br />
- and start fresh
- </Button>,
- <Button
- key="latest-version"
- variant="tertiary"
- iconPosition="right"
- style={{ width: "50%" }}
- icon={<ExternalLinkSquareAltIcon />}
- isLarge={true}
- onClick={() => {
- window.open(LATEST_VERSION_COMPATIBLE_WITH_LFS);
- }}
- >
- Open latest
- <br />
- compatible version
- </Button>,
- ]}
- >
- <br />
- <TextContent>
- <Text component={TextVariants.h4}>This action cannot be undone.</Text>
- </TextContent>
- <br />
- <hr />
- <br />
- Continuing will delete all models you have saved on this browser. Please certify that your work is already
- persisted somewhere else.
- <br />
- <br />
- {`If you're not sure, proceed to the latest compatible version to push or download your models.`}
- </Modal>
- <Modal
- showClose={false}
- isOpen={!isDeleteConfirmationModalOpen}
- variant={ModalVariant.medium}
- title={"Oops!"}
- titleIconVariant={KieIcon}
- actions={[
- <Button
- key="delete-everything"
- variant="primary"
- isLarge={true}
- style={{ width: "50%" }}
- onClick={() => setDeleteConfirmationModalOpen(true)}
- >
- Delete everything
- <br />
- and start fresh
- </Button>,
- <Button
- key="latest-version"
- variant="secondary"
- iconPosition="right"
- style={{ width: "50%" }}
- icon={<ExternalLinkSquareAltIcon />}
- isLarge={true}
- onClick={() => {
- window.open(LATEST_VERSION_COMPATIBLE_WITH_LFS);
- }}
- >
- Open latest
- <br />
- compatible version
- </Button>,
- ]}
- >
- <br />
- <TextContent>
- <Text component={TextVariants.h4}>{`${APP_NAME} has changed the way it saves your models.`}</Text>
- </TextContent>
- <br />
- <hr />
- <br />
- {`If you have work that is not saved outside of this browser yet, proceed to the latest compatible version to push or download your models.`}
- <br />
- <br />
- {`If your work is already safe somewhere else, start fresh by deleting the old models.`}
- <br />
- </Modal>
- </StartupBlockerTemplate>
- );
-}
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/IncompatibleBrowser.tsx b/packages/serverless-logic-web-tools/src/workspace/startupBlockers/IncompatibleBrowser.tsx
index db9742e797..1f3af7c7bd 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/IncompatibleBrowser.tsx
+++ b/packages/serverless-logic-web-tools/src/workspace/startupBlockers/IncompatibleBrowser.tsx
@@ -21,10 +21,11 @@ import { StartupBlockerTemplate } from "./StartupBlockerTemplate";
import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
import { List, ListItem } from "@patternfly/react-core/dist/js/components/List";
import { KieIcon } from "./KieIcon";
-import { LATEST_VERSION_COMPATIBLE_WITH_LFS } from "./LatestCompatibleVersion";
import { APP_NAME } from "../../AppConstants";
import { BROWSER_DETAILS, SUPPORTED_BROWSERS } from "./SupportedBrowsers";
+export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+
export async function isTrue() {
return !BROWSER_DETAILS.isCompatible;
}
diff --git a/packages/serverless-workflow-diagram-editor/lienzo-core/src/main/java/com/ait/lienzo/client/core/shape/toolbox/items/tooltip/Tooltip.java b/packages/serverless-workflow-diagram-editor/lienzo-core/src/main/java/com/ait/lienzo/client/core/shape/toolbox/items/tooltip/Tooltip.java
index 9a46dc5221..9121cd0bbd 100644
--- a/packages/serverless-workflow-diagram-editor/lienzo-core/src/main/java/com/ait/lienzo/client/core/shape/toolbox/items/tooltip/Tooltip.java
+++ b/packages/serverless-workflow-diagram-editor/lienzo-core/src/main/java/com/ait/lienzo/client/core/shape/toolbox/items/tooltip/Tooltip.java
@@ -26,6 +26,7 @@ import com.ait.lienzo.client.core.shape.Group;
import com.ait.lienzo.client.core.shape.IPrimitive;
import com.ait.lienzo.client.core.shape.MultiPath;
import com.ait.lienzo.client.core.shape.Text;
+import com.ait.lienzo.client.core.shape.TextLineBreakWrap;
import com.ait.lienzo.client.core.types.BoundingBox;
import com.ait.lienzo.client.core.types.Point2D;
import com.ait.lienzo.shared.core.types.Direction;
@@ -53,6 +54,7 @@ public class Tooltip {
new Text("")
.setFillColor(TEXT_COLOR).
setStrokeWidth(TEXT_STROKE_WIDTH);
+ this.text.setWrapper(new TextLineBreakWrap(this.text));
this.group =
new Group()
.setAlpha(0)
@@ -213,7 +215,7 @@ public class Tooltip {
case WEST:
path.setRotationDegrees(180);
textLoc.setX(-hl - tpw - tw)
- .setY((th / 2) - tph);
+ .setY(((th / 2) - tph) * -1);
break;
case NORTH:
path.setRotationDegrees(270);
@@ -228,7 +230,7 @@ public class Tooltip {
default:
path.setRotationDegrees(0);
textLoc.setX(hl + tpw)
- .setY((th / 2) - tph);
+ .setY(((th / 2) - tph) * -1);
}
// Location.
diff --git a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/BasicWiresExample.java b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/BasicWiresExample.java
index 143538687c..776dc14a40 100644
--- a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/BasicWiresExample.java
+++ b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/BasicWiresExample.java
@@ -10,6 +10,8 @@ import com.ait.lienzo.client.core.shape.wires.WiresContainer;
import com.ait.lienzo.client.core.shape.wires.WiresManager;
import com.ait.lienzo.client.core.shape.wires.WiresShape;
import com.ait.lienzo.client.core.types.Point2D;
+import com.ait.lienzo.shared.core.types.EventPropagationMode;
+import com.ait.lienzo.tools.client.event.HandlerRegistration;
import static org.kie.lienzo.client.util.WiresUtils.connect;
@@ -19,12 +21,11 @@ public class BasicWiresExample extends BaseExample implements Example {
public static final String BLUE_RECTANGLE = "blueRectangle";
public static final String CIRCLE = "circle";
public static final String PARENT = "parent";
-
+ private HandlerRegistration redRectangleMouseEnterHandler;
+ private HandlerRegistration redRectangleMouseExitHandler;
+ private HandlerRegistration parentMouseEnterHandler;
+ private HandlerRegistration parentMouseExitHandler;
private WiresManager wiresManager;
- private WiresShape shapeRedRectangle;
- private WiresShape shapeCircle;
- private WiresShape shapeBlueRectangle;
- private WiresShape shapeParent;
public BasicWiresExample(final String title) {
super(title);
@@ -51,29 +52,44 @@ public class BasicWiresExample extends BaseExample implements Example {
wiresManager.setLocationAcceptor(ILocationAcceptor.ALL);
wiresManager.setControlPointsAcceptor(IControlPointsAcceptor.ALL);
- shapeRedRectangle = createShape(RED_RECTANGLE,
- new MultiPath().rect(0, 0, 100, 100)
- .setStrokeColor("#FF0000")
- .setFillColor("#FF0000"),
- new Point2D(100, 50));
-
- shapeCircle = createShape(CIRCLE,
- new MultiPath().circle(50)
- .setStrokeColor("#FF0000")
- .setFillColor("#FF0000"),
- new Point2D(400, 50));
-
- shapeBlueRectangle = createShape(BLUE_RECTANGLE,
- new MultiPath().rect(0, 0, 100, 100)
- .setStrokeColor("#0000FF")
- .setFillColor("#0000FF"),
- new Point2D(650, 50));
-
- shapeParent = createShape(PARENT,
- new MultiPath().rect(0, 0, 600, 250)
- .setStrokeColor("#000000")
- .setFillColor("#FFFFFF"),
- new Point2D(50, 300));
+ MultiPath redRectangle = new MultiPath().rect(0, 0, 100, 100)
+ .setStrokeColor("#FF0000")
+ .setFillColor("#FF0000");
+ redRectangleMouseEnterHandler = redRectangle.addNodeMouseEnterHandler(event -> {
+ console.log("red rectangle ENTER");
+ });
+ redRectangleMouseExitHandler = redRectangle.addNodeMouseExitHandler(event -> {
+ console.log("red rectangle EXIT");
+ });
+ redRectangle.setEventPropagationMode(EventPropagationMode.LAST_ANCESTOR);
+ WiresShape shapeRedRectangle = createShape(RED_RECTANGLE,
+ redRectangle,
+ new Point2D(100, 50));
+
+ WiresShape shapeCircle = createShape(CIRCLE,
+ new MultiPath().circle(50)
+ .setStrokeColor("#FF0000")
+ .setFillColor("#FF0000"),
+ new Point2D(400, 50));
+
+ WiresShape shapeBlueRectangle = createShape(BLUE_RECTANGLE,
+ new MultiPath().rect(0, 0, 100, 100)
+ .setStrokeColor("#0000FF")
+ .setFillColor("#0000FF"),
+ new Point2D(650, 50));
+
+ MultiPath parent = new MultiPath().rect(0, 0, 600, 250)
+ .setStrokeColor("#000000")
+ .setFillColor("#FFFFFF");
+ parentMouseEnterHandler = parent.addNodeMouseEnterHandler(event -> {
+ console.log("PARENT ENTER");
+ });
+ parentMouseExitHandler = parent.addNodeMouseExitHandler(event -> {
+ console.log("PARENT EXIT");
+ });
+ WiresShape shapeParent = createShape(PARENT,
+ parent,
+ new Point2D(50, 300));
connect(shapeRedRectangle.getMagnets(),
3,
@@ -126,4 +142,13 @@ public class BasicWiresExample extends BaseExample implements Example {
}
return true;
}
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ redRectangleMouseEnterHandler.removeHandler();
+ redRectangleMouseExitHandler.removeHandler();
+ parentMouseEnterHandler.removeHandler();
+ parentMouseExitHandler.removeHandler();
+ }
}
diff --git a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/EventExample.java b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/EventExample.java
index 2ca9b43891..b5bf359acf 100644
--- a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/EventExample.java
+++ b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/EventExample.java
@@ -31,10 +31,13 @@ import com.ait.lienzo.client.core.shape.Triangle;
import com.ait.lienzo.client.core.types.Point2D;
import com.ait.lienzo.gwtlienzo.event.shared.EventHandler;
import com.ait.lienzo.shared.core.types.ColorName;
+import com.ait.lienzo.shared.core.types.EventPropagationMode;
import org.kie.lienzo.client.util.Console;
public class EventExample extends BaseExample implements Example {
+ MultiPath container;
+
public EventExample(final String title) {
super(title);
}
@@ -56,16 +59,26 @@ public class EventExample extends BaseExample implements Example {
}
private void createDragTests() {
- Rectangle rect = new Rectangle(500, 200);
- rect.setX(50).setY(50);
- rect.setFillColor(ColorName.PALEVIOLETRED);
- rect.setStrokeColor(ColorName.PALEVIOLETRED);
- rect.setDraggable(true);
- layer.add(rect);
-
- addHandlers(rect, NodeDragStartHandler.class, NodeDragMoveHandler.class, NodeDragEndHandler.class);
-
- rect = new Rectangle(100, 100);
+ container = new MultiPath().rect(50, 50, 500, 200);
+ container.setID("Container");
+ container.setX(50).setY(50);
+ container.setFillColor(ColorName.PALEVIOLETRED);
+ container.setStrokeColor(ColorName.PALEVIOLETRED);
+ container.setEventPropagationMode(EventPropagationMode.NO_ANCESTORS);
+ container.setDraggable(true);
+ layer.add(container);
+
+ addHandlers(container,
+ NodeDragStartHandler.class,
+ NodeDragMoveHandler.class,
+ NodeDragEndHandler.class,
+ NodeMouseClickHandler.class,
+ NodeMouseEnterHandler.class,
+ NodeMouseExitHandler.class,
+ NodeMouseOutHandler.class,
+ NodeMouseOverHandler.class);
+
+ Rectangle rect = new Rectangle(100, 100);
rect.setX(250).setY(100);
rect.setFillColor(ColorName.DARKGRAY);
rect.setStrokeColor(ColorName.DARKGRAY);
@@ -77,13 +90,15 @@ public class EventExample extends BaseExample implements Example {
private void createMouseEnterExitTests() {
Circle circ = new Circle(50);
+ circ.setID("YELLOWGREEN circle");
circ.setX(150).setY(150);
circ.setFillColor(ColorName.YELLOWGREEN);
circ.setStrokeColor(ColorName.YELLOWGREEN);
- circ.setDraggable(true);
+ circ.setEventPropagationMode(EventPropagationMode.FIRST_ANCESTOR);
+ circ.setDraggable(false);
layer.add(circ);
- addHandlers(circ, NodeMouseEnterHandler.class, NodeMouseExitHandler.class);
+ addHandlers(circ, NodeMouseEnterHandler.class, NodeMouseExitHandler.class, NodeMouseClickHandler.class);
circ = new Circle(50);
circ.setX(150).setY(350);
@@ -208,57 +223,57 @@ public class EventExample extends BaseExample implements Example {
@Override
public void onNodeDragStart(final NodeDragStartEvent event) {
- console.log("drag start");
+ console.log(event.getSource().getID() + ": " + "drag start");
}
@Override
public void onNodeDragMove(final NodeDragMoveEvent event) {
- console.log("drag move");
+ console.log(event.getSource().getID() + ": " + "drag move");
}
@Override
public void onNodeDragEnd(final NodeDragEndEvent event) {
- console.log("drag end");
+ console.log(event.getSource().getID() + ": " + "drag end");
}
@Override
public void onNodeMouseEnter(final NodeMouseEnterEvent event) {
- console.log("mouse enter");
+ console.log(event.getSource().getID() + ": " + "mouse enter");
}
@Override
public void onNodeMouseExit(final NodeMouseExitEvent event) {
- console.log("mouse exit");
+ console.log(event.getSource().getID() + ": " + "mouse exit");
}
@Override
public void onNodeMouseUp(final NodeMouseUpEvent event) {
- console.log("mouse up");
+ console.log(event.getSource().getID() + ": " + "mouse up");
}
@Override
public void onNodeMouseDown(final NodeMouseDownEvent event) {
- console.log("mouse down");
+ console.log(event.getSource().getID() + ": " + "mouse down");
}
@Override
public void onNodeMouseClick(final NodeMouseClickEvent event) {
- console.log("mouse click");
+ console.log(event.getSource().getID() + ": " + "mouse click");
}
@Override
public void onNodeMouseDoubleClick(final NodeMouseDoubleClickEvent event) {
- console.log("mouse double click");
+ console.log(event.getSource().getID() + ": " + "mouse double click");
}
@Override
public void onNodeMouseOver(final NodeMouseOverEvent event) {
- console.log("mouse over");
+ console.log(event.getSource().getID() + ": " + "mouse over");
}
@Override
public void onNodeMouseOut(final NodeMouseOutEvent event) {
- console.log("mouse out");
+ console.log(event.getSource().getID() + ": " + "mouse out");
}
}
}
diff --git a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/WiresDockingExample.java b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/WiresDockingExample.java
index 8301bada40..3757aa1336 100644
--- a/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/WiresDockingExample.java
+++ b/packages/serverless-workflow-diagram-editor/lienzo-webapp/src/main/java/org/kie/lienzo/client/WiresDockingExample.java
@@ -24,9 +24,6 @@ public class WiresDockingExample extends BaseExample implements Example {
@Override
public void run() {
-
-// getToolBarContainer().add(m_label);
-
final WiresManager wires_manager = WiresManager.get(layer);
wires_manager.setContainmentAcceptor(IContainmentAcceptor.ALL);
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ModelUtils.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ModelUtils.java
index 0e6fc851f3..68808ec05b 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ModelUtils.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ModelUtils.java
@@ -79,7 +79,6 @@ public class ModelUtils {
state.setName((String) Js.undefined());
state.setType((String) Js.undefined());
state.setTransition((String) Js.undefined());
- state.setEventTimeout((String) Js.undefined());
state.setCompensatedBy((String) Js.undefined());
state.setEnd(false);
if (null != state.getOnErrors()) {
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ParallelStateBranch.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ParallelStateBranch.java
index ed1c18ef02..90ecab16ad 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ParallelStateBranch.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/ParallelStateBranch.java
@@ -16,11 +16,7 @@
package org.kie.workbench.common.stunner.sw.definition;
-import jakarta.json.bind.annotation.JsonbTypeDeserializer;
-import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jsinterop.annotations.JsType;
-import org.kie.workbench.common.stunner.sw.definition.custom.WorkflowTimeoutsJsonDeserializer;
-import org.kie.workbench.common.stunner.sw.definition.custom.WorkflowTimeoutsJsonSerializer;
@JsType
public class ParallelStateBranch {
@@ -28,9 +24,7 @@ public class ParallelStateBranch {
private String name;
private ActionNode[] actions;
- @JsonbTypeSerializer(WorkflowTimeoutsJsonSerializer.class)
- @JsonbTypeDeserializer(WorkflowTimeoutsJsonDeserializer.class)
- private Object timeouts;
+ private WorkflowTimeouts timeouts;
public final String getName() {
return name;
@@ -48,11 +42,11 @@ public class ParallelStateBranch {
this.actions = actions;
}
- public final Object getTimeouts() {
+ public final WorkflowTimeouts getTimeouts() {
return timeouts;
}
- public final void setTimeouts(Object timeouts) {
+ public final void setTimeouts(WorkflowTimeouts timeouts) {
this.timeouts = timeouts;
}
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/State.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/State.java
index af2c38e2f3..15627ded35 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/State.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/State.java
@@ -35,13 +35,11 @@ import org.kie.workbench.common.stunner.sw.definition.custom.StateEndDefinitionJ
import org.kie.workbench.common.stunner.sw.definition.custom.StateEndDefinitionJsonbTypeSerializer;
import org.kie.workbench.common.stunner.sw.definition.custom.StateTransitionDefinitionJsonbTypeDeserializer;
import org.kie.workbench.common.stunner.sw.definition.custom.StateTransitionDefinitionJsonbTypeSerializer;
-import org.kie.workbench.common.stunner.sw.definition.custom.WorkflowTimeoutsJsonDeserializer;
-import org.kie.workbench.common.stunner.sw.definition.custom.WorkflowTimeoutsJsonSerializer;
/**
* This class defines workflow states define building blocks of the workflow execution instructions.
* They define the control flow logic instructions on what the workflow is supposed to do.
- *
+ * <p>
* Type of the state is specified by its category, which is set in constructor for all its descendants.
*/
@Bindable
@@ -94,11 +92,6 @@ public class State {
*/
private ErrorTransition[] onErrors;
- /**
- * State specific timeouts.
- */
- private String eventTimeout;
-
/**
* Unique name of a workflow state which is responsible for compensation of this state.
*/
@@ -106,10 +99,7 @@ public class State {
private StateDataFilter stateDataFilter;
-
- @JsonbTypeSerializer(WorkflowTimeoutsJsonSerializer.class)
- @JsonbTypeDeserializer(WorkflowTimeoutsJsonDeserializer.class)
- private Object timeouts;
+ private WorkflowTimeouts timeouts;
public State() {
this.name = "State";
@@ -160,15 +150,6 @@ public class State {
return this;
}
- public String getEventTimeout() {
- return eventTimeout;
- }
-
- public State setEventTimeout(String eventTimeout) {
- this.eventTimeout = eventTimeout;
- return this;
- }
-
public String getCompensatedBy() {
return compensatedBy;
}
@@ -193,6 +174,7 @@ public class State {
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
+
public StateDataFilter getStateDataFilter() {
return stateDataFilter;
}
@@ -201,11 +183,11 @@ public class State {
this.stateDataFilter = stateDataFilter;
}
- public Object getTimeouts() {
+ public WorkflowTimeouts getTimeouts() {
return timeouts;
}
- public void setTimeouts(Object timeouts) {
+ public void setTimeouts(WorkflowTimeouts timeouts) {
this.timeouts = timeouts;
}
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/Timeout.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/Timeout.java
index b9a69ab74b..ce772a3105 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/Timeout.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/definition/Timeout.java
@@ -25,7 +25,6 @@ import org.kie.workbench.common.stunner.core.definition.annotation.definition.Ca
import org.kie.workbench.common.stunner.core.definition.annotation.definition.Labels;
import org.kie.workbench.common.stunner.core.definition.annotation.morph.MorphBase;
-// TODO: Timeouts are not being used for now, consider dropping all related classes and usages.
@MorphBase(defaultType = EventTimeout.class)
public class Timeout {
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshalling.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshalling.java
index cf89fee5a6..42241df6f3 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshalling.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/main/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshalling.java
@@ -34,7 +34,6 @@ import org.kie.workbench.common.stunner.sw.definition.ErrorTransition;
import org.kie.workbench.common.stunner.sw.definition.EventConditionTransition;
import org.kie.workbench.common.stunner.sw.definition.EventRef;
import org.kie.workbench.common.stunner.sw.definition.EventState;
-import org.kie.workbench.common.stunner.sw.definition.EventTimeout;
import org.kie.workbench.common.stunner.sw.definition.ForEachState;
import org.kie.workbench.common.stunner.sw.definition.OnEvent;
import org.kie.workbench.common.stunner.sw.definition.OperationState;
@@ -125,13 +124,6 @@ public interface StateMarshalling {
List<Edge> outEdges = stateNode.getOutEdges();
for (Edge edge : outEdges) {
if (edge.getContent() instanceof Dock) {
- Node timeoutNode = edge.getTargetNode();
- if (null != timeoutNode) {
- Object def = getElementDefinition(timeoutNode);
- if (def instanceof EventTimeout) {
- state.setEventTimeout(((EventTimeout) def).getEventTimeout());
- }
- }
} else {
Object def = getElementDefinition(edge);
if (def instanceof ErrorTransition) {
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/test/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshallingTest.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/test/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshallingTest.java
index 9bb96f9b7c..7eeb7b5a40 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/test/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshallingTest.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-api/src/test/java/org/kie/workbench/common/stunner/sw/marshall/StateMarshallingTest.java
@@ -63,9 +63,8 @@ public class StateMarshallingTest extends BaseMarshallingTest {
assertTrue(workflow.getStates()[0].getEnd() instanceof StateEnd);
final StateEnd end = (StateEnd) workflow.getStates()[0].getEnd();
assertTrue(end.getTerminate());
- assertEquals("{}",end.getContinueAs());
+ assertEquals("{}", end.getContinueAs());
assertFalse(end.getCompensate());
- //assertTrue(end.get("produceEvents").equals("[]"));
}
@Test
@@ -123,7 +122,6 @@ public class StateMarshallingTest extends BaseMarshallingTest {
assertNull(state1.getTransition());
assertFalse(DefinitionTypeUtils.getEnd(state1.getEnd()));
assertNull(state1.getCompensatedBy());
- assertNull(state1.getEventTimeout());
assertNull(state1.getOnErrors());
}
@@ -144,7 +142,6 @@ public class StateMarshallingTest extends BaseMarshallingTest {
assertNull(state1.getTransition());
assertFalse(DefinitionTypeUtils.getEnd(state1.getEnd()));
assertNull(state1.getCompensatedBy());
- assertNull(state1.getEventTimeout());
assertNotNull(state1.getOnErrors());
assertEquals(1, state1.getOnErrors().length);
ErrorTransition onError = state1.getOnErrors()[0];
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/ShapeFactory.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/ShapeFactory.java
index 592c452e14..f8527c2b1b 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/ShapeFactory.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/ShapeFactory.java
@@ -71,7 +71,7 @@ public class ShapeFactory
} else if (instance instanceof End) {
return new EndShape();
} else if (instance instanceof State) {
- return new StateShape((State) instance, resourceContentService);
+ return StateShape.create((State) instance, resourceContentService);
} else if (TransitionShape.isTransition(instance)) {
return TransitionShape.create(instance).setAppearance(instance);
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/CallbackStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/CallbackStateShape.java
new file mode 100644
index 0000000000..9f4f21b87f
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/CallbackStateShape.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.CallbackState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class CallbackStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#EC7A08";
+ public static final String ICON_SVG = "M63.97,36.13c0-2.13-1.64-3.95-3.76-4.07-2.31-.13-4.23,1.7-4.23,3.99,0,6.61-5.37,11.98-11.98,11.98H24.03v-4.99c0-1.18-.7-2.25-1.78-2.74-1.08-.47-2.34-.28-3.23,.52l-9.98,8.98c-.63,.56-.99,1.37-.99,2.22s.36,1.66,.99,2.23l9.98,8.98c.56,.51,1.28,.77,2,.77,.41,0,.83-.09,1.22-.26,1.08-.48,1.78-1.55,1.78-2.74v-4.99h19.97c10.98,0,19.92-8.91,19.97-19.89ZM20,16.08h19.85l.11,4.99c0,1.18,.7,2.25,1.78,2.74,.4,.17,.81,.26,1.11,.26,.73,0,1.44-.27,2.01-.77l9.98- [...]
+
+ public CallbackStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ CallbackState state = (CallbackState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "EventTimeout: " + state.getTimeouts().getEventTimeout() + "\r\n"
+ + "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout() + "\r\n"
+ + "ActionExecTimeout: " + state.getTimeouts().getActionExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShape.java
index 50d854263f..503a4404a2 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShape.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShape.java
@@ -16,11 +16,10 @@
package org.kie.workbench.common.stunner.sw.client.shapes;
-import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
-
-public class EndShape extends NodeShapeImpl {
+public class EndShape extends ServerlessWorkflowShape<EndShapeView> {
public EndShape() {
super(new EndShapeView().asAbstractShape());
+ getShape().getShapeView().setController(this);
}
}
\ No newline at end of file
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShapeView.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShapeView.java
index 61be9546d7..841eafce69 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShapeView.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EndShapeView.java
@@ -18,7 +18,7 @@ package org.kie.workbench.common.stunner.sw.client.shapes;
import com.ait.lienzo.client.core.shape.MultiPath;
-public class EndShapeView extends ServerlessWorkflowBasicShape<EndShapeView> {
+public class EndShapeView extends ServerlessWorkflowShapeView<EndShapeView> {
private final static int END_SHAPE_SIZE = 46;
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EventStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EventStateShape.java
new file mode 100644
index 0000000000..6a23a4ad98
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/EventStateShape.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.EventState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class EventStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#F4C145";
+ public static final String ICON_SVG = "M 45.254 45.197 L 36.216 45.197 L 42.206 31.792 C 42.613 30.98 42.307 29.965 41.597 29.355 C 40.887 28.746 39.768 28.849 39.06 29.457 L 19.561 45.705 C 18.953 46.215 18.646 47.128 18.953 47.939 C 19.258 48.754 19.968 49.262 20.883 49.262 L 29.921 49.262 L 23.928 62.667 C 23.521 63.478 23.825 64.493 24.538 65.103 C 24.943 65.51 25.247 65.609 25.756 65.609 C 26.263 65.609 26.67 65.406 27.076 65.103 L 46.573 48.854 C 47.183 48.347 47.488 47.431 47. [...]
+
+ public EventStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ EventState state = (EventState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "EventTimeout: " + state.getTimeouts().getEventTimeout() + "\r\n"
+ + "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout() + "\r\n"
+ + "ActionExecTimeout: " + state.getTimeouts().getActionExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ForEachStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ForEachStateShape.java
new file mode 100644
index 0000000000..05b0f81d14
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ForEachStateShape.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.ForEachState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class ForEachStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#8F4700";
+ public static final String ICON_SVG = "M64,32.22v27.24c0,2.34-1.91,4.49-4.24,4.65-2.68,.19-4.9-1.92-4.9-4.56v-27.43c0-2.64,2.22-4.75,4.9-4.56,2.34,.16,4.24,2.31,4.24,4.65M45.71,59.56c0,2.64-2.22,4.75-4.9,4.56-2.34-.16-4.24-2.31-4.24-4.65v-27.24c0-2.34,1.91-4.49,4.24-4.65,2.68-.19,4.9,1.92,4.9,4.56v27.43M27.43,4.79v27.24c0,2.34-1.91,4.49-4.24,4.65-2.68,.19-4.9-1.92-4.9-4.56V4.7C18.29,2.07,20.51-.04,23.18,.14c2.34,.16,4.24,2.31,4.24,4.65M9.14,32.13c0,2.64-2.22,4.75-4.9,4.56C1.91,36.53, [...]
+
+ public ForEachStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ ForEachState state = (ForEachState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout() + "\r\n"
+ + "ActionExecTimeout: " + state.getTimeouts().getActionExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/InjectStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/InjectStateShape.java
new file mode 100644
index 0000000000..f4620915d9
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/InjectStateShape.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class InjectStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#8BC1F7";
+ public static final String ICON_SVG = "M35.02,28.49s-.03-.03-.05-.04l-10.29-10.29c-1.78-1.78-4.68-1.79-6.46,0-1.79,1.79-1.78,4.68,0,6.46l2.81,2.81H4.57c-2.52,0-4.57,2.04-4.57,4.57s2.05,4.57,4.57,4.57H20.94l-2.75,2.75c-1.78,1.78-1.79,4.68,0,6.46s4.68,1.78,6.46,0l10.09-10.09c.28-.2,.54-.44,.77-.71,.5-.58,.82-1.27,.97-2,.37-1.59-.11-3.33-1.46-4.5M.01,4.23C.19,1.83,2.25,0,4.66,0H59.43c2.53,0,4.57,2.05,4.57,4.57s-2.04,4.57-4.57,4.57H4.57C1.93,9.14-.18,6.91,.01,4.23M46.09,18.29h13.24c2.34, [...]
+
+ public InjectStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/OperationStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/OperationStateShape.java
new file mode 100644
index 0000000000..59d1377091
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/OperationStateShape.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.OperationState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class OperationStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#0066CC";
+ public static final String ICON_SVG = "M61.99,20.83c.41,1.07,.06,2.29-.79,3.07l-5.41,4.93c.14,1.04,.21,2.1,.21,3.17s-.08,2.14-.21,3.17l5.41,4.92c.85,.79,1.2,2,.79,3.08-.55,1.49-1.21,2.92-1.96,4.29l-.59,1.01c-.83,1.38-1.75,2.68-2.76,3.91-.75,.89-1.96,1.2-3.06,.85l-6.96-2.22c-1.68,1.29-3.64,2.36-5.5,3.19l-1.56,7.14c-.25,1.12-1.12,1.92-2.28,2.22-1.72,.29-3.5,.44-5.42,.44-1.7,0-3.48-.15-5.2-.44-1.15-.3-2.02-1.1-2.27-2.22l-1.56-7.14c-1.98-.83-3.83-1.9-5.5-3.19l-6.96,2.22c-1.1,.35-2.32,.04 [...]
+
+ public OperationStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ OperationState state = (OperationState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout() + "\r\n"
+ + "ActionExecTimeout: " + state.getTimeouts().getActionExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ParallelStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ParallelStateShape.java
new file mode 100644
index 0000000000..c8f8448d4e
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ParallelStateShape.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.ParallelState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class ParallelStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#4CB140";
+ public static final String ICON_SVG = "M50.54,.01c2.34,.16,4.24,2.31,4.24,4.65V59.43c0,2.64-2.23,4.75-4.91,4.56-2.33-.17-4.23-2.31-4.23-4.65V4.57c0-2.63,2.22-4.75,4.9-4.56M13.46,63.99c-2.34-.16-4.24-2.31-4.24-4.65V4.57c0-2.52,2.04-4.57,4.57-4.57s4.57,2.05,4.57,4.57V59.43c0,2.64-2.22,4.75-4.9,4.56Z";
+
+ public ParallelStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ ParallelState state = (ParallelState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "BranchExecTimeout: " + state.getTimeouts().getBranchExecTimeout() + "\r\n"
+ + "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShape.java
new file mode 100644
index 0000000000..acd6097e67
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShape.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import com.ait.lienzo.client.core.event.NodeMouseEnterHandler;
+import com.ait.lienzo.client.core.event.NodeMouseExitHandler;
+import org.kie.workbench.common.stunner.core.client.shape.ShapeState;
+import org.kie.workbench.common.stunner.core.client.shape.impl.AbstractShape;
+import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
+import org.kie.workbench.common.stunner.core.client.shape.impl.ShapeStateHandler;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public abstract class ServerlessWorkflowShape<V extends ServerlessWorkflowShapeView> extends NodeShapeImpl<State, V> {
+
+ public ServerlessWorkflowShape(final AbstractShape shape) {
+ super(shape);
+ }
+
+ public NodeMouseExitHandler getExitHandler() {
+ return event -> {
+ if (getShapeStateHandler().getShapeState() == ShapeState.SELECTED) {
+ return;
+ }
+ getShapeStateHandler().applyState(ShapeState.NONE);
+ getShapeView().getShape().getLayer().batch();
+ };
+ }
+
+ public NodeMouseEnterHandler getEnterHandler() {
+ return event -> {
+ if (getShapeStateHandler().getShapeState() == ShapeState.SELECTED) {
+ return;
+ }
+ getShapeStateHandler().applyState(ShapeState.HIGHLIGHT);
+ getShapeView().getShape().getLayer().batch();
+ };
+ }
+
+ protected ShapeStateHandler getShapeStateHandler() {
+ return getShapeView().getShapeStateHandler();
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowBasicShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShapeView.java
similarity index 66%
rename from packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowBasicShape.java
rename to packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShapeView.java
index e173674522..d76deba61f 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowBasicShape.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/ServerlessWorkflowShapeView.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.kie.workbench.common.stunner.sw.client.shapes;
import com.ait.lienzo.client.core.event.NodeMouseEnterHandler;
@@ -12,12 +27,11 @@ import com.ait.lienzo.tools.client.event.HandlerRegistration;
import org.kie.workbench.common.stunner.client.lienzo.shape.impl.ShapeStateDefaultHandler;
import org.kie.workbench.common.stunner.client.lienzo.shape.view.ViewEventHandlerManager;
import org.kie.workbench.common.stunner.client.lienzo.shape.view.wires.ext.WiresShapeViewExt;
-import org.kie.workbench.common.stunner.core.client.shape.ShapeState;
import org.kie.workbench.common.stunner.core.client.shape.impl.AbstractShape;
import org.kie.workbench.common.stunner.core.client.shape.impl.ShapeStateHandler;
import org.kie.workbench.common.stunner.core.client.shape.view.event.ShapeViewSupportedEvents;
-public abstract class ServerlessWorkflowBasicShape<T extends ServerlessWorkflowBasicShape> extends WiresShapeViewExt<T> {
+public abstract class ServerlessWorkflowShapeView<VIEW extends ServerlessWorkflowShapeView<VIEW>> extends WiresShapeViewExt<VIEW> {
protected final static String SHAPE_STROKE_COLOR = "#ccc";
protected final static String SHAPE_FILL_COLOR = "#fff";
@@ -26,14 +40,16 @@ public abstract class ServerlessWorkflowBasicShape<T extends ServerlessWorkflowB
protected final static double SHAPE_TITLE_FONT_SIZE = 12.00;
protected final static String SHAPE_TITLE_FONT_FAMILY = "Open Sans";
+ private ServerlessWorkflowShape<VIEW> controller;
+
private ShapeStateDefaultHandler shapeStateHandler = new ShapeStateDefaultHandler().setBorderShape((() -> this))
.setBackgroundShape(() -> this);
- private final HandlerRegistration mouseEnterHandler;
+ private HandlerRegistration mouseEnterHandler;
- private final HandlerRegistration mouseExitHandler;
+ private HandlerRegistration mouseExitHandler;
- public ServerlessWorkflowBasicShape(MultiPath path, String title) {
+ public ServerlessWorkflowShapeView(MultiPath path, String title) {
this(path);
setTitle(title);
setTitlePosition(VerticalAlignment.MIDDLE, HorizontalAlignment.CENTER, ReferencePosition.INSIDE, Orientation.HORIZONTAL);
@@ -45,7 +61,7 @@ public abstract class ServerlessWorkflowBasicShape<T extends ServerlessWorkflowB
isTitleListening(false);
}
- public ServerlessWorkflowBasicShape(MultiPath path) {
+ public ServerlessWorkflowShapeView(MultiPath path) {
super(path
.setAlpha(1.00)
.setDraggable(false)
@@ -57,48 +73,46 @@ public abstract class ServerlessWorkflowBasicShape<T extends ServerlessWorkflowB
setEventHandlerManager(new ViewEventHandlerManager(getShape(), getShape(), ShapeViewSupportedEvents.ALL_DESKTOP_EVENT_TYPES));
getShape().setEventPropagationMode(EventPropagationMode.NO_ANCESTORS);
+ }
- NodeMouseEnterHandler enterEvent = event -> {
- if (shapeStateHandler.getShapeState() == ShapeState.SELECTED) {
- return;
- }
- shapeStateHandler.applyState(ShapeState.HIGHLIGHT);
- };
- mouseEnterHandler = getShape().addNodeMouseEnterHandler(enterEvent);
+ public void setController(ServerlessWorkflowShape<VIEW> controller) {
+ this.controller = controller;
+ mouseEnterHandler = getShape().addNodeMouseEnterHandler(getEnterHandler());
+ mouseExitHandler = getShape().addNodeMouseExitHandler(getExitHandler());
+ }
- NodeMouseExitHandler exitEvent = event -> {
- if (shapeStateHandler.getShapeState() == ShapeState.SELECTED) {
- return;
- }
- shapeStateHandler.applyState(ShapeState.NONE);
- };
- mouseExitHandler = getShape().addNodeMouseExitHandler(exitEvent);
+ public NodeMouseExitHandler getExitHandler() {
+ return controller.getExitHandler();
+ }
+
+ public NodeMouseEnterHandler getEnterHandler() {
+ return controller.getEnterHandler();
}
public ShapeStateHandler getShapeStateHandler() {
return shapeStateHandler;
}
- public AbstractShape<ServerlessWorkflowBasicShape> asAbstractShape() {
- return new AbstractShape<ServerlessWorkflowBasicShape>() {
+ public AbstractShape<ServerlessWorkflowShapeView<VIEW>> asAbstractShape() {
+ return new AbstractShape<ServerlessWorkflowShapeView<VIEW>>() {
@Override
public ShapeStateHandler getShapeStateHandler() {
- return ServerlessWorkflowBasicShape.this.getShapeStateHandler();
+ return ServerlessWorkflowShapeView.this.getShapeStateHandler();
}
@Override
public void setUUID(String uuid) {
- ServerlessWorkflowBasicShape.this.setUUID(uuid);
+ ServerlessWorkflowShapeView.this.setUUID(uuid);
}
@Override
public String getUUID() {
- return ServerlessWorkflowBasicShape.this.getUUID();
+ return ServerlessWorkflowShapeView.this.getUUID();
}
@Override
- public ServerlessWorkflowBasicShape getShapeView() {
- return ServerlessWorkflowBasicShape.this;
+ public ServerlessWorkflowShapeView<VIEW> getShapeView() {
+ return ServerlessWorkflowShapeView.this;
}
};
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SleepStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SleepStateShape.java
new file mode 100644
index 0000000000..d0d3bc45dd
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SleepStateShape.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.SleepState;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class SleepStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#5752D1";
+ public static final String ICON_SVG = "M54.24,53.11c3.71-4.77,5.92-10.77,5.92-17.28,0-15.56-12.61-28.17-28.17-28.17S3.83,20.27,3.83,35.83c0,6.49,2.19,12.46,5.87,17.22l-2.53,2.53c-1.63,1.63-1.8,4.46-.28,6.2,1.74,2,4.76,2.07,6.59,.24l2.8-2.8c4.49,3.02,9.9,4.79,15.71,4.79s11.17-1.75,15.65-4.74l2.75,2.75c1.63,1.63,4.46,1.8,6.2,.28,2-1.74,2.07-4.76,.24-6.59l-2.59-2.59Zm-13.09-8.11l-10.59-7.06c-.74-.4-1.18-1.22-1.18-2.11l-.1-15c0-1.47,1.28-2.65,2.65-2.65,1.57,0,2.75,1.18,2.75,2.65v13.58l9. [...]
+
+ public SleepStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ SleepState state = (SleepState) element.getContent().getDefinition();
+ getView().addChild(new CornerIcon(IconPath.CLOCK, "Duration: " + state.getDuration()));
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
index 06bac41e46..61972f5a82 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShape.java
@@ -16,11 +16,10 @@
package org.kie.workbench.common.stunner.sw.client.shapes;
-import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
-
-public class StartShape extends NodeShapeImpl {
+public class StartShape extends ServerlessWorkflowShape<StartShapeView> {
public StartShape() {
super(new StartShapeView().asAbstractShape());
+ getShape().getShapeView().setController(this);
}
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShapeView.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShapeView.java
index 7924057f95..0c12529a83 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShapeView.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StartShapeView.java
@@ -18,7 +18,7 @@ package org.kie.workbench.common.stunner.sw.client.shapes;
import com.ait.lienzo.client.core.shape.MultiPath;
-public class StartShapeView extends ServerlessWorkflowBasicShape<StartShapeView> {
+public class StartShapeView extends ServerlessWorkflowShapeView<StartShapeView> {
private final static double START_SHAPE_RADIUS = 25;
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShape.java
index 9a3efd283b..2caf80386e 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShape.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShape.java
@@ -16,35 +16,77 @@
package org.kie.workbench.common.stunner.sw.client.shapes;
+import com.ait.lienzo.client.core.event.NodeMouseExitHandler;
import com.ait.lienzo.client.core.shape.Picture;
import com.ait.lienzo.client.core.types.Transform;
import org.appformer.kogito.bridge.client.resource.ResourceContentService;
import org.appformer.kogito.bridge.client.resource.interop.ResourceContentOptions;
import org.kie.workbench.common.stunner.core.client.shape.HasShapeState;
-import org.kie.workbench.common.stunner.core.client.shape.impl.NodeShapeImpl;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.client.shape.ShapeState;
+import org.kie.workbench.common.stunner.core.client.shape.impl.ShapeStateHandler;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
import org.kie.workbench.common.stunner.core.util.StringUtils;
import org.kie.workbench.common.stunner.sw.definition.State;
-public class StateShape extends NodeShapeImpl implements HasShapeState {
+import static java.lang.Math.floor;
+import static java.lang.Math.min;
+import static java.lang.Math.pow;
+import static java.lang.Math.sqrt;
+import static org.kie.workbench.common.stunner.sw.client.shapes.StateShapeView.STATE_CORNER_RADIUS;
+
+public class StateShape extends ServerlessWorkflowShape<StateShapeView> implements HasShapeState {
- public static final String INJECT_STATE_ICON = "M35.02,28.49s-.03-.03-.05-.04l-10.29-10.29c-1.78-1.78-4.68-1.79-6.46,0-1.79,1.79-1.78,4.68,0,6.46l2.81,2.81H4.57c-2.52,0-4.57,2.04-4.57,4.57s2.05,4.57,4.57,4.57H20.94l-2.75,2.75c-1.78,1.78-1.79,4.68,0,6.46s4.68,1.78,6.46,0l10.09-10.09c.28-.2,.54-.44,.77-.71,.5-.58,.82-1.27,.97-2,.37-1.59-.11-3.33-1.46-4.5M.01,4.23C.19,1.83,2.25,0,4.66,0H59.43c2.53,0,4.57,2.05,4.57,4.57s-2.04,4.57-4.57,4.57H4.57C1.93,9.14-.18,6.91,.01,4.23M46.09,18.29h13 [...]
- public static final String SWITCH_STATE_ICON = "M60.6,46.54h-6.53v-8.71c-.06-1.38-.72-2.69-1.83-3.52l-7.42-5.56h0l-8.41-6.36V4.4C36.4,1.87,34.26-.17,31.69,.01c-2.25,.16-4.09,2.22-4.09,4.48V22.41l-8.41,6.31h0l-7.42,5.55c-1.11,.83-1.76,2.14-1.83,3.52v8.71H3.4c-2.94-.03-4.42,3.53-2.34,5.61l11.01,10.89c1.29,1.29,3.38,1.29,4.68,0l11.01-10.89c2.08-1.96,.61-5.52-2.34-5.47h-6.67v-6.63s8.22-6.08,13.28-9.87c4.96,3.73,13.2,9.92,13.24,9.9v6.63h-6.67c-2.94-.05-4.42,3.51-2.34,5.47l11.01,10.89c1.29 [...]
- public static final String OPERATION_STATE_ICON = "M61.99,20.83c.41,1.07,.06,2.29-.79,3.07l-5.41,4.93c.14,1.04,.21,2.1,.21,3.17s-.08,2.14-.21,3.17l5.41,4.92c.85,.79,1.2,2,.79,3.08-.55,1.49-1.21,2.92-1.96,4.29l-.59,1.01c-.83,1.38-1.75,2.68-2.76,3.91-.75,.89-1.96,1.2-3.06,.85l-6.96-2.22c-1.68,1.29-3.64,2.36-5.5,3.19l-1.56,7.14c-.25,1.12-1.12,1.92-2.28,2.22-1.72,.29-3.5,.44-5.42,.44-1.7,0-3.48-.15-5.2-.44-1.15-.3-2.02-1.1-2.27-2.22l-1.56-7.14c-1.98-.83-3.83-1.9-5.5-3.19l-6.96,2.22c-1.1, [...]
- public static final String EVENT_STATE_ICON = "M 45.254 45.197 L 36.216 45.197 L 42.206 31.792 C 42.613 30.98 42.307 29.965 41.597 29.355 C 40.887 28.746 39.768 28.849 39.06 29.457 L 19.561 45.705 C 18.953 46.215 18.646 47.128 18.953 47.939 C 19.258 48.754 19.968 49.262 20.883 49.262 L 29.921 49.262 L 23.928 62.667 C 23.521 63.478 23.825 64.493 24.538 65.103 C 24.943 65.51 25.247 65.609 25.756 65.609 C 26.263 65.609 26.67 65.406 27.076 65.103 L 46.573 48.854 C 47.183 48.347 47.488 47 [...]
- public static final String CALLBACK_STATE_ICON = "M63.97,36.13c0-2.13-1.64-3.95-3.76-4.07-2.31-.13-4.23,1.7-4.23,3.99,0,6.61-5.37,11.98-11.98,11.98H24.03v-4.99c0-1.18-.7-2.25-1.78-2.74-1.08-.47-2.34-.28-3.23,.52l-9.98,8.98c-.63,.56-.99,1.37-.99,2.22s.36,1.66,.99,2.23l9.98,8.98c.56,.51,1.28,.77,2,.77,.41,0,.83-.09,1.22-.26,1.08-.48,1.78-1.55,1.78-2.74v-4.99h19.97c10.98,0,19.92-8.91,19.97-19.89ZM20,16.08h19.85l.11,4.99c0,1.18,.7,2.25,1.78,2.74,.4,.17,.81,.26,1.11,.26,.73,0,1.44-.27,2.0 [...]
- public static final String FOR_EACH_STATE_ICON = "M64,32.22v27.24c0,2.34-1.91,4.49-4.24,4.65-2.68,.19-4.9-1.92-4.9-4.56v-27.43c0-2.64,2.22-4.75,4.9-4.56,2.34,.16,4.24,2.31,4.24,4.65M45.71,59.56c0,2.64-2.22,4.75-4.9,4.56-2.34-.16-4.24-2.31-4.24-4.65v-27.24c0-2.34,1.91-4.49,4.24-4.65,2.68-.19,4.9,1.92,4.9,4.56v27.43M27.43,4.79v27.24c0,2.34-1.91,4.49-4.24,4.65-2.68,.19-4.9-1.92-4.9-4.56V4.7C18.29,2.07,20.51-.04,23.18,.14c2.34,.16,4.24,2.31,4.24,4.65M9.14,32.13c0,2.64-2.22,4.75-4.9,4.56C [...]
- public static final String PARALLEL_STATE_ICON = "M50.54,.01c2.34,.16,4.24,2.31,4.24,4.65V59.43c0,2.64-2.23,4.75-4.91,4.56-2.33-.17-4.23-2.31-4.23-4.65V4.57c0-2.63,2.22-4.75,4.9-4.56M13.46,63.99c-2.34-.16-4.24-2.31-4.24-4.65V4.57c0-2.52,2.04-4.57,4.57-4.57s4.57,2.05,4.57,4.57V59.43c0,2.64-2.22,4.75-4.9,4.56Z";
- public static final String SLEEP_STATE_ICON = "M54.24,53.11c3.71-4.77,5.92-10.77,5.92-17.28,0-15.56-12.61-28.17-28.17-28.17S3.83,20.27,3.83,35.83c0,6.49,2.19,12.46,5.87,17.22l-2.53,2.53c-1.63,1.63-1.8,4.46-.28,6.2,1.74,2,4.76,2.07,6.59,.24l2.8-2.8c4.49,3.02,9.9,4.79,15.71,4.79s11.17-1.75,15.65-4.74l2.75,2.75c1.63,1.63,4.46,1.8,6.2,.28,2-1.74,2.07-4.76,.24-6.59l-2.59-2.59Zm-13.09-8.11l-10.59-7.06c-.74-.4-1.18-1.22-1.18-2.11l-.1-15c0-1.47,1.28-2.65,2.65-2.65,1.57,0,2.75,1.18,2.75,2.65v [...]
public static final String ANSIBLE_STATE_ICON = "M 31.047 11.68 L 47.108 46.485 L 22.848 29.706 L 31.047 11.68 Z M 59.577 54.501 L 34.874 2.301 C 34.167 0.796 32.757 0 31.047 0 C 29.331 0 27.819 0.796 27.114 2.301 L 0 59.559 L 9.274 59.559 L 20.008 35.95 L 52.04 58.671 C 53.326 59.586 54.256 60 55.466 60 C 57.885 60 60 58.407 60 56.109 C 60 55.734 59.85 55.14 59.577 54.501 Z";
public static final String KAOTO_STATE_ICON = "M 13.524 8.426 L 4.212 16.823 L 21.506 16.823 C 35.471 16.823 38.797 16.463 38.797 15.142 C 38.797 13.823 24.387 -0.091 23.056 0.03 C 22.833 0.03 18.512 3.868 13.524 8.426M 44.007 0.87 C 43.564 1.23 43.23 5.067 43.23 9.264 C 43.23 15.743 43.564 16.823 45.227 16.823 C 46.336 16.823 47.776 17.421 48.552 18.262 C 49.661 19.461 51.654 17.901 57.751 11.185 C 62.297 6.387 65.401 2.069 64.958 1.349 C 64.071 -0.091 45.227 -0.569 44.007 0.87M 54. [...]
private final StateShapeView shapeView;
+ private final ResourceContentService resourceContentService;
+
+ protected StateShape(State state, ResourceContentService resourceContentService) {
+ this(state.getName(), resourceContentService);
+ }
+
+ protected StateShape(String name, ResourceContentService resourceContentService) {
+ super(new StateShapeView(name).asAbstractShape());
- public StateShape(State state, ResourceContentService resourceContentService) {
- this(state.getName());
+ this.resourceContentService = resourceContentService;
+ this.shapeView = getShape().getShapeView();
+ this.shapeView.setController(this);
+ }
+
+ public static StateShape create(State state, ResourceContentService resourceContentService) {
+ switch (state.getType()) {
+ case "inject":
+ return new InjectStateShape(state, resourceContentService);
+ case "switch":
+ return new SwitchStateShape(state, resourceContentService);
+ case "operation":
+ return new OperationStateShape(state, resourceContentService);
+ case "event":
+ return new EventStateShape(state, resourceContentService);
+ case "callback":
+ return new CallbackStateShape(state, resourceContentService);
+ case "foreach":
+ return new ForEachStateShape(state, resourceContentService);
+ case "parallel":
+ return new ParallelStateShape(state, resourceContentService);
+ case "sleep":
+ return new SleepStateShape(state, resourceContentService);
+ default:
+ // If type is missing create Inject By default.
+ return new InjectStateShape(state, resourceContentService);
+ }
+ }
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ State state = element.getContent().getDefinition();
if (state.metadata == null) {
- setType(state.getType());
+ shapeView.setSvgIcon(getIconColor(), getIconSvg());
return;
}
@@ -62,20 +104,14 @@ public class StateShape extends NodeShapeImpl implements HasShapeState {
}
if (StringUtils.nonEmpty(state.metadata.type)) {
- setType(state.metadata.type);
+ setPredefinedIcon(state.metadata.type);
}
if (isIconEmpty()) {
- setType(state.getType());
+ shapeView.setSvgIcon(getIconColor(), getIconSvg());
}
}
- public StateShape(String name) {
- super(new StateShapeView(name).asAbstractShape());
-
- shapeView = (StateShapeView) getShape().getShapeView();
- }
-
private void loadIconFromFile(State state, ResourceContentService resourceContentService) {
resourceContentService
.get(state.metadata.icon, ResourceContentOptions.binary())
@@ -105,32 +141,8 @@ public class StateShape extends NodeShapeImpl implements HasShapeState {
return iconData;
}
- public StateShape setType(String type) {
+ public StateShape setPredefinedIcon(String type) {
switch (type) {
- case "inject":
- shapeView.setSvgIcon("#8BC1F7", INJECT_STATE_ICON);
- break;
- case "switch":
- shapeView.setSvgIcon("#009596", SWITCH_STATE_ICON);
- break;
- case "operation":
- shapeView.setSvgIcon("#0066CC", OPERATION_STATE_ICON);
- break;
- case "event":
- shapeView.setSvgIcon("#F4C145", EVENT_STATE_ICON);
- break;
- case "callback":
- shapeView.setSvgIcon("#EC7A08", CALLBACK_STATE_ICON);
- break;
- case "foreach":
- shapeView.setSvgIcon("#8F4700", FOR_EACH_STATE_ICON);
- break;
- case "parallel":
- shapeView.setSvgIcon("#4CB140", PARALLEL_STATE_ICON);
- break;
- case "sleep":
- shapeView.setSvgIcon("#5752D1", SLEEP_STATE_ICON);
- break;
case "ansible":
shapeView.setSvgIcon("#BB271A", ANSIBLE_STATE_ICON);
break;
@@ -142,6 +154,89 @@ public class StateShape extends NodeShapeImpl implements HasShapeState {
return this;
}
+ public String getIconColor() {
+ return "";
+ }
+
+ public String getIconSvg() {
+ return "";
+ }
+
+ public NodeMouseExitHandler getExitHandler() {
+ return event -> {
+ if (getShapeStateHandler().getShapeState() == ShapeState.SELECTED) {
+ return;
+ }
+
+ if (isInsideOfTheState(floor(event.getX() - event.getSource().getAbsoluteLocation().getX()),
+ floor(event.getY() - event.getSource().getAbsoluteLocation().getY()))) {
+ return;
+ }
+
+ getShapeStateHandler().applyState(ShapeState.NONE);
+ shapeView.batch();
+ };
+ }
+
+ protected ShapeStateHandler getShapeStateHandler() {
+ return getView().getShapeStateHandler();
+ }
+
+ protected boolean isInsideOfTheState(double x, double y) {
+ double width = getActualWidth();
+ double height = getActualHeight();
+
+ if (isOutsideOfTheBox(x, y, width, height)) {
+ return false;
+ }
+
+ return !isOutsideOfCorners(x, y, width, height);
+ }
+
+ public boolean isOutsideOfTheBox(double x, double y, double width, double height) {
+ return x <= getX()
+ || x >= getX() + width
+ || y <= getY()
+ || y >= getY() + height;
+ }
+
+ public static boolean isOutsideOfCorners(double x, double y, double width, double height) {
+ double checkX = width - x < STATE_CORNER_RADIUS ? width - x : x; // Normalize location to the top left corner
+ double checkY = height - y < STATE_CORNER_RADIUS ? height - y : y; // Normalize location to the top left corner
+ return isOutsideOfCorner(checkX, checkY);
+ }
+
+ public static boolean isOutsideOfCorner(double xCursorPosition, double yCursorPosition) {
+ // If cursor position is more than corner radius it means position is not at the corner but over the icon
+ if (STATE_CORNER_RADIUS < xCursorPosition
+ || STATE_CORNER_RADIUS < yCursorPosition) {
+ return false;
+ }
+ return sqrt(pow(STATE_CORNER_RADIUS - xCursorPosition, 2)
+ + pow(STATE_CORNER_RADIUS - yCursorPosition, 2))
+ >= STATE_CORNER_RADIUS;
+ }
+
+ protected double getActualWidth() {
+ return shapeView.getShape().getBoundingBox().getWidth()
+ * shapeView.getShape().asNode().getAbsoluteTransform().getScaleX()
+ - 2; // to compensate border
+ }
+
+ protected double getActualHeight() {
+ return shapeView.getShape().getBoundingBox().getHeight()
+ * shapeView.getShape().asNode().getAbsoluteTransform().getScaleY()
+ - 1; // to compensate border
+ }
+
+ protected double getX() {
+ return shapeView.getShape().getX();
+ }
+
+ protected double getY() {
+ return shapeView.getShape().getY();
+ }
+
public boolean isIconEmpty() {
return shapeView.isIconEmpty();
}
@@ -172,7 +267,6 @@ public class StateShape extends NodeShapeImpl implements HasShapeState {
*/
public static double calculateIconScale(int width, int height) {
double size = StateShapeView.STATE_SHAPE_ICON_RADIUS * 2;
- int min = Math.min(width, height);
- return size / min;
+ return size / min(width, height);
}
}
\ No newline at end of file
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeView.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeView.java
index 63463ae68f..6449f263d6 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeView.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeView.java
@@ -29,19 +29,19 @@ import com.ait.lienzo.shared.core.types.EventPropagationMode;
import com.ait.lienzo.shared.core.types.TextAlign;
import com.ait.lienzo.shared.core.types.TextBaseLine;
-public class StateShapeView extends ServerlessWorkflowBasicShape<StateShapeView> {
+public class StateShapeView extends ServerlessWorkflowShapeView<StateShapeView> {
private Group iconImage;
private Circle backgroundCircle;
-
- private final static double STATE_SHAPE_WIDTH = 250;
- private final static double STATE_SHAPE_HEIGHT = 90;
+ protected final static double STATE_SHAPE_WIDTH = 250;
+ protected final static double STATE_SHAPE_HEIGHT = 90;
public final static double STATE_SHAPE_ICON_RADIUS = 25;
+ public final static double STATE_CORNER_RADIUS = 5.00;
public StateShapeView(String name) {
super(new MultiPath()
.rect(0, 0, STATE_SHAPE_WIDTH, STATE_SHAPE_HEIGHT)
- .setCornerRadius(5.00));
+ .setCornerRadius(STATE_CORNER_RADIUS));
initialize(name);
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SwitchStateShape.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SwitchStateShape.java
new file mode 100644
index 0000000000..c9114e5707
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/SwitchStateShape.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.appformer.kogito.bridge.client.resource.ResourceContentService;
+import org.kie.workbench.common.stunner.core.client.shape.MutationContext;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.CornerIcon;
+import org.kie.workbench.common.stunner.sw.client.shapes.icons.IconPath;
+import org.kie.workbench.common.stunner.sw.definition.State;
+import org.kie.workbench.common.stunner.sw.definition.SwitchState;
+
+public class SwitchStateShape extends StateShape {
+
+ public static final String ICON_COLOR = "#009596";
+ public static final String ICON_SVG = "M60.6,46.54h-6.53v-8.71c-.06-1.38-.72-2.69-1.83-3.52l-7.42-5.56h0l-8.41-6.36V4.4C36.4,1.87,34.26-.17,31.69,.01c-2.25,.16-4.09,2.22-4.09,4.48V22.41l-8.41,6.31h0l-7.42,5.55c-1.11,.83-1.76,2.14-1.83,3.52v8.71H3.4c-2.94-.03-4.42,3.53-2.34,5.61l11.01,10.89c1.29,1.29,3.38,1.29,4.68,0l11.01-10.89c2.08-1.96,.61-5.52-2.34-5.47h-6.67v-6.63s8.22-6.08,13.28-9.87c4.96,3.73,13.2,9.92,13.24,9.9v6.63h-6.67c-2.94-.05-4.42,3.51-2.34,5.47l11.01,10.89c1.29,1.29,3.3 [...]
+
+ public SwitchStateShape(State state, ResourceContentService resourceContentService) {
+ super(state, resourceContentService);
+ }
+
+ @Override
+ public void applyProperties(Node<View<State>, Edge> element, MutationContext mutationContext) {
+ super.applyProperties(element, mutationContext);
+ SwitchState state = (SwitchState) element.getContent().getDefinition();
+ if (state.getTimeouts() != null) {
+ getView().addChild(new CornerIcon(IconPath.CLOCK,
+ "EventTimeout: " + state.getTimeouts().getEventTimeout() + "\r\n"
+ + "StateExecTimeout: " + state.getTimeouts().getStateExecTimeout()));
+ }
+ }
+
+ @Override
+ public String getIconColor() {
+ return ICON_COLOR;
+ }
+
+ @Override
+ public String getIconSvg() {
+ return ICON_SVG;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/TransitionView.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/TransitionView.java
index 526163ad27..ddc7f103d6 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/TransitionView.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/TransitionView.java
@@ -28,7 +28,7 @@ public class TransitionView extends WiresConnectorViewExt<TransitionView> {
private static final double SELECTION_OFFSET = 30;
private static final double DECORATOR_WIDTH = 8;
private static final double DECORATOR_HEIGHT = 12;
-
+ private static final double OVERLAP_CORRECTION = 3;
private static final double STROKE_WIDTH = 2;
private static final double[] DEFAULT_POLYLINE_POINTS = {0, 0, 100, 100};
@@ -71,11 +71,11 @@ public class TransitionView extends WiresConnectorViewExt<TransitionView> {
private static MultiPath getArrowMultiPath() {
return new MultiPath()
.M(DECORATOR_WIDTH,
- DECORATOR_HEIGHT)
+ DECORATOR_HEIGHT + OVERLAP_CORRECTION)
.L(0,
- DECORATOR_HEIGHT)
+ DECORATOR_HEIGHT + OVERLAP_CORRECTION)
.L(DECORATOR_WIDTH / 2,
- 0)
+ OVERLAP_CORRECTION)
.Z();
}
}
\ No newline at end of file
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/CornerIcon.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/CornerIcon.java
new file mode 100644
index 0000000000..d46281c066
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/CornerIcon.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes.icons;
+
+import com.ait.lienzo.client.core.shape.Group;
+import com.ait.lienzo.client.core.shape.MultiPath;
+import com.ait.lienzo.client.core.shape.Rectangle;
+import com.ait.lienzo.client.core.shape.toolbox.items.tooltip.PrimitiveTextTooltip;
+import com.ait.lienzo.shared.core.types.EventPropagationMode;
+import com.ait.lienzo.tools.client.event.HandlerRegistration;
+
+public class CornerIcon extends Group {
+
+ private final HandlerRegistration mouseEnterHandler;
+ private final HandlerRegistration mouseExitHandler;
+ private final String tooltipText;
+
+ private final Rectangle border = new Rectangle(20, 20)
+ .setFillColor("white")
+ .setFillAlpha(0.001)
+ .setStrokeAlpha(0.001)
+ .setStrokeColor("white")
+ .setCornerRadius(9)
+ .setEventPropagationMode(EventPropagationMode.NO_ANCESTORS)
+ .setListening(true);
+
+ public CornerIcon(String icon, String tooltip) {
+ setX(224);
+ setY(6);
+ setListening(true);
+ add(border);
+ this.tooltipText = tooltip;
+
+ PrimitiveTextTooltip tooltipElement = PrimitiveTextTooltip.Builder.build(tooltipText);
+ tooltipElement.withText(t -> {
+ t.setText(tooltipText);
+ t.setFontSize(12);
+ });
+ add(tooltipElement.asPrimitive());
+ tooltipElement.forComputedBoundingBox(border::getBoundingBox);
+
+ MultiPath clockIcon = new MultiPath(icon)
+ .setScale(2)
+ .setStrokeWidth(0)
+ .setFillColor("#CCC")
+ .setListening(false);
+ add(clockIcon);
+
+ mouseEnterHandler = border.addNodeMouseEnterHandler(event -> {
+ this.getParent().moveToTop();
+ tooltipElement.show();
+ clockIcon.setFillColor("#4F5255");
+ });
+ mouseExitHandler = border.addNodeMouseExitHandler(event -> {
+ tooltipElement.hide();
+ clockIcon.setFillColor("#CCC");
+ border.getLayer().batch();
+ });
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mouseEnterHandler.removeHandler();
+ mouseExitHandler.removeHandler();
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/IconPath.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/IconPath.java
new file mode 100644
index 0000000000..7a5ad766a0
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/main/java/org/kie/workbench/common/stunner/sw/client/shapes/icons/IconPath.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes.icons;
+
+public interface IconPath {
+
+ String CLOCK = "M 4.531 2.344 C 4.531 2.084 4.74 1.875 5 1.875 C 5.26 1.875 5.469 2.084 5.469 2.344 L 5.469 4.75 L 7.135 5.859 C 7.35 6.004 7.408 6.295 7.248 6.51 C 7.121 6.725 6.83 6.783 6.615 6.623 L 4.74 5.373 C 4.609 5.303 4.531 5.156 4.531 4.982 L 4.531 2.344 Z M 5 0 C 7.762 0 10 2.238 10 5 C 10 7.762 7.762 10 5 10 C 2.238 10 0 7.762 0 5 C 0 2.238 2.238 0 5 0 Z M 0.938 5 C 0.938 7.244 2.756 9.063 5 9.063 C 7.244 9.063 9.063 7.244 9.063 5 C 9.063 2.756 7.244 0.938 5 0.938 C 2.756 [...]
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateNode.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateNode.java
new file mode 100644
index 0000000000..5f20c32918
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import java.util.List;
+import java.util.Set;
+
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class StateNode implements Node<View<State>, Edge> {
+
+ private View<State> view;
+
+ public StateNode(View<State> view) {
+ this.view = view;
+ }
+
+ @Override
+ public List<Edge> getInEdges() {
+ return null;
+ }
+
+ @Override
+ public List<Edge> getOutEdges() {
+ return null;
+ }
+
+ @Override
+ public String getUUID() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getLabels() {
+ return null;
+ }
+
+ @Override
+ public View<State> getContent() {
+ return view;
+ }
+
+ @Override
+ public void setContent(View<State> content) {
+ this.view = content;
+ }
+
+ @Override
+ public Node<View<State>, Edge> asNode() {
+ return null;
+ }
+
+ @Override
+ public Edge<View<State>, Node> asEdge() {
+ return null;
+ }
+}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeTest.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeTest.java
index cd99e8da50..032145ca08 100644
--- a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeTest.java
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateShapeTest.java
@@ -13,22 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.kie.workbench.common.stunner.sw.client.shapes;
+import com.ait.lienzo.client.core.event.NodeMouseExitEvent;
import com.ait.lienzo.test.LienzoMockitoTestRunner;
import elemental2.promise.Promise;
import org.appformer.kogito.bridge.client.resource.ResourceContentService;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.kie.workbench.common.stunner.core.client.shape.ShapeState;
+import org.kie.workbench.common.stunner.core.client.shape.impl.ShapeStateHandler;
+import org.kie.workbench.common.stunner.core.graph.Edge;
+import org.kie.workbench.common.stunner.core.graph.Node;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.definition.CallbackState;
+import org.kie.workbench.common.stunner.sw.definition.EventState;
+import org.kie.workbench.common.stunner.sw.definition.ForEachState;
+import org.kie.workbench.common.stunner.sw.definition.InjectState;
import org.kie.workbench.common.stunner.sw.definition.Metadata;
+import org.kie.workbench.common.stunner.sw.definition.OperationState;
+import org.kie.workbench.common.stunner.sw.definition.ParallelState;
+import org.kie.workbench.common.stunner.sw.definition.SleepState;
import org.kie.workbench.common.stunner.sw.definition.State;
+import org.kie.workbench.common.stunner.sw.definition.SwitchState;
import org.mockito.Mock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.kie.workbench.common.stunner.sw.client.shapes.StateShapeView.STATE_SHAPE_HEIGHT;
+import static org.kie.workbench.common.stunner.sw.client.shapes.StateShapeView.STATE_SHAPE_WIDTH;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -60,7 +78,8 @@ public class StateShapeTest {
private final String SLEEP_COLOR = "#5752D1";
private final String ANSIBLE_COLOR = "#BB271A";
private final String KAOTO_COLOR = "#332174";
- private final String DEFAULT_EMPTY_COLOR = "#FFF";
+ private final int SHAPE_X = 50;
+ private final int SHAPE_Y = 50;
@Mock
ResourceContentService kogitoService;
@@ -115,35 +134,9 @@ public class StateShapeTest {
customTypeStateIconTest(ANSIBLE, ANSIBLE, ANSIBLE_COLOR);
}
- public void simpleStateIconTest(String type, String color) {
- State state = createState(type);
-
- StateShape shape = new StateShape(state, kogitoService);
- assertFalse(shape.getView().isIconEmpty());
- assertEquals(color, shape.getView().getIconBackgroundColor());
- }
-
- private State createState(String type) {
- State state = new State();
- state.setName(NAME);
- state.setType(type);
- return state;
- }
-
- public void customTypeStateIconTest(String defaultType, String customType, String color) {
- State state = createState(defaultType);
- Metadata metadata = new Metadata();
- metadata.setType(customType);
- state.setMetadata(metadata);
-
- StateShape shape = new StateShape(state, kogitoService);
- assertFalse(shape.getView().isIconEmpty());
- assertEquals(color, shape.getView().getIconBackgroundColor());
- }
-
@Test
public void setNullPictureTest() {
- StateShape shape = spy(new StateShape(createState(INJECT), kogitoService));
+ StateShape shape = spy(StateShape.create(createState(INJECT), kogitoService));
shape.setIconPicture(null, "icon.png");
verify(shape, never()).setIconPicture(any());
@@ -151,7 +144,7 @@ public class StateShapeTest {
@Test
public void setEmptyPictureTest() {
- StateShape shape = spy(new StateShape(createState(INJECT), kogitoService));
+ StateShape shape = spy(StateShape.create(createState(INJECT), kogitoService));
shape.setIconPicture("", "icon.png");
verify(shape, never()).setIconPicture(any());
@@ -159,7 +152,7 @@ public class StateShapeTest {
@Test
public void setValidPictureTest() {
- StateShape shape = spy(new StateShape(createState(INJECT), kogitoService));
+ StateShape shape = spy(StateShape.create(createState(INJECT), kogitoService));
shape.setIconPicture("base64string", "icon.png");
verify(shape, times(1)).setIconPicture(any());
@@ -172,7 +165,11 @@ public class StateShapeTest {
metadata.setIcon("data://png..lalala");
state.setMetadata(metadata);
- StateShape shape = new StateShape(state, kogitoService);
+ StateShape shape = StateShape.create(state, kogitoService);
+ assertTrue(shape.getView().isIconEmpty());
+ assertNull(shape.getView().getIconBackgroundColor());
+
+ shape.applyProperties(createElement(state), null);
assertFalse(shape.getView().isIconEmpty());
assertEquals("#FFF", shape.getView().getIconBackgroundColor());
}
@@ -187,7 +184,11 @@ public class StateShapeTest {
when(kogitoService.get(eq("png..lalala"), any())).thenReturn(new Promise<>((resolve, reject) -> {
}));
- StateShape shape = new StateShape(state, kogitoService);
+ StateShape shape = StateShape.create(state, kogitoService);
+ assertTrue(shape.getView().isIconEmpty());
+ assertNull(shape.getView().getIconBackgroundColor());
+
+ shape.applyProperties(createElement(state), null);
assertFalse(shape.getView().isIconEmpty());
assertEquals(INJECT_COLOR, shape.getView().getIconBackgroundColor());
}
@@ -195,33 +196,33 @@ public class StateShapeTest {
@Test
public void scaleLargeWidthSmallHeightTest() {
assertEquals(2.0,
- StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4,
- (int) StateShapeView.STATE_SHAPE_ICON_RADIUS),
- 0.0);
+ StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4,
+ (int) StateShapeView.STATE_SHAPE_ICON_RADIUS),
+ 0.0);
}
@Test
public void scaleLargeHeightSmallWidthTest() {
assertEquals(2.0,
- StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS,
- (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4),
- 0.0);
+ StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS,
+ (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4),
+ 0.0);
}
@Test
public void scaleLargeWidthLargerHeightTest() {
assertEquals(0.5,
- StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4,
- (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 8),
- 0.0);
+ StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4,
+ (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 8),
+ 0.0);
}
@Test
public void scaleLargeHeightLargerWidthTest() {
assertEquals(0.5,
- StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 8,
- (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4),
- 0.0);
+ StateShape.calculateIconScale((int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 8,
+ (int) StateShapeView.STATE_SHAPE_ICON_RADIUS * 4),
+ 0.0);
}
@Test
@@ -238,4 +239,210 @@ public class StateShapeTest {
public void base64StringFromIncorrectPathGenerationTest() {
assertEquals(IMAGE_DATA, StateShape.iconDataUri("imagejpeg", IMAGE_DATA));
}
+
+ @Test
+ public void leftTopCornerOutsideTest() {
+ assertTrue(isCoordinateOutsideTest(0.5, 0.5));
+ }
+
+ @Test
+ public void leftTopCornerInsideTest() {
+ assertFalse(isCoordinateOutsideTest(6, 6));
+ }
+
+ @Test
+ public void rightTopCornerOutsideTest() {
+ assertTrue(isCoordinateOutsideTest(STATE_SHAPE_WIDTH - 0.5, 0.5));
+ }
+
+ @Test
+ public void rightTopCornerInsideTest() {
+ assertFalse(isCoordinateOutsideTest(STATE_SHAPE_WIDTH - 6, 6));
+ }
+
+ @Test
+ public void leftBottomCornerOutsideTest() {
+ assertTrue(isCoordinateOutsideTest(0.5, STATE_SHAPE_HEIGHT - 0.5));
+ }
+
+ @Test
+ public void leftBottomCornerInsideTest() {
+ assertFalse(isCoordinateOutsideTest(6, STATE_SHAPE_HEIGHT - 6));
+ }
+
+ @Test
+ public void rightBottomCornerOutsideTest() {
+ assertTrue(isCoordinateOutsideTest(STATE_SHAPE_WIDTH - 0.5, STATE_SHAPE_HEIGHT - 0.5));
+ }
+
+ @Test
+ public void rightBottomCornerInsideTest() {
+ assertFalse(isCoordinateOutsideTest(STATE_SHAPE_WIDTH - 6, STATE_SHAPE_HEIGHT - 6));
+ }
+
+ @Test
+ public void exitFromSelectedShapeTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.SELECTED);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent(49, 49);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, never()).applyState(any());
+ }
+
+ @Test
+ public void exitFromTheShapeToTopTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.HIGHLIGHT);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent(55, 49);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, times(1)).applyState(ShapeState.NONE);
+ }
+
+ @Test
+ public void exitFromTheLeftShapeTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.HIGHLIGHT);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent(SHAPE_X - 5, SHAPE_Y + 5);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, times(1)).applyState(ShapeState.NONE);
+ }
+
+ @Test
+ public void exitFromTheRightShapeTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.HIGHLIGHT);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent((int) STATE_SHAPE_WIDTH + SHAPE_X + 5, SHAPE_Y + 5);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, times(1)).applyState(ShapeState.NONE);
+ }
+
+ @Test
+ public void exitFromTheBottomShapeTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.HIGHLIGHT);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent(SHAPE_X + 5, (int) STATE_SHAPE_HEIGHT + SHAPE_Y + 5);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, times(1)).applyState(ShapeState.NONE);
+ }
+
+ @Test
+ public void raisedExitInsideOfTheShapeTest() {
+ ShapeStateHandler stateHandler = mock(ShapeStateHandler.class);
+
+ StateShape shape = prepareShapeForExitTests(stateHandler, ShapeState.HIGHLIGHT);
+ NodeMouseExitEvent exitEvent = prepareMouseExitEvent(SHAPE_X + 5, SHAPE_Y + 5);
+
+ shape.getExitHandler().onNodeMouseExit(exitEvent);
+
+ verify(stateHandler, never()).applyState(ShapeState.NONE);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private NodeMouseExitEvent prepareMouseExitEvent(int mouseX, int mouseY) {
+ NodeMouseExitEvent exitEvent = mock(NodeMouseExitEvent.class);
+ when(exitEvent.getX()).thenReturn(mouseX);
+ when(exitEvent.getY()).thenReturn(mouseY);
+ com.ait.lienzo.client.core.shape.Node node = mock(com.ait.lienzo.client.core.shape.Node.class);
+ when(exitEvent.getSource()).thenReturn(node);
+ com.ait.lienzo.client.core.types.Point2D point = new com.ait.lienzo.client.core.types.Point2D(SHAPE_X, SHAPE_Y);
+ when(node.getAbsoluteLocation()).thenReturn(point);
+ return exitEvent;
+ }
+
+ private StateShape prepareShapeForExitTests(ShapeStateHandler stateHandler, ShapeState currentState) {
+ State state = createState(INJECT);
+ StateShape shape = spy(StateShape.create(state, kogitoService));
+ shape.applyProperties(createElement(state), null);
+
+ when(stateHandler.getShapeState()).thenReturn(currentState);
+ when(shape.getShapeStateHandler()).thenReturn(stateHandler);
+
+ return shape;
+ }
+
+ private void simpleStateIconTest(String type, String color) {
+ State state = createState(type);
+
+ StateShape shape = StateShape.create(state, kogitoService);
+ assertTrue(shape.getView().isIconEmpty());
+ assertNull(shape.getView().getIconBackgroundColor());
+
+ shape.applyProperties(createElement(state), null);
+ assertFalse(shape.getView().isIconEmpty());
+ assertEquals(color, shape.getView().getIconBackgroundColor());
+ }
+
+ private State createState(String type) {
+ State state;
+ switch (type) {
+ case "inject":
+ state = new InjectState();
+ break;
+ case "switch":
+ state = new SwitchState();
+ break;
+ case "operation":
+ state = new OperationState();
+ break;
+ case "event":
+ state = new EventState();
+ break;
+ case "callback":
+ state = new CallbackState();
+ break;
+ case "foreach":
+ state = new ForEachState();
+ break;
+ case "parallel":
+ state = new ParallelState();
+ break;
+ case "sleep":
+ state = new SleepState();
+ break;
+ default:
+ state = new State();
+ }
+ state.setName(NAME);
+ state.setType(type);
+ return state;
+ }
+
+ private void customTypeStateIconTest(String defaultType, String customType, String color) {
+ State state = createState(defaultType);
+ Metadata metadata = new Metadata();
+ metadata.setType(customType);
+ state.setMetadata(metadata);
+
+ StateShape shape = StateShape.create(state, kogitoService);
+ assertTrue(shape.getView().isIconEmpty());
+ assertNull(shape.getView().getIconBackgroundColor());
+
+ shape.applyProperties(createElement(state), null);
+ assertFalse(shape.getView().isIconEmpty());
+ assertEquals(color, shape.getView().getIconBackgroundColor());
+ }
+
+ private Node<View<State>, Edge> createElement(State state) {
+ StateView view = new StateView(state);
+ return new StateNode(view);
+ }
+
+ private boolean isCoordinateOutsideTest(double x, double y) {
+ return StateShape.isOutsideOfCorners(x, y, STATE_SHAPE_WIDTH, STATE_SHAPE_HEIGHT);
+ }
}
diff --git a/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateView.java b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateView.java
new file mode 100644
index 0000000000..d170bb52d8
--- /dev/null
+++ b/packages/serverless-workflow-diagram-editor/sw-editor/sw-editor-client/src/test/java/org/kie/workbench/common/stunner/sw/client/shapes/StateView.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.kie.workbench.common.stunner.sw.client.shapes;
+
+import org.kie.workbench.common.stunner.core.graph.content.Bounds;
+import org.kie.workbench.common.stunner.core.graph.content.view.View;
+import org.kie.workbench.common.stunner.sw.definition.State;
+
+public class StateView implements View<State> {
+
+ private State state;
+
+ public StateView(State state) {
+ this.state = state;
+ }
+
+ @Override
+ public Bounds getBounds() {
+ return null;
+ }
+
+ @Override
+ public void setBounds(Bounds bounds) {
+
+ }
+
+ @Override
+ public State getDefinition() {
+ return state;
+ }
+
+ @Override
+ public void setDefinition(State definition) {
+ this.state = definition;
+ }
+}
diff --git a/packages/stunner-editors/kie-wb-common-dmn/kie-dmn-feel-gwt/src/main/java/org/kie/dmn/feel/super/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java b/packages/stunner-editors/kie-wb-common-dmn/kie-dmn-feel-gwt/src/main/java/org/kie/dmn/feel/super/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
new file mode 100644
index 0000000000..969c131a6c
--- /dev/null
+++ b/packages/stunner-editors/kie-wb-common-dmn/kie-dmn-feel-gwt/src/main/java/org/kie/dmn/feel/super/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+
+package org.kie.dmn.feel.lang.ast.visitor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.kie.dmn.api.feel.runtime.events.FEELEvent;
+import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
+import org.kie.dmn.feel.lang.ast.ASTNode;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.ast.NullNode;
+import org.kie.dmn.feel.lang.ast.RangeNode;
+import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.runtime.events.ASTHeuristicCheckEvent;
+import org.kie.dmn.feel.util.Msg;
+
+public class ASTHeuristicCheckerVisitor extends DefaultedVisitor<List<FEELEvent>> {
+
+ @Override
+ public List<FEELEvent> defaultVisit(ASTNode n) {
+ List<FEELEvent> result = new ArrayList<>();
+ for (ASTNode node : n.getChildrenNode()) {
+ if (node != null) {
+ result.addAll(node.accept(this));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public List<FEELEvent> visit(InfixOpNode n) {
+ if (!(n.getLeft() instanceof UnaryTestNode || n.getLeft() instanceof RangeNode) && (n.getRight() instanceof UnaryTestNode || n.getRight() instanceof RangeNode)) {
+ return Arrays.asList(new ASTHeuristicCheckEvent(Severity.WARN, Msg.createMessage(Msg.COMPARING_TO_UT, n.getOperator().symbol + " (" + n.getRight().getText()) + ")", n));
+ }
+ return defaultVisit(n);
+ }
+
+ @Override
+ public List<FEELEvent> visit(UnaryTestNode n) {
+ if (n.getValue() instanceof UnaryTestNode || n.getValue() instanceof RangeNode) {
+ return Arrays.asList(new ASTHeuristicCheckEvent(Severity.WARN, Msg.createMessage(Msg.UT_OF_UT, n.getOperator().symbol + " (" + n.getValue().getText()) + ")", n));
+ }
+ return defaultVisit(n);
+ }
+
+ @Override
+ public List<FEELEvent> visit(RangeNode n) {
+ if ((n.getStart() instanceof NullNode && n.getEnd() instanceof RangeNode)
+ || (n.getStart() instanceof RangeNode && n.getEnd() instanceof NullNode)) {
+ return Arrays.asList(new ASTHeuristicCheckEvent(Severity.WARN, Msg.createMessage(Msg.UT_OF_UT, n.getText()), n));
+ }
+ return defaultVisit(n);
+ }
+}
diff --git a/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/pom.xml b/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/pom.xml
index f31910aa5f..ae6befcae7 100644
--- a/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/pom.xml
+++ b/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/pom.xml
@@ -27,19 +27,7 @@
<artifactId>kie-wb-common-dmn-client</artifactId>
<name>Kie Workbench - Common - DMN - Client</name>
<description>Kie Workbench - Common - DMN - Client</description>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>11</source>
- <target>11</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <packaging>jar</packaging>
+ <packaging>jar</packaging>
<properties>
<java.module.name>org.kie.wb.common.dmn.client</java.module.name>
diff --git a/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/src/main/java/org/kie/workbench/common/dmn/client/editors/expressions/types/dtable/DecisionTableEditorDefinitionEnricher.java b/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/src/main/java/org/kie/workbench/common/dmn/client/editors/expressions/types/dtable/DecisionTableEditorDefinitionEnricher.java
index 3d84b8383f..d03841ea69 100644
--- a/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/src/main/java/org/kie/workbench/common/dmn/client/editors/expressions/types/dtable/DecisionTableEditorDefinitionEnricher.java
+++ b/packages/stunner-editors/kie-wb-common-dmn/kie-wb-common-dmn-client/src/main/java/org/kie/workbench/common/dmn/client/editors/expressions/types/dtable/DecisionTableEditorDefinitionEnricher.java
@@ -417,7 +417,7 @@ public class DecisionTableEditorDefinitionEnricher implements ExpressionEditorMo
}
private QName getQName(final ItemDefinition itemDefinition) {
- if (!itemDefinitionUtils.findByName(itemDefinition.getName().getValue()).isEmpty()) {
+ if (itemDefinitionUtils.findByName(itemDefinition.getName().getValue()).isPresent()) {
return getQNameFromItemDefinitionName(itemDefinition);
} else {
return itemDefinition.getTypeRef();
diff --git a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/toolbox/actions/AbstractActionsToolboxView.java b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/toolbox/actions/AbstractActionsToolboxView.java
index 4ef4afaa50..e5983b7825 100644
--- a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/toolbox/actions/AbstractActionsToolboxView.java
+++ b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/toolbox/actions/AbstractActionsToolboxView.java
@@ -172,6 +172,7 @@ public abstract class AbstractActionsToolboxView<V extends AbstractActionsToolbo
final IsToolboxActionDraggable toolboxAction,
final ButtonItem button,
final NodeMouseMoveEvent event) {
+ button.disable();
toolboxAction.onMoveStart(toolbox.getCanvasHandler(),
toolbox.getElementUUID(),
new MouseMoveEvent(event.getX(),
diff --git a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/customproperties/AssociationList.java b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/cu [...]
index 794bcbc6d5..8b0a8c9a0f 100644
--- a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/customproperties/AssociationList.java
+++ b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/customproperties/AssociationList.java
@@ -19,11 +19,9 @@ package org.kie.workbench.common.stunner.bpmn.client.marshall.converters.customp
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.kie.workbench.common.stunner.core.util.StringUtils;
import org.uberfire.commons.UUID;
import static java.util.stream.Collectors.toList;
@@ -60,14 +58,17 @@ public class AssociationList {
}
public static AssociationList fromString(String encoded) {
- return Optional.ofNullable(encoded)
- .filter(StringUtils::nonEmpty)
- .map(s -> new AssociationList(
- Arrays.stream(s.replaceAll(REGEX_DELIMITER, REPLACE_DELIMITER_AVOID_CONFLICTS)
- .split(REPLACED_DELIMITER))
- .map(AssociationDeclaration::fromString)
- .collect(toList())))
- .orElse(new AssociationList());
+ // The change below is to fix SDM issue on Mac OS
+ if (encoded == null || encoded.isEmpty()) {
+ return new AssociationList();
+ } else {
+ return new AssociationList(
+ Arrays.stream(encoded.replaceAll(REGEX_DELIMITER, REPLACE_DELIMITER_AVOID_CONFLICTS)
+ .split(REPLACED_DELIMITER))
+ .map(AssociationDeclaration::fromString)
+ .collect(toList()));
+
+ }
}
public List<AssociationDeclaration> getInputs() {
diff --git a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/tostunner/processes/ProcessConverterDelegate.java b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/c [...]
index 8479455034..3409dcf939 100644
--- a/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/tostunner/processes/ProcessConverterDelegate.java
+++ b/packages/stunner-editors/kie-wb-common-stunner/kie-wb-common-stunner-sets/kie-wb-common-stunner-bpmn/kie-wb-common-stunner-bpmn-marshalling/src/main/java/org/kie/workbench/common/stunner/bpmn/client/marshall/converters/tostunner/processes/ProcessConverterDelegate.java
@@ -16,7 +16,9 @@
package org.kie.workbench.common.stunner.bpmn.client.marshall.converters.tostunner.processes;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -25,6 +27,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import elemental2.dom.DomGlobal;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.Lane;
@@ -112,19 +115,37 @@ final class ProcessConverterDelegate {
}
private Result<Map<String, BpmnNode>> convertFlowElements(List<FlowElement> flowElements) {
- final List<Result<BpmnNode>> results = flowElements
- .stream()
- .map(converterFactory.flowElementConverter()::convertNode)
- .collect(Collectors.toList());
-
- final Map<String, BpmnNode> resultMap = results.stream()
- .map(Result::value)
- .filter(Objects::nonNull)
- .collect(Collectors.toMap(n -> n.value().getUUID(), n -> n));
-
- return ResultComposer.composeResults(resultMap, results);
+ final List<Result<BpmnNode>> results = new ArrayList<>();
+ final Map<String, BpmnNode> resultMap = new HashMap<>();
+ for (FlowElement element : flowElements) {
+ try {
+ logMessage("Converting " + element);
+ Result<BpmnNode> result = converterFactory.flowElementConverter().convertNode(element);
+ results.add(result);
+ logMessage("Mapping " + result);
+ if (result.value() != null) {
+ BpmnNode n = result.value();
+ resultMap.put(n.value().getUUID(), n);
+ }
+ } catch (Throwable t) {
+ logMessage("Failed to convert/map " + element + t);
+ }
+ }
+ Result toReturn = null;
+ try {
+ logMessage("Composing result");
+ toReturn = ResultComposer.composeResults(resultMap, results);
+ } catch (Throwable t) {
+ logMessage("Failed to compose result " + t);
+ }
+ return toReturn;
}
+ private void logMessage(String message) {
+ if (DomGlobal.console != null) { //Safe for Unit Test
+ DomGlobal.console.log(message);
+ }
+ }
private Result<BpmnNode>[] convertLane(Lane lane, List<Lane> parents, Map<String, BpmnNode> freeFloatingNodes, BpmnNode firstDiagramNode) {
if (lane.getChildLaneSet() != null) {
parents.add(lane);
diff --git a/packages/uniforms-bootstrap4-codegen/package.json b/packages/uniforms-bootstrap4-codegen/package.json
index a5db7597e4..62861e3196 100644
--- a/packages/uniforms-bootstrap4-codegen/package.json
+++ b/packages/uniforms-bootstrap4-codegen/package.json
@@ -27,8 +27,8 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"underscore": "^1.13.1",
- "uniforms": "^3.5.5",
- "uniforms-bridge-simple-schema-2": "^3.5.5"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-simple-schema-2": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/uniforms-bootstrap4-codegen/src/__tests__/_createContext.ts b/packages/uniforms-bootstrap4-codegen/src/__tests__/_createContext.ts
index d56d008b2f..382b7a6095 100644
--- a/packages/uniforms-bootstrap4-codegen/src/__tests__/_createContext.ts
+++ b/packages/uniforms-bootstrap4-codegen/src/__tests__/_createContext.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { Context, randomIds } from "uniforms/cjs";
+import { Context, BaseForm, randomIds } from "uniforms/cjs";
import createSchema from "./_createSchema";
@@ -32,6 +32,16 @@ export default function createContext(schema?: {}, context?: Partial<Context<any
randomId,
submitting: false,
validating: false,
+ formRef: new BaseForm<any>({
+ autosave: false,
+ autosaveDelay: 0,
+ error: false,
+ label: true,
+ model: {},
+ noValidate: false,
+ onSubmit: (event) => {},
+ schema: createSchema(schema),
+ }),
...context,
schema: createSchema(schema),
submitted: false,
diff --git a/packages/uniforms-bootstrap4-codegen/src/uniforms/BootstrapCodeGenContext.tsx b/packages/uniforms-bootstrap4-codegen/src/uniforms/BootstrapCodeGenContext.tsx
index 9c2cd9b55b..79a3060b60 100644
--- a/packages/uniforms-bootstrap4-codegen/src/uniforms/BootstrapCodeGenContext.tsx
+++ b/packages/uniforms-bootstrap4-codegen/src/uniforms/BootstrapCodeGenContext.tsx
@@ -16,7 +16,7 @@
import React, { createContext, useContext } from "react";
-import { Bridge, context, Context, randomIds } from "uniforms/cjs";
+import { Bridge, BaseForm, context, Context, randomIds } from "uniforms/cjs";
import { FormElement } from "../api";
@@ -56,6 +56,16 @@ export const CodeGenContextProvider: React.FC<ProviderProps> = (props) => {
onSubmit: (event) => {},
randomId: randomIds(),
schema: props.schema,
+ formRef: new BaseForm<any>({
+ autosave: false,
+ autosaveDelay: 0,
+ error: false,
+ label: true,
+ model: {},
+ noValidate: false,
+ onSubmit: (event) => {},
+ schema: props.schema,
+ }),
state: {
readOnly: false,
disabled: false,
diff --git a/packages/uniforms-patternfly-codegen/package.json b/packages/uniforms-patternfly-codegen/package.json
index aad9d79292..5f091ee6ee 100644
--- a/packages/uniforms-patternfly-codegen/package.json
+++ b/packages/uniforms-patternfly-codegen/package.json
@@ -26,8 +26,8 @@
"prettier": "^2.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-simple-schema-2": "^3.5.5"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-simple-schema-2": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/uniforms-patternfly-codegen/src/__tests__/_createContext.ts b/packages/uniforms-patternfly-codegen/src/__tests__/_createContext.ts
index d56d008b2f..382b7a6095 100644
--- a/packages/uniforms-patternfly-codegen/src/__tests__/_createContext.ts
+++ b/packages/uniforms-patternfly-codegen/src/__tests__/_createContext.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { Context, randomIds } from "uniforms/cjs";
+import { Context, BaseForm, randomIds } from "uniforms/cjs";
import createSchema from "./_createSchema";
@@ -32,6 +32,16 @@ export default function createContext(schema?: {}, context?: Partial<Context<any
randomId,
submitting: false,
validating: false,
+ formRef: new BaseForm<any>({
+ autosave: false,
+ autosaveDelay: 0,
+ error: false,
+ label: true,
+ model: {},
+ noValidate: false,
+ onSubmit: (event) => {},
+ schema: createSchema(schema),
+ }),
...context,
schema: createSchema(schema),
submitted: false,
diff --git a/packages/uniforms-patternfly-codegen/src/uniforms/CodeGenContext.tsx b/packages/uniforms-patternfly-codegen/src/uniforms/CodeGenContext.tsx
index b7057cf8a6..a65e4e605c 100644
--- a/packages/uniforms-patternfly-codegen/src/uniforms/CodeGenContext.tsx
+++ b/packages/uniforms-patternfly-codegen/src/uniforms/CodeGenContext.tsx
@@ -16,7 +16,7 @@
import React, { createContext, useContext } from "react";
-import { Bridge, context, Context, randomIds } from "uniforms/cjs";
+import { Bridge, BaseForm, context, Context, randomIds } from "uniforms/cjs";
import { FormElement } from "../api";
@@ -56,6 +56,16 @@ export const CodeGenContextProvider: React.FC<ProviderProps> = (props) => {
onSubmit: (event) => {},
randomId: randomIds(),
schema: props.schema,
+ formRef: new BaseForm<any>({
+ autosave: false,
+ autosaveDelay: 0,
+ error: false,
+ label: true,
+ model: {},
+ noValidate: false,
+ onSubmit: (event) => {},
+ schema: props.schema,
+ }),
state: {
readOnly: false,
disabled: false,
diff --git a/packages/uniforms-patternfly/.vscode/launch.json b/packages/uniforms-patternfly/.vscode/launch.json
new file mode 100644
index 0000000000..edebfa0ad2
--- /dev/null
+++ b/packages/uniforms-patternfly/.vscode/launch.json
@@ -0,0 +1,29 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Current TS File",
+ "type": "node",
+ "request": "launch",
+ "env": {},
+ "args": ["${relativeFile}"],
+ "runtimeArgs": ["-r", "ts-node/register"],
+ "cwd": "${workspaceRoot}",
+ "protocol": "inspector",
+ "internalConsoleOptions": "openOnSessionStart"
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest Current File",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["${fileBasenameNoExtension}", "--config", "jest.config.js"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest/bin/jest"
+ }
+ }
+ ]
+}
diff --git a/packages/uniforms-patternfly/README.md b/packages/uniforms-patternfly/README.md
new file mode 100644
index 0000000000..3d4f5ad446
--- /dev/null
+++ b/packages/uniforms-patternfly/README.md
@@ -0,0 +1,97 @@
+# Basic usage
+
+`uniforms` is a plugin for React to be able to create dynamic forms with built-in state management and form validation.
+`uniforms` provides you with simple re-usable form components which allows for rapid prototyping and cleaner React components.
+
+This package extends uniforms to provide [Patternfly React](https://www.patternfly.org/v4/) components inside your forms.
+For more information about `uniforms` please go to https://uniforms.tools/
+
+Looking for building mobile enabled forms? Check [Uniforms-ionic](https://github.com/aerogear/uniforms-ionic) package that provides Ionic extensions
+
+### 1. Install the required packages
+
+To start using uniforms, we have to install three independent packages:
+
+1. Core
+2. Bridge
+3. Theme
+
+In this example, we will use the JSON Schema to describe our desired data format and style our form using the Pattenfly UI theme.
+
+```shell
+npm install uniforms@^3.10.2
+npm install uniforms-bridge-json-schema@^3.10.2
+npm install @kie-tools/uniforms-patternfly
+npm install @patternfly/react-core @patternfly/react-icons
+```
+
+Don't forget that it's necessary to correctly load the styles from Patternfly. To do it, we recommend taking a look into the
+[Patternfly React Seed](https://github.com/patternfly/patternfly-react-seed), or you can simply load the styles directly into
+your `index.html` like in the example app of this repo.
+
+Obs: If you use a previous version of the `tslib` indirectly (version 1), it should be necessary to add this dependency as well.
+
+```shell
+npm install tslib@^2.3.1
+```
+
+### 2. Start by defining a schema
+
+After we've installed required packages, it's time to define our schema. We can do it in a plain JSON, which is a valid JSON Schema instance:
+
+```js
+const schema = {
+ type: "object",
+ properties: {
+ foo: {
+ type: "string",
+ },
+ },
+};
+```
+
+### 3. Then create the bridge
+
+Now that we have the schema, we can create the uniforms bridge of it, by using the corresponding uniforms bridge package.
+Creating the bridge instance is necessary - without it, uniforms would not be able to process form generation and validation.
+As we are using the JSON Schema, we have to import the `uniforms-bridge-json-schema` package. Also, because we're doing an
+example of a JSON Schema, it's necessary to use a JSON Schema validation library, and in this example we'll be using the AJV.
+
+```js
+import { JSONSchemaBridge } from "uniforms-bridge-json-schema";
+import AJV from "ajv";
+
+const ajv = new Ajv({ allErrors: true, useDefaults: true });
+
+function createValidator(schema) {
+ const validator = ajv.compile(schema);
+
+ return (model) => {
+ validator(model);
+ return validator.errors?.length ? { details: validator.errors } : null;
+ };
+}
+
+const bridge = new JSONSchemaBridge(schema, createValidator(schema));
+```
+
+### 4. Finally, use it in a form! 🎉
+
+Uniforms theme packages provide the `AutoForm` component, which is able to generate the form based on the given schema.
+All we have to do now is to pass the previously created Bridge to the `AutoForm`:
+
+```js
+import * as React from "react";
+import { AutoForm } from "@kie-tools/uniforms-patternfly/dist/esm";
+
+import schema from "./schema";
+
+export default function MyForm() {
+ return <AutoForm schema={bridge} onSubmit={console.log} />;
+}
+```
+
+And that's it! `AutoForm` will generate a complete form with labeled fields, errors list (if any) and a submit button.
+
+Also, it will take care of validation and handle model changes. In case you need more advanced feature, take a deeper look
+into the Uniforms docs.
diff --git a/packages/uniforms-patternfly/__mocks__/styleMock.js b/packages/uniforms-patternfly/__mocks__/styleMock.js
new file mode 100644
index 0000000000..f053ebf797
--- /dev/null
+++ b/packages/uniforms-patternfly/__mocks__/styleMock.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/env/index.js
similarity index 61%
copy from packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/env/index.js
index 38ca944907..ac71eb1337 100644
--- a/packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/env/index.js
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,4 +14,11 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.23.0";
+const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");
+
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+ vars: varsWithName({}),
+ get env() {
+ return {};
+ },
+});
diff --git a/packages/uniforms-patternfly/jest.config.js b/packages/uniforms-patternfly/jest.config.js
new file mode 100644
index 0000000000..076ed79f77
--- /dev/null
+++ b/packages/uniforms-patternfly/jest.config.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.exports = {
+ globals: {
+ "ts-jest": {
+ tsconfig: "<rootDir>/tsconfig.esm.json",
+ },
+ },
+ reporters: ["default", ["jest-junit", { outputFile: "./dist-tests/junit-report.xml" }]],
+ setupFilesAfterEnv: ["./src/__tests__/jest.setup.ts"],
+ moduleDirectories: ["node_modules"],
+ testRegex: "src/__tests__/.*\\.test\\.(jsx?|tsx?)$",
+ transform: {
+ "^.+\\.jsx?$": ["babel-jest", { presets: [["@babel/env", { targets: { node: "current" } }], "@babel/react"] }],
+ "^.+\\.tsx?$": "ts-jest",
+ },
+ moduleNameMapper: {
+ "\\.(css|less|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
+ },
+};
diff --git a/packages/uniforms-patternfly-codegen/package.json b/packages/uniforms-patternfly/package.json
similarity index 60%
copy from packages/uniforms-patternfly-codegen/package.json
copy to packages/uniforms-patternfly/package.json
index aad9d79292..4b1db7a9d2 100644
--- a/packages/uniforms-patternfly-codegen/package.json
+++ b/packages/uniforms-patternfly/package.json
@@ -1,8 +1,12 @@
{
- "name": "@kie-tools/uniforms-patternfly-codegen",
+ "name": "@kie-tools/uniforms-patternfly",
"version": "0.0.0",
- "description": "",
+ "description": "Patternfly forms for uniforms",
"license": "Apache-2.0",
+ "author": {
+ "name": "Gianluca",
+ "email": "gzuccare@redhat.com"
+ },
"keywords": [],
"homepage": "https://github.com/kiegroup/kie-tools",
"repository": {
@@ -16,49 +20,48 @@
"dist"
],
"scripts": {
- "build:dev": "rimraf dist && webpack --env dev",
- "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
+ "build:dev": "rimraf dist && tsc --build tsconfig.cjs.json && tsc --build tsconfig.esm.json",
+ "build:prod": "rimraf dist && pnpm lint && pnpm test && rimraf dist && tsc --build tsconfig.cjs.json && tsc --build tsconfig.esm.json",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then \"kie-tools--eslint ./src\"",
- "test": "run-script-if --ignore-errors \"$(build-env tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest --silent --verbose --passWithNoTests\""
+ "test": "run-script-if --ignore-errors \"$(build-env tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest --verbose --passWithNoTests\""
},
"dependencies": {
+ "@types/invariant": "^2.2.35",
+ "invariant": "^2.2.4",
"lodash": "^4.17.21",
- "prettier": "^2.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-simple-schema-2": "^3.5.5"
+ "uniforms": "^3.10.2"
},
"devDependencies": {
- "@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-react": "^7.16.0",
- "@kie-tools-core/webpack-base": "workspace:*",
+ "@kie-tools-scripts/build-env": "workspace:*",
"@kie-tools/eslint": "workspace:*",
"@kie-tools/root-env": "workspace:*",
"@kie-tools/tsconfig": "workspace:*",
+ "@patternfly/react-core": "^4.157.3",
+ "@patternfly/react-icons": "^4.11.17",
+ "@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
- "@types/jest-when": "^2.7.4",
"@types/lodash": "^4.14.168",
- "@types/prettier": "^2.2.1",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
"@types/simpl-schema": "^1.12.0",
+ "@types/testing-library__jest-dom": "^5.9.1",
"@types/testing-library__react": "^9.1.2",
"copy-webpack-plugin": "^11.0.0",
"jest": "^26.6.3",
- "jest-junit": "^14.0.0",
- "jest-raw-loader": "^1.0.1",
- "jest-when": "^3.5.0",
- "raw-loader": "^4.0.2",
"rimraf": "^3.0.2",
+ "simpl-schema": "^1.12.0",
"ts-jest": "^26.5.6",
+ "ts-node": "^10.9.1",
"typescript": "^4.4.2",
+ "uniforms-bridge-simple-schema-2": "^3.10.2",
"webpack": "^5.36.2",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.7.3",
- "webpack-merge": "^5.8.0",
- "webpack-node-externals": "^3.0.0"
+ "webpack-merge": "^5.8.0"
}
}
\ No newline at end of file
diff --git a/packages/unitables/src/uniforms/AutoField.tsx b/packages/uniforms-patternfly/src/AutoField.tsx
similarity index 59%
copy from packages/unitables/src/uniforms/AutoField.tsx
copy to packages/uniforms-patternfly/src/AutoField.tsx
index 2fed18b7e6..2182ec1228 100644
--- a/packages/unitables/src/uniforms/AutoField.tsx
+++ b/packages/uniforms-patternfly/src/AutoField.tsx
@@ -1,11 +1,11 @@
/*
- * Copyright 2021 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,19 +14,20 @@
* limitations under the License.
*/
-import {
- BoolField,
- DateField,
- ListField,
- NestField,
- NumField,
- RadioField,
- SelectField,
- TextField,
-} from "uniforms-patternfly";
import { createAutoField } from "uniforms";
+import invariant from "invariant";
+import BoolField from "./BoolField";
+import DateField from "./DateField";
+import ListField from "./ListField";
+import NestField from "./NestField";
+import NumField from "./NumField";
+import RadioField from "./RadioField";
+import SelectField from "./SelectField";
+import TextField from "./TextField";
-export const AutoField = createAutoField((props) => {
+export type AutoFieldProps = Parameters<typeof AutoField>[0];
+
+const AutoField = createAutoField((props) => {
if (props.allowedValues) {
return props.checkboxes && props.fieldType !== Array ? RadioField : SelectField;
}
@@ -43,7 +44,10 @@ export const AutoField = createAutoField((props) => {
case Object:
return NestField;
case String:
- default:
return TextField;
}
+
+ return invariant(false, "Unsupported field type: %s", props.fieldType);
});
+
+export default AutoField;
diff --git a/packages/uniforms-patternfly/src/AutoFields.tsx b/packages/uniforms-patternfly/src/AutoFields.tsx
new file mode 100644
index 0000000000..09b779fff5
--- /dev/null
+++ b/packages/uniforms-patternfly/src/AutoFields.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ComponentType, createElement } from "react";
+import { useForm } from "uniforms";
+import AutoField from "./AutoField";
+
+export type AutoFieldsProps = {
+ autoField?: ComponentType<{ name: string }>;
+ element?: ComponentType | string;
+ fields?: string[];
+ omitFields?: string[];
+};
+
+function AutoFields({ autoField = AutoField, element = "div", fields, omitFields = [], ...props }: AutoFieldsProps) {
+ const { schema } = useForm();
+
+ return createElement(
+ element!,
+ props,
+ (fields ?? schema.getSubfields())
+ .filter((field) => !omitFields!.includes(field))
+ .map((field) => createElement(autoField!, { key: field, name: field }))
+ );
+}
+
+export default AutoFields;
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/AutoForm.tsx
similarity index 64%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/AutoForm.tsx
index 7f7980f259..f8a58b03e1 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/AutoForm.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,15 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import { AutoForm } from "uniforms";
+import ValidatedQuickForm from "./ValidatedQuickForm";
+
+function Auto(parent: any): any {
+ class _ extends AutoForm.Auto(parent) {
+ static Auto = Auto;
+ }
+
+ return _;
+}
+
+export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-patternfly/src/BaseForm.tsx b/packages/uniforms-patternfly/src/BaseForm.tsx
new file mode 100644
index 0000000000..4e0d65e544
--- /dev/null
+++ b/packages/uniforms-patternfly/src/BaseForm.tsx
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Form } from "@patternfly/react-core";
+import { BaseForm, context } from "uniforms";
+
+function Patternfly(parent: any): any {
+ class _ extends parent {
+ static Patternfly = Patternfly;
+
+ static displayName = `Patternfly${parent.displayName}`;
+
+ render() {
+ return (
+ <context.Provider value={this.getContext()}>
+ <Form data-testid="base-form" {...this.getNativeFormProps()} />
+ </context.Provider>
+ );
+ }
+ }
+
+ return _;
+}
+
+export default Patternfly(BaseForm);
diff --git a/packages/uniforms-patternfly/src/BoolField.tsx b/packages/uniforms-patternfly/src/BoolField.tsx
new file mode 100644
index 0000000000..c0565d0bdd
--- /dev/null
+++ b/packages/uniforms-patternfly/src/BoolField.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Checkbox, CheckboxProps } from "@patternfly/react-core/dist/js/components/Checkbox";
+import { Switch, SwitchProps } from "@patternfly/react-core/dist/js/components/Switch";
+import { connectField, FieldProps } from "uniforms";
+import wrapField from "./wrapField";
+
+enum ComponentType {
+ checkbox = "checkbox",
+ switch = "switch",
+}
+
+export type BoolFieldProps = FieldProps<
+ boolean,
+ CheckboxProps & SwitchProps,
+ {
+ appearance?: ComponentType;
+ inputRef?: React.RefObject<Switch | Checkbox> & React.RefObject<HTMLInputElement>;
+ }
+>;
+
+function BoolField({ appearance, disabled, id, inputRef, label, name, onChange, value, ...props }: BoolFieldProps) {
+ const Component = appearance === ComponentType.switch ? Switch : Checkbox;
+ return wrapField(
+ { id, ...props },
+ <Component
+ data-testid={"bool-field"}
+ isChecked={value ?? false}
+ isDisabled={disabled}
+ id={id}
+ name={name}
+ onChange={() => disabled || onChange(!value)}
+ ref={inputRef}
+ label={label}
+ />
+ );
+}
+
+BoolField.defaultProps = { appearance: ComponentType.checkbox };
+
+export default connectField(BoolField);
diff --git a/packages/uniforms-patternfly/src/DateField.tsx b/packages/uniforms-patternfly/src/DateField.tsx
new file mode 100644
index 0000000000..e98a8f562e
--- /dev/null
+++ b/packages/uniforms-patternfly/src/DateField.tsx
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { useCallback, useMemo } from "react";
+import { connectField, FieldProps } from "uniforms";
+import { DatePicker } from "@patternfly/react-core/dist/js/components/DatePicker";
+import { InputGroup } from "@patternfly/react-core/dist/js/components/InputGroup";
+import { TimePicker } from "@patternfly/react-core/dist/js/components/TimePicker";
+import { TextInputProps } from "@patternfly/react-core/dist/js/components/TextInput";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
+import wrapField from "./wrapField";
+
+export type DateFieldProps = FieldProps<
+ string,
+ TextInputProps,
+ {
+ inputRef?: React.RefObject<HTMLInputElement>;
+ max?: string;
+ min?: string;
+ }
+>;
+
+const DateConstructor = (typeof global === "object" ? global : window).Date;
+
+function DateField({ onChange, ...props }: DateFieldProps) {
+ const dateValue = useCallback(
+ (newDate?: Date) => {
+ if (newDate) {
+ return new DateConstructor(newDate);
+ }
+ if (!props.value) {
+ return undefined;
+ }
+ return new DateConstructor(props.value);
+ },
+ [props.value]
+ );
+
+ const parseDate = useMemo(() => {
+ const date = dateValue();
+ if (!date) {
+ return "";
+ }
+ return date.toISOString().slice(0, -14);
+ }, [dateValue]);
+
+ const parseTime = useMemo(() => {
+ const date = dateValue();
+ if (!date) {
+ return "";
+ }
+ return `${date.getUTCHours()}:${date.getUTCMinutes()}`;
+ }, [dateValue]);
+
+ const onDateChange = useCallback(
+ (value: string, date?: Date) => {
+ if (!date) {
+ onChange(date);
+ } else {
+ const newDate = dateValue(date);
+ const time = parseTime;
+ if (time !== "") {
+ newDate?.setUTCHours(parseInt(time?.split(":")[0]));
+ newDate?.setUTCMinutes(parseInt(time?.split(":")[1]?.split(" ")[0]));
+ } else {
+ newDate?.setUTCHours(0);
+ newDate?.setUTCMinutes(0);
+ }
+ onChange(newDate?.toISOString());
+ }
+ },
+ [onChange, parseTime, dateValue]
+ );
+
+ const isInvalid = useMemo(() => {
+ const date = dateValue();
+ if (date) {
+ if (props.min) {
+ const minDate = new Date(props.min);
+ if (minDate.toString() === "Invalid Date") {
+ return false;
+ } else if (date < minDate) {
+ return `Should be after ${minDate.toISOString()}`;
+ }
+ }
+ if (props.max) {
+ const maxDate = new Date(props.max);
+ if (maxDate.toString() === "Invalid Date") {
+ return false;
+ } else if (date > maxDate) {
+ return `Should be before ${maxDate.toISOString()}`;
+ }
+ }
+ }
+ return false;
+ }, [dateValue, props.min, props.max]);
+
+ const onTimeChange = useCallback(
+ (time: string, hours?: number, minutes?: number) => {
+ const newDate = dateValue();
+ if (newDate) {
+ if (hours && minutes) {
+ newDate.setUTCHours(hours);
+ newDate.setUTCMinutes(minutes);
+ } else if (time !== "") {
+ const localeHours = parseInt(time?.split(":")[0]);
+ const localeMinutes = parseInt(time?.split(":")[1]?.split(" ")[0]);
+ if (!isNaN(localeHours) && !isNaN(localeMinutes)) {
+ newDate.setUTCHours(localeHours);
+ newDate.setUTCMinutes(localeMinutes);
+ }
+ } else {
+ newDate.setUTCHours(0);
+ newDate.setUTCMinutes(0);
+ }
+ onChange(newDate.toISOString());
+ }
+ },
+ [onChange, dateValue]
+ );
+
+ return wrapField(
+ props as any,
+ <Flex
+ data-testid={"date-field"}
+ style={{ margin: 0 }}
+ direction={{ default: "column" }}
+ id={props.id}
+ name={props.name}
+ ref={props.inputRef}
+ >
+ <FlexItem style={{ margin: 0 }}>
+ <InputGroup style={{ background: "transparent" }}>
+ <DatePicker
+ id={`date-picker-${props.id}`}
+ data-testid={`date-picker`}
+ isDisabled={props.disabled}
+ name={props.name}
+ onChange={onDateChange}
+ value={parseDate}
+ />
+ <TimePicker
+ id={`time-picker-${props.id}`}
+ data-testid={`time-picker`}
+ isDisabled={props.disabled || !props.value}
+ name={props.name}
+ onChange={onTimeChange}
+ style={{ width: "120px" }}
+ value={parseTime}
+ is24Hour
+ />
+ </InputGroup>
+ </FlexItem>
+ {isInvalid && (
+ <div
+ id={`${props.id}-invalid-date-time`}
+ style={{
+ fontSize: "0.875rem",
+ color: "#c9190b",
+ marginTop: "0.25rem",
+ }}
+ >
+ {isInvalid}
+ </div>
+ )}
+ </Flex>
+ );
+}
+
+export default connectField(DateField);
diff --git a/packages/uniforms-patternfly/src/ErrorField.tsx b/packages/uniforms-patternfly/src/ErrorField.tsx
new file mode 100644
index 0000000000..fff76f5c7f
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ErrorField.tsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { HTMLProps } from "react";
+import { connectField, filterDOMProps, Override } from "uniforms";
+
+export type ErrorFieldProps = Override<
+ HTMLProps<HTMLDivElement>,
+ {
+ error?: boolean;
+ errorMessage?: string;
+ }
+>;
+
+function ErrorField({ children, error, errorMessage, ...props }: ErrorFieldProps) {
+ return !error ? null : (
+ <div data-testid={"error-field"} {...filterDOMProps(props)}>
+ {children ? children : <div style={{ margin: "3px" }}>{errorMessage}</div>}
+ </div>
+ );
+}
+
+ErrorField.defaultProps = {
+ style: {
+ backgroundColor: "rgba(255, 85, 0, 0.2)",
+ border: "1px solid rgb(255, 85, 0)",
+ borderRadius: "7px",
+ margin: "20px 0px",
+ padding: "10px",
+ },
+};
+
+export default connectField<ErrorFieldProps>(ErrorField, { initialValue: false });
diff --git a/packages/uniforms-patternfly/src/ErrorsField.tsx b/packages/uniforms-patternfly/src/ErrorsField.tsx
new file mode 100644
index 0000000000..b62f66027a
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ErrorsField.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { HTMLProps } from "react";
+import { useForm, filterDOMProps } from "uniforms";
+
+export type ErrorsFieldProps = HTMLProps<HTMLDivElement>;
+
+function ErrorsField({ children, ...props }: ErrorsFieldProps) {
+ const { error, schema } = useForm();
+
+ return !error && !children ? null : (
+ <div data-testid={"errors-field"} {...filterDOMProps(props)}>
+ {children}
+ <ul>
+ {schema.getErrorMessages(error).map((message, index) => (
+ <li key={index} style={{ margin: "3px" }}>
+ {message}
+ </li>
+ ))}
+ </ul>
+ </div>
+ );
+}
+
+ErrorsField.defaultProps = {
+ style: {
+ backgroundColor: "rgba(255, 85, 0, 0.2)",
+ border: "1px solid rgb(255, 85, 0)",
+ borderRadius: "7px",
+ margin: "20px 0px",
+ padding: "10px",
+ },
+};
+
+export default ErrorsField;
diff --git a/packages/uniforms-patternfly/src/HiddenField.tsx b/packages/uniforms-patternfly/src/HiddenField.tsx
new file mode 100644
index 0000000000..633dc3b892
--- /dev/null
+++ b/packages/uniforms-patternfly/src/HiddenField.tsx
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { HTMLProps, Ref, useEffect } from "react";
+import { useField, filterDOMProps } from "uniforms";
+
+export type HiddenFieldProps = {
+ inputRef?: Ref<HTMLInputElement>;
+ name: string;
+ noDOM?: boolean;
+ value?: any;
+} & HTMLProps<HTMLInputElement>;
+
+export default function HiddenField({ value, ...rawProps }: HiddenFieldProps) {
+ const props = useField(rawProps.name, rawProps, { initialValue: false })[0];
+
+ useEffect(() => {
+ if (value !== undefined && value !== props.value) props.onChange(value);
+ });
+
+ return props.noDOM ? null : (
+ <input
+ data-testid="hidden-field"
+ disabled={props.disabled}
+ name={props.name}
+ ref={props.inputRef}
+ type="hidden"
+ value={value ?? props.value ?? ""}
+ {...filterDOMProps(props)}
+ />
+ );
+}
diff --git a/packages/uniforms-patternfly/src/ListAddField.tsx b/packages/uniforms-patternfly/src/ListAddField.tsx
new file mode 100644
index 0000000000..923f3c6eb8
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ListAddField.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import cloneDeep from "lodash/cloneDeep";
+import { Button, ButtonProps } from "@patternfly/react-core/dist/js/components/Button";
+import { PlusCircleIcon } from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
+import { connectField, FieldProps, filterDOMProps, joinName, useField } from "uniforms";
+
+export type ListAddFieldProps = FieldProps<
+ unknown,
+ ButtonProps,
+ {
+ initialCount?: number;
+ name: string;
+ disabled?: boolean;
+ value?: unknown;
+ }
+>;
+
+function ListAddField({ disabled = false, name, value, ...props }: ListAddFieldProps) {
+ const nameParts = joinName(null, name);
+ const parentName = joinName(nameParts.slice(0, -1));
+ const parent = useField<{ maxCount?: number }, unknown[]>(parentName, {}, { absoluteName: true })[0];
+
+ const limitNotReached = !disabled && !(parent.maxCount! <= parent.value!.length);
+
+ return (
+ <Button
+ data-testid={"list-add-field"}
+ variant="plain"
+ style={{ paddingLeft: "0", paddingRight: "0" }}
+ disabled={!limitNotReached}
+ onClick={() => {
+ !disabled && limitNotReached && parent.onChange(parent.value!.concat([cloneDeep(value)]));
+ }}
+ {...filterDOMProps(props)}
+ >
+ <PlusCircleIcon color="#0088ce" />
+ </Button>
+ );
+}
+
+export default connectField<ListAddFieldProps>(ListAddField, {
+ initialValue: false,
+ kind: "leaf",
+});
diff --git a/packages/uniforms-patternfly/src/ListDelField.tsx b/packages/uniforms-patternfly/src/ListDelField.tsx
new file mode 100644
index 0000000000..cfe69d527d
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ListDelField.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ReactNode } from "react";
+import { Button, ButtonProps } from "@patternfly/react-core/dist/js/components/Button";
+import { MinusCircleIcon } from "@patternfly/react-icons/dist/js/icons/minus-circle-icon";
+import { connectField, FieldProps, filterDOMProps, joinName, useField } from "uniforms";
+
+export type ListDelFieldProps = FieldProps<unknown, ButtonProps, { icon?: ReactNode }>;
+
+function ListDelField({ name, disabled, ...props }: ListDelFieldProps) {
+ const nameParts = joinName(null, name);
+ const nameIndex = +nameParts[nameParts.length - 1];
+ const parentName = joinName(nameParts.slice(0, -1));
+ const parent = useField<{ minCount?: number }, unknown[]>(parentName, {}, { absoluteName: true })[0];
+
+ const limitNotReached = !disabled && !(parent.minCount! >= parent.value!.length);
+
+ return (
+ <Button
+ data-testid={"list-del-field"}
+ disabled={!limitNotReached || disabled}
+ variant="plain"
+ style={{ paddingLeft: "0", paddingRight: "0" }}
+ onClick={() => {
+ const value = parent.value!.slice();
+ value.splice(nameIndex, 1);
+ !disabled && limitNotReached && parent.onChange(value);
+ }}
+ {...filterDOMProps(props)}
+ >
+ <MinusCircleIcon color="#cc0000" />
+ </Button>
+ );
+}
+
+export default connectField<ListDelFieldProps>(ListDelField, {
+ initialValue: false,
+ kind: "leaf",
+});
diff --git a/packages/uniforms-patternfly/src/ListField.tsx b/packages/uniforms-patternfly/src/ListField.tsx
new file mode 100644
index 0000000000..f6c6c2ba75
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ListField.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Children, cloneElement, isValidElement, ReactNode } from "react";
+import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
+import { Split, SplitItem } from "@patternfly/react-core/dist/js/layouts/Split";
+import { OutlinedQuestionCircleIcon } from "@patternfly/react-icons/dist/js/icons/outlined-question-circle-icon";
+import { connectField, filterDOMProps, HTMLFieldProps } from "uniforms";
+import ListItemField from "./ListItemField";
+import ListAddField from "./ListAddField";
+
+export type ListFieldProps = HTMLFieldProps<
+ unknown[],
+ HTMLDivElement,
+ {
+ children?: ReactNode;
+ info?: string;
+ error?: boolean;
+ initialCount?: number;
+ itemProps?: object;
+ showInlineError?: boolean;
+ }
+>;
+
+declare module "uniforms" {
+ interface FilterDOMProps {
+ wrapperCol: never;
+ labelCol: never;
+ }
+}
+
+filterDOMProps.register("minCount", "wrapperCol", "labelCol");
+
+function ListField({
+ children = <ListItemField name="$" />,
+ error,
+ errorMessage,
+ info,
+ initialCount,
+ itemProps,
+ label,
+ name,
+ value,
+ showInlineError,
+ ...props
+}: ListFieldProps) {
+ return (
+ <div data-testid={"list-field"} {...filterDOMProps(props)}>
+ <Split hasGutter>
+ <SplitItem>
+ {label && (
+ <label>
+ {label}
+ {!!info && (
+ <span>
+
+ <Tooltip content={info}>
+ <OutlinedQuestionCircleIcon />
+ </Tooltip>
+ </span>
+ )}
+ </label>
+ )}
+ </SplitItem>
+ <SplitItem isFilled />
+ <SplitItem>
+ <ListAddField name={"$"} initialCount={initialCount} />
+ </SplitItem>
+ </Split>
+
+ <div>
+ {value?.map((item, itemIndex) =>
+ Children.map(children, (child, childIndex) =>
+ isValidElement(child)
+ ? cloneElement(child as React.ReactElement<{ name: string }, string>, {
+ key: `${itemIndex}-${childIndex}`,
+ name: child.props.name
+ ?.split(/\$(.*)/s)
+ .slice(0, -1)
+ .join(`${itemIndex}`),
+ ...itemProps,
+ })
+ : child
+ )
+ )}
+ </div>
+ </div>
+ );
+}
+
+export default connectField(ListField);
diff --git a/packages/uniforms-patternfly/src/ListItemField.tsx b/packages/uniforms-patternfly/src/ListItemField.tsx
new file mode 100644
index 0000000000..8152e2e96b
--- /dev/null
+++ b/packages/uniforms-patternfly/src/ListItemField.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ReactNode } from "react";
+import { connectField } from "uniforms";
+import AutoField from "./AutoField";
+import ListDelField from "./ListDelField";
+
+export type ListItemFieldProps = {
+ children?: ReactNode;
+ value?: unknown;
+};
+
+function ListItemField({ children = <AutoField label={null} name={""} /> }: ListItemFieldProps) {
+ return (
+ <div
+ data-testid={"list-item-field"}
+ style={{
+ marginBottom: "1rem",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <div style={{ width: "100%", marginRight: "10px" }}>{children}</div>
+ <div>
+ <ListDelField name={""} />
+ </div>
+ </div>
+ );
+}
+
+export default connectField<ListItemFieldProps>(ListItemField, {
+ initialValue: false,
+});
diff --git a/packages/uniforms-patternfly/src/LongTextField.tsx b/packages/uniforms-patternfly/src/LongTextField.tsx
new file mode 100644
index 0000000000..aa3d7bb272
--- /dev/null
+++ b/packages/uniforms-patternfly/src/LongTextField.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
+import { connectField, filterDOMProps, HTMLFieldProps } from "uniforms";
+
+export type LongTextFieldProps = HTMLFieldProps<
+ string,
+ HTMLDivElement,
+ {
+ inputRef?: React.RefObject<HTMLInputElement>;
+ onChange: (value: string, event: React.ChangeEvent<HTMLTextAreaElement>) => void;
+ value?: string;
+ prefix?: string;
+ }
+>;
+
+function LongTextField({
+ disabled,
+ id,
+ inputRef,
+ label,
+ name,
+ onChange,
+ placeholder,
+ value,
+ ...props
+}: LongTextFieldProps) {
+ return (
+ <div data-testid={"long-text-field"} {...filterDOMProps(props)}>
+ {label && <label htmlFor={id}>{label}</label>}
+ <TextArea
+ id={id}
+ disabled={disabled}
+ name={name}
+ aria-label={name}
+ onChange={(value, event) => onChange(event.target.value)}
+ placeholder={placeholder}
+ ref={inputRef}
+ value={value ?? ""}
+ />
+ </div>
+ );
+}
+
+export default connectField(LongTextField);
diff --git a/packages/uniforms-patternfly/src/NestField.tsx b/packages/uniforms-patternfly/src/NestField.tsx
new file mode 100644
index 0000000000..f9d527babf
--- /dev/null
+++ b/packages/uniforms-patternfly/src/NestField.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { connectField, filterDOMProps, HTMLFieldProps } from "uniforms";
+import { Card, CardBody } from "@patternfly/react-core/dist/js/components/Card";
+import AutoField from "./AutoField";
+
+export type NestFieldProps = HTMLFieldProps<object, HTMLDivElement, { helperText?: string; itemProps?: object }>;
+
+function NestField({
+ children,
+ error,
+ errorMessage,
+ fields,
+ itemProps,
+ label,
+ name,
+ showInlineError,
+ disabled,
+ ...props
+}: NestFieldProps) {
+ return (
+ <Card data-testid={"nest-field"} {...filterDOMProps(props)}>
+ <CardBody className="pf-c-form">
+ {label && (
+ <label>
+ <b>{label}</b>
+ </label>
+ )}
+ {children || fields?.map((field) => <AutoField key={field} disabled={disabled} name={field} {...itemProps} />)}
+ </CardBody>
+ </Card>
+ );
+}
+
+export default connectField(NestField);
diff --git a/packages/uniforms-patternfly/src/NumField.tsx b/packages/uniforms-patternfly/src/NumField.tsx
new file mode 100644
index 0000000000..b778e1bcb2
--- /dev/null
+++ b/packages/uniforms-patternfly/src/NumField.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Ref } from "react";
+import { TextInput, TextInputProps } from "@patternfly/react-core/dist/js/components/TextInput";
+import { connectField } from "uniforms";
+import wrapField from "./wrapField";
+
+export type NumFieldProps = {
+ id: string;
+ decimal?: boolean;
+ inputRef?: Ref<HTMLInputElement>;
+ onChange: (value?: number) => void;
+ disabled?: boolean;
+ value?: number;
+ error?: boolean;
+} & Omit<TextInputProps, "isDisabled">;
+
+function NumField(props: NumFieldProps) {
+ const onChange = (value: string, event: React.FormEvent<HTMLInputElement>) => {
+ const parse = props.decimal ? parseFloat : parseInt;
+ const v = parse((event.target as any)?.value);
+ props.onChange(isNaN(v) ? undefined : v);
+ };
+
+ return wrapField(
+ props,
+ <TextInput
+ data-testid={"num-field"}
+ name={props.name}
+ isDisabled={props.disabled}
+ id={props.id}
+ max={props.max}
+ min={props.min}
+ onChange={onChange}
+ placeholder={props.placeholder}
+ ref={props.inputRef}
+ step={props.decimal ? 0.01 : 1}
+ type="number"
+ value={props.value ?? ""}
+ validated={props.error ? "error" : "default"}
+ />
+ );
+}
+
+export default connectField(NumField);
diff --git a/packages/uniforms-patternfly/src/QuickForm.tsx b/packages/uniforms-patternfly/src/QuickForm.tsx
new file mode 100644
index 0000000000..e9ce315645
--- /dev/null
+++ b/packages/uniforms-patternfly/src/QuickForm.tsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { QuickForm } from "uniforms";
+import AutoField from "./AutoField";
+import BaseForm from "./BaseForm";
+import ErrorsField from "./ErrorsField";
+import SubmitField from "./SubmitField";
+
+function Quick(parent: any): any {
+ class _ extends QuickForm.Quick(parent) {
+ static Quick = Quick;
+
+ getAutoField() {
+ return AutoField;
+ }
+
+ getErrorsField() {
+ return ErrorsField;
+ }
+
+ getSubmitField() {
+ return SubmitField;
+ }
+ }
+
+ return _;
+}
+
+export default Quick(BaseForm);
diff --git a/packages/uniforms-patternfly/src/RadioField.tsx b/packages/uniforms-patternfly/src/RadioField.tsx
new file mode 100644
index 0000000000..8ed5cfc86d
--- /dev/null
+++ b/packages/uniforms-patternfly/src/RadioField.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Radio } from "@patternfly/react-core/dist/js/components/Radio";
+import { connectField, filterDOMProps, HTMLFieldProps } from "uniforms";
+import wrapField from "./wrapField";
+
+export type RadioFieldProps = HTMLFieldProps<
+ string,
+ HTMLDivElement,
+ {
+ transform?: (string?: string) => string;
+ allowedValues: string[];
+ onChange: (value: string) => void;
+ value?: string;
+ disabled?: boolean;
+ }
+>;
+
+function RadioField(props: RadioFieldProps) {
+ filterDOMProps.register("checkboxes", "decimal");
+ return wrapField(
+ props,
+ <div data-testid={"radio-field"} {...filterDOMProps(props)}>
+ {props.allowedValues?.map((item) => (
+ <React.Fragment key={item}>
+ <Radio
+ isChecked={item === props.value}
+ isDisabled={props.disabled}
+ id={`${props.id}`}
+ name={props.name}
+ label={props.transform ? props.transform(item) : item}
+ aria-label={props.name}
+ onChange={() => props.onChange(item)}
+ />
+ </React.Fragment>
+ ))}
+ </div>
+ );
+}
+
+export default connectField(RadioField);
diff --git a/packages/uniforms-patternfly/src/SelectCheckboxField.tsx b/packages/uniforms-patternfly/src/SelectCheckboxField.tsx
new file mode 100644
index 0000000000..1852633542
--- /dev/null
+++ b/packages/uniforms-patternfly/src/SelectCheckboxField.tsx
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { useMemo } from "react";
+import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
+import { Radio } from "@patternfly/react-core/dist/js/components/Radio";
+import { filterDOMProps } from "uniforms";
+import { SelectCheckboxProps } from "./SelectField";
+
+function xor<T>(item: T, array: T[]) {
+ const index = array.indexOf(item);
+ if (index === -1) {
+ return array.concat([item]);
+ }
+
+ return array.slice(0, index).concat(array.slice(index + 1));
+}
+
+filterDOMProps.register("autoValue");
+
+function SelectCheckboxField(props: SelectCheckboxProps) {
+ const Group = useMemo(() => (props.fieldType === Array ? Checkbox : Radio), [props]);
+
+ return (
+ <div data-testid={"select-checkbox-field"} {...filterDOMProps(props)}>
+ {props.label && <label>{props.label}</label>}
+ {props.allowedValues!.map((item: string, index: number) => {
+ return (
+ <React.Fragment key={index}>
+ <label htmlFor={props.id}>{props.transform ? props.transform(item) : item}</label>
+ <Group
+ id={`${props.id}-${item}`}
+ isDisabled={props.disabled}
+ name={props.name}
+ aria-label={props.name}
+ value={props.value}
+ isChecked={
+ props.fieldType === Array && Array.isArray(props.value)
+ ? props.value!.includes(item)
+ : props.value === item
+ }
+ onChange={() => {
+ props.onChange(props.fieldType === Array && Array.isArray(props.value) ? xor(item, props.value) : item);
+ }}
+ />
+ </React.Fragment>
+ );
+ })}
+ </div>
+ );
+}
+
+export default SelectCheckboxField;
diff --git a/packages/uniforms-patternfly/src/SelectField.tsx b/packages/uniforms-patternfly/src/SelectField.tsx
new file mode 100644
index 0000000000..3992324cf5
--- /dev/null
+++ b/packages/uniforms-patternfly/src/SelectField.tsx
@@ -0,0 +1,53 @@
+import * as React from "react";
+import { SelectDirection, SelectProps } from "@patternfly/react-core/dist/js/components/Select";
+import { connectField, FieldProps } from "uniforms";
+import SelectCheckboxField from "./SelectCheckboxField";
+import SelectInputsField from "./SelectInputsField";
+import { CheckboxProps } from "@patternfly/react-core/dist/js/components/Checkbox";
+import { RadioProps } from "@patternfly/react-core/dist/js/components/Radio";
+
+export type SelectCheckboxProps = FieldProps<
+ string | string[],
+ CheckboxProps | RadioProps,
+ {
+ onChange: (value?: string | string[]) => void;
+ transform?: (value?: string) => string;
+ allowedValues: string[];
+ id?: string;
+ fieldType?: typeof Array;
+ disabled?: boolean;
+ }
+>;
+
+export type SelectInputProps = FieldProps<
+ string | string[],
+ SelectProps,
+ {
+ checkboxes?: boolean;
+ required?: boolean;
+ fieldType?: typeof Array;
+ onChange: (value?: string | string[] | number | number[]) => void;
+ placeholder?: string;
+ allowedValues?: (string | number)[];
+ disabled?: boolean;
+ error?: boolean;
+ transform?: (value?: string | number) => string | number;
+ direction?: SelectDirection;
+ menuAppendTo?: HTMLElement;
+ }
+>;
+
+type SelectFieldProps = SelectCheckboxProps | SelectInputProps;
+
+function isSelectCheckboxProps(toBeDetermined: SelectFieldProps): toBeDetermined is SelectCheckboxProps {
+ return (toBeDetermined as SelectInputProps).checkboxes === true;
+}
+
+function SelectField(props: SelectFieldProps) {
+ if (isSelectCheckboxProps(props)) {
+ return <SelectCheckboxField {...props} />;
+ }
+ return <SelectInputsField {...props} />;
+}
+
+export default connectField<SelectFieldProps>(SelectField);
diff --git a/packages/uniforms-patternfly/src/SelectInputsField.tsx b/packages/uniforms-patternfly/src/SelectInputsField.tsx
new file mode 100644
index 0000000000..d0fa71f4e0
--- /dev/null
+++ b/packages/uniforms-patternfly/src/SelectInputsField.tsx
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import {
+ Select,
+ SelectOption,
+ SelectOptionObject,
+ SelectVariant,
+} from "@patternfly/react-core/dist/js/components/Select";
+import wrapField from "./wrapField";
+import { SelectInputProps } from "./SelectField";
+
+type SelectFieldValue = string | string[] | number | number[];
+
+function isSelectOptionObject(
+ toBeDetermined: string | number | SelectOptionObject
+): toBeDetermined is SelectOptionObject {
+ return typeof toBeDetermined === "object" && !Array.isArray(toBeDetermined) && toBeDetermined !== null;
+}
+
+function isSelectOptionString(toBeDetermined: string[] | number[]): toBeDetermined is string[] {
+ return (toBeDetermined.length > 0 && typeof toBeDetermined[0] === "string") || toBeDetermined.length === 0;
+}
+
+function SelectInputsField(props: SelectInputProps) {
+ const [expanded, setExpanded] = useState<boolean>(false);
+ const [selected, setSelected] = useState<SelectFieldValue | undefined>(() => {
+ if (!props.value) {
+ return [];
+ }
+ if (Array.isArray(props.value)) {
+ return [...props.value];
+ }
+ return props.value;
+ });
+
+ const parseInput = useCallback(
+ (selection: string | number | SelectOptionObject, fieldType: typeof Array): SelectFieldValue => {
+ const parsedSelection = isSelectOptionObject(selection) ? selection.toString() : selection;
+
+ if (fieldType !== Array) {
+ return parsedSelection !== "" ? parsedSelection : "";
+ }
+
+ if (Array.isArray(selected)) {
+ if (isSelectOptionString(selected) && typeof parsedSelection === "string") {
+ if (selected.includes(parsedSelection)) {
+ return selected.filter((s) => s !== parsedSelection);
+ }
+ return [parsedSelection, ...selected];
+ } else if (!isSelectOptionString(selected) && typeof parsedSelection === "number") {
+ if (selected.includes(parsedSelection)) {
+ return selected.filter((s) => s !== parsedSelection);
+ }
+ return [parsedSelection, ...selected];
+ }
+ }
+ return [];
+ },
+ [selected]
+ );
+
+ const handleSelect = useCallback(
+ (event: React.MouseEvent | React.ChangeEvent, selection: string | SelectOptionObject) => {
+ if (selection === props.placeholder) {
+ props.onChange(undefined);
+ setSelected([]);
+ } else {
+ const items = parseInput(selection, props.fieldType);
+ props.onChange(items);
+ setSelected(items);
+ }
+ setExpanded(false);
+ },
+ [parseInput, props]
+ );
+
+ const selectOptions = useMemo(() => {
+ const options: JSX.Element[] = [];
+ if (props.placeholder) {
+ options.push(
+ <SelectOption key={`placeholder ${props.allowedValues!.length}`} isPlaceholder value={props.placeholder} />
+ );
+ }
+ props.allowedValues?.forEach((value) =>
+ options.push(
+ <SelectOption key={value} value={value}>
+ {props.transform ? props.transform(value) : value}
+ </SelectOption>
+ )
+ );
+ return options;
+ }, [props]);
+
+ return wrapField(
+ props as any,
+ <div data-testid={"select-inputs-field"} id={props.id}>
+ <Select
+ isDisabled={props.disabled}
+ id={props.id}
+ variant={props.fieldType === Array ? SelectVariant.typeaheadMulti : SelectVariant.single}
+ name={props.name}
+ placeholderText={props.placeholder}
+ isOpen={expanded}
+ selections={selected}
+ onToggle={(isExpanded) => setExpanded(isExpanded)}
+ onSelect={handleSelect}
+ value={props.value || (props.fieldType === Array ? [] : undefined)}
+ menuAppendTo={props.menuAppendTo}
+ direction={props.direction}
+ >
+ {selectOptions}
+ </Select>
+ </div>
+ );
+}
+
+export default SelectInputsField;
diff --git a/packages/uniforms-patternfly/src/SubmitField.tsx b/packages/uniforms-patternfly/src/SubmitField.tsx
new file mode 100644
index 0000000000..a404a18c49
--- /dev/null
+++ b/packages/uniforms-patternfly/src/SubmitField.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Button, ButtonProps } from "@patternfly/react-core/dist/js/components/Button";
+import { Override, useForm } from "uniforms";
+
+export type SubmitFieldProps = Override<ButtonProps, { inputRef?: React.RefObject<HTMLButtonElement> }>;
+
+function SubmitField({ disabled, inputRef, value, ...props }: SubmitFieldProps) {
+ const { error, state } = useForm();
+
+ return (
+ <Button
+ data-testid={"submit-field"}
+ isDisabled={disabled === undefined ? !!(error || state.disabled) : disabled}
+ type="submit"
+ ref={inputRef}
+ variant="primary"
+ >
+ {value}
+ </Button>
+ );
+}
+
+SubmitField.defaultProps = { value: "Submit" };
+
+export default SubmitField;
diff --git a/packages/uniforms-patternfly/src/TextField.tsx b/packages/uniforms-patternfly/src/TextField.tsx
new file mode 100644
index 0000000000..92d5274302
--- /dev/null
+++ b/packages/uniforms-patternfly/src/TextField.tsx
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Ref, useCallback, useMemo } from "react";
+import { DatePicker } from "@patternfly/react-core/dist/js/components/DatePicker";
+import { TextInput, TextInputProps } from "@patternfly/react-core/dist/js/components/TextInput";
+import { TimePicker } from "@patternfly/react-core/dist/js/components/TimePicker";
+import { connectField, filterDOMProps } from "uniforms";
+import wrapField from "./wrapField";
+
+export type TextFieldProps = {
+ id: string;
+ decimal?: boolean;
+ inputRef?: Ref<HTMLInputElement>;
+ onChange: (value?: string) => void;
+ value?: string;
+ disabled?: boolean;
+ error?: boolean;
+ errorMessage?: string;
+ helperText?: string;
+ field?: { format: string };
+} & Omit<TextInputProps, "isDisabled">;
+
+const timeRgx = /^([0-1]?[0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9])?/;
+
+function TextField({ onChange, ...props }: TextFieldProps) {
+ const isDateInvalid = useMemo(() => {
+ if (typeof props.value === "string" && (props.type === "date" || props.field?.format === "date")) {
+ const date = new Date(props.value);
+ if (typeof props.min === "string") {
+ const minDate = new Date(props.min);
+ if (minDate.toString() === "Invalid Date") {
+ return false;
+ } else if (date.toISOString() < minDate.toISOString()) {
+ return props.errorMessage && props.errorMessage.trim().length > 0
+ ? props.errorMessage
+ : `Should be after ${props.min}`;
+ }
+ }
+ if (typeof props.max === "string") {
+ const maxDate = new Date(props.max);
+ if (maxDate.toString() === "Invalid Date") {
+ return false;
+ } else if (date.toISOString() > maxDate.toISOString()) {
+ return props.errorMessage && props.errorMessage.trim().length > 0
+ ? props.errorMessage
+ : `Should be before ${props.max}`;
+ }
+ }
+ }
+ return false;
+ }, [props.value, props.max, props.min, props.errorMessage, props.type, props.field]);
+
+ const parseTime = useCallback((time: string) => {
+ const parsedTime = timeRgx.exec(time);
+ const date = new Date();
+ if (!parsedTime) {
+ return undefined;
+ }
+ date.setUTCHours(Number(parsedTime[1]), Number(parsedTime[2]!));
+ return date;
+ }, []);
+
+ const isTimeInvalid = useMemo(() => {
+ if (typeof props.value === "string" && (props.type === "time" || props.field?.format === "time")) {
+ const parsedTime = parseTime(props.value);
+ if (parsedTime && typeof props.min === "string" && timeRgx.exec(props.min)) {
+ const parsedMin = parseTime(props.min)!;
+ if (parsedTime < parsedMin) {
+ if (parsedMin.getUTCMinutes() < 10) {
+ return `Should be after ${parsedMin.getUTCHours()}:0${parsedMin.getUTCMinutes()}`;
+ }
+ return `Should be after ${parsedMin.getUTCHours()}:${parsedMin.getUTCMinutes()}`;
+ }
+ }
+ if (parsedTime && typeof props.max === "string" && timeRgx.exec(props.max)) {
+ const parsedMax = parseTime(props.max)!;
+ if (parsedTime > parsedMax) {
+ if (parsedMax.getUTCMinutes() < 10) {
+ return `Should be before ${parsedMax.getUTCHours()}:0${parsedMax.getUTCMinutes()}`;
+ }
+ return `Should be before ${parsedMax.getUTCHours()}:${parsedMax.getUTCMinutes()}`;
+ }
+ }
+ }
+ return false;
+ }, [props.type, props.field, props.value, props.max, props.min, parseTime]);
+
+ const onDateChange = useCallback(
+ (value: string) => {
+ onChange(value);
+ },
+ [onChange]
+ );
+
+ const onTimeChange = useCallback(
+ (time: string) => {
+ const parsedTime = time.split(":");
+ if (parsedTime.length === 2) {
+ onChange([...parsedTime, "00"].join(":"));
+ } else {
+ onChange(time);
+ }
+ },
+ [onChange]
+ );
+
+ const { helperText, ...withoutHelperTextProps } = props;
+
+ return wrapField(
+ props,
+ props.type === "date" || props.field?.format === "date" ? (
+ <>
+ <DatePicker
+ data-testid={"text-field-date-picker"}
+ name={props.name}
+ isDisabled={props.disabled}
+ onChange={onDateChange}
+ value={props.value ?? ""}
+ {...filterDOMProps(props)}
+ />
+ {isDateInvalid && (
+ <div
+ style={{
+ fontSize: "0.875rem",
+ color: "#c9190b",
+ marginTop: "0.25rem",
+ }}
+ >
+ {isDateInvalid}
+ </div>
+ )}
+ </>
+ ) : props.type === "time" || props.field?.format === "time" ? (
+ <>
+ <TimePicker
+ data-testid={"text-field-time-picker"}
+ name={props.name}
+ isDisabled={props.disabled}
+ onChange={onTimeChange}
+ is24Hour
+ value={props.value ?? ""}
+ />
+ {isTimeInvalid && (
+ <div
+ style={{
+ fontSize: "0.875rem",
+ color: "#c9190b",
+ marginTop: "0.25rem",
+ }}
+ >
+ {isTimeInvalid}
+ </div>
+ )}
+ </>
+ ) : (
+ <TextInput
+ data-testid={"text-field"}
+ name={props.name}
+ isDisabled={props.disabled}
+ validated={props.error ? "error" : "default"}
+ onChange={(value, event) => onChange((event.target as any)?.value)}
+ placeholder={props.placeholder}
+ ref={props.inputRef}
+ type={props.type ?? "text"}
+ value={props.value ?? ""}
+ {...filterDOMProps(withoutHelperTextProps)}
+ />
+ )
+ );
+}
+
+export default connectField(TextField);
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/ValidatedForm.tsx
similarity index 64%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/ValidatedForm.tsx
index 7f7980f259..67e88ce074 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/ValidatedForm.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,15 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import { ValidatedForm } from "uniforms";
+import BaseForm from "./BaseForm";
+
+function Validated(parent: any): any {
+ class _ extends ValidatedForm.Validated(parent) {
+ static Validated = Validated;
+ }
+
+ return _;
+}
+
+export default Validated(BaseForm);
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/ValidatedQuickForm.tsx
similarity index 70%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/ValidatedQuickForm.tsx
index 7f7980f259..a794533c0e 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/ValidatedQuickForm.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import BaseForm from "./BaseForm";
+import QuickForm from "./QuickForm";
+import ValidatedForm from "./ValidatedForm";
+
+export default ValidatedForm.Validated(QuickForm.Quick(BaseForm));
diff --git a/packages/uniforms-patternfly/src/__tests__/AutoField.test.tsx b/packages/uniforms-patternfly/src/__tests__/AutoField.test.tsx
new file mode 100644
index 0000000000..ac55835414
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/AutoField.test.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { AutoField } from "..";
+import { usingUniformsContext } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<AutoField> - works - default field", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: String } }));
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders RadioField", () => {
+ render(
+ usingUniformsContext(<AutoField name="x" />, {
+ x: {
+ type: String,
+ allowedValues: ["x", "y"],
+ uniforms: { checkboxes: true },
+ },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders SelectField - input", () => {
+ render(
+ usingUniformsContext(<AutoField name="x" />, {
+ x: { type: Array, allowedValues: ["x", "y"] },
+ "x.$": { type: String },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders SelectField - checkbox", () => {
+ render(
+ usingUniformsContext(
+ <AutoField name="x" checkboxes={true} />,
+
+ {
+ x: { type: Array, allowedValues: ["x", "y"] },
+ "x.$": { type: String },
+ }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders DateField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: Date } }));
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders ListField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: Array }, "x.$": { type: String } }));
+ expect(screen.getByTestId("list-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders NumField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: Number } }));
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders NestField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: Object } }));
+ expect(screen.getByTestId("nest-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders TextField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: String } }));
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders BoolField", () => {
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: Boolean } }));
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+});
+
+test("<AutoField> - renders Component (model)", () => {
+ const Component = jest.fn(() => null);
+ render(usingUniformsContext(<AutoField name="x" />, { x: { type: String, uniforms: { component: Component } } }));
+ expect(Component).toHaveBeenCalledTimes(1);
+});
+
+test("<AutoField> - renders Component (specified)", () => {
+ const Component = jest.fn(() => null);
+ render(usingUniformsContext(<AutoField name="x" component={Component} />, { x: { type: String } }));
+ expect(Component).toHaveBeenCalledTimes(1);
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/AutoFields.test.tsx b/packages/uniforms-patternfly/src/__tests__/AutoFields.test.tsx
new file mode 100644
index 0000000000..421d64b822
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/AutoFields.test.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { AutoFields } from "..";
+import { usingUniformsContext } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<AutoFields> - works", () => {
+ render(usingUniformsContext(<AutoFields />, { x: { type: String } }));
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+});
+
+test("<AutoFields> - render all fields by default", () => {
+ render(
+ usingUniformsContext(<AutoFields />, {
+ x: { type: String },
+ y: { type: String },
+ z: { type: String },
+ })
+ );
+
+ expect(screen.getAllByTestId("text-field")).toHaveLength(3);
+});
+
+test("<AutoFields> - renders only specified fields", () => {
+ render(
+ usingUniformsContext(
+ <AutoFields fields={["x", "y"]} />,
+
+ {
+ x: { type: String },
+ y: { type: String },
+ z: { type: String },
+ }
+ )
+ );
+
+ expect(screen.getAllByTestId("text-field")).toHaveLength(2);
+ expect(screen.queryByLabelText("z")).toBeNull();
+});
+
+test("<AutoFields> - does not render ommited fields", () => {
+ render(
+ usingUniformsContext(
+ <AutoFields omitFields={["x"]} />,
+
+ {
+ x: { type: String },
+ y: { type: String },
+ z: { type: String },
+ }
+ )
+ );
+
+ expect(screen.getAllByTestId("text-field")).toHaveLength(2);
+ expect(screen.queryByLabelText("x")).toBeNull();
+});
+
+test("<AutoFields> - works with custom component", () => {
+ const Component = jest.fn(() => null);
+
+ render(
+ usingUniformsContext(
+ <AutoFields autoField={Component} />,
+
+ {
+ x: { type: String },
+ y: { type: String },
+ z: { type: String },
+ }
+ )
+ );
+
+ expect(Component).toHaveBeenCalledTimes(3);
+});
+
+test("<AutoFields> - wraps fields in specified element", () => {
+ render(
+ usingUniformsContext(
+ <AutoFields element="section" />,
+
+ {
+ x: { type: String },
+ y: { type: String },
+ z: { type: String },
+ }
+ )
+ );
+
+ expect(screen.getAllByTestId("text-field")).toHaveLength(3);
+});
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/AutoForm.test.tsx
similarity index 57%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/__tests__/AutoForm.test.tsx
index 7f7980f259..81eacdf661 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/AutoForm.test.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import { AutoForm } from "../";
+import { createSimpleSchema, usingUniformsContext } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<AutoForm> - works", () => {
+ render(usingUniformsContext(<AutoForm schema={createSimpleSchema()} />));
+ expect(screen.getByTestId("base-form")).toBeInTheDocument();
+});
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/BaseForm.test.tsx
similarity index 57%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/__tests__/BaseForm.test.tsx
index 7f7980f259..65d5244541 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/BaseForm.test.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import { BaseForm } from "../";
+import { usingUniformsContext, createSimpleSchema } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<BaseForm> - works", () => {
+ render(usingUniformsContext(<BaseForm schema={createSimpleSchema()} />));
+ expect(screen.getByTestId("base-form")).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/BoolField.test.tsx b/packages/uniforms-patternfly/src/__tests__/BoolField.test.tsx
new file mode 100644
index 0000000000..208df40ba0
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/BoolField.test.tsx
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { BoolField } from "..";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<BoolField> - renders an input", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+});
+
+test("<BoolField> - renders a input with correct id (inherited)", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field").getAttribute("id")).toEqual("uniforms-0000-0001");
+});
+
+test("<BoolField> - renders a input with correct id (specified)", () => {
+ render(usingUniformsContext(<BoolField name="x" id="y" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field").getAttribute("id")).toBe("y");
+});
+
+test("<BoolField> - renders a input with correct name", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field").getAttribute("name")).toBe("x");
+});
+
+test("<BoolField> - renders an input with correct type", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field").getAttribute("type")).toBe("checkbox");
+});
+
+test("<BoolField> - renders an input with correct disabled state", () => {
+ render(usingUniformsContext(<BoolField name="x" disabled={true} />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field")).toBeDisabled();
+});
+
+test("<BoolField> - renders a input with correct label (specified)", () => {
+ render(usingUniformsContext(<BoolField name="x" label="BoolFieldLabel" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByText("BoolFieldLabel")).toBeInTheDocument();
+});
+
+test("<BoolField> - renders a input with correct value (default)", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field")).not.toHaveAttribute("checked");
+});
+
+test("<BoolField> - renders a input with correct value (model)", () => {
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }, { model: { x: true } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field")).toHaveAttribute("checked");
+});
+
+test("<BoolField> - renders a input with correct value (specified)", () => {
+ render(usingUniformsContext(<BoolField name="x" value />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("bool-field")).toHaveAttribute("checked");
+});
+
+test("<BoolField> - renders a input which correctly reacts on change", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<BoolField name="x" />, { x: { type: Boolean } }, { onChange }));
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+
+ fireEvent.click(screen.getByTestId("bool-field"));
+ expect(onChange).toHaveBeenLastCalledWith("x", true);
+});
+
+test("<BoolField> - renders a wrapper with unknown props", () => {
+ render(usingUniformsContext(<BoolField name="x" data-x="x" data-y="y" data-z="z" />, { x: { type: Boolean } }));
+
+ expect(screen.getByTestId("bool-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getAttribute("data-x")).toBe("x");
+ expect(screen.getByTestId("wrapper-field").getAttribute("data-y")).toBe("y");
+ expect(screen.getByTestId("wrapper-field").getAttribute("data-z")).toBe("z");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/DateField.test.tsx b/packages/uniforms-patternfly/src/__tests__/DateField.test.tsx
new file mode 100644
index 0000000000..9df35ac27f
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/DateField.test.tsx
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { DateField } from "../";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<DateField> - renders an input", () => {
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+});
+
+test("<DateField> - renders a input with correct id (inherited)", () => {
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByTestId("date-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("time-picker")).toBeInTheDocument();
+});
+
+test("<DateField> - renders a input with correct id (specified)", () => {
+ render(usingUniformsContext(<DateField name="x" id="y" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByTestId("date-picker").getAttribute("id")).toBe("date-picker-y");
+ // TimePicker component id is in an inside div
+ expect(screen.getByTestId("time-picker").getElementsByClassName("pf-c-select")[0].getAttribute("id")).toBe(
+ "time-picker-y"
+ );
+});
+
+test("<DateField> - renders a input with correct name", () => {
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByTestId("date-field").getAttribute("name")).toBe("x");
+});
+
+test("<DateField> - renders an input with correct disabled state", () => {
+ render(usingUniformsContext(<DateField name="x" disabled />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+
+ const inputs = screen.getByTestId("date-field").getElementsByTagName("input");
+ expect(inputs[0]).toBeDisabled();
+ expect(inputs[1]).toBeDisabled();
+});
+
+test("<DateField> - renders a input with correct label (specified)", () => {
+ render(usingUniformsContext(<DateField required={false} name="x" label="DateFieldLabel" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByText("DateFieldLabel")).toBeInTheDocument();
+});
+
+test("<DateField> - renders a input with correct label (specified)", () => {
+ render(usingUniformsContext(<DateField required={true} name="x" label="DateFieldLabel" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByText("DateFieldLabel")).toBeInTheDocument();
+ expect(screen.getByText("*")).toBeInTheDocument();
+});
+
+test("<DateField> - renders a input with correct value (default)", () => {
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+
+ const inputs = screen.getByTestId("date-field").getElementsByTagName("input");
+ expect(inputs[0].getAttribute("value")).toBe("");
+ expect(inputs[1].getAttribute("value")).toBe("");
+});
+
+test("<DateField> - renders a input with correct value (model)", () => {
+ const now = new Date();
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }, { model: { x: now } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+ expect(screen.getByTestId("time-picker").getAttribute("value")).toEqual(
+ `${now.getUTCHours()}:${now.getUTCMinutes()}`
+ );
+});
+
+test("<DateField> - renders a input with correct value (specified)", () => {
+ const now = new Date();
+ render(usingUniformsContext(<DateField name="x" value={now.toISOString()} />, { x: { type: Date } }));
+
+ expect(screen.getByTestId("date-field")).toBeInTheDocument();
+
+ const inputs = screen.getByTestId("date-field").getElementsByTagName("input");
+ expect(inputs[0].getAttribute("value")).toEqual(now.toISOString().slice(0, -14));
+ expect(inputs[1].getAttribute("value")).toBe("");
+});
+
+test("<DateField> - renders a input which correctly reacts on change (DatePicker)", () => {
+ const onChange = jest.fn();
+
+ const now = "2000-04-04";
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }, { onChange }));
+
+ const input = screen.getByTestId("date-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: now } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", `${now}T00:00:00.000Z`);
+});
+
+test("<DateField> - renders a input which correctly reacts on change (DatePicker - empty)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<DateField name="x" onChange={onChange} />, { x: { type: Date } }));
+
+ const input = screen.getByTestId("date-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: "" } });
+
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<DateField> - renders a input which correctly reacts on change (TimePicker - invalid)", () => {
+ const onChange = jest.fn();
+
+ const now = "10:00";
+ render(usingUniformsContext(<DateField name="x" />, { x: { type: Date } }, { onChange }));
+
+ const input = screen.getByTestId("time-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: now } });
+
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<DateField> - renders a input which correctly reacts on change (TimePicker - valid)", () => {
+ const onChange = jest.fn();
+
+ const date = "2000-04-04";
+ const time = "10:30";
+ render(usingUniformsContext(<DateField name="x" value={`${date}T00:00:00Z`} />, { x: { type: Date } }, { onChange }));
+
+ const input = screen.getByTestId("time-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: time } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", `${date}T${time}:00.000Z`);
+});
+
+test("<DateField> - test max property - valid", () => {
+ const date = "1998-12-31";
+ const max = "1999-01-01T00:00:00Z";
+ render(usingUniformsContext(<DateField name="x" max={max} value={`${date}T00:00:00Z`} />, { x: { type: Date } }));
+
+ expect(screen.queryByTestId("Should be before")).toBeNull();
+});
+
+test("<DateField> - test max property - invalid", () => {
+ const date = "1999-01-02";
+ const max = "1999-01-01T00:00:00.000Z";
+ render(usingUniformsContext(<DateField name="x" max={max} value={`${date}T00:00:00Z`} />, { x: { type: Date } }));
+
+ expect(screen.getByText(`Should be before ${max}`)).toBeInTheDocument();
+});
+
+test("<DateField> - test min property - valid", () => {
+ const date = "1999-01-02";
+ const min = "1999-01-01T00:00:00Z";
+ render(usingUniformsContext(<DateField name="x" min={min} value={`${date}T00:00:00Z`} />, { x: { type: Date } }));
+
+ expect(screen.queryByTestId("Should be after")).toBeNull();
+});
+
+test("<DateField> - test min property - invalid", () => {
+ const date = "1998-12-31";
+ const min = "1999-01-01T00:00:00.000Z";
+ render(usingUniformsContext(<DateField name="x" min={min} value={`${date}T00:00:00Z`} />, { x: { type: Date } }));
+
+ expect(screen.getByText(`Should be after ${min}`)).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ErrorField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ErrorField.test.tsx
new file mode 100644
index 0000000000..496539759c
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ErrorField.test.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ErrorField } from "..";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+const error = {
+ error: "validation-error",
+ reason: "X is required",
+ details: [{ name: "x", type: "required", details: { value: null } }],
+ message: "X is required [validation-error]",
+};
+
+test("<ErrorField> - works", () => {
+ render(usingUniformsContext(<ErrorField name="x" error={true} />, { x: { type: String } }));
+
+ expect(screen.getByTestId("error-field")).toBeInTheDocument();
+});
+
+test("<ErrorField> - renders correct error message (context)", () => {
+ render(usingUniformsContext(<ErrorField name="x" />, { x: { type: String } }, { error }));
+
+ expect(screen.getByTestId("error-field")).toBeInTheDocument();
+ expect(screen.getByText(error.reason)).toBeInTheDocument();
+});
+
+test("<ErrorField> - renders correct error message (specified)", () => {
+ render(
+ usingUniformsContext(<ErrorField name="x" error={error.details[0]} errorMessage={error.reason} />, {
+ x: { type: String },
+ })
+ );
+
+ expect(screen.getByTestId("error-field")).toBeInTheDocument();
+ expect(screen.getByText(error.reason)).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ErrorsField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ErrorsField.test.tsx
new file mode 100644
index 0000000000..0b5fd0230d
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ErrorsField.test.tsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ErrorsField } from "..";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+const error = {
+ error: "validation-error",
+ reason: "X is required",
+ details: [
+ { name: "x", type: "required", details: { value: null } },
+ { name: "y", type: "required", details: { value: null } },
+ { name: "z", type: "required", details: { value: null } },
+ ],
+ message: "X is required [validation-error]",
+};
+
+test("<ErrorsField> - renders list of correct error messages (context)", () => {
+ render(
+ usingUniformsContext(
+ <ErrorsField name="x" />,
+ { x: { type: String }, y: { type: String }, z: { type: String } },
+ { error }
+ )
+ );
+
+ expect(screen.getByTestId("errors-field")).toBeInTheDocument();
+ expect(screen.getByText("X is required")).toBeInTheDocument();
+ expect(screen.getByText("Y is required")).toBeInTheDocument();
+ expect(screen.getByText("Z is required")).toBeInTheDocument();
+});
+
+test("<ErrorsField> - renders children (specified)", () => {
+ render(
+ usingUniformsContext(
+ <ErrorsField name="x">Error message list</ErrorsField>,
+ { x: { type: String }, y: { type: String }, z: { type: String } },
+ { error }
+ )
+ );
+
+ expect(screen.getByText("Error message list")).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/HiddenField.test.tsx b/packages/uniforms-patternfly/src/__tests__/HiddenField.test.tsx
new file mode 100644
index 0000000000..3855356b5c
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/HiddenField.test.tsx
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { HiddenField } from "..";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<HiddenField> - renders an input", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+});
+
+test("<HiddenField> - renders an input with correct id (inherited)", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("id")).toBeTruthy();
+});
+
+test("<HiddenField> - renders an input with correct id (specified)", () => {
+ render(usingUniformsContext(<HiddenField name="x" id="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("id")).toBe("y");
+});
+
+test("<HiddenField> - renders an input with correct name", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("name")).toBe("x");
+});
+
+test("<HiddenField> - renders an input with correct type", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("type")).toBe("hidden");
+});
+
+test("<HiddenField> - renders an input with correct value (default)", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("value")).toBe("");
+});
+
+test("<HiddenField> - renders an input with correct value (model)", () => {
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }, { model: { x: "y" } }));
+
+ expect(screen.getByTestId("hidden-field")).toBeInTheDocument();
+ expect(screen.getByTestId("hidden-field").getAttribute("value")).toBe("y");
+});
+
+test("<HiddenField> - renders an input which correctly reacts on model change", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }, { onChange }));
+
+ fireEvent.change(screen.getByTestId("hidden-field"), { target: { value: "y" } });
+ expect(screen.getByTestId("hidden-field").getAttribute("value")).toBe("y");
+});
+
+test("<HiddenField> - renders an input which correctly reacts on model change (empty)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }, { onChange }));
+
+ fireEvent.change(screen.getByTestId("hidden-field"), { target: { value: undefined } });
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<HiddenField> - renders an input which correctly reacts on model change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<HiddenField name="x" />, { x: { type: String } }, { model: { x: "y" }, onChange }));
+
+ fireEvent.change(screen.getByTestId("hidden-field"), { target: { value: "y" } });
+
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<HiddenField noDOM> - renders nothing", () => {
+ render(usingUniformsContext(<HiddenField noDOM name="x" />, { x: { type: String } }));
+
+ expect(screen.queryByTestId("hidden-field")).toBeNull();
+});
+
+test("<HiddenField noDOM> - renders nothing which correctly reacts on model change", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<HiddenField noDOM name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.queryByTestId("hidden-field")).toBeNull();
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<HiddenField noDOM> - renders nothing which correctly reacts on model change (empty)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<HiddenField noDOM name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.queryByTestId("hidden-field")).toBeNull();
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<HiddenField noDOM> - renders nothing which correctly reacts on model change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(<HiddenField noDOM name="x" />, { x: { type: String } }, { model: { x: "y" }, onChange })
+ );
+
+ expect(screen.queryByTestId("hidden-field")).toBeNull();
+ expect(onChange).not.toHaveBeenCalled();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ListAddField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ListAddField.test.tsx
new file mode 100644
index 0000000000..868dbbe9cf
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ListAddField.test.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ListAddField } from "../";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+const onChange = jest.fn();
+
+const context = { onChange, model: { x: [] } };
+const schema = { x: { type: Array, maxCount: 3 }, "x.$": String };
+
+beforeEach(() => {
+ onChange.mockClear();
+});
+
+test("<ListAddField> - works", () => {
+ render(usingUniformsContext(<ListAddField name="x.$" />, schema, context));
+
+ expect(screen.getByTestId("list-add-field")).toBeInTheDocument();
+});
+
+test("<ListAddField> - prevents onClick when disabled", () => {
+ render(usingUniformsContext(<ListAddField name="x.1" disabled />, schema, context));
+
+ fireEvent.click(screen.getByTestId("list-add-field"));
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<ListAddField> - prevents onClick when limit reached", () => {
+ render(usingUniformsContext(<ListAddField name="x.1" />, { ...schema, x: { ...schema.x, maxCount: 0 } }, context));
+
+ fireEvent.click(screen.getByTestId("list-add-field"));
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<ListAddField> - correctly reacts on click", () => {
+ render(usingUniformsContext(<ListAddField name="x.1" value="y" />, schema, context));
+
+ fireEvent.click(screen.getByTestId("list-add-field"));
+ expect(onChange).toHaveBeenLastCalledWith("x", ["y"]);
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ListDelField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ListDelField.test.tsx
new file mode 100644
index 0000000000..cdf5710e7e
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ListDelField.test.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ListDelField } from "../";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+const onChange = jest.fn();
+
+const context = { onChange, model: { x: ["x", "y", "z"] } };
+const schema = { x: { type: Array, maxCount: 3 }, "x.$": String };
+
+beforeEach(() => {
+ onChange.mockClear();
+});
+
+test("<ListDelField> - works", () => {
+ render(usingUniformsContext(<ListDelField name="x.1" />, schema, context));
+
+ expect(screen.getByTestId("list-del-field")).toBeInTheDocument();
+});
+
+test("<ListDelField> - prevents onClick when disabled", () => {
+ render(usingUniformsContext(<ListDelField name="x.1" disabled />, schema, context));
+
+ fireEvent.click(screen.getByTestId("list-del-field"));
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<ListDelField> - prevents onClick when limit reached", () => {
+ render(usingUniformsContext(<ListDelField name="x.1" />, { ...schema, x: { ...schema.x, minCount: 3 } }, context));
+
+ fireEvent.click(screen.getByTestId("list-del-field"));
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<ListDelField> - correctly reacts on click", () => {
+ render(usingUniformsContext(<ListDelField name="x.1" />, schema, context));
+
+ fireEvent.click(screen.getByTestId("list-del-field"));
+ expect(onChange).toHaveBeenLastCalledWith("x", ["x", "z"]);
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ListField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ListField.test.tsx
new file mode 100644
index 0000000000..8501938884
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ListField.test.tsx
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ListField } from "../";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<ListField> - works", () => {
+ render(usingUniformsContext(<ListField name="x" />, { x: { type: Array }, "x.$": { type: String } }));
+
+ expect(screen.getByTestId("list-field")).toBeInTheDocument();
+});
+
+test("<ListField> - renders ListAddField", () => {
+ render(
+ usingUniformsContext(<ListField name="x" label="ListFieldLabel" />, { x: { type: Array }, "x.$": { type: String } })
+ );
+
+ expect(screen.getByTestId("list-add-field")).toBeInTheDocument();
+ expect(screen.getByText("ListFieldLabel")).toBeInTheDocument();
+});
+
+test("<ListField> - renders correct label (specified)", () => {
+ render(
+ usingUniformsContext(<ListField name="x" label="ListFieldLabel" />, { x: { type: Array }, "x.$": { type: String } })
+ );
+
+ expect(screen.getByText("ListFieldLabel")).toBeInTheDocument();
+});
+
+test("<ListField> - renders correct numer of items with initialCount (specified)", () => {
+ render(
+ usingUniformsContext(<ListField name="x" initialCount={3} />, { x: { type: Array }, "x.$": { type: String } })
+ );
+
+ expect(screen.getAllByTestId("text-field")).toHaveLength(3);
+});
+
+test("<ListField> - renders children (specified)", () => {
+ const Child: () => null = jest.fn(() => null);
+
+ render(
+ usingUniformsContext(
+ <ListField name="x" initialCount={2}>
+ <Child />
+ </ListField>,
+ { x: { type: Array }, "x.$": { type: String } }
+ )
+ );
+
+ expect(Child).toHaveBeenCalledTimes(2);
+});
+
+test("<ListField> - renders children with correct name (children)", () => {
+ const Child: any = jest.fn((props: any) => <div {...props} data-testid={"child-div"} />);
+
+ render(
+ usingUniformsContext(
+ <ListField name="x" initialCount={2}>
+ <Child name="$" />
+ </ListField>,
+ { x: { type: Array }, "x.$": { type: String } }
+ )
+ );
+
+ const childDivs = screen.getAllByTestId("child-div");
+ expect(childDivs[0].getAttribute("name")).toBe("0");
+ expect(childDivs[1].getAttribute("name")).toBe("1");
+});
+
+test("<ListField> - renders children with correct name (value)", () => {
+ render(
+ usingUniformsContext(<ListField name="x" initialCount={2} />, { x: { type: Array }, "x.$": { type: String } })
+ );
+
+ const textFields = screen.getAllByTestId("text-field");
+ expect(textFields[0].getAttribute("name")).toBe("x.0");
+ expect(textFields[1].getAttribute("name")).toBe("x.1");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/ListItemField.test.tsx b/packages/uniforms-patternfly/src/__tests__/ListItemField.test.tsx
new file mode 100644
index 0000000000..086f75f283
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/ListItemField.test.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { ListItemField } from "../";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<ListItemField> - works", () => {
+ render(usingUniformsContext(<ListItemField name="x.1" />, { x: { type: Array }, "x.$": { type: String } }));
+
+ expect(screen.getByTestId("list-item-field")).toBeInTheDocument();
+});
+
+test("<ListItemField> - renders AutoField", () => {
+ const element = <ListItemField name="x.1" />;
+ render(usingUniformsContext(element, { x: { type: Array }, "x.$": { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+});
+
+test("<ListItemField> - renders children if specified", () => {
+ const Child: () => null = jest.fn(() => null);
+
+ render(
+ usingUniformsContext(
+ <ListItemField name="x.1">
+ <Child />
+ </ListItemField>,
+ { x: { type: Array }, "x.$": { type: String } }
+ )
+ );
+
+ expect(Child).toHaveBeenCalledTimes(1);
+});
+
+test("<ListItemField> - renders ListDelField", () => {
+ render(usingUniformsContext(<ListItemField name="x.1" />, { x: { type: Array }, "x.$": { type: String } }));
+
+ expect(screen.getByTestId("list-del-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("name")).toBe("x.1");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/LongTextField.test.tsx b/packages/uniforms-patternfly/src/__tests__/LongTextField.test.tsx
new file mode 100644
index 0000000000..4dcdcb0878
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/LongTextField.test.tsx
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { LongTextField } from "../";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<LongTextField> - renders a textarea", () => {
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+});
+
+test("<LongTextField> - renders a textarea with correct disabled state", () => {
+ render(usingUniformsContext(<LongTextField name="x" disabled />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea).toBeDisabled();
+});
+
+test("<LongTextField> - renders a textarea with correct id (inherited)", () => {
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea.getAttribute("id")).toBeTruthy();
+});
+
+test("<LongTextField> - renders a textarea with correct id (specified)", () => {
+ render(usingUniformsContext(<LongTextField name="x" id="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea.getAttribute("id")).toBe("y");
+});
+
+test("<LongTextField> - renders a textarea with correct name", () => {
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea.getAttribute("name")).toBe("x");
+});
+
+test("<LongTextField> - renders a textarea with correct placeholder", () => {
+ render(usingUniformsContext(<LongTextField name="x" placeholder="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea.getAttribute("placeholder")).toBe("y");
+});
+
+test("<LongTextField> - renders a textarea with correct value (default)", () => {
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ expect(textarea.getAttribute("value")).toBe(null);
+});
+
+test("<LongTextField> - renders a textarea with correct value (model)", () => {
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }, { model: { x: "y" } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ expect(screen.getByText("y")).toBeInTheDocument();
+});
+
+test("<LongTextField> - renders a textarea with correct value (specified)", () => {
+ render(usingUniformsContext(<LongTextField name="x" value="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ expect(screen.getByText("y")).toBeInTheDocument();
+});
+
+test("<LongTextField> - renders a textarea which correctly reacts on change", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ fireEvent.change(textarea, { target: { value: "y" } });
+ expect(onChange).toHaveBeenLastCalledWith("x", "y");
+});
+
+test("<LongTextField> - renders a textarea which correctly reacts on change (empty)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ fireEvent.change(textarea, { target: { value: "" } });
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<LongTextField> - renders a textarea which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<LongTextField name="x" />, { x: { type: String } }, { model: { x: "y" }, onChange }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ const textarea = screen.getByTestId("long-text-field").getElementsByTagName("textarea")[0];
+ fireEvent.change(textarea, { target: { value: "y" } });
+ expect(screen.getByText("y")).toBeInTheDocument();
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<LongTextField> - renders a label", () => {
+ render(usingUniformsContext(<LongTextField name="x" label="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("long-text-field")).toBeInTheDocument();
+ expect(screen.getByText("y")).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/NestField.test.tsx b/packages/uniforms-patternfly/src/__tests__/NestField.test.tsx
new file mode 100644
index 0000000000..930fcd4923
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/NestField.test.tsx
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { NestField } from "..";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<NestField> - renders an <AutoField> for each field", () => {
+ render(
+ usingUniformsContext(<NestField name="x" />, {
+ x: { type: Object },
+ "x.a": { type: String },
+ "x.b": { type: Number },
+ })
+ );
+
+ expect(screen.getByTestId("nest-field")).toBeInTheDocument();
+ expect(screen.getByTestId("nest-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("nest-field").getElementsByTagName("input")[0].getAttribute("name")).toBe("x.a");
+ expect(screen.getByTestId("nest-field").getElementsByTagName("input")[1].getAttribute("name")).toBe("x.b");
+});
+
+test("<NestField> - renders custom content if given", () => {
+ render(
+ usingUniformsContext(
+ <NestField name="x">
+ <article data-test="content" />
+ </NestField>,
+ {
+ x: { type: Object },
+ "x.a": { type: String },
+ "x.b": { type: Number },
+ }
+ )
+ );
+
+ expect(screen.getByTestId("nest-field")).toBeInTheDocument();
+ expect(screen.getByTestId("nest-field").getElementsByTagName("article")).toHaveLength(1);
+ expect(screen.getByTestId("nest-field").getElementsByTagName("article")[0].getAttribute("data-test")).toBe("content");
+});
+
+test("<NestField> - renders a label", () => {
+ render(
+ usingUniformsContext(<NestField name="x" label="y" />, {
+ x: { type: Object },
+ "x.a": { type: String },
+ "x.b": { type: Number },
+ })
+ );
+
+ expect(screen.getByTestId("nest-field")).toBeInTheDocument();
+ expect(screen.getByTestId("nest-field").getElementsByTagName("label")).toHaveLength(3);
+ expect(screen.getByTestId("nest-field").getElementsByTagName("label")[0].textContent).toBe("y");
+ expect(screen.getByTestId("nest-field").getElementsByTagName("label")[1].textContent).toBe("A *");
+ expect(screen.getByTestId("nest-field").getElementsByTagName("label")[2].textContent).toBe("B *");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/NumField.test.tsx b/packages/uniforms-patternfly/src/__tests__/NumField.test.tsx
new file mode 100644
index 0000000000..f083604b77
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/NumField.test.tsx
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { NumField } from "..";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<NumField> - renders an input", () => {
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+});
+
+test("<NumField> - renders an input with correct disabled state", () => {
+ render(usingUniformsContext(<NumField name="x" disabled />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field")).toBeDisabled();
+});
+
+test("<NumField> - renders an input with correct id (inherited)", () => {
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("id")).toBeTruthy();
+});
+
+test("<NumField> - renders an input with correct id (specified)", () => {
+ render(usingUniformsContext(<NumField name="x" id="y" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("id")).toBe("y");
+});
+
+test("<NumField> - renders an input with correct max", () => {
+ render(usingUniformsContext(<NumField name="x" max={10} />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("max")).toBe("10");
+});
+
+test("<NumField> - renders an input with correct min", () => {
+ render(usingUniformsContext(<NumField name="x" min={10} />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("min")).toBe("10");
+});
+
+test("<NumField> - renders an input with correct name", () => {
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("name")).toBe("x");
+});
+
+test("<NumField> - renders an input with correct placeholder", () => {
+ render(usingUniformsContext(<NumField name="x" placeholder="y" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("placeholder")).toBe("y");
+});
+
+test("<NumField> - renders an input with correct step (decimal)", () => {
+ render(usingUniformsContext(<NumField name="x" decimal />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("step")).toBe("0.01");
+});
+
+test("<NumField> - renders an input with correct step (integer)", () => {
+ render(usingUniformsContext(<NumField name="x" decimal={false} />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("step")).toBe("1");
+});
+
+test("<NumField> - renders an input with correct type", () => {
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("type")).toBe("number");
+});
+
+test("<NumField> - renders an input with correct value (default)", () => {
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("value")).toBe("");
+});
+
+test("<NumField> - renders an input with correct value (decimal)", () => {
+ const onChange = jest.fn();
+ render(usingUniformsContext(<NumField name="x" decimal={true} />, { x: { type: Number } }, { onChange }));
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+
+ // NOTE: All following tests are here to cover hacky NumField implementation.
+ const spy = jest.spyOn(global.console, "error").mockImplementation(() => {});
+
+ [
+ { value: "0.1", expected: 0.1 },
+ { value: "2", expected: 2 },
+ { value: "-1", expected: -1 },
+ ].forEach(({ value, expected }) => {
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+ expect(onChange).toHaveBeenLastCalledWith("x", expected);
+ });
+
+ spy.mockRestore();
+});
+
+test("<NumField> - renders an input with correct value (not decimal)", () => {
+ const onChange = jest.fn();
+ render(usingUniformsContext(<NumField name="x" decimal={false} />, { x: { type: Number } }, { onChange }));
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+
+ // NOTE: All following tests are here to cover hacky NumField implementation.
+ const spy = jest.spyOn(global.console, "error").mockImplementation(() => {});
+
+ [
+ { value: "0.1", expected: 0 },
+ { value: "2", expected: 2 },
+ { value: "-1", expected: -1 },
+ ].forEach(({ value, expected }) => {
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+ expect(onChange).toHaveBeenLastCalledWith("x", expected);
+ });
+
+ spy.mockRestore();
+});
+
+test("<NumField> - renders an input with correct value (specified)", () => {
+ render(usingUniformsContext(<NumField name="x" value={2} />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ expect(screen.getByTestId("num-field").getAttribute("value")).toBe("2");
+});
+
+test("<NumField> - renders an input which correctly reacts on change", () => {
+ const onChange = jest.fn();
+ const value = "1";
+
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }, { onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", 1);
+});
+
+test("<NumField> - renders an input which correctly reacts on change (decimal on decimal)", () => {
+ const onChange = jest.fn();
+ const value = "2.5";
+
+ render(usingUniformsContext(<NumField name="x" decimal />, { x: { type: Number } }, { onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", 2.5);
+});
+
+test("<NumField> - renders an input which correctly reacts on change (decimal on integer)", () => {
+ const onChange = jest.fn();
+ const value = "2.5";
+
+ render(usingUniformsContext(<NumField name="x" decimal={false} />, { x: { type: Number } }, { onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", 2);
+});
+
+test("<NumField> - renders an input which correctly reacts on change (empty)", () => {
+ const onChange = jest.fn();
+ const value = "";
+
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }, { onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<NumField> - renders an input which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+ const value = "1";
+
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }, { model: { x: 1 }, onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<NumField> - renders an input which correctly reacts on change (zero)", () => {
+ const onChange = jest.fn();
+ const value = "0";
+
+ render(usingUniformsContext(<NumField name="x" />, { x: { type: Number } }, { onChange }));
+
+ expect(screen.getByTestId("num-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("num-field"), { target: { value } });
+
+ expect(onChange).toHaveBeenLastCalledWith("x", 0);
+});
+
+test("<NumField> - renders a label", () => {
+ render(usingUniformsContext(<NumField required={false} name="x" label="y" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y");
+ const id = screen.getByTestId("num-field").getAttribute("id");
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].getAttribute("for")).toBe(id);
+});
+
+test("<NumField> - renders a label", () => {
+ render(usingUniformsContext(<NumField required={true} name="x" label="y" />, { x: { type: Number } }));
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+ const id = screen.getByTestId("num-field").getAttribute("id");
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].getAttribute("for")).toBe(id);
+});
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/QuickForm.test.tsx
similarity index 56%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/__tests__/QuickForm.test.tsx
index 7f7980f259..db096667b1 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/QuickForm.test.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import { QuickForm } from "..";
+import { usingUniformsContext, createSimpleSchema } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<QuickForm> - works", () => {
+ render(usingUniformsContext(<QuickForm schema={createSimpleSchema()} />));
+ expect(screen.getByTestId("base-form")).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/RadioField.test.tsx b/packages/uniforms-patternfly/src/__tests__/RadioField.test.tsx
new file mode 100644
index 0000000000..b1f6f51aa7
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/RadioField.test.tsx
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { RadioField } from "..";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<RadioField> - renders a set of checkboxes", () => {
+ render(usingUniformsContext(<RadioField name="x" allowedValues={[]} />, { x: { type: String, allowedValues: [] } }));
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(0);
+});
+
+test("<RadioField> - renders a set of checkboxes", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+});
+
+test("<RadioField> - renders a set of checkboxes with correct disabled state", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" disabled allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0]).toBeDisabled();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1]).toBeDisabled();
+});
+
+test("<RadioField> - renders a set of checkboxes with correct id (inherited)", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0].getAttribute("id")).toBeTruthy();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1].getAttribute("id")).toBeTruthy();
+});
+
+test("<RadioField> - renders a set of checkboxes with correct id (specified)", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" id="y" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0].getAttribute("id")).toBe("y");
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1].getAttribute("id")).toBe("y");
+});
+
+test("<RadioField> - renders a set of checkboxes with correct name", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0].getAttribute("name")).toBe("x");
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1].getAttribute("name")).toBe("x");
+});
+
+test("<RadioField> - renders a set of checkboxes with correct options", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("label")[0].textContent).toBe("a");
+ expect(screen.getByTestId("radio-field").getElementsByTagName("label")[1].textContent).toBe("b");
+});
+
+test("<RadioField> - renders a set of checkboxes with correct options (transform)", () => {
+ render(
+ usingUniformsContext(
+ <RadioField name="x" transform={(x: string) => x.toUpperCase()} allowedValues={["a", "b"]} />,
+ { x: { type: String, allowedValues: ["a", "b"] } }
+ )
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("label")[0].textContent).toBe("A");
+ expect(screen.getByTestId("radio-field").getElementsByTagName("label")[1].textContent).toBe("B");
+});
+
+test("<RadioField> - renders a set of checkboxes with correct value (default)", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1]).not.toBeChecked();
+});
+
+test("<RadioField> - renders a set of checkboxes with correct value (model)", () => {
+ render(
+ usingUniformsContext(
+ <RadioField name="x" allowedValues={["a", "b"]} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" } }
+ )
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1]).toBeChecked();
+});
+
+test("<RadioField> - renders a set of checkboxes with correct value (specified)", () => {
+ render(
+ usingUniformsContext(<RadioField name="x" value="b" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("radio-field").getElementsByTagName("input")[1]).toBeChecked();
+});
+
+test("<RadioField> - renders a set of checkboxes which correctly reacts on change", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <RadioField name="x" allowedValues={["a", "b"]} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ const inputs = screen.getByTestId("radio-field").getElementsByTagName("input");
+ expect(inputs).toHaveLength(2);
+ fireEvent.click(inputs[1]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "b");
+});
+
+test("<RadioField> - renders a set of checkboxes which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <RadioField name="x" allowedValues={["a", "b"]} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" }, onChange }
+ )
+ );
+
+ expect(screen.getByTestId("radio-field")).toBeInTheDocument();
+ const inputs = screen.getByTestId("radio-field").getElementsByTagName("input");
+ expect(inputs).toHaveLength(2);
+ fireEvent.click(inputs[0]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "a");
+});
+
+test("<RadioField> - renders a label", () => {
+ render(
+ usingUniformsContext(<RadioField required={false} name="x" label="y" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(3);
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y");
+});
+
+test("<RadioField> - renders a label (required)", () => {
+ render(
+ usingUniformsContext(<RadioField required={true} name="x" label="y" allowedValues={["a", "b"]} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(3);
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/SelectField.test.tsx b/packages/uniforms-patternfly/src/__tests__/SelectField.test.tsx
new file mode 100644
index 0000000000..74d2e4c6b3
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/SelectField.test.tsx
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { SelectField } from "..";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<SelectField checkboxes> - renders a set of checkboxes", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct disabled state", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" disabled checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0]).toBeDisabled();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]).toBeDisabled();
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct id (inherited)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0].getAttribute("id")).toBeTruthy();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1].getAttribute("id")).toBeTruthy();
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct id (specified)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" id="y" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0].getAttribute("id")).toBe("y-a");
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1].getAttribute("id")).toBe("y-b");
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct name", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0].getAttribute("name")).toBe("x");
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1].getAttribute("name")).toBe("x");
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct options", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")[0].textContent).toBe("a");
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")[1].textContent).toBe("b");
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct options (transform)", () => {
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" transform={(x: string) => x.toUpperCase()} checkboxes={true} />,
+ { x: { type: String, allowedValues: ["a", "b"] } }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")[0].textContent).toBe("A");
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")[1].textContent).toBe("B");
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct value (default)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]).not.toBeChecked();
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct value (model)", () => {
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" checkboxes={true} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" } }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]).toBeChecked();
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes with correct value (specified)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" value="b" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0]).not.toBeChecked();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]).toBeChecked();
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes which correctly reacts on change", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" checkboxes={true} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+
+ fireEvent.click(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "b");
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes which correctly reacts on change (array check)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" checkboxes={true} />,
+ {
+ x: { type: Array },
+ "x.$": { type: String, allowedValues: ["a", "b"] },
+ },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+
+ fireEvent.click(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]);
+ expect(onChange).toHaveBeenLastCalledWith("x", ["b"]);
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes which correctly reacts on change (array uncheck)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" value={["b"]} checkboxes={true} />,
+ {
+ x: { type: Array },
+ "x.$": { type: String, allowedValues: ["a", "b"] },
+ },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+
+ fireEvent.click(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[1]);
+ expect(onChange).toHaveBeenLastCalledWith("x", []);
+});
+
+test("<SelectField checkboxes> - renders a set of checkboxes which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" checkboxes={true} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" }, onChange }
+ )
+ );
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")).toHaveLength(2);
+
+ fireEvent.click(screen.getByTestId("select-checkbox-field").getElementsByTagName("input")[0]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "a");
+});
+
+test("<SelectField checkboxes> - renders a label", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" label="y" checkboxes={true} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-checkbox-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")).toHaveLength(3);
+ expect(screen.getByTestId("select-checkbox-field").getElementsByTagName("label")[1].textContent).toBe("a");
+});
+
+test("<SelectField> - renders a select", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+});
+
+test("<SelectField> - renders a select with correct disabled state", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" disabled />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]).toBeDisabled();
+});
+
+test("<SelectField> - renders a select with correct id (specified)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" id="y" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").getAttribute("id")).toBe("y");
+});
+
+test("<SelectField> - renders a select with correct name", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ // patternfly don't pass down the name property
+ // expect(screen.getByTestId("select-inputs-field").getAttribute("name")).toBe("x");
+});
+
+test("<SelectField> - renders a select with correct options", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[1].textContent).toBe("a");
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2].textContent).toBe("b");
+});
+
+test("<SelectField> - renders a select with correct options (transform)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" transform={(x: string) => x.toUpperCase()} />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[1].textContent).toBe("A");
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2].textContent).toBe("B");
+});
+
+test("<SelectField> - renders a select with correct options (numbers)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" />, { x: { type: String, allowedValues: [1, 2] } })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[1].textContent).toBe("1");
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2].textContent).toBe("2");
+});
+
+test("<SelectField> - renders a select with correct placeholder (implicit)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" placeholder="y" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("span")[0].textContent).toBe("y");
+ expect(screen.getByTestId("select-inputs-field").getAttribute("value")).toBe(null);
+});
+
+test("<SelectField> - renders a select with correct value (default)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").getAttribute("value")).toBe(null);
+});
+
+test("<SelectField> - renders a select with correct value (model)", () => {
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" } }
+ )
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").textContent).toBe("b");
+});
+
+test("<SelectField> - renders a select with correct value (specified)", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} name="x" value="b" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("span")[0].textContent).toBe("b");
+});
+
+test("<SelectField> - renders a select which correctly reacts on change", () => {
+ const onChange = jest.fn();
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "b");
+});
+
+test("<SelectField> - renders a select which correctly reacts on change (array)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" value={undefined} />,
+ {
+ x: { type: Array },
+ "x.$": { type: String, allowedValues: ["a", "b"] },
+ },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2]);
+ expect(onChange).toHaveBeenLastCalledWith("x", ["b"]);
+});
+
+test("<SelectField> - renders a select which correctly reacts on change (placeholder)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" placeholder={"test"} />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(4);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[1]);
+ expect(onChange).toHaveBeenCalled();
+});
+
+test("<SelectField> - renders a select which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(
+ usingUniformsContext(
+ <SelectField onToggle={() => {}} name="x" />,
+ { x: { type: String, allowedValues: ["a", "b"] } },
+ { model: { x: "b" }, onChange }
+ )
+ );
+
+ expect(screen.getByTestId("select-inputs-field")).toBeInTheDocument();
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(1);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[0]);
+ expect(screen.getByTestId("select-inputs-field").getElementsByTagName("button")).toHaveLength(3);
+ fireEvent.click(screen.getByTestId("select-inputs-field").getElementsByTagName("button")[2]);
+ expect(onChange).toHaveBeenLastCalledWith("x", "b");
+});
+
+test("<SelectField> - renders a label", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} required={false} name="x" label="y" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(1);
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y");
+});
+
+test("<SelectField> - renders a label", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} required={true} name="x" label="y" />, {
+ x: { type: String, allowedValues: ["a", "b"] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(1);
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+});
+
+test("<SelectField> - renders a number label", () => {
+ render(
+ usingUniformsContext(<SelectField onToggle={() => {}} required={true} name="x" label={1} />, {
+ x: { type: Number, allowedValues: [1, 2] },
+ })
+ );
+
+ expect(screen.getByTestId("wrapper-field")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")).toHaveLength(1);
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("1 *");
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/SubmitField.test.tsx b/packages/uniforms-patternfly/src/__tests__/SubmitField.test.tsx
new file mode 100644
index 0000000000..3bb1c07a54
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/SubmitField.test.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { SubmitField } from "..";
+import { render, screen } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<SubmitField> - renders", () => {
+ render(usingUniformsContext(<SubmitField />));
+
+ expect(screen.getByTestId("submit-field")).toBeInTheDocument();
+});
+
+test("<SubmitField> - renders disabled if error", () => {
+ render(usingUniformsContext(<SubmitField />, undefined, { error: {} }));
+
+ expect(screen.getByTestId("submit-field")).toBeInTheDocument();
+ expect(screen.getByTestId("submit-field")).toBeDisabled();
+});
+
+test("<SubmitField> - renders enabled if error and enabled", () => {
+ render(usingUniformsContext(<SubmitField disabled={false} />, undefined, { error: {} }));
+
+ expect(screen.getByTestId("submit-field")).toBeInTheDocument();
+ expect(screen.getByTestId("submit-field")).toBeEnabled();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/TextField.test.tsx b/packages/uniforms-patternfly/src/__tests__/TextField.test.tsx
new file mode 100644
index 0000000000..4f2e0d4682
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/TextField.test.tsx
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { TextField } from "../";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { usingUniformsContext } from "./test-utils";
+
+test("<TextField> - renders an input", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+});
+
+test("<TextField> - renders an input with correct disabled state", () => {
+ render(usingUniformsContext(<TextField name="x" disabled />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field")).toBeDisabled();
+});
+
+test("<TextField> - renders an input with correct id (inherited)", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("id")).toBeTruthy();
+});
+
+test("<TextField> - renders an input with correct id (specified)", () => {
+ render(usingUniformsContext(<TextField name="x" id="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("id")).toBe("y");
+});
+
+test("<TextField> - renders an input with correct name", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("name")).toBe("x");
+});
+
+test("<TextField> - renders an input with correct placeholder", () => {
+ render(usingUniformsContext(<TextField name="x" placeholder="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("placeholder")).toBe("y");
+});
+
+test("<TextField> - renders an input with correct type", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("type")).toBe("text");
+});
+
+test("<TextField> - renders an input with correct value (default)", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("value")).toBe("");
+});
+
+test("<TextField> - renders an input with correct value (model)", () => {
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }, { model: { x: "y" } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("value")).toBe("y");
+});
+
+test("<TextField> - renders an input with correct value (specified)", () => {
+ render(usingUniformsContext(<TextField name="x" value="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field").getAttribute("value")).toBe("y");
+});
+
+test("<TextField> - renders an input which correctly reacts on change", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("text-field"), { target: { value: "y" } });
+ expect(onChange).toHaveBeenLastCalledWith("x", "y");
+});
+
+test("<TextField> - renders an input which correctly reacts on change (empty)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }, { onChange }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("text-field"), { target: { value: "" } });
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<TextField> - renders an input which correctly reacts on change (same value)", () => {
+ const onChange = jest.fn();
+
+ render(usingUniformsContext(<TextField name="x" />, { x: { type: String } }, { model: { x: "y" }, onChange }));
+
+ expect(screen.getByTestId("text-field")).toBeInTheDocument();
+ fireEvent.change(screen.getByTestId("text-field"), { target: { value: "y" } });
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<TextField> - renders a label", () => {
+ render(usingUniformsContext(<TextField required={false} name="x" label="y" />, { x: { type: String } }));
+
+ expect(screen.getByText("y")).toBeInTheDocument();
+});
+
+test("<TextField> - renders a label", () => {
+ render(usingUniformsContext(<TextField required={true} name="x" label="y" />, { x: { type: String } }));
+
+ expect(screen.getByText("y")).toBeInTheDocument();
+ expect(screen.getByText("*")).toBeInTheDocument();
+});
+
+test("<TextField> - renders a help", () => {
+ render(usingUniformsContext(<TextField required={false} name="x" helperText="y" />, { x: { type: String } }));
+
+ expect(screen.getByTestId("wrapper-field").querySelector(".pf-c-form__helper-text")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").querySelector(".pf-c-form__helper-text")?.textContent).toBe("y");
+});
+
+test("<TextField> - renders a initial value on date field (DatePicker)", () => {
+ const date = "2000-04-04";
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"date"} />,
+ { x: { type: String } },
+ { model: { x: date } }
+ )
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field-date-picker").getElementsByTagName("input")[0].value).toBe(date);
+});
+
+test("<TextField> - renders a disabled date field (DatePicker)", () => {
+ render(
+ usingUniformsContext(<TextField required={true} name="x" label="y" type={"date"} disabled={true} />, {
+ x: { type: String },
+ })
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field-date-picker").getElementsByTagName("input")[0]).toBeDisabled();
+});
+
+test("<TextField> - renders a input which correctly reacts on change (DatePicker)", () => {
+ const onChange = jest.fn();
+ const date = "2000-04-04";
+
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"date"} />,
+ { x: { type: String } },
+ { onChange }
+ )
+ );
+
+ const input = screen.getByTestId("text-field-date-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: date } });
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+ expect(onChange).toHaveBeenLastCalledWith("x", date);
+});
+
+test("<TextField> - renders a input which correctly reacts on change (DatePicker - empty)", () => {
+ const onChange = jest.fn();
+ const date = "";
+
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"date"} />,
+ { x: { type: String } },
+ { onChange }
+ )
+ );
+
+ const input = screen.getByTestId("text-field-date-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: date } });
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<TextField> - renders a initial value on time field (TimePicker)", () => {
+ const time = "10:00";
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"time"} />,
+ { x: { type: String } },
+ { model: { x: time } }
+ )
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field-time-picker").getAttribute("value")).toBe(time);
+});
+
+test("<TextField> - renders a disabled date field (TimePicker)", () => {
+ render(
+ usingUniformsContext(<TextField required={true} name="x" label="y" type={"time"} disabled={true} />, {
+ x: { type: String },
+ })
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("text-field-time-picker").getElementsByTagName("input")[0]).toBeDisabled();
+});
+
+test("<TextField> - renders a input which correctly reacts on change (TimePicker)", () => {
+ const onChange = jest.fn();
+ const time = "10:10";
+
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"time"} />,
+ { x: { type: String } },
+ { onChange }
+ )
+ );
+
+ const input = screen.getByTestId("text-field-time-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: time } });
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+ expect(onChange).toHaveBeenLastCalledWith("x", "10:10:00");
+});
+
+test("<TextField> - renders a input which correctly reacts on change (TimePicker - empty)", () => {
+ const onChange = jest.fn();
+ const time = "";
+
+ render(
+ usingUniformsContext(
+ <TextField required={true} name="x" label="y" type={"time"} />,
+ { x: { type: String } },
+ { onChange }
+ )
+ );
+
+ const input = screen.getByTestId("text-field-time-picker").getElementsByTagName("input")[0];
+ fireEvent.change(input, { target: { value: time } });
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.getByTestId("wrapper-field").getElementsByTagName("label")[0].textContent).toBe("y *");
+ expect(onChange).not.toHaveBeenCalled();
+});
+
+test("<TextField> - test max property (TimePicker - valid)", () => {
+ const time = "10:00";
+ const max = "12:00";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" max={max} type={"time"} value={time} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be before")).not.toBeInTheDocument();
+});
+
+test("<TextField> - test max property (TimePicker - invalid)", () => {
+ const time = "13:00";
+ const max = "12:00";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" max={max} type={"time"} value={time} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be before 12:00")).toBeInTheDocument();
+});
+
+test("<TextField> - test min property (TimePicker - valid)", () => {
+ const time = "13:00";
+ const min = "12:00";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" min={min} type={"time"} value={time} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be after")).not.toBeInTheDocument();
+});
+
+test("<TextField> - test min property (TimePicker - invalid)", () => {
+ const time = "10:00";
+ const min = "12:00";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" min={min} type={"time"} value={time} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-time-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be after 12:00")).toBeInTheDocument();
+});
+
+test("<TextField> - test max property (DatePicker - valid)", () => {
+ const date = "2000-01-01";
+ const max = "2000-01-02";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" max={max} type={"date"} value={date} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be before")).not.toBeInTheDocument();
+});
+
+test("<TextField> - test max property (DatePicker - invalid)", () => {
+ const date = "2000-01-02";
+ const max = "2000-01-01";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" max={max} type={"date"} value={date} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be before 2000-01-01")).toBeInTheDocument();
+});
+
+test("<TextField> - test min property (DatePicker - valid)", () => {
+ const date = "2000-01-02";
+ const min = "2000-01-01";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" min={min} type={"date"} value={date} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be after")).not.toBeInTheDocument();
+});
+
+test("<TextField> - test min property (DatePicker - invalid)", () => {
+ const date = "2000-01-01";
+ const min = "2000-01-02";
+ render(
+ usingUniformsContext(<TextField name="x" label="y" min={min} type={"date"} value={date} />, { x: { type: String } })
+ );
+
+ expect(screen.getByTestId("text-field-date-picker")).toBeInTheDocument();
+ expect(screen.queryByText("Should be after 2000-01-02")).toBeInTheDocument();
+});
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/ValidateQuickForm.test.tsx
similarity index 55%
copy from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
copy to packages/uniforms-patternfly/src/__tests__/ValidateQuickForm.test.tsx
index 7f7980f259..f412b22d69 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/ValidateQuickForm.test.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import { ValidatedQuickForm } from "..";
+import { render, screen } from "@testing-library/react";
+import { createSimpleSchema, usingUniformsContext } from "./test-utils";
+
+test("<ValidatedQuickForm> - works", () => {
+ render(usingUniformsContext(<ValidatedQuickForm schema={createSimpleSchema()} />));
+ expect(screen.getByTestId("base-form")).toBeInTheDocument();
+});
diff --git a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/ValidatedForm.test.tsx
similarity index 56%
rename from packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
rename to packages/uniforms-patternfly/src/__tests__/ValidatedForm.test.tsx
index 7f7980f259..41d09b69e3 100644
--- a/packages/serverless-logic-web-tools/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/ValidatedForm.test.tsx
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.25.0";
+import * as React from "react";
+import { ValidatedForm } from "..";
+import { createSimpleSchema, usingUniformsContext } from "./test-utils";
+import { render, screen } from "@testing-library/react";
+
+test("<ValidatedForm> - works", () => {
+ render(usingUniformsContext(<ValidatedForm schema={createSimpleSchema()} />));
+ expect(screen.getByTestId("base-form")).toBeInTheDocument();
+});
diff --git a/packages/uniforms-patternfly/src/__tests__/index.test.ts b/packages/uniforms-patternfly/src/__tests__/index.test.ts
new file mode 100644
index 0000000000..a893f84235
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/index.test.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as unstyled from "..";
+
+it("exports everything", () => {
+ expect(unstyled).toEqual({
+ AutoFields: expect.any(Function),
+ AutoField: expect.any(Function),
+ AutoForm: expect.any(Function),
+ BaseForm: expect.any(Function),
+ BoolField: expect.any(Function),
+ DateField: expect.any(Function),
+ ErrorField: expect.any(Function),
+ ErrorsField: expect.any(Function),
+ HiddenField: expect.any(Function),
+ ListAddField: expect.any(Function),
+ ListDelField: expect.any(Function),
+ ListField: expect.any(Function),
+ ListItemField: expect.any(Function),
+ LongTextField: expect.any(Function),
+ NestField: expect.any(Function),
+ NumField: expect.any(Function),
+ QuickForm: expect.any(Function),
+ RadioField: expect.any(Function),
+ SelectField: expect.any(Function),
+ SubmitField: expect.any(Function),
+ TextField: expect.any(Function),
+ ValidatedForm: expect.any(Function),
+ ValidatedQuickForm: expect.any(Function),
+ });
+});
diff --git a/packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts b/packages/uniforms-patternfly/src/__tests__/jest.setup.ts
similarity index 75%
rename from packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts
rename to packages/uniforms-patternfly/src/__tests__/jest.setup.ts
index 38ca944907..b8ba348a89 100644
--- a/packages/online-editor/src/workspace/startupBlockers/LatestCompatibleVersion.ts
+++ b/packages/uniforms-patternfly/src/__tests__/jest.setup.ts
@@ -1,11 +1,11 @@
/*
- * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
-export const LATEST_VERSION_COMPATIBLE_WITH_LFS = "0.23.0";
+import "@testing-library/jest-dom";
diff --git a/packages/uniforms-patternfly/src/__tests__/test-utils.tsx b/packages/uniforms-patternfly/src/__tests__/test-utils.tsx
new file mode 100644
index 0000000000..a3848ffe86
--- /dev/null
+++ b/packages/uniforms-patternfly/src/__tests__/test-utils.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { Context, BaseForm, context, randomIds } from "uniforms";
+import SimpleSchema from "simpl-schema";
+import { SimpleSchema2Bridge } from "uniforms-bridge-simple-schema-2";
+
+const randomId = randomIds();
+
+export function createSimpleSchema(schema = {}) {
+ return new SimpleSchema2Bridge(new SimpleSchema(schema));
+}
+
+export function usingUniformsContext(children: React.ReactElement, schema = {}, ctx?: Partial<Context<any>>) {
+ const partialCtx = {
+ changed: false,
+ changedMap: {},
+ error: null,
+ model: {},
+ name: [],
+ onChange: () => {},
+ onSubmit: () => {},
+ randomId,
+ submitting: false,
+ validating: false,
+ submitted: false,
+ schema: createSimpleSchema(schema),
+ formRef: new BaseForm<any>({
+ autosave: false,
+ autosaveDelay: 0,
+ error: false,
+ label: true,
+ model: {},
+ noValidate: false,
+ onSubmit: (event) => {},
+ schema: createSimpleSchema(schema),
+ }),
+ ...ctx,
+ state: {
+ disabled: false,
+ label: false,
+ placeholder: false,
+ showInlineError: false,
+ readOnly: false,
+ },
+ };
+ return <context.Provider value={partialCtx}>{children}</context.Provider>;
+}
diff --git a/packages/uniforms-patternfly/src/index.ts b/packages/uniforms-patternfly/src/index.ts
new file mode 100644
index 0000000000..0300e9e461
--- /dev/null
+++ b/packages/uniforms-patternfly/src/index.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as AutoFields } from "./AutoFields";
+export { default as AutoField } from "./AutoField";
+export { default as AutoForm } from "./AutoForm";
+export { default as BaseForm } from "./BaseForm";
+export { default as BoolField } from "./BoolField";
+export { default as DateField } from "./DateField";
+export { default as ErrorField } from "./ErrorField";
+export { default as ErrorsField } from "./ErrorsField";
+export { default as HiddenField } from "./HiddenField";
+export { default as ListAddField } from "./ListAddField";
+export { default as ListDelField } from "./ListDelField";
+export { default as ListField } from "./ListField";
+export { default as ListItemField } from "./ListItemField";
+export { default as LongTextField } from "./LongTextField";
+export { default as NestField } from "./NestField";
+export { default as NumField } from "./NumField";
+export { default as QuickForm } from "./QuickForm";
+export { default as RadioField } from "./RadioField";
+export { default as SelectField } from "./SelectField";
+export { default as SubmitField } from "./SubmitField";
+export { default as TextField } from "./TextField";
+export { default as ValidatedForm } from "./ValidatedForm";
+export { default as ValidatedQuickForm } from "./ValidatedQuickForm";
diff --git a/packages/uniforms-patternfly/src/wrapField.tsx b/packages/uniforms-patternfly/src/wrapField.tsx
new file mode 100644
index 0000000000..f0204b6a2c
--- /dev/null
+++ b/packages/uniforms-patternfly/src/wrapField.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { FormGroup, FormGroupProps } from "@patternfly/react-core/dist/js/components/Form";
+import { filterDOMProps } from "uniforms";
+
+declare module "uniforms" {
+ interface FilterDOMProps {
+ decimal: never;
+ minCount: never;
+ autoValue: never;
+ isDisabled: never;
+ checkboxes: never;
+ exclusiveMaximum: never;
+ exclusiveMinimum: never;
+ menuAppendTo: never;
+ }
+}
+
+filterDOMProps.register(
+ "decimal",
+ "minCount",
+ "autoValue",
+ "isDisabled",
+ "exclusiveMaximum",
+ "exclusiveMinimum",
+ "menuAppendTo"
+);
+
+type WrapperProps = {
+ id: string;
+ error?: boolean;
+ errorMessage?: string;
+ help?: string;
+ showInlineError?: boolean;
+} & Omit<FormGroupProps, "onChange" | "fieldId">;
+
+export default function wrapField(
+ { id, label, type, disabled, error, errorMessage, showInlineError, help, required, ...props }: WrapperProps,
+ children: React.ReactNode
+) {
+ return (
+ <FormGroup
+ data-testid={"wrapper-field"}
+ fieldId={id}
+ label={label}
+ isRequired={required}
+ validated={error ? "error" : "default"}
+ type={type}
+ helperText={help}
+ helperTextInvalid={errorMessage}
+ {...filterDOMProps(props)}
+ >
+ {children}
+ </FormGroup>
+ );
+}
diff --git a/packages/uniforms-patternfly/tsconfig.cjs.json b/packages/uniforms-patternfly/tsconfig.cjs.json
new file mode 100644
index 0000000000..5197e7369d
--- /dev/null
+++ b/packages/uniforms-patternfly/tsconfig.cjs.json
@@ -0,0 +1,13 @@
+{
+ "extends": "@kie-tools/tsconfig/tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "dist/cjs",
+ "rootDir": "src",
+ "module": "commonjs",
+ "target": "es6",
+ "esModuleInterop": true,
+ "moduleResolution": "node"
+ },
+ "include": ["src"]
+}
diff --git a/packages/uniforms-patternfly/tsconfig.esm.json b/packages/uniforms-patternfly/tsconfig.esm.json
new file mode 100644
index 0000000000..ebfe721109
--- /dev/null
+++ b/packages/uniforms-patternfly/tsconfig.esm.json
@@ -0,0 +1,13 @@
+{
+ "extends": "@kie-tools/tsconfig/tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "dist/esm",
+ "rootDir": "src",
+ "module": "es6",
+ "target": "es6",
+ "esModuleInterop": true,
+ "moduleResolution": "node"
+ },
+ "include": ["src"]
+}
diff --git a/packages/unitables-dmn/package.json b/packages/unitables-dmn/package.json
index ce07fabd6a..57800c96da 100644
--- a/packages/unitables-dmn/package.json
+++ b/packages/unitables-dmn/package.json
@@ -44,9 +44,8 @@
"react-dom": "^17.0.2",
"react-id-generator": "^3.0.1",
"react-table": "^7.6.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5",
- "uniforms-patternfly": "^4.7.9"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/unitables/package.json b/packages/unitables/package.json
index f3b3bab2e6..7e0dfee795 100644
--- a/packages/unitables/package.json
+++ b/packages/unitables/package.json
@@ -31,6 +31,7 @@
"@kie-tools/boxed-expression-component": "workspace:*",
"@kie-tools/form": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
+ "@kie-tools/uniforms-patternfly": "workspace:*",
"@patternfly/react-core": "^4.157.3",
"@patternfly/react-icons": "^4.11.17",
"@types/lodash": "^4.14.168",
@@ -43,9 +44,8 @@
"react-dom": "^17.0.2",
"react-id-generator": "^3.0.1",
"react-table": "^7.6.2",
- "uniforms": "^3.5.5",
- "uniforms-bridge-json-schema": "^3.5.5",
- "uniforms-patternfly": "^4.7.9"
+ "uniforms": "^3.10.2",
+ "uniforms-bridge-json-schema": "^3.10.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
diff --git a/packages/unitables/src/uniforms/AutoField.tsx b/packages/unitables/src/uniforms/AutoField.tsx
index 2fed18b7e6..f52a468f1e 100644
--- a/packages/unitables/src/uniforms/AutoField.tsx
+++ b/packages/unitables/src/uniforms/AutoField.tsx
@@ -23,7 +23,7 @@ import {
RadioField,
SelectField,
TextField,
-} from "uniforms-patternfly";
+} from "@kie-tools/uniforms-patternfly/dist/esm";
import { createAutoField } from "uniforms";
export const AutoField = createAutoField((props) => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c5cf573b2d..960d5da083 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,8 +28,8 @@ importers:
specifier: ^0.6.1
version: 0.6.1(prettier@2.3.0)
"@types/node":
- specifier: ^15.0.2
- version: 15.6.0
+ specifier: ^18.13.0
+ version: 18.13.0
filemanager-webpack-plugin:
specifier: ^7.0.0
version: 7.0.0
@@ -450,6 +450,94 @@ importers:
specifier: ^5.8.0
version: 5.8.0
+ examples/uniforms-patternfly:
+ dependencies:
+ "@kie-tools-core/patternfly-base":
+ specifier: workspace:*
+ version: link:../../packages/patternfly-base
+ "@kie-tools/uniforms-patternfly":
+ specifier: workspace:*
+ version: link:../../packages/uniforms-patternfly
+ "@patternfly/react-core":
+ specifier: ^4.157.3
+ version: 4.168.8(react-dom@17.0.2)(react@17.0.2)
+ "@patternfly/react-icons":
+ specifier: ^4.11.17
+ version: 4.19.8(react-dom@17.0.2)(react@17.0.2)
+ ajv:
+ specifier: ^6.12.6
+ version: 6.12.6
+ react:
+ specifier: ^17.0.2
+ version: 17.0.2
+ react-dom:
+ specifier: ^17.0.2
+ version: 17.0.2(react@17.0.2)
+ simpl-schema:
+ specifier: ^1.12.0
+ version: 1.12.0
+ uniforms:
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
+ uniforms-bridge-json-schema:
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
+ uniforms-bridge-simple-schema:
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
+ uniforms-bridge-simple-schema-2:
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
+ devDependencies:
+ "@kie-tools-core/webpack-base":
+ specifier: workspace:*
+ version: link:../../packages/webpack-base
+ "@kie-tools/root-env":
+ specifier: workspace:*
+ version: link:../../packages/root-env
+ "@kie-tools/tsconfig":
+ specifier: workspace:*
+ version: link:../../packages/tsconfig
+ "@types/react":
+ specifier: ^17.0.6
+ version: 17.0.21
+ "@types/react-dom":
+ specifier: ^17.0.5
+ version: 17.0.8
+ "@types/react-router":
+ specifier: ^5.1.14
+ version: 5.1.14
+ "@types/react-router-dom":
+ specifier: ^5.1.7
+ version: 5.1.7
+ "@types/simpl-schema":
+ specifier: ^1.12.0
+ version: 1.12.0
+ copy-webpack-plugin:
+ specifier: ^11.0.0
+ version: 11.0.0(webpack@5.70.0)
+ react-router-dom:
+ specifier: ^5.2.1
+ version: 5.3.0(react@17.0.2)
+ rimraf:
+ specifier: ^3.0.2
+ version: 3.0.2
+ typescript:
+ specifier: ^4.4.2
+ version: 4.8.4
+ webpack:
+ specifier: ^5.36.2
+ version: 5.70.0(webpack-cli@4.10.0)
+ webpack-cli:
+ specifier: ^4.10.0
+ version: 4.10.0(webpack-dev-server@4.7.3)(webpack@5.70.0)
+ webpack-dev-server:
+ specifier: ^4.7.3
+ version: 4.7.3(webpack-cli@4.10.0)(webpack@5.70.0)
+ webpack-merge:
+ specifier: ^5.8.0
+ version: 5.8.0
+
examples/webapp:
dependencies:
"@kie-tools-core/editor":
@@ -1943,6 +2031,9 @@ importers:
"@kie-tools/dashbuilder-component-api":
specifier: workspace:*
version: link:../dashbuilder-component-api
+ "@kie-tools/uniforms-patternfly":
+ specifier: workspace:*
+ version: link:../uniforms-patternfly
"@patternfly/react-core":
specifier: ^4.157.3
version: 4.168.8(react-dom@17.0.2)(react@17.0.2)
@@ -1962,14 +2053,11 @@ importers:
specifier: ^17.0.2
version: 17.0.2(react@17.0.2)
uniforms:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
uniforms-bridge-json-schema:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
- uniforms-patternfly:
- specifier: ^4.7.9
- version: 4.7.9(@patternfly/react-core@4.168.8)(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
devDependencies:
"@babel/core":
specifier: ^7.16.0
@@ -3283,6 +3371,9 @@ importers:
"@kie-tools/i18n-common-dictionary":
specifier: workspace:*
version: link:../i18n-common-dictionary
+ "@kie-tools/uniforms-patternfly":
+ specifier: workspace:*
+ version: link:../uniforms-patternfly
"@patternfly/react-core":
specifier: ^4.157.3
version: 4.168.8(react-dom@17.0.2)(react@17.0.2)
@@ -3308,14 +3399,11 @@ importers:
specifier: ^17.0.2
version: 17.0.2(react@17.0.2)
uniforms:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
uniforms-bridge-json-schema:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
- uniforms-patternfly:
- specifier: ^4.7.9
- version: 4.7.9(@patternfly/react-core@4.168.8)(@patternfly/react-icons@4.19.8)(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
devDependencies:
"@babel/core":
specifier: ^7.16.0
@@ -3392,6 +3480,9 @@ importers:
"@kie-tools/i18n-common-dictionary":
specifier: workspace:*
version: link:../i18n-common-dictionary
+ "@kie-tools/uniforms-patternfly":
+ specifier: workspace:*
+ version: link:../uniforms-patternfly
"@patternfly/react-core":
specifier: ^4.157.3
version: 4.168.8(react-dom@17.0.2)(react@17.0.2)
@@ -3417,14 +3508,11 @@ importers:
specifier: ^17.0.2
version: 17.0.2(react@17.0.2)
uniforms:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
uniforms-bridge-json-schema:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
- uniforms-patternfly:
- specifier: ^4.7.9
- version: 4.7.9(@patternfly/react-core@4.168.8)(@patternfly/react-icons@4.19.8)(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
devDependencies:
"@babel/core":
specifier: ^7.16.0
@@ -3511,11 +3599,11 @@ importers:
specifier: ^4.17.21
version: 4.17.21
uniforms:
- specifier: ^3.5.5
- version: 3.6.2
+ specifier: ^3.10.2
+ version: 3.10.2
uniforms-bridge-json-schema:
- specifier: ^3.5.5
- version: 3.6.2
+ specifier: ^3.10.2
+ version: 3.10.2
devDependencies:
"@babel/core":
specifier: ^7.16.0
@@ -6763,11 +6851,11 @@ importers:
specifier: ^1.13.1
version: 1.13.1
uniforms:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
uniforms-bridge-simple-schema-2:
- specifier: ^3.5.5
- version: 3.6.2(react@17.0.2)
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
devDependencies:
"@babel/core":
specifier: ^7.16.0
@@ -6860,6 +6948,115 @@ importers:
specifier: ^3.0.0
version: 3.0.0
+ packages/uniforms-patternfly:
+ dependencies:
+ "@types/invariant":
+ specifier: ^2.2.35
+ version: 2.2.35
+ invariant:
+ specifier: ^2.2.4
+ version: 2.2.4
+ lodash:
+ specifier: ^4.17.21
+ version: 4.17.21
+ react:
+ specifier: ^17.0.2
+ version: 17.0.2
+ react-dom:
+ specifier: ^17.0.2
+ version: 17.0.2(react@17.0.2)
+ uniforms:
+ specifier: ^3.10.2
+ version: 3.10.2(react@17.0.2)
+ devDependencies:
+ "@babel/preset-env":
+ specifier: ^7.16.0
+ version: 7.16.11
+ "@babel/preset-react":
+ specifier: ^7.16.0
+ version: 7.16.0
+ "@kie-tools-scripts/build-env":
+ specifier: workspace:*
+ version: link:../../scripts/build-env
+ "@kie-tools/eslint":
+ specifier: workspace:*
+ version: link:../eslint
+ "@kie-tools/root-env":
+ specifier: workspace:*
+ version: link:../root-env
+ "@kie-tools/tsconfig":
+ specifier: workspace:*
+ version: link:../tsconfig
+ "@patternfly/react-core":
+ specifier: ^4.157.3
+ version: 4.168.8(react-dom@17.0.2)(react@17.0.2)
... 2579 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org