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 3daeaf23be1 KOGITO-10042: Migrate SWF Dev UI Java module from 
kogito-apps to kie-tools (#2167)
3daeaf23be1 is described below

commit 3daeaf23be1fa78bdaaf0869c8bf387ed600726e
Author: Fabrizio Antonangeli <[email protected]>
AuthorDate: Mon Mar 25 20:35:52 2024 +0100

    KOGITO-10042: Migrate SWF Dev UI Java module from kogito-apps to kie-tools 
(#2167)
    
    Co-authored-by: Yeser Amer <[email protected]>
    Co-authored-by: Thiago Lugli <[email protected]>
    Co-authored-by: Paulo Martins <[email protected]>
---
 .../env/index.js                                   |  31 +++
 .../sonataflow-quarkus-devui-extension/install.js  |  25 +++
 .../package.json                                   |  41 ++++
 .../sonataflow-quarkus-devui-extension/pom.xml     | 150 ++++++++++++++
 .../pom.xml                                        | 201 ++++++++++++++++++
 .../swf/tools/deployment/DevConsoleProcessor.java  | 133 ++++++++++++
 .../SonataFlowQuarkusExtensionProcessor.java       |  32 +++
 .../src/main/resources/dev-templates/embedded.html |  53 +++++
 .../main/resources/dev-templates/monitoring.html   |  44 ++++
 .../resources/dev-templates/workflowInstances.html |  45 ++++
 .../src/main/resources/static/index.html           |  45 ++++
 .../sonataflow-quarkus-devui-extension/pom.xml     | 159 +++++++++++++++
 .../custom/dashboard/CustomDashboardService.java   |  83 ++++++++
 .../custom/dashboard/CustomDashboardStorage.java   |  36 ++++
 .../CustomDashboardFilterParamConverter.java       |  40 ++++
 ...ustomDashboardFilterParamConverterProvider.java |  41 ++++
 .../dashboard/impl/CustomDashboardStorageImpl.java | 226 +++++++++++++++++++++
 .../dashboard/model/CustomDashboardFilter.java     |  50 +++++
 .../dashboard/model/CustomDashboardInfo.java       |  95 +++++++++
 .../src/main/resources/META-INF/beans.xml          |   7 +
 .../main/resources/META-INF/quarkus-extension.yaml |  28 +++
 .../dashboard/impl/CustomDashboardStorageTest.java | 115 +++++++++++
 .../impl/CustomDashboardStorageTestProfile.java    |  46 +++++
 .../resources/custom/dashboards/products.dash.yaml |  61 ++++++
 .../custom/dashboards/subdir/age.dash.yml          |  44 ++++
 pnpm-lock.yaml                                     |  15 ++
 repo/graph.dot                                     |   2 +
 repo/graph.json                                    |   7 +
 28 files changed, 1855 insertions(+)

diff --git a/packages/sonataflow-quarkus-devui-extension/env/index.js 
b/packages/sonataflow-quarkus-devui-extension/env/index.js
new file mode 100644
index 00000000000..33ffd575a68
--- /dev/null
+++ b/packages/sonataflow-quarkus-devui-extension/env/index.js
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const { varsWithName, composeEnv, getOrDefault } = 
require("@kie-tools-scripts/build-env");
+
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+  vars: varsWithName({}),
+  get env() {
+    return {
+      sonataflowQuarkusDevuiExtension: {
+        version: require("../package.json").version,
+      },
+    };
+  },
+});
diff --git a/packages/sonataflow-quarkus-devui-extension/install.js 
b/packages/sonataflow-quarkus-devui-extension/install.js
new file mode 100644
index 00000000000..99bfadb8cf8
--- /dev/null
+++ b/packages/sonataflow-quarkus-devui-extension/install.js
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const buildEnv = require("./env");
+const { setup } = require("@kie-tools/maven-config-setup-helper");
+
+setup(`
+    -Drevision=${buildEnv.env.sonataflowQuarkusDevuiExtension.version}
+`);
diff --git a/packages/sonataflow-quarkus-devui-extension/package.json 
b/packages/sonataflow-quarkus-devui-extension/package.json
new file mode 100644
index 00000000000..9407dfdba19
--- /dev/null
+++ b/packages/sonataflow-quarkus-devui-extension/package.json
@@ -0,0 +1,41 @@
+{
+  "private": true,
+  "name": "@kie-tools/sonataflow-quarkus-devui-extension",
+  "version": "0.0.0",
+  "description": "",
+  "license": "Apache-2.0",
+  "homepage": "https://github.com/apache/incubator-kie-tools";,
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/apache/incubator-kie-tools.git";
+  },
+  "bugs": {
+    "url": "https://github.com/apache/incubator-kie-tools/issues";
+  },
+  "scripts": {
+    "build:dev": "run-script-os",
+    "build:dev:darwin:linux": "mvn clean install -DskipTests",
+    "build:dev:win32": "pnpm powershell \"mvn clean install -DskipTests \"",
+    "build:prod": "pnpm lint && run-script-os",
+    "build:prod:darwin:linux": "mvn clean install -DskipTests=$(build-env 
tests.run --not) -Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)",
+    "build:prod:win32": "pnpm powershell \"mvn clean install `-DskipTests 
`-Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)\"",
+    "install": "node install.js",
+    "lint": "echo 'Linting'",
+    "powershell": "@powershell -NoProfile -ExecutionPolicy Unrestricted 
-Command",
+    "quarkus:dev": "run-script-os",
+    "quarkus:dev:darwin:linux": "mvn clean package quarkus:dev -DskipTests",
+    "quarkus:dev:win32": "mvn clean package quarkus:dev -DskipTests"
+  },
+  "devDependencies": {
+    "@kie-tools/maven-config-setup-helper": "workspace:*",
+    "@kie-tools/root-env": "workspace:*",
+    "@kie-tools/serverless-workflow-dev-ui-webapp": "workspace:*",
+    "run-script-os": "^1.1.6"
+  },
+  "kieTools": {
+    "requiredPreinstalledCliCommands": [
+      "java",
+      "mvn"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/packages/sonataflow-quarkus-devui-extension/pom.xml 
b/packages/sonataflow-quarkus-devui-extension/pom.xml
new file mode 100644
index 00000000000..cded104b09b
--- /dev/null
+++ b/packages/sonataflow-quarkus-devui-extension/pom.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";
+  xmlns="http://maven.apache.org/POM/4.0.0";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+>
+
+  <modelVersion>4.0.0</modelVersion>
+  <name>KIE Tools :: SonataFlow Quarkus Dev UI Extension</name>
+  <groupId>org.apache.kie.sonataflow</groupId>
+  <version>${revision}</version>
+  <artifactId>sonataflow-quarkus-devui-extension-parent</artifactId>
+  <packaging>pom</packaging>
+
+  <repositories>
+    <repository>
+        <!-- Duplicating the Maven Central repository here (as it is already 
coming from Super POM) makes the build much faster,
+             as the Maven Central is now treated as the first (default) 
repository (because it is before the Apache Nexus one).
+             Artifacts with release (fixed) versions are being downloaded 
primarily from there. Without the central being the
+             first repository the Apache Nexus would be contacted first and 
since it is quite slow it slows down the build.
+             We use Apache repo only to download our SNAPSHOTs. -->
+        <id>central</id>
+        <name>Central Repository</name>
+        <url>https://repo.maven.apache.org/maven2</url>
+        <layout>default</layout>
+        <snapshots>
+            <enabled>false</enabled>
+        </snapshots>
+    </repository>
+    <repository>
+        <id>apache-public-repository-group</id>
+        <name>Apache Public Repository Group</name>
+        <url>https://repository.apache.org/content/groups/public/</url>
+        <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+        </releases>
+        <snapshots>
+            <enabled>true</enabled>
+            <updatePolicy>daily</updatePolicy>
+        </snapshots>
+    </repository>
+  </repositories>
+
+  <properties>
+    <compiler-plugin.version>3.12.1</compiler-plugin.version>
+    <maven.compiler.source>17</maven.compiler.source>
+    <maven.compiler.target>17</maven.compiler.target>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <version.resources.plugin>3.2.0</version.resources.plugin>
+    <java.module.name>org.kie.kogito.quarkus.swf.dev.ui</java.module.name>
+    <version.flatten.plugin>1.3.0</version.flatten.plugin>
+    <quarkus.platform.version>3.2.9.Final</quarkus.platform.version>
+    <version.org.kie.kogito>999-20240218-SNAPSHOT</version.org.kie.kogito>
+  </properties>
+
+  <modules>
+    <module>sonataflow-quarkus-devui-extension-deployment</module>
+    <module>sonataflow-quarkus-devui-extension</module>
+  </modules>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>io.quarkus</groupId>
+        <artifactId>quarkus-bom</artifactId>
+        <version>${quarkus.platform.version}</version> 
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <build>
+      <plugins>
+          <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>flatten-maven-plugin</artifactId>
+              <version>${version.flatten.plugin}</version>
+              <configuration>
+                  <updatePomFile>true</updatePomFile>
+                  <flattenMode>resolveCiFriendliesOnly</flattenMode>
+              </configuration>
+              <executions>
+                  <execution>
+                      <id>flatten-revision</id>
+                      <phase>process-resources</phase>
+                      <goals>
+                          <goal>flatten</goal>
+                      </goals>
+                  </execution>
+                  <execution>
+                      <id>flatten-revision-clean</id>
+                      <phase>clean</phase>
+                      <goals>
+                          <goal>clean</goal>
+                      </goals>
+                  </execution>
+              </executions>
+          </plugin>
+      </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>io.quarkus</groupId>
+          <artifactId>quarkus-maven-plugin</artifactId>
+        </plugin>
+        <plugin>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <systemPropertyVariables>
+              
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+            </systemPropertyVariables>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-failsafe-plugin</artifactId>
+          <configuration>
+            <systemPropertyVariables>
+              
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+            </systemPropertyVariables>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/pom.xml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/pom.xml
new file mode 100644
index 00000000000..e319b361962
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/pom.xml
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";
+  xmlns="http://maven.apache.org/POM/4.0.0";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+>
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.kie.sonataflow</groupId>
+    <artifactId>sonataflow-quarkus-devui-extension-parent</artifactId>
+    <version>${revision}</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>sonataflow-quarkus-devui-extension-deployment</artifactId>
+  <name>KIE Tools :: SonataFlow Quarkus Dev UI Extension :: Deployment</name>
+
+  <properties>
+      
<path.to.webapp.app>../../serverless-workflow-dev-ui-webapp</path.to.webapp.app>
+  </properties>
+
+  <dependencies>
+    <!-- quarkus -->
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-development-mode-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-core-deployment</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-arc-deployment</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-deployment</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-jackson-deployment</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-rest-client-deployment</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-multipart-deployment</artifactId>
+    </dependency>
+
+    <!-- Undertow is needed so that the static resource serving can correctly 
locate CP resources from `META-INF/resources` of the application, as it would 
be normally expected.
+         See https://issues.redhat.com/browse/KOGITO-3477 -->
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-undertow-deployment</artifactId>
+    </dependency>
+
+    <!-- test -->
+    <dependency>
+      <groupId>io.rest-assured</groupId>
+      <artifactId>rest-assured</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kie.sonataflow</groupId>
+      <artifactId>sonataflow-quarkus-devui-extension</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-junit5-internal</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>${compiler-plugin.version}</version>
+        <configuration>
+          <annotationProcessorPaths>
+            <path>
+              <groupId>io.quarkus</groupId>
+              <artifactId>quarkus-extension-processor</artifactId>
+              <version>${quarkus.platform.version}</version> 
+            </path>
+          </annotationProcessorPaths>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>${version.resources.plugin}</version>
+        <executions>
+          <execution>
+            <id>copy-webapp</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              
<outputDirectory>${basedir}/target/classes/dev-static/resources/webapp</outputDirectory>
+              <resources>
+                <resource>
+                  
<directory>${path.to.webapp.app}/dist/resources/webapp</directory>
+                  <filtering>false</filtering>
+                </resource>
+                <resource>
+                  <directory>${path.to.webapp.app}/dist/webapp</directory>
+                  <filtering>false</filtering>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>copy-envelope-resources</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              
<outputDirectory>${basedir}/target/classes/dev-static</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>${path.to.webapp.app}/dist</directory>
+                  <includes>
+                    <include>form-displayer.html</include>
+                    <include>form-displayer.js</include>
+                    
<include>serverless-workflow-combined-editor-envelope.html</include>
+                    
<include>serverless-workflow-combined-editor-envelope.js</include>
+                    
<include>serverless-workflow-text-editor-envelope.html</include>
+                    
<include>serverless-workflow-text-editor-envelope.js</include>
+                    
<include>serverless-workflow-diagram-editor-envelope.html</include>
+                    
<include>serverless-workflow-diagram-editor-envelope.js</include>
+                    <include>vendors-*.bundle.js</include>
+                    <include>*.worker.js</include>
+                  </includes>
+                </resource>
+                <!--copy diagram into the dev-static-->
+                <resource>
+                  <directory>${path.to.webapp.app}/dist</directory>
+                  <includes>
+                    <include>diagram/</include>
+                  </includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>copy-index</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              
<outputDirectory>${basedir}/target/classes/dev-static</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>${basedir}/target/classes/static</directory>
+                  <includes>
+                    <include>index.html</include>
+                  </includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/DevConsoleProcessor.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/DevConsoleProcessor.java
new file mode 100644
index 00000000000..721a00c4e2e
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/DevConsoleProcessor.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.deployment;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.file.Path;
+
+import io.quarkus.deployment.IsDevelopment;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.ConfigurationBuildItem;
+import io.quarkus.deployment.builditem.LaunchModeBuildItem;
+import io.quarkus.deployment.builditem.LiveReloadBuildItem;
+import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
+import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
+import io.quarkus.deployment.util.WebJarUtil;
+import io.quarkus.devui.spi.page.CardPageBuildItem;
+import io.quarkus.devui.spi.page.Page;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
+import io.quarkus.vertx.http.deployment.RouteBuildItem;
+import io.quarkus.vertx.http.runtime.devmode.DevConsoleRecorder;
+import 
io.quarkus.vertx.http.runtime.management.ManagementInterfaceBuildTimeConfig;
+
+public class DevConsoleProcessor {
+
+    private static final String STATIC_RESOURCES_PATH = "dev-static/";
+    private static final String BASE_RELATIVE_URL = 
"/q/dev-v1/org.apache.kie.sonataflow.sonataflow-quarkus-devui-extension";
+
+    @BuildStep(onlyIf = IsDevelopment.class)
+    public CardPageBuildItem pages(NonApplicationRootPathBuildItem 
nonApplicationRootPathBuildItem,
+            ManagementInterfaceBuildTimeConfig 
managementInterfaceBuildTimeConfig,
+            LaunchModeBuildItem launchModeBuildItem,
+            ConfigurationBuildItem configurationBuildItem) throws 
UnsupportedEncodingException {
+
+        String uiPath = 
nonApplicationRootPathBuildItem.resolveManagementPath(BASE_RELATIVE_URL,
+                managementInterfaceBuildTimeConfig, launchModeBuildItem, true);
+
+        String devUIUrl = getProperty(configurationBuildItem, 
"kogito.dev-ui.url");
+        String devUIUrlQueryParam = devUIUrl != null ? "&devUIUrl=" + 
URLEncoder.encode(devUIUrl, "UTF-8") : "";
+
+        String dataIndexUrl = getProperty(configurationBuildItem, 
"kogito.data-index.url");
+        String dataIndexUrlQueryParam = dataIndexUrl != null ? 
"&dataIndexUrl=" + URLEncoder.encode(dataIndexUrl, "UTF-8") : "";
+
+        CardPageBuildItem cardPageBuildItem = new CardPageBuildItem();
+
+        cardPageBuildItem.addPage(Page.externalPageBuilder("Workflows")
+                .url(uiPath + "/index.html?page=Workflows" + 
devUIUrlQueryParam + dataIndexUrlQueryParam, uiPath)
+                .isHtmlContent()
+                .icon("font-awesome-solid:diagram-project"));
+
+        cardPageBuildItem.addPage(Page.externalPageBuilder("Monitoring")
+                .url(uiPath + "/index.html?page=Monitoring" + 
devUIUrlQueryParam + dataIndexUrlQueryParam, uiPath)
+                .isHtmlContent()
+                .icon("font-awesome-solid:gauge-high"));
+
+        return cardPageBuildItem;
+    }
+
+    @BuildStep(onlyIf = IsDevelopment.class)
+    @Record(ExecutionTime.RUNTIME_INIT)
+    public void deployStaticResources(final DevConsoleRecorder recorder,
+            final CurateOutcomeBuildItem curateOutcomeBuildItem,
+            final LiveReloadBuildItem liveReloadBuildItem,
+            final LaunchModeBuildItem launchMode,
+            final ShutdownContextBuildItem shutdownContext,
+            final BuildProducer<RouteBuildItem> routeBuildItemBuildProducer) 
throws IOException {
+        ResolvedDependency devConsoleResourcesArtifact = 
WebJarUtil.getAppArtifact(curateOutcomeBuildItem,
+                "org.apache.kie.sonataflow",
+                "sonataflow-quarkus-devui-extension-deployment");
+
+        Path devConsoleStaticResourcesDeploymentPath = 
WebJarUtil.copyResourcesForDevOrTest(
+                liveReloadBuildItem,
+                curateOutcomeBuildItem,
+                launchMode,
+                devConsoleResourcesArtifact,
+                STATIC_RESOURCES_PATH,
+                true);
+
+        routeBuildItemBuildProducer.produce(new RouteBuildItem.Builder()
+                .route(BASE_RELATIVE_URL + "/*")
+                
.handler(recorder.devConsoleHandler(devConsoleStaticResourcesDeploymentPath.toString(),
+                        shutdownContext))
+                .build());
+    }
+
+    private static String getProperty(ConfigurationBuildItem 
configurationBuildItem,
+            String propertyKey) {
+
+        String propertyValue = configurationBuildItem
+                .getReadResult()
+                .getAllBuildTimeValues()
+                .get(propertyKey);
+
+        if (propertyValue == null) {
+            propertyValue = configurationBuildItem
+                    .getReadResult()
+                    .getBuildTimeRunTimeValues()
+                    .get(propertyKey);
+        } else {
+            return propertyValue;
+        }
+
+        if (propertyValue == null) {
+            propertyValue = configurationBuildItem
+                    .getReadResult()
+                    .getRunTimeDefaultValues()
+                    .get(propertyKey);
+        }
+
+        return propertyValue;
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/SonataFlowQuarkusExtensionProcessor.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/SonataFlowQuarkusExtensionProcessor.java
new file mode 100644
index 00000000000..60d10d1853b
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/java/org/kie/sonataflow/swf/tools/deployment/SonataFlowQuarkusExtensionProcessor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.deployment;
+
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+class SonataFlowQuarkusExtensionProcessor {
+
+    private static final String FEATURE = "sonataflow-quarkus-devui-extension";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/embedded.html
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/embedded.html
new file mode 100644
index 00000000000..da2e7069430
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/embedded.html
@@ -0,0 +1,53 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<a href="{urlbase}/workflowInstances" class="badge badge-light">
+  <i class="fa fa-project-diagram fa-fw"></i>
+  Workflow Instances
+  <span id="workflowInstancesCount" class="badge badge-light" />
+</a>
+<a href="{urlbase}/monitoring" class="badge badge-light">
+  <i class="fa fa-tachometer fa-fw"></i>
+  Monitoring
+</a>
+<script>
+  const graphqlUrl = "{config:property('kogito.data-index.url') ?: 
''}/graphql";
+
+  {|
+      const fillCount = () => {
+          fetch(graphqlUrl, {
+              method: "POST",
+              headers: {
+                  "Content-Type": "application/json",
+                  Accept: "application/json",
+              },
+              body: JSON.stringify({query: "query getAllProcessesIds{  
ProcessInstances{ id } }"}),
+          })
+              .then(r => r.json())
+              .then(json => 
$("#workflowInstancesCount").text(json.data.ProcessInstances.length))
+              .catch(error => {
+                  console.log("Error while trying to fetch workflow instances 
count.");
+                  console.error(error);
+              });
+      };
+
+      fillCount();
+  |}
+</script>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/monitoring.html
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/monitoring.html
new file mode 100644
index 00000000000..2132fd4c35c
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/monitoring.html
@@ -0,0 +1,44 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+{#include main fluid=true} {#style} .main-container { margin: 0; padding: 0; } 
#envelope-app { width: 100vw; height:
+calc(100vh - 98px); } {/style} {#title}Runtime UI{/title} {#body}
+<div id="envelope-app"></div>
+
+<script src="resources/webapp/standalone.js"></script>
+<script>
+  const devUIUrl= {#if 
config:property('kogito.dev-ui.url')}"{config:property('kogito.dev-ui.url')}"{#else}window.location.origin{/if};
+  const devUI = RuntimeToolsDevUI.open({
+      container: document.getElementById("envelope-app"),
+      isDataIndexAvailable: true,
+      dataIndexUrl: "{config:property('kogito.data-index.url') ?: ''}/graphql",
+      page: "Monitoring",
+      devUIUrl,
+      openApiBaseUrl: devUIUrl,
+      openApiPath: "q/openapi.json",
+      availablePages: ["Workflows", "Monitoring", "CustomDashboard"],
+      omittedWorkflowTimelineEvents: ["EmbeddedStart", "EmbeddedEnd", 
"Script"],
+      diagramPreviewSize: {
+          width: 1000,
+          height: 1000
+      }
+  })
+</script>
+{/body} {/include}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/workflowInstances.html
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/workflowInstances.html
new file mode 100644
index 00000000000..90370483336
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/dev-templates/workflowInstances.html
@@ -0,0 +1,45 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+{#include main fluid=true} {#style} .main-container { margin: 0; padding: 0; } 
#envelope-app { width: 100vw; height:
+calc(100vh - 98px); } {/style} {#title}Runtime UI{/title} {#body}
+<div id="envelope-app"></div>
+
+<script src="resources/webapp/standalone.js"></script>
+<script>
+  const devUIUrl= {#if 
config:property('kogito.dev-ui.url')}"{config:property('kogito.dev-ui.url')}"{#else}window.location.origin{/if};
+
+  const devUI = RuntimeToolsDevUI.open({
+      container: document.getElementById("envelope-app"),
+      isDataIndexAvailable: true,
+      dataIndexUrl: "{config:property('kogito.data-index.url') ?: ''}/graphql",
+      devUIUrl,
+      page: "Workflows",
+      openApiBaseUrl: devUIUrl,
+      openApiPath: "q/openapi.json",
+      availablePages: ["Workflows", "Monitoring", "CustomDashboard"],
+      omittedWorkflowTimelineEvents: ["EmbeddedStart", "EmbeddedEnd", 
"Script"],
+      diagramPreviewSize: {
+          width: 1000,
+          height: 1000
+      }
+  })
+</script>
+{/body} {/include}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/static/index.html
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/static/index.html
new file mode 100644
index 00000000000..8e850ece508
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension-deployment/src/main/resources/static/index.html
@@ -0,0 +1,45 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<div id="envelope-app"></div>
+
+<script src="resources/webapp/standalone.js"></script>
+<script>
+  const urlParams = new URLSearchParams(window.location.search);
+  const page = urlParams.get("page");
+  const devUIUrl = urlParams.get("devUIUrl");
+  const dataIndexUrl = urlParams.get("dataIndexUrl");
+
+  const devUI = RuntimeToolsDevUI.open({
+    container: document.getElementById("envelope-app"),
+    isDataIndexAvailable: true,
+    dataIndexUrl: dataIndexUrl ? dataIndexUrl : "" + "/graphql",
+    page: page,
+    devUIUrl: devUIUrl ? devUIUrl : window.location.origin,
+    openApiBaseUrl: devUIUrl ? devUIUrl : window.location.origin,
+    openApiPath: "q/openapi.json",
+    availablePages: ["Workflows", "Monitoring", "CustomDashboard"],
+    omittedWorkflowTimelineEvents: ["EmbeddedStart", "EmbeddedEnd", "Script"],
+    diagramPreviewSize: {
+      width: 1000,
+      height: 1000,
+    },
+  });
+</script>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/pom.xml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/pom.xml
new file mode 100644
index 00000000000..87e8bf44fe4
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/pom.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";
+  xmlns="http://maven.apache.org/POM/4.0.0";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.kie.sonataflow</groupId>
+    <artifactId>sonataflow-quarkus-devui-extension-parent</artifactId>
+    <version>${revision}</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+  <artifactId>sonataflow-quarkus-devui-extension</artifactId>
+  <name>KIE Tools :: SonataFlow Quarkus Dev UI Extension :: Runtime</name>
+  <description>Runtime development tools for Serverless Workflows</description>
+  <dependencies>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-jackson</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-rest-client</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-multipart</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-arc</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus.arc</groupId>
+      <artifactId>arc-processor</artifactId>
+    </dependency>
+
+    <!-- Undertow is needed so that the static resource serving can correctly 
locate CP resources from `META-INF/resources` of the application, as it would 
be normally expected.
+         See https://issues.redhat.com/browse/KOGITO-3477 -->
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-undertow</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>jakarta.annotation</groupId>
+      <artifactId>jakarta.annotation-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-junit-jupiter</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-junit5</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-junit5-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>io.rest-assured</groupId>
+      <artifactId>rest-assured</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.awaitility</groupId>
+      <artifactId>awaitility</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>io.quarkus</groupId>
+        <artifactId>quarkus-extension-maven-plugin</artifactId>
+        <version>${quarkus.platform.version}</version>
+        <executions>
+          <execution>
+            <phase>compile</phase>
+            <goals>
+              <goal>extension-descriptor</goal>
+            </goals>
+            <configuration>
+              
<deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}</deployment>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>${compiler-plugin.version}</version>
+        <configuration>
+          <annotationProcessorPaths>
+            <path>
+              <groupId>io.quarkus</groupId>
+              <artifactId>quarkus-extension-processor</artifactId>
+              <version>${quarkus.platform.version}</version>
+            </path>
+          </annotationProcessorPaths>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardService.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardService.java
new file mode 100644
index 00000000000..530819d4cae
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardService.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard;
+
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+@Path("/customDashboard")
+public class CustomDashboardService {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(CustomDashboardService.class);
+
+    private CustomDashboardStorage storage;
+
+    @Inject
+    public void setStorage(CustomDashboardStorage storage) {
+        this.storage = storage;
+    }
+
+    @GET
+    @Path("/count")
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response getCustomDashboardFilesCount() {
+        try {
+            return Response.ok(storage.getCustomDashboardFilesCount()).build();
+        } catch (Exception e) {
+            LOGGER.warn("Error while getting CustomDashboard file count: ", e);
+            return Response.status(INTERNAL_SERVER_ERROR.getStatusCode(), 
"Unexpected error while getting CustomDashboard files count: " + 
e.getMessage()).build();
+        }
+    }
+
+    @GET
+    @Path("/list")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getCustomDashboardFiles(@QueryParam("names") 
CustomDashboardFilter filter) {
+        try {
+            return 
Response.ok(storage.getCustomDashboardFiles(filter)).build();
+        } catch (Exception e) {
+            LOGGER.warn("Error while getting CustomDashboard list: ", e);
+            return Response.status(INTERNAL_SERVER_ERROR.getStatusCode(), 
"Unexpected error while getting CustomDashboard files list: " + 
e.getMessage()).build();
+        }
+    }
+
+    @GET
+    @Path("/{name:\\S+}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getCustomDashboardFileContent(@PathParam("name") String 
name) {
+        try {
+            return 
Response.ok(storage.getCustomDashboardFileContent(name)).build();
+        } catch (Exception e) {
+            LOGGER.warn("Error while getting CustomDashboard file content: ", 
e);
+            return Response.status(INTERNAL_SERVER_ERROR.getStatusCode(), 
"Unexpected error while getting CustomDashboard file content: " + 
e.getMessage()).build();
+        }
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardStorage.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardStorage.java
new file mode 100644
index 00000000000..29f6096ad69
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/CustomDashboardStorage.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+import org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardInfo;
+
+public interface CustomDashboardStorage {
+
+    int getCustomDashboardFilesCount();
+
+    Collection<CustomDashboardInfo> 
getCustomDashboardFiles(CustomDashboardFilter filter);
+
+    String getCustomDashboardFileContent(String name) throws IOException;
+
+    void updateCustomDashboard(String content);
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverter.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverter.java
new file mode 100644
index 00000000000..fe648a586ad
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverter.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.converter;
+
+import java.util.Collections;
+import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class CustomDashboardFilterParamConverter implements 
ParamConverter<CustomDashboardFilter> {
+    public CustomDashboardFilter fromString(String names) {
+        StringTokenizer stringTokenizer = new StringTokenizer(names, ";");
+        return new 
CustomDashboardFilter(Collections.list(stringTokenizer).stream().map(s -> 
(String) s).collect(Collectors.toList()));
+    }
+
+    public String toString(CustomDashboardFilter names) {
+        return names.toString();
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverterProvider.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverterProvider.java
new file mode 100644
index 00000000000..dcf1487657b
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/converter/CustomDashboardFilterParamConverterProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.converter;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.ws.rs.ext.ParamConverterProvider;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class CustomDashboardFilterParamConverterProvider implements 
ParamConverterProvider {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type 
genericType, Annotation[] annotations) {
+        if (rawType.isAssignableFrom(CustomDashboardFilter.class)) {
+            return (ParamConverter<T>) new 
CustomDashboardFilterParamConverter();
+        }
+        return null;
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageImpl.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageImpl.java
new file mode 100644
index 00000000000..5060c20f749
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageImpl.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.kie.sonataflow.swf.tools.custom.dashboard.CustomDashboardStorage;
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+import org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+@ApplicationScoped
+public class CustomDashboardStorageImpl implements CustomDashboardStorage {
+
+    public static final String PROJECT_CUSTOM_DASHBOARD_STORAGE_PROP = 
"quarkus.kogito-runtime-tools.custom.dashboard.folder";
+    private static final String CUSTOM_DASHBOARD_STORAGE_PATH = "/dashboards/";
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(CustomDashboardStorageImpl.class);
+
+    private final Map<String, CustomDashboardInfo> customDashboardInfoMap = 
new HashMap<>();
+
+    private URL classLoaderCustomDashboardUrl;
+    private URL customDashStorageUrl;
+
+    public CustomDashboardStorageImpl() {
+        
start(Thread.currentThread().getContextClassLoader().getResource(CUSTOM_DASHBOARD_STORAGE_PATH));
+    }
+
+    public CustomDashboardStorageImpl(final URL classLoaderFormsUrl) {
+        start(classLoaderFormsUrl);
+    }
+
+    private void start(final URL classLoaderFormsUrl) {
+        start(classLoaderFormsUrl, 
getCustomDashboardStorageUrl(classLoaderFormsUrl));
+    }
+
+    private void start(final URL classLoaderCustomDashboardUrl, final URL 
customDashStorageUrl) {
+        try {
+            this.classLoaderCustomDashboardUrl = classLoaderCustomDashboardUrl;
+            this.customDashStorageUrl = customDashStorageUrl;
+        } catch (Exception ex) {
+            LOGGER.warn("Couldn't properly initialize 
CustomDashboardStorageImpl");
+        } finally {
+            if (classLoaderCustomDashboardUrl == null) {
+                return;
+            }
+
+            init(readCustomDashboardResources());
+            String storageUrl = getStorageUrl(classLoaderCustomDashboardUrl);
+            Thread t = new Thread(new DashboardFilesWatcher(reload(), 
storageUrl));
+            t.start();
+        }
+    }
+
+    protected String getStorageUrl(URL classLoaderCustomDashboardUrl) {
+        return ConfigProvider.getConfig()
+                .getOptionalValue(PROJECT_CUSTOM_DASHBOARD_STORAGE_PROP, 
String.class)
+                .orElseGet(() -> classLoaderCustomDashboardUrl.getFile());
+    }
+
+    private URL getCustomDashboardStorageUrl(URL 
classLoaderCustomDashboardUrl) {
+        if (classLoaderCustomDashboardUrl == null) {
+            return null;
+        }
+
+        String storageUrl = getStorageUrl(classLoaderCustomDashboardUrl);
+
+        File customDashStorageeFolder = new File(storageUrl);
+
+        if (!customDashStorageeFolder.exists() || 
!customDashStorageeFolder.isDirectory()) {
+            LOGGER.warn("Cannot initialize form storage folder in path '" + 
customDashStorageeFolder.getPath() + "'");
+        }
+
+        try {
+            return customDashStorageeFolder.toURI().toURL();
+        } catch (MalformedURLException ex) {
+            LOGGER.warn("Cannot initialize form storage folder in path '" + 
customDashStorageeFolder.getPath() + "'", ex);
+        }
+        return null;
+    }
+
+    @Override
+    public int getCustomDashboardFilesCount() {
+        return customDashboardInfoMap.size();
+    }
+
+    @Override
+    public Collection<CustomDashboardInfo> 
getCustomDashboardFiles(CustomDashboardFilter filter) {
+        if (filter != null && !filter.getNames().isEmpty()) {
+            return customDashboardInfoMap.entrySet().stream()
+                    .filter(entry -> 
StringUtils.containsAnyIgnoreCase(entry.getKey(), filter.getNames().toArray(new 
String[0])))
+                    .map(Map.Entry::getValue)
+                    .collect(Collectors.toList());
+        } else {
+            return customDashboardInfoMap.values();
+        }
+    }
+
+    @Override
+    public String getCustomDashboardFileContent(String name) throws 
IOException {
+        try {
+            return IOUtils.toString(new 
FileInputStream(customDashboardInfoMap.get(name).getPath()), 
StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            LOGGER.info("custom-dashboard's file {} can not ready, because of 
{}", customDashboardInfoMap.get(name).getPath(), e.getMessage());
+            throw e;
+        }
+    }
+
+    @Override
+    public void updateCustomDashboard(String content) {
+
+    }
+
+    private void init(Collection<File> files) {
+        customDashboardInfoMap.clear();
+        files.stream()
+                .forEach(file -> {
+                    LocalDateTime lastModified = 
LocalDateTime.ofInstant(Instant.ofEpochMilli(file.lastModified()), 
TimeZone.getDefault().toZoneId());
+                    customDashboardInfoMap.put(file.getName(),
+                            new CustomDashboardInfo(file.getName(), 
file.getPath(), lastModified));
+                });
+    }
+
+    private Collection<File> readCustomDashboardResources() {
+        if (classLoaderCustomDashboardUrl != null) {
+            LOGGER.info("custom-dashboard's files path is {}", 
classLoaderCustomDashboardUrl.toString());
+            File rootFolder = FileUtils.toFile(classLoaderCustomDashboardUrl);
+            return FileUtils.listFiles(rootFolder, new String[] { "dash.yaml", 
"dash.yml" }, true);
+        }
+        return Collections.emptyList();
+    }
+
+    private Consumer<Collection<File>> reload() {
+        return this::init;
+    }
+
+    private class DashboardFilesWatcher implements Runnable {
+
+        private final Map<WatchKey, Path> keys = new HashMap<>();
+        private Consumer<Collection<File>> consumer;
+        private String folder;
+
+        public DashboardFilesWatcher(Consumer<Collection<File>> consumer, 
String folder) {
+            this.consumer = consumer;
+            this.folder = folder;
+        }
+
+        @Override
+        public void run() {
+            try (WatchService ws = FileSystems.getDefault().newWatchService()) 
{
+                Path path = Path.of(folder);
+                keys.put(path.register(ws, ENTRY_MODIFY, ENTRY_CREATE), path);
+
+                Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+                    @Override
+                    public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs) throws IOException {
+                        keys.put(dir.register(ws, ENTRY_MODIFY, ENTRY_CREATE, 
ENTRY_DELETE), dir);
+                        return FileVisitResult.CONTINUE;
+                    }
+                });
+                WatchKey key;
+                while ((key = ws.take()) != null) {
+                    for (WatchEvent<?> event : key.pollEvents()) {
+                        LOGGER.warn("Event kind: {}. File affected: {}", 
event.kind(), event.context());
+                        consumer.accept(readCustomDashboardResources());
+                    }
+                    key.reset();
+                }
+            } catch (InterruptedException e) {
+                LOGGER.warn("Exception in custom dashboard folder watcher for 
folder: {}, message: {}", folder, e.getMessage(), e);
+                Thread.currentThread().interrupt();
+            } catch (IOException ex) {
+                LOGGER.warn("Exception in custom dashboard folder watcher for 
folder: {}, message: {}", folder, ex.getMessage(), ex);
+            }
+        }
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardFilter.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardFilter.java
new file mode 100644
index 00000000000..e4a59b5917e
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomDashboardFilter {
+
+    private final List<String> names;
+
+    public CustomDashboardFilter() {
+        this.names = new ArrayList<>();
+    }
+
+    public CustomDashboardFilter(List<String> names) {
+        this.names = names;
+    }
+
+    public List<String> getNames() {
+        return names;
+    }
+
+    public void setNames(List<String> names) {
+        this.names.addAll(names);
+    }
+
+    @Override
+    public String toString() {
+        return "CustomDashboardFilter{" +
+                "names=" + names +
+                '}';
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardInfo.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardInfo.java
new file mode 100644
index 00000000000..7c873cbd136
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/java/org/kie/sonataflow/swf/tools/custom/dashboard/model/CustomDashboardInfo.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.model;
+
+import java.time.LocalDateTime;
+
+public class CustomDashboardInfo {
+    String name;
+    String path;
+    LocalDateTime lastModified;
+
+    public CustomDashboardInfo(String name, String path, LocalDateTime 
lastModified) {
+        this.name = name;
+        this.path = path;
+        this.lastModified = lastModified;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public LocalDateTime getLastModified() {
+        return lastModified;
+    }
+
+    public void setLastModified(LocalDateTime lastModified) {
+        this.lastModified = lastModified;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        CustomDashboardInfo that = (CustomDashboardInfo) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+        if (path != null ? !path.equals(that.path) : that.path != null) {
+            return false;
+        }
+        return lastModified != null ? lastModified.equals(that.lastModified) : 
that.lastModified == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (path != null ? path.hashCode() : 0);
+        result = 31 * result + (lastModified != null ? lastModified.hashCode() 
: 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "CustomDashboardInfo{" +
+                "name='" + name + '\'' +
+                ", path='" + path + '\'' +
+                ", lastModified=" + lastModified +
+                '}';
+    }
+
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/beans.xml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/beans.xml
new file mode 100644
index 00000000000..030bdcbec5b
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,7 @@
+<beans
+  xmlns="http://java.sun.com/xml/ns/javaee";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd";
+>
+
+</beans>
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/quarkus-extension.yaml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 00000000000..06ec65f1e4c
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Serverless Workflow Tools
+metadata:
+  keywords:
+    - "sonataflow"
+    - "workflows"
+  guide: "https://quarkus.io/guides/kogito";
+  categories:
+    - "business-automation"
+  status: "preview"
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTest.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTest.java
new file mode 100644
index 00000000000..912c021d9a6
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.kie.sonataflow.swf.tools.custom.dashboard.CustomDashboardStorage;
+import 
org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardFilter;
+import org.kie.sonataflow.swf.tools.custom.dashboard.model.CustomDashboardInfo;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class CustomDashboardStorageTest {
+
+    private static String[] DASHBOARD_NAMES = { "age.dash.yml", 
"products.dash.yaml" };
+    private static String DASHBOARD_NAME = "age.dash.yml";
+
+    private CustomDashboardStorage customDashboardStorage;
+    private URL tempFolder;
+
+    @BeforeAll
+    public void init() {
+        tempFolder = 
Thread.currentThread().getContextClassLoader().getResource("custom/dashboards/");
+
+        customDashboardStorage = new CustomDashboardStorageImpl(tempFolder);
+    }
+
+    @Test
+    public void testGetFormInfoList() {
+        Collection<CustomDashboardInfo> customDashboardInfoFilterAll = 
customDashboardStorage.getCustomDashboardFiles(null);
+        assertEquals(2, customDashboardInfoFilterAll.size());
+
+        CustomDashboardFilter filterEmpty = new CustomDashboardFilter();
+        filterEmpty.setNames(Collections.emptyList());
+        Collection<CustomDashboardInfo> customDashboardInfoAllEmptyFilter = 
customDashboardStorage.getCustomDashboardFiles(filterEmpty);
+        assertEquals(2, customDashboardInfoAllEmptyFilter.size());
+
+        CustomDashboardFilter filter = new CustomDashboardFilter();
+        filter.setNames(Arrays.asList(DASHBOARD_NAMES));
+
+        Collection<CustomDashboardInfo> formInfos = 
customDashboardStorage.getCustomDashboardFiles(filter);
+        assertEquals(2, formInfos.size());
+    }
+
+    @Test
+    public void testHotReloading() throws IOException {
+        String storageUrl = 
Thread.currentThread().getContextClassLoader().getResource("custom/dashboards/").getFile();
+        File srcFile = new File(storageUrl + "products.dash.yaml");
+        File targetFile = new File(storageUrl + "copy.dash.yml");
+
+        assertEquals(false, targetFile.exists());
+        FileUtils.copyFile(srcFile, targetFile);
+        assertEquals(true, targetFile.exists());
+        await().atMost(20, TimeUnit.SECONDS).until(() -> testBeforeDelete());
+        Collection<CustomDashboardInfo> 
customDashboardInfoFilterAllBeforeDelete = 
customDashboardStorage.getCustomDashboardFiles(null);
+        assertEquals(3, customDashboardInfoFilterAllBeforeDelete.size());
+
+        assertEquals(true, targetFile.exists());
+        FileUtils.delete(targetFile);
+        assertEquals(false, targetFile.exists());
+        await().atMost(20, TimeUnit.SECONDS).until(() -> testAfterDelete());
+
+        Collection<CustomDashboardInfo> 
customDashboardInfoFilterAllAfterDelete = 
customDashboardStorage.getCustomDashboardFiles(null);
+        assertEquals(2, customDashboardInfoFilterAllAfterDelete.size());
+    }
+
+    private boolean testBeforeDelete() {
+        if (customDashboardStorage.getCustomDashboardFiles(null).size() == 3) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean testAfterDelete() {
+        if (customDashboardStorage.getCustomDashboardFiles(null).size() == 2) {
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void testGetFormContent() throws IOException {
+        String content = 
customDashboardStorage.getCustomDashboardFileContent(DASHBOARD_NAME);
+        assertNotNull(content);
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTestProfile.java
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTestProfile.java
new file mode 100644
index 00000000000..9b9e3350be9
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/java/org/kie/sonataflow/swf/tools/custom/dashboard/impl/CustomDashboardStorageTestProfile.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.sonataflow.swf.tools.custom.dashboard.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Collections;
+import java.util.Map;
+
+import io.quarkus.test.junit.QuarkusTestProfile;
+
+import static 
org.kie.sonataflow.swf.tools.custom.dashboard.impl.CustomDashboardStorageImpl.PROJECT_CUSTOM_DASHBOARD_STORAGE_PROP;
+
+public class CustomDashboardStorageTestProfile implements QuarkusTestProfile {
+
+    private String storagePath;
+
+    public CustomDashboardStorageTestProfile() throws IOException {
+        File storage = 
Files.createTempDirectory("CustomDashboardStorageTestProfile").toFile();
+        storage.deleteOnExit();
+        storage.mkdir();
+        storagePath = storage.getAbsolutePath();
+    }
+
+    @Override
+    public Map<String, String> getConfigOverrides() {
+        return Collections.singletonMap(PROJECT_CUSTOM_DASHBOARD_STORAGE_PROP, 
storagePath);
+    }
+}
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/products.dash.yaml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/products.dash.yaml
new file mode 100644
index 00000000000..ea685a0b5c3
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/products.dash.yaml
@@ -0,0 +1,61 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+datasets:
+  - uuid: products
+    content: >-
+      [
+        ["Computers", "Scanner", 5, 3],
+        ["Computers", "Printer", 7, 4],
+        ["Computers", "Laptop", 3, 2],
+        ["Electronics", "Camera", 10, 7],
+        ["Electronics", "Headphones", 5, 9]
+      ]
+    columns:
+      - id: Section
+        type: LABEL
+      - id: Product
+        type: LABEL
+      - id: Quantity
+        type: NUMBER
+      - id: Quantity2
+        type: NUMBER
+pages:
+  - components:
+      - html: Welcome to Dashbuilder!
+        properties:
+          font-size: xx-large
+          margin-bottom: 30px
+      - settings:
+          type: BARCHART
+          dataSetLookup:
+            uuid: products
+            group:
+              - columnGroup:
+                  source: Product
+                groupFunctions:
+                  - source: Product
+                  - source: Quantity
+                    function: SUM
+                  - source: Quantity2
+                    function: SUM
+      - settings:
+          type: TABLE
+          dataSetLookup:
+            uuid: products
diff --git 
a/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/subdir/age.dash.yml
 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/subdir/age.dash.yml
new file mode 100644
index 00000000000..011aff8684e
--- /dev/null
+++ 
b/packages/sonataflow-quarkus-devui-extension/sonataflow-quarkus-devui-extension/src/test/resources/custom/dashboards/subdir/age.dash.yml
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+datasets:
+  - uuid: age
+    content: >-
+      [
+        ["John", 5],
+        ["Mary", 7],
+        ["Mark",  3]
+      ]
+    columns:
+      - id: Name
+        type: LABEL
+      - id: Age
+        type: Number
+pages:
+  - components:
+      - settings:
+          type: BARCHART
+          dataSetLookup:
+            uuid: age
+            group:
+              - columnGroup:
+                  source: Name
+                groupFunctions:
+                  - source: Name
+                  - source: Age
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dac30f69a52..ddf6f313063 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9221,6 +9221,21 @@ importers:
         specifier: ^5.9.0
         version: 5.9.0
 
+  packages/sonataflow-quarkus-devui-extension:
+    devDependencies:
+      "@kie-tools/maven-config-setup-helper":
+        specifier: workspace:*
+        version: link:../maven-config-setup-helper
+      "@kie-tools/root-env":
+        specifier: workspace:*
+        version: link:../root-env
+      "@kie-tools/serverless-workflow-dev-ui-webapp":
+        specifier: workspace:*
+        version: link:../serverless-workflow-dev-ui-webapp
+      run-script-os:
+        specifier: ^1.1.6
+        version: 1.1.6
+
   packages/storybook-base:
     devDependencies:
       "@kie-tools-core/webpack-base":
diff --git a/repo/graph.dot b/repo/graph.dot
index 30d6dff5996..ec49e8db3f4 100644
--- a/repo/graph.dot
+++ b/repo/graph.dot
@@ -150,6 +150,7 @@ digraph G {
   "@kie-tools/serverless-workflow-service-catalog" [ color = "blue", fontcolor 
= "blue", style = "rounded" ];
   "@kie-tools/serverless-workflow-language-service" [ color = "blue", 
fontcolor = "blue", style = "rounded" ];
   "swf-vscode-extension" [ color = "blue", fontcolor = "blue", style = 
"rounded" ];
+  "@kie-tools/sonataflow-quarkus-devui-extension" [ color = "black", fontcolor 
= "black", style = "dashed, rounded" ];
   "@kie-tools/stunner-editors-dmn-loader" [ color = "blue", fontcolor = 
"blue", style = "rounded" ];
   "@kie-tools/unitables" [ color = "blue", fontcolor = "blue", style = 
"rounded" ];
   "vscode-extension-dashbuilder-editor" [ color = "blue", fontcolor = "blue", 
style = "rounded" ];
@@ -462,6 +463,7 @@ digraph G {
   "swf-vscode-extension" -> "@kie-tools/vscode-extension-common-test-helpers" 
[ style = "dashed", color = "blue" ];
   "sonataflow-deployment-webapp" -> "@kie-tools-core/react-hooks" [ style = 
"dashed", color = "blue" ];
   "sonataflow-deployment-webapp" -> 
"@kie-tools/runtime-tools-webapp-components" [ style = "dashed", color = "blue" 
];
+  "@kie-tools/sonataflow-quarkus-devui-extension" -> 
"@kie-tools/serverless-workflow-dev-ui-webapp" [ style = "dashed", color = 
"black" ];
   "@kie-tools/storybook-base" -> "@kie-tools-core/webpack-base" [ style = 
"dashed", color = "blue" ];
   "@kie-tools/storybook-base" -> "@kie-tools/tsconfig" [ style = "dashed", 
color = "blue" ];
   "@kie-tools/stunner-editors" -> "@kie-tools/stunner-editors-dmn-loader" [ 
style = "solid", color = "black" ];
diff --git a/repo/graph.json b/repo/graph.json
index 3440aac19f1..7014bcd673e 100644
--- a/repo/graph.json
+++ b/repo/graph.json
@@ -155,6 +155,7 @@
       { "id": "@kie-tools/serverless-workflow-jq-expressions" },
       { "id": "@kie-tools/serverless-workflow-service-catalog" },
       { "id": "swf-vscode-extension" },
+      { "id": "@kie-tools/sonataflow-quarkus-devui-extension" },
       { "id": "vscode-extension-dashbuilder-editor" },
       { "id": "vscode-extension-kie-ba-bundle" },
       { "id": "vscode-extension-kogito-bundle" },
@@ -963,6 +964,11 @@
         "weight": 1
       },
       { "source": "swf-vscode-extension", "target": 
"@kie-tools/vscode-extension-common-test-helpers", "weight": 1 },
+      {
+        "source": "@kie-tools/sonataflow-quarkus-devui-extension",
+        "target": "@kie-tools/serverless-workflow-dev-ui-webapp",
+        "weight": 1
+      },
       { "source": "vscode-extension-dashbuilder-editor", "target": 
"@kie-tools-core/vscode-extension", "weight": 1 },
       {
         "source": "vscode-extension-dashbuilder-editor",
@@ -1141,6 +1147,7 @@
     ["@kie-tools/serverless-workflow-text-editor", 
"packages/serverless-workflow-text-editor"],
     ["swf-vscode-extension", "packages/serverless-workflow-vscode-extension"],
     ["sonataflow-deployment-webapp", "packages/sonataflow-deployment-webapp"],
+    ["@kie-tools/sonataflow-quarkus-devui-extension", 
"packages/sonataflow-quarkus-devui-extension"],
     ["@kie-tools/storybook-base", "packages/storybook-base"],
     ["@kie-tools/stunner-editors", "packages/stunner-editors"],
     ["@kie-tools/stunner-editors-dmn-loader", 
"packages/stunner-editors-dmn-loader"],


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


Reply via email to