This is an automated email from the ASF dual-hosted git repository.

tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new aab8cc10780 kie-issues#1852: Load custom forms in jBPM Quarkus Dev UI 
extension’s Tasks page (#2948)
aab8cc10780 is described below

commit aab8cc107809a519cf1650daf2c255cfd40a443a
Author: Luiz João Motta <[email protected]>
AuthorDate: Fri Feb 28 22:02:29 2025 -0300

    kie-issues#1852: Load custom forms in jBPM Quarkus Dev UI extension’s Tasks 
page (#2948)
---
 .rat-excludes                                      |   8 ++
 .../main/resources/custom-forms-dev/hiring.config  |   7 ++
 .../src/main/resources/custom-forms-dev/hiring.tsx | 101 +++++++++++++++++++++
 .../custom-forms-dev/hiring_ITInterview.config     |  12 +++
 .../custom-forms-dev/hiring_ITInterview.html       |  71 +++++++++++++++
 .../devui/runtime/forms/impl/FormsStorageImpl.java |   9 --
 packages/jbpm-quarkus-devui/package.json           |   4 +-
 .../CustomTaskFormDisplayer.tsx                    |  43 +++++----
 .../src/TaskForms/TaskFormGatewayApi.ts            |  29 +++++-
 .../envelope/components/FormEditor/FormEditor.tsx  |   2 +-
 .../src/formDisplayer/api/types.ts                 |   9 --
 .../embedded/EmbeddedFormDisplayer.tsx             |   2 +-
 .../components/FormDisplayer/FormDisplayer.tsx     |  33 ++++---
 .../HtmlFormRenderer/HtmlFormRenderer.tsx          |   2 +-
 .../ReactFormRenderer/ReactFormRenderer.tsx        |   2 +-
 .../ResourcesContainer/ResourcesContainer.tsx      |   2 +-
 16 files changed, 271 insertions(+), 65 deletions(-)

diff --git a/.rat-excludes b/.rat-excludes
index 4e47f2f52e3..50cc8b07991 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -510,6 +510,14 @@ README.md
 ImportJavaClasses.test.tsx.snap
 # packages/jbpm-quarkus-devui/jbpm-quarkus-devui-parent.iml
 jbpm-quarkus-devui-parent.iml
+# 
packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.html
+hiring_ITInterview.html
+# 
packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.config
+hiring_ITInterview.config
+# 
packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.tsx
+hiring.tsx
+# 
packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.config
+hiring.config
 # 
packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/test/resources/forms/hiring_HRInterview.config
 hiring_HRInterview.config
 # 
packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/test/resources/forms/hiring_ITInterview.config
diff --git 
a/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.config
 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.config
new file mode 100644
index 00000000000..90c1c53baa0
--- /dev/null
+++ 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.config
@@ -0,0 +1,7 @@
+{
+  "schema" : 
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"type\":\"object\",\"properties\":{\"candidate\":{\"type\":\"string\"},\"experience\":{\"type\":\"integer\"},\"skills\":{\"type\":\"string\"}}}";,
+  "resources" : {
+    "scripts" : { },
+    "styles" : { }
+  }
+}
\ No newline at end of file
diff --git 
a/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.tsx
 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.tsx
new file mode 100644
index 00000000000..88b3c92bc55
--- /dev/null
+++ 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring.tsx
@@ -0,0 +1,101 @@
+import React, { useCallback, useEffect, useState } from "react";
+import { TextInput, FormGroup } from "@patternfly/react-core";
+const Form__hiring: React.FC<any> = (props: any) => {
+  const [formApi, setFormApi] = useState<any>();
+  const [candidate, set__candidate] = useState<string>("");
+  const [experience, set__experience] = useState<number>();
+  const [skills, set__skills] = useState<string>("");
+  /* Utility function that fills the form with the data received from the 
kogito runtime */
+  const setFormData = (data) => {
+    if (!data) {
+      return;
+    }
+    set__candidate(data?.candidate ?? "");
+    set__experience(data?.experience);
+    set__skills(data?.skills ?? "");
+  };
+  /* Utility function to generate the expected form output as a json object */
+  const getFormData = useCallback(() => {
+    const formData: any = {};
+    formData.candidate = candidate;
+    formData.experience = experience;
+    formData.skills = skills;
+    return formData;
+  }, [candidate, experience, skills]);
+  /* Utility function to validate the form on the 'beforeSubmit' Lifecycle 
Hook */
+  const validateForm = useCallback(() => {}, []);
+  /* Utility function to perform actions on the on the 'afterSubmit' Lifecycle 
Hook */
+  const afterSubmit = useCallback((result) => {}, []);
+  useEffect(() => {
+    if (formApi) {
+      /*
+        Form Lifecycle Hook that will be executed before the form is submitted.
+        Throwing an error will stop the form submit. Usually should be used to 
validate the form.
+      */
+      formApi.beforeSubmit = () => validateForm();
+      /*
+        Form Lifecycle Hook that will be executed after the form is submitted.
+        It will receive a response object containing the `type` flag 
indicating if the submit has been successful and `info` with extra information 
about the submit result.
+      */
+      formApi.afterSubmit = (result) => afterSubmit(result);
+      /* Generates the expected form output object to be posted */
+      formApi.getFormData = () => getFormData();
+    }
+  }, [getFormData, validateForm, afterSubmit]);
+  useEffect(() => {
+    /*
+      Call to the Kogito console form engine. It will establish the connection 
with the console embeding the form
+      and return an instance of FormAPI that will allow hook custom code into 
the form lifecycle.
+      The `window.Form.openForm` call expects an object with the following 
entries:
+        - onOpen: Callback that will be called after the connection with the 
console is established. The callback
+        will receive the following arguments:
+          - data: the data to be bound into the form
+          - ctx: info about the context where the form is being displayed. 
This will contain information such as the form JSON Schema, process/task, 
user...
+    */
+    const api = window.Form.openForm({
+      onOpen: (data, context) => {
+        setFormData(data);
+      },
+    });
+    setFormApi(api);
+  }, []);
+  return (
+    <div className={"pf-c-form"}>
+      <FormGroup fieldId={"uniforms-0006-0000"} label={"Candidate"} 
isRequired={false}>
+        <TextInput
+          name={"candidate"}
+          id={"uniforms-0006-0000"}
+          isDisabled={false}
+          placeholder={""}
+          type={"text"}
+          value={candidate}
+          onChange={set__candidate}
+        />
+      </FormGroup>
+      <FormGroup fieldId={"uniforms-0006-0002"} label={"Experience Level"} 
isRequired={false}>
+        <TextInput
+          type={"number"}
+          name={"experience"}
+          isDisabled={false}
+          id={"uniforms-0006-0002"}
+          placeholder={""}
+          step={1}
+          value={experience}
+          onChange={(newValue) => set__experience(Number(newValue))}
+        />
+      </FormGroup>
+      <FormGroup fieldId={"uniforms-0006-0003"} label={"Skills"} 
isRequired={false}>
+        <TextInput
+          name={"skills"}
+          id={"uniforms-0006-0003"}
+          isDisabled={false}
+          placeholder={""}
+          type={"text"}
+          value={skills}
+          onChange={set__skills}
+        />
+      </FormGroup>
+    </div>
+  );
+};
+export default Form__hiring;
diff --git 
a/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.config
 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.config
new file mode 100644
index 00000000000..ddbc10aaf7c
--- /dev/null
+++ 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.config
@@ -0,0 +1,12 @@
+{
+  "schema": 
"{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"type\":\"object\",\"properties\":{\"approve\":{\"type\":\"boolean\",\"input\":true,\"output\":true},\"baseSalary\":{\"type\":\"integer\",\"input\":true},\"bonus\":{\"type\":\"integer\",\"input\":true},\"candidate\":{\"type\":\"string\",\"input\":true},\"category\":{\"type\":\"string\",\"input\":true}}}";,
+  "resources": {
+    "styles": {
+      "bootstrap.min.css": 
"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css";
+    },
+    "scripts": {
+      "jquery.js": 
"https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js";,
+      "bootstrap.bundle.min.js": 
"https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js";
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.html
 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.html
new file mode 100644
index 00000000000..246f41c2ff3
--- /dev/null
+++ 
b/packages/jbpm-quarkus-devui/dev/src/main/resources/custom-forms-dev/hiring_ITInterview.html
@@ -0,0 +1,71 @@
+<div>
+  <div class="form-check">
+    <input type="checkbox" id="approve" name="approve" 
class="form-check-input" />
+    <label class="form-check-label" for="approve">I approve this 
candidate!</label>
+  </div>
+  <div class="form-group">
+    <label for="baseSalary">Base salary</label>
+    <input type="number" class="form-control" id="baseSalary" 
name="baseSalary" disabled step="1" value="" />
+  </div>
+  <div class="form-group">
+    <label for="bonus">Bonus</label>
+    <input type="number" class="form-control" id="bonus" name="bonus" disabled 
step="1" value="" />
+  </div>
+  <div class="form-group">
+    <label for="candidate">Candidate</label>
+    <input type="text" id="candidate" name="candidate" class="form-control" 
disabled value="" />
+  </div>
+  <div class="form-group">
+    <label for="category">Area</label>
+    <input type="text" id="category" name="category" class="form-control" 
disabled value="" />
+  </div>
+  <script>
+    /* Utility function that fills the form with the data received from the 
kogito runtime */
+    function setFormData(data) {
+      if (!data) {
+        return;
+      }
+      document.getElementById("approve").checked = data?.approve;
+      document.getElementById("baseSalary").value = data?.baseSalary ?? "";
+      document.getElementById("bonus").value = data?.bonus ?? "";
+      document.getElementById("candidate").value = data?.candidate ?? "";
+      document.getElementById("category").value = data?.category ?? "";
+    }
+    /* Utility function to generate the expected form output as a json object 
*/
+    function getFormData() {
+      const formData = {};
+      formData.approve = document.getElementById("approve").checked;
+      return formData;
+    }
+    /* Utility function to validate the form on the 'beforeSubmit' Lifecycle 
Hook */
+    function validateForm() {}
+    /*
+            Call to the Kogito console form engine. It will establish the 
connection with the console embeding the form
+            and return an instance of FormAPI that will allow hook custom code 
into the form lifecycle.
+            The `window.Form.openForm` call expects an object with the 
following entries:
+                - onOpen: Callback that will be called after the connection 
with the console is established. The callback
+                will receive the following arguments:
+                    - data: the data to be bound into the form
+                    - ctx: info about the context where the form is being 
displayed. This will contain information such as the form JSON Schema, 
process/task, user...
+        */
+    const formApi = window.Form.openForm({
+      onOpen: (data, context) => {
+        setFormData(data);
+      },
+    });
+    /*
+            Form Lifecycle Hook that will be executed before the form is 
submitted.
+            Throwing an error will stop the form submit. Usually should be 
used to validate the form.
+        */
+    formApi.beforeSubmit = () => {
+      validateForm();
+    };
+    /*
+            Form Lifecycle Hook that will be executed after the form is 
submitted.
+            It will receive a response object containing the `type` flag 
indicating if the submit has been successful and `info` with extra information 
about the submit result.
+        */
+    formApi.afterSubmit = (response) => {};
+    /* Generates the expected form output object to be posted */
+    formApi.getFormData = () => getFormData();
+  </script>
+</div>
diff --git 
a/packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/main/java/org/jbpm/quarkus/devui/runtime/forms/impl/FormsStorageImpl.java
 
b/packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/main/java/org/jbpm/quarkus/devui/runtime/forms/impl/FormsStorageImpl.java
index 6bea503cffd..95a57bf79b6 100644
--- 
a/packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/main/java/org/jbpm/quarkus/devui/runtime/forms/impl/FormsStorageImpl.java
+++ 
b/packages/jbpm-quarkus-devui/jbpm-quarkus-devui-runtime/src/main/java/org/jbpm/quarkus/devui/runtime/forms/impl/FormsStorageImpl.java
@@ -57,14 +57,10 @@ import jakarta.enterprise.context.ApplicationScoped;
 public class FormsStorageImpl implements FormsStorage {
 
     public static final String PROJECT_FORM_STORAGE_PROP = 
"quarkus.kogito-runtime-tools.forms.folder";
-
     private static final String CONFIG_EXT = ".config";
-
     private static final String FORMS_STORAGE_PATH = "/custom-forms-dev";
-
     private static final String JAR_FORMS_STORAGE_PATH = "/target/classes" + 
FORMS_STORAGE_PATH;
     private static final String FS_FORMS_STORAGE_PATH = "/src/main/resources" 
+ FORMS_STORAGE_PATH;
-
     private static final Logger LOGGER = 
LoggerFactory.getLogger(FormsStorageImpl.class);
 
     private final Map<String, FormInfo> formInfoMap = new HashMap<>();
@@ -179,13 +175,10 @@ public class FormsStorageImpl implements FormsStorage {
         }
 
         JsonObject configJSON = new JsonObject(configStr);
-
         FormResources resources = new FormResources();
-
         JsonObject resourcesJSON = configJSON.getJsonObject("resources");
 
         resourcesJSON.getJsonObject("scripts").stream().forEach(entry -> 
resources.getScripts().put(entry.getKey(), entry.getValue().toString()));
-
         resourcesJSON.getJsonObject("styles").stream().forEach(entry -> 
resources.getStyles().put(entry.getKey(), entry.getValue().toString()));
 
         return new FormConfiguration(configJSON.getString("schema"), 
resources);
@@ -225,14 +218,12 @@ public class FormsStorageImpl implements FormsStorage {
         }
 
         FileUtils.write(formFile, formContent.getSource(), 
StandardCharsets.UTF_8);
-
         FileUtils.write(configFile, 
JsonObject.mapFrom(formContent.getConfiguration()).encodePrettily(), 
StandardCharsets.UTF_8);
 
         LocalDateTime lastModified = 
LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), 
TimeZone.getDefault().toZoneId());
         FormInfo newInfo = new FormInfo(formName, formInfo.getType(), 
lastModified);
 
         formInfoMap.put(formName, newInfo);
-
         modifiedForms.put(formName, new Form(newInfo, formContent.getSource(), 
formContent.getConfiguration()));
     }
 
diff --git a/packages/jbpm-quarkus-devui/package.json 
b/packages/jbpm-quarkus-devui/package.json
index 353cf95be0c..973a09bd8d4 100644
--- a/packages/jbpm-quarkus-devui/package.json
+++ b/packages/jbpm-quarkus-devui/package.json
@@ -26,8 +26,8 @@
     "quarkus:dev:darwin:linux": "mvn clean package quarkus:dev -DskipTests",
     "quarkus:dev:win32": "mvn clean package quarkus:dev `-DskipTests",
     "start": "run-script-os",
-    "start:darwin:linux": "pnpm build:dev && mvn -f ./dev/pom.xml quarkus:dev",
-    "start:win32": "pnpm build:dev && mvn -f ./dev/pom.xml quarkus:dev 
-Dquarkus.http.host=127.0.0.1  -Dkogito.service.url=http://127.0.0.1:8080/kie 
-Dkogito.jobs-service.url=http://127.0.0.1:8080/kie 
-Dkogito.data-index.urll=http://127.0.0.1:8080/kie";
+    "start:darwin:linux": "pnpm build:dev && mvn -f ./dev/pom.xml clean 
quarkus:dev",
+    "start:win32": "pnpm build:dev && mvn -f ./dev/pom.xml clean quarkus:dev 
-Dquarkus.http.host=127.0.0.1  -Dkogito.service.url=http://127.0.0.1:8080/kie 
-Dkogito.jobs-service.url=http://127.0.0.1:8080/kie 
-Dkogito.data-index.urll=http://127.0.0.1:8080/kie";
   },
   "dependencies": {
     "@kie-tools/maven-base": "workspace:*"
diff --git 
a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx
 
b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx
index d3719005377..4261e55d695 100644
--- 
a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx
+++ 
b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React, { useEffect, useRef, useState } from "react";
+import React, { useEffect, useRef, useState, useCallback } from "react";
 import { v4 as uuidv4 } from "uuid";
 import { UserTaskInstance } from 
"@kie-tools/runtime-tools-process-gateway-api/dist/types";
 import { generateFormData } from "../utils/TaskFormDataUtils";
@@ -65,24 +65,27 @@ const CustomTaskFormDisplayer: 
React.FC<CustomTaskFormDisplayerProps & OUIAProps
   const [formOpened, setFormOpened] = useState<FormOpened>();
   const [submitted, setSubmitted] = useState<boolean>(false);
 
-  const doSubmit = async (phase: string, payload: any) => {
-    const formDisplayerApi = formDisplayerApiRef.current;
+  const doSubmit = useCallback(
+    async (phase: string, payload: any) => {
+      const formDisplayerApi = formDisplayerApiRef.current;
 
-    try {
-      const response = await driver.doSubmit(phase, payload);
-      formDisplayerApi!.notifySubmitResult({
-        type: FormSubmitResponseType.SUCCESS,
-        info: response,
-      });
-    } catch (error) {
-      formDisplayerApi!.notifySubmitResult({
-        type: FormSubmitResponseType.FAILURE,
-        info: error,
-      });
-    } finally {
-      setSubmitted(true);
-    }
-  };
+      try {
+        const response = await driver.doSubmit(phase, payload);
+        formDisplayerApi!.notifySubmitResult({
+          type: FormSubmitResponseType.SUCCESS,
+          info: response,
+        });
+      } catch (error) {
+        formDisplayerApi!.notifySubmitResult({
+          type: FormSubmitResponseType.FAILURE,
+          info: error,
+        });
+      } finally {
+        setSubmitted(true);
+      }
+    },
+    [driver]
+  );
 
   useEffect(() => {
     if (phases) {
@@ -104,13 +107,13 @@ const CustomTaskFormDisplayer: 
React.FC<CustomTaskFormDisplayerProps & OUIAProps
       });
       setFormActions(actions);
     }
-  }, []);
+  }, [doSubmit, phases]);
 
   useEffect(() => {
     if (formOpened) {
       document.getElementById(`${formUUID}-form`)!.style.visibility = 
"visible";
     }
-  }, [formOpened]);
+  }, [formOpened, formUUID]);
 
   return (
     <div {...componentOuiaProps(ouiaId, "custom-form-displayer", ouiaSafe)} 
style={{ height: "100%" }}>
diff --git 
a/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts
 
b/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts
index 282bfdb48e0..71408a62191 100644
--- 
a/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts
+++ 
b/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts
@@ -28,7 +28,7 @@ import { Form } from 
"@kie-tools/runtime-tools-shared-gateway-api/dist/types";
 export interface TaskFormGatewayApi {
   getTaskFormSchema(userTask: UserTaskInstance, headers?: any): 
Promise<Record<string, any>>;
 
-  getCustomForm(userTask: UserTaskInstance): Promise<Form>;
+  getCustomForm(userTask: UserTaskInstance, headers?: any): Promise<Form>;
 
   doSubmit(userTask: UserTaskInstance, phase: string, payload: any, headers?: 
any): Promise<any>;
 
@@ -92,6 +92,27 @@ export class TaskFormGatewayApiImpl implements 
TaskFormGatewayApi {
     });
   }
 
+  fetchCustomForm(endpoint: string, headers?: any) {
+    return new Promise<Form>((resolve, reject) => {
+      axios
+        .get(this.replaceEndpointBaseUrl(endpoint), {
+          headers: {
+            "Content-Type": "application/json",
+            Accept: "application/json",
+            ...headers,
+          },
+        })
+        .then((response) => {
+          if (response.status == 200) {
+            resolve(response.data);
+          } else {
+            reject(response);
+          }
+        })
+        .catch((error) => reject(error));
+    });
+  }
+
   fetchTaskTransitionPhases(endpoint: string, headers?: any) {
     return new Promise<string[]>((resolve, reject) => {
       axios
@@ -128,8 +149,10 @@ export class TaskFormGatewayApiImpl implements 
TaskFormGatewayApi {
     return this.fetchTaskFormSchema(endpoint, headers);
   }
 
-  getCustomForm(userTask: UserTaskInstance): Promise<Form> {
-    return Promise.reject();
+  getCustomForm(userTask: UserTaskInstance, headers?: any): Promise<Form> {
+    const baseUrl = cleanUserTaskEndpoint(userTask);
+    const endpoint = `${baseUrl}/forms/${userTask.processId}_${userTask.name}`;
+    return this.fetchCustomForm(endpoint, headers);
   }
 
   getTaskPhases(userTask: UserTaskInstance, headers?: any): Promise<string[]> {
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDetails/envelope/components/FormEditor/FormEditor.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDetails/envelope/components/FormEditor/FormEditor.tsx
index e2518edd6e4..97b53f049b7 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDetails/envelope/components/FormEditor/FormEditor.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDetails/envelope/components/FormEditor/FormEditor.tsx
@@ -61,7 +61,7 @@ export const FormEditor = React.forwardRef<ResizableContent, 
FormEditorProps>(
     { code, formType, formContent, setFormContent, saveFormContent, isSource = 
false, isConfig = false },
     forwardedRef
   ) => {
-    const [formSourceCode, setFormSourceCode] = useState("");
+    const [formSourceCode, setFormSourceCode] = useState(formContent.source);
     const appContext = useFormDetailsContext();
     const container = useRef<HTMLDivElement>(null);
 
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/api/types.ts
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/api/types.ts
index 60449ccdc71..1b02e7c3fee 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/api/types.ts
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/api/types.ts
@@ -58,12 +58,3 @@ export interface Association {
   origin: string;
   envelopeServerId: string;
 }
-
-export interface FormResources {
-  scripts: {
-    [key: string]: string;
-  };
-  styles: {
-    [key: string]: string;
-  };
-}
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/embedded/EmbeddedFormDisplayer.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/embedded/EmbeddedFormDisplayer.tsx
index e5dc93d6a59..2846cc106a7 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/embedded/EmbeddedFormDisplayer.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/embedded/EmbeddedFormDisplayer.tsx
@@ -72,7 +72,7 @@ export const EmbeddedFormDisplayer = React.forwardRef((props: 
Props, forwardedRe
         }
       );
     },
-    []
+    [props.context, props.data, props.formContent]
   );
 
   return (
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/FormDisplayer/FormDisplayer.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/FormDisplayer/FormDisplayer.tsx
index e2284fa5975..249e7fdd1a4 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/FormDisplayer/FormDisplayer.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/FormDisplayer/FormDisplayer.tsx
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-import React, { useCallback, useEffect, useImperativeHandle, useState } from 
"react";
+import React, { useMemo, useCallback, useEffect, useImperativeHandle, useState 
} from "react";
 import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
 import { BallBeat } from "react-pure-loaders";
-import { Form } from "@kie-tools/runtime-tools-shared-gateway-api/src/types";
+import { Form, FormResources } from 
"@kie-tools/runtime-tools-shared-gateway-api/src/types";
 import { FormOpened, FormOpenedState } from "../../../api";
 import ReactFormRenderer from "../ReactFormRenderer/ReactFormRenderer";
 import HtmlFormRenderer from "../HtmlFormRenderer/HtmlFormRenderer";
@@ -39,29 +39,27 @@ interface FormDisplayerProps {
 export const FormDisplayer = React.forwardRef<EmbeddedFormApi, 
FormDisplayerProps & OUIAProps>(
   ({ isEnvelopeConnectedToChannel, content, data, context, onOpenForm, ouiaId, 
ouiaSafe }, forwardedRef) => {
     const [source, setSource] = useState<string>();
-    const [resources, setResources] = useState<any>();
+    const [resources, setResources] = useState<FormResources>();
     const [formData, setFormData] = useState<string>();
     const [formApi, setFormApi] = useState<InternalFormDisplayerApi>({} as 
InternalFormDisplayerApi);
     const [isExecuting, setIsExecuting] = useState<boolean>(false);
 
-    const doOpenForm = (config: FormConfig): EmbeddedFormApi => {
-      const api: EmbeddedFormApi = {};
-      setFormApi(new InternalFormDisplayerApiImpl(api, config.onOpen!));
-      return api;
-    };
-
-    const canDisplayForm = useCallback(() => {
-      return isEnvelopeConnectedToChannel && !isExecuting && source;
-    }, [isEnvelopeConnectedToChannel, isExecuting, source]);
+    const canDisplayForm = useMemo(
+      () => isEnvelopeConnectedToChannel && !isExecuting && source && 
resources,
+      [isEnvelopeConnectedToChannel, isExecuting, source, resources]
+    );
 
     useEffect(() => {
       window.Form = {
-        openForm: doOpenForm,
+        openForm: (config: FormConfig): EmbeddedFormApi => {
+          const api: EmbeddedFormApi = {};
+          setFormApi(new InternalFormDisplayerApiImpl(api, config.onOpen!));
+          return api;
+        },
       };
     }, []);
 
     useEffect(() => {
-      /* istanbul ignore else */
       if (isEnvelopeConnectedToChannel) {
         setSource(content.source);
         setResources(content.configuration.resources);
@@ -85,18 +83,19 @@ export const FormDisplayer = 
React.forwardRef<EmbeddedFormApi, FormDisplayerProp
           });
         }, 500);
       }
+      // eslint-disable-next-line
     }, [formApi]);
 
     useImperativeHandle(forwardedRef, () => formApi, [formApi]);
 
     return (
       <div {...componentOuiaProps(ouiaId, "form-displayer", ouiaSafe)}>
-        {canDisplayForm() ? (
+        {canDisplayForm ? (
           <div id={"inner-form-container"}>
             {content.formInfo && content.formInfo.type === "TSX" ? (
-              <ReactFormRenderer source={source!} resources={resources} 
setIsExecuting={setIsExecuting} />
+              <ReactFormRenderer source={source!} resources={resources!} 
setIsExecuting={setIsExecuting} />
             ) : (
-              <HtmlFormRenderer source={source!} resources={resources} />
+              <HtmlFormRenderer source={source!} resources={resources!} />
             )}
           </div>
         ) : (
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/HtmlFormRenderer/HtmlFormRenderer.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/HtmlFormRenderer/HtmlFormRenderer.tsx
index b91f3ef2735..81267be202b 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/HtmlFormRenderer/HtmlFormRenderer.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/HtmlFormRenderer/HtmlFormRenderer.tsx
@@ -19,7 +19,7 @@
 
 import React from "react";
 import InnerHTML from "dangerously-set-html-content";
-import { FormResources } from "../../../api";
+import { FormResources } from 
"@kie-tools/runtime-tools-shared-gateway-api/src/types";
 import ResourcesContainer from "../ResourcesContainer/ResourcesContainer";
 
 interface HtmlFormRendererProps {
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ReactFormRenderer/ReactFormRenderer.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ReactFormRenderer/ReactFormRenderer.tsx
index 8eee4681aa9..61363f8e2d8 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ReactFormRenderer/ReactFormRenderer.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ReactFormRenderer/ReactFormRenderer.tsx
@@ -23,7 +23,7 @@ import { transform } from "@babel/standalone";
 import ReactDOM from "react-dom";
 import * as PatternflyReact from "@patternfly/react-core/dist/js";
 import * as PatternflyReactIcons from "@patternfly/react-icons/dist/js";
-import { FormResources } from "../../../api";
+import { FormResources } from 
"@kie-tools/runtime-tools-shared-gateway-api/src/types";
 import { sourceHandler } from "../../../utils";
 import ResourcesContainer from "../ResourcesContainer/ResourcesContainer";
 
diff --git 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ResourcesContainer/ResourcesContainer.tsx
 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ResourcesContainer/ResourcesContainer.tsx
index cdbeaa0421a..1fcea6c5183 100644
--- 
a/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ResourcesContainer/ResourcesContainer.tsx
+++ 
b/packages/runtime-tools-shared-enveloped-components/src/formDisplayer/envelope/components/ResourcesContainer/ResourcesContainer.tsx
@@ -19,7 +19,7 @@
 
 import React, { ReactElement } from "react";
 import { Helmet } from "react-helmet";
-import { FormResources } from "../../../api";
+import { FormResources } from 
"@kie-tools/runtime-tools-shared-gateway-api/src/types";
 
 interface ResourcesContainerProps {
   resources: FormResources;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to