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

porcelli pushed a commit to branch KOGITO-8015-feature-preview
in repository 
https://gitbox.apache.org/repos/asf/incubator-kie-tools-temporary-rnd-do-not-use.git

commit 20b87604b1f7f72072e595144b79dd9d5f120c25
Merge: 1e1e5ebb9a 3d075e9645
Author: fantonangeli <[email protected]>
AuthorDate: Thu May 25 11:55:59 2023 +0200

    Merge remote-tracking branch 'upstream/main' into 
KOGITO-8015-feature-preview

 .ci/jenkins/Jenkinsfile.vscode                     |   4 -
 .github/workflows/daily_dev_publish.yml            |  22 +-
 .github/workflows/release_build.yml                |  77 ++-
 .github/workflows/release_dry_run.yml              |   2 +-
 .github/workflows/release_publish.yml              |   2 +-
 .github/workflows/staging_build.yml                |  26 +-
 .gitignore                                         |   3 +
 .../external/ExternalDataSetClientProvider.java    |   5 +
 .../client/external/metrics/MetricsParser.java     |   7 +-
 .../client/external/metrics/MetricsParserTest.java |  45 +-
 .../dataset/def/ExternalDataSetDef.java            |  17 +-
 .../dataset/def/ExternalServiceType.java           |  57 ++
 .../dataset/json/ExternalDefJSONMarshaller.java    |  18 +-
 .../kie-editors-dev-vscode-extension/package.json  |   4 +-
 packages/kie-sandbox-distribution/README.md        |  57 ++
 .../kie-sandbox-distribution/docker-compose.yaml   |  26 +
 packages/kie-sandbox-distribution/env/index.js     |  93 +++
 packages/kie-sandbox-distribution/package.json     |  30 +
 .../src/resources/kubernetes/Deployment.ts         |  18 +
 .../src/resources/openshift/Route.ts               |  14 +
 .../env/index.js                                   |  20 +-
 .../install.js}                                    |  15 +-
 .../package.json                                   |  40 ++
 .../pom.xml                                        | 164 ++++++
 .../src/main/java/org/kie/kogito/AppStartup.java   |  67 +++
 .../org/kie/kogito/FileStructureConstants.java     |  36 ++
 .../java/org/kie/kogito/HotReloadResource.java     | 103 ++++
 .../org/kie/kogito/StaticContentCachingFilter.java |  48 ++
 .../main/java/org/kie/kogito/api/FileService.java  |  44 ++
 .../java/org/kie/kogito/api/FileValidation.java}   |  13 +-
 .../java/org/kie/kogito/api/UploadService.java}    |  16 +-
 .../main/java/org/kie/kogito/api/ZipService.java}  |  16 +-
 .../kie/kogito/health/LivenessHealthCheck.java}    |  20 +-
 .../kie/kogito/health/ReadinessHealthCheck.java}   |  20 +-
 .../org/kie/kogito/health/StartupHealthCheck.java} |  20 +-
 .../main/java/org/kie/kogito/model/FileType.java}  |  11 +-
 .../org/kie/kogito/model/FileValidationResult.java |  71 +++
 .../org/kie/kogito/model/UploadException.java}     |  12 +-
 .../org/kie/kogito/model/ValidationException.java} |  20 +-
 .../org/kie/kogito/service/FileServiceImpl.java    | 189 +++++++
 .../org/kie/kogito/service/UploadServiceImpl.java  | 135 +++++
 .../org/kie/kogito/service/ZipServiceImpl.java     |  60 ++
 .../kie/kogito/validation/OpenApiValidation.java   |  69 +++
 .../kogito/validation/PropertiesValidation.java    |  41 ++
 .../validation/ServerlessWorkflowValidation.java   |  65 +++
 .../src/main/resources/application.properties      |  12 +
 .../src/main/resources/hello.sw.json               |  26 +
 .../org/kie/kogito/service/FileServiceTest.java    | 210 +++++++
 .../org/kie/kogito/service/ZipServiceTest.java     |  52 ++
 .../src/test/resources/test-with-invalid.zip       | Bin 0 -> 1943 bytes
 .../src/test/resources/test.zip                    | Bin 0 -> 1415 bytes
 .../env/index.js                                   |  43 ++
 .../package.json                                   |  18 +
 .../.dockerignore                                  |   4 +
 .../Containerfile                                  |  46 ++
 .../Dockerfile                                     |   1 +
 .../env/index.js                                   |  41 ++
 .../package.json                                   |  34 ++
 .../build/defaultEnvJson.ts}                       |  25 +-
 packages/serverless-logic-web-tools/env/index.js   |  43 +-
 packages/serverless-logic-web-tools/package.json   |  10 +-
 packages/serverless-logic-web-tools/src/App.tsx    |  19 +-
 .../serverless-logic-web-tools/src/AppConstants.ts |   4 +
 .../src/ResponsiveDropdown/ResponsiveDropdown.tsx  |   1 +
 .../src/accelerator/Accelerators.ts                |  43 ++
 .../src/accelerator/useAccelerator.tsx             | 272 +++++++++
 .../src/alerts/Alerts.tsx                          |  10 +-
 .../src/alerts/GlobalAlertsContext.tsx             | 122 ++++
 .../src/editor/CreateGitHubRepositoryModal.tsx     | 170 +++---
 .../src/editor/Deploy/ConfirmDeployModal.tsx       |   9 +-
 .../src/editor/Deploy/DeployDropdownItems.tsx      | 154 -----
 .../src/editor/EditorPage.tsx                      |  16 +-
 .../src/editor/EditorToolbar.tsx                   |  68 +--
 .../KieSandboxExtendedServicesButtons.tsx          |   7 +-
 .../KieSandboxExtendedServicesDropdownGroup.tsx    |  11 +-
 .../src/editor/NewFileDropdownMenu.tsx             |   6 +-
 .../editor/api/RemoteServiceRegistryCatalogApi.ts  |   2 +-
 .../src/editor/hooks/EditorContext.tsx             |  49 ++
 .../src/editor/hooks/useDeployDropdownItems.tsx    | 411 ++++++++++++++
 .../src/editor/hooks/useEditorNotifications.tsx    |   8 +-
 .../src/env/EnvContext.tsx                         |  15 +-
 .../src/env/EnvContextProvider.tsx                 |  14 +-
 .../OpenShiftConstants.ts => env/EnvJson.ts}       |  10 +-
 .../src/extension/index.ts                         |  16 +-
 .../src/fetch/index.ts}                            |  17 +-
 .../src/home/sample/{sampleApi.ts => SampleApi.ts} |  46 +-
 .../src/home/sample/SampleCard.tsx                 |   2 +-
 .../src/home/sample/SampleConstants.ts}            |  23 +-
 .../src/home/sample/SamplesCatalog.tsx             |   2 +-
 .../src/home/sample/hooks/SampleContext.tsx        |  22 +-
 .../src/homepage/recentModels/RecentModels.tsx     |  10 +-
 .../recentModels/workspaceFiles/WorkspaceFiles.tsx |  11 +-
 .../serverless-logic-web-tools/src/i18n/AppI18n.ts |  70 ---
 .../src/i18n/locales/en.ts                         |  78 +--
 .../KieSandboxExtendedServicesContextProvider.tsx  |  58 +-
 .../KieSandboxExtendedServicesIcon.tsx             |   2 +-
 .../KieSandboxExtendedServicesModal.tsx            |  12 +-
 .../src/openshift/DeployConstants.ts}              |  14 +-
 .../src/openshift/OpenShiftConstants.ts            |   4 +
 .../src/openshift/OpenShiftContext.tsx             |   6 +-
 .../src/openshift/OpenShiftContextProvider.tsx     |  55 +-
 .../src/openshift/deploy/BaseContainerImages.ts    |  11 +-
 .../src/openshift/deploy/DeploymentStrategy.ts     |  17 -
 .../strategies/DashboardSingleModelDeployment.ts   |   3 +-
 .../strategies/DashboardWorkspaceDeployment.ts     |   3 +-
 .../deploy/strategies/KogitoProjectDeployment.ts   |   3 +-
 .../deploy/strategies/KogitoSwfModelDeployment.ts  |   3 +-
 .../src/openshift/deploy/types.ts                  |  14 +-
 .../dropdown/OpenShiftDeploymentDropdownItem.tsx   |  77 ++-
 .../dropdown/OpenshiftDeploymentsDropdown.tsx      | 188 +++++--
 .../src/openshift/hooks/useDeploymentStrategy.ts   |   3 +-
 .../pipelines/DevModeDeploymentLoaderPipeline.ts   | 123 ++++
 .../pipelines/KnativeDeploymentLoaderPipeline.ts   |   1 +
 .../openshift/pipelines/RestartDevModePipeline.ts  | 112 ++++
 .../openshift/pipelines/SpinUpDevModePipeline.ts   | 241 ++++++++
 .../src/openshift/swfDevMode/DevModeConstants.ts   |  83 +++
 .../src/openshift/swfDevMode/DevModeContext.tsx    | 292 ++++++++++
 .../src/settings/SettingsContext.tsx               |  29 +-
 .../src/settings/openshift/OpenShiftSettings.tsx   |   9 +-
 .../settings/openshift/OpenShiftSettingsConfig.tsx |  10 +
 .../openshift/OpenShiftSettingsSimpleConfig.tsx    |  50 +-
 .../src/settings/storage/StorageSettings.tsx       |  10 +-
 .../src/upgrade/UpgradeContext.tsx                 |  67 +++
 .../components/NewWorkspaceFromSample.tsx          |   4 +-
 .../hooks/WebToolsWorkspaceContextProvider.tsx     |  30 +
 .../src/workspace/worker/sharedWorker.ts           |   6 +-
 .../src/zip/index.ts}                              |  21 +-
 .../serverless-logic-web-tools/static/env.json     |   2 +-
 .../static/resources/style.css                     | 100 +---
 packages/serverless-logic-web-tools/tsconfig.json  |  11 +-
 .../serverless-logic-web-tools/webpack.config.js   | 302 ----------
 .../serverless-logic-web-tools/webpack.config.ts   | 328 +++++++++++
 .../package.json                                   |   1 +
 .../ServerlessWorkflowCombinedEditorChannelApi.ts  |   6 +
 ...ServerlessWorkflowCombinedEditorEnvelopeApi.ts} |  13 +-
 .../editor/ServerlessWorkflowCombinedEditor.tsx    |  28 +
 .../ServerlessWorkflowCombinedEditorView.tsx       |  14 +-
 .../src/editor/helpers/ColorNodes.ts               |  45 ++
 ...verlessWorkflowCombinedEditorEnvelopeApiImpl.ts |  52 ++
 .../src/impl/SwfCombinedEditorChannelApiImpl.ts    |   4 +
 .../src/impl/index.ts                              |   1 +
 .../ServerlessWorkflowDiagramEditorEnvelopeApi.ts  |   4 +-
 .../src/api/StunnerAPI.ts                          |  76 +++
 .../src/api/StunnerEditorEnvelopeAPI.ts            | 107 ++++
 .../src/api/StunnerEditorEnvelopeAPIFactory.ts     |  48 ++
 .../src/api/SwfStunnerEditorAPI.ts                 | 182 ++++++
 .../envelope/ServerlessWorkflowDiagramEditor.ts    |  93 ++-
 ...rverlessWorkflowDiagramEditorEnvelopeApiImpl.ts | 110 +++-
 .../envelope/ServerlessWorkflowStunnerEditor.ts    | 108 ++++
 .../canvas/controls/ControlPointControlImpl.java   |   2 +-
 .../client/widgets/editor/StunnerEditor.java       |   1 +
 .../common/stunner/core/graph/content/Bound.java   |   7 +-
 .../common/stunner/core/graph/content/Bounds.java  |   7 +-
 .../core/graph/content/view/ControlPoint.java      |   9 +-
 .../stunner/core/graph/content/view/Point2D.java   |   9 +-
 .../stunner/core/client/api/JsStunnerEditor.java   |   2 +
 .../stunner/core/client/api/JsStunnerSession.java  |  21 +-
 .../common/stunner/core/client/api/JsWindow.java   |   1 +
 .../core/graph/content/view/MagnetConnection.java  |   9 +-
 .../core/graph/content/view/Point2DConnection.java |   7 +-
 .../core/graph/content/view/ViewConnectorImpl.java |   9 +-
 .../stunner/core/graph/content/view/ViewImpl.java  |   7 +-
 .../common/stunner/core/graph/impl/NodeImpl.java   |   8 +-
 .../impl/AbstractControlPointCommandTest.java      |   6 +-
 .../com/ait/lienzo/client/core/types/JsCanvas.java |   5 +
 .../stunner/sw/client/editor/DiagramEditor.java    |   2 +-
 .../common/stunner/sw/KogitoSWEditor.gwt.xml       |   2 +-
 .../sw/client/editor/DiagramEditorTest.java        |   6 +-
 ...neServerlessWorkflowCombinedEditorChannelApi.ts |   4 +
 .../src/main/resources}/hello-world.sw.json        |   0
 ...-workflow-editor-extension-svg-filepath.test.ts | 123 ++++
 .../package.json                                   |   4 +-
 packages/stunner-editors/pom.xml                   |   4 +-
 .../package.json                                   |   4 +-
 .../src/VSCodeTestHelper.ts                        |  40 ++
 .../package.json                                   |   2 +-
 .../.mocharc.json                                  |   7 -
 .../.vscode/launch.json                            |  24 -
 .../.vscode/settings.json                          |   9 -
 .../.vscode/tasks.json                             |  18 -
 .../CHANGELOG.md                                   | 149 -----
 .../LICENSE                                        | 201 -------
 .../README.md                                      |  86 ---
 .../icon.png                                       | Bin 22915 -> 0 bytes
 .../it-tests/helpers/swf/SwfEditorTestHelper.ts    | 174 ------
 .../autocompletion/autocompletion.sw.json          |  15 -
 .../autocompletion/autocompletion.sw.json.result   |  28 -
 .../autocompletion/autocompletion.sw.yaml          |  16 -
 .../autocompletion/autocompletion.sw.yaml.result   |  27 -
 .../emptyfile_autocompletion.sw.json               |   0
 .../emptyfile_autocompletion.sw.json.result        |  41 --
 .../emptyfile_autocompletion.sw.yaml               |   0
 .../emptyfile_autocompletion.sw.yaml.result        |  25 -
 .../emptyworkflow_autocompletion.sw.json           |   0
 .../emptyworkflow_autocompletion.sw.json.result    |  11 -
 .../resources/autocompletion/specs/api.yaml        |  15 -
 .../resources/basic-operations/greet.sw.json       |  67 ---
 .../applicant-request-decision.sw.json             |  59 --
 .../resources/expression/expression.sw.json        |  35 --
 .../resources/expression/expression.sw.yaml        |  22 -
 .../resources/expression/schema/schema.json        |  24 -
 .../resources/expression/specs/openapi.json        |  49 --
 .../it-tests/resources/functions/function.sw.json  |  14 -
 .../resources/functions/function.sw.json.result    |  30 -
 .../it-tests/resources/functions/function.sw.yaml  |  10 -
 .../resources/functions/function.sw.yaml.result    |  18 -
 .../it-tests/resources/functions/routes/camel.json |  29 -
 .../it-tests/resources/functions/routes/camel.yaml |  12 -
 .../resources/functions/specs/asyncapi.json        |  17 -
 .../resources/functions/specs/asyncapi.yaml        |  10 -
 .../resources/functions/specs/openapi.json         |  41 --
 .../resources/functions/specs/openapi.yaml         |  25 -
 .../it-tests/resources/greeting-flow/.dockerignore |   5 -
 .../it-tests/resources/greeting-flow/.gitignore    |  39 --
 .../it-tests/resources/greeting-flow/pom.xml       | 144 -----
 .../org/kie/tools/it/tests/GreetingResource.java   |  16 -
 .../src/main/resources/application.properties      |   1 -
 .../src/main/resources/greetings.sw.json           |  81 ---
 .../greeting-flow/src/main/resources/openapi.yaml  |  37 --
 .../org/kie/tools/it/tests/GreetingResourceIT.java |   9 -
 .../kie/tools/it/tests/GreetingResourceTest.java   |  21 -
 .../syntax-highlight-hello-world.sw.json           |  18 -
 ...orkflow-editor-extension-autocompletion.test.ts | 255 ---------
 ...kflow-editor-extension-basic-operations.test.ts | 141 -----
 ...low-editor-extension-diagram-navigation.test.ts |  84 ---
 ...ss-workflow-editor-extension-expression.test.ts |  85 ---
 ...ess-workflow-editor-extension-functions.test.ts | 177 ------
 ...verless-workflow-editor-extension-smoke.test.ts |  62 --
 ...kflow-editor-extension-syntax-highlight.test.ts |  96 ----
 .../it-tests/settings.json                         |  14 -
 .../jsonLanguageConfiguration.json                 |  23 -
 .../yamlLanguageConfiguration.json                 |  38 --
 .../mocha-reporter-config.json                     |  15 -
 .../package.json                                   | 388 -------------
 .../src/extension/RedHatAuthExtensionStateStore.ts |  53 --
 ...erverlessWorkflowDiagramEditorChannelApiImpl.ts | 261 ---------
 ...rlessWorkflowDiagramEditorChannelApiProducer.ts |  70 ---
 .../builtInVsCodeEditorSwfContributions.ts         | 320 -----------
 .../src/extension/commandIds.ts                    |  30 -
 .../src/extension/configuration.ts                 | 152 -----
 .../src/extension/extension.ts                     | 138 -----
 .../fs/JqExpressionsReadSchemaFromFs.ts            |  62 --
 .../SwfLanguageServiceChannelApiImpl.ts            |  45 --
 .../languageService/VsCodeSwfLanguageService.ts    | 212 -------
 .../SwfServiceCatalogChannelApiImpl.ts             |  63 ---
 .../serviceCatalog/SwfServiceCatalogStore.ts       |  71 ---
 .../SwfServiceCatalogSupportActions.ts             |  74 ---
 .../fs/FsWatchingServiceCatalogRelativeStore.ts    | 220 --------
 .../serviceRegistry/ServiceRegistriesStore.ts      | 174 ------
 .../ServiceRegistryInstanceClient.ts               |  88 ---
 .../serviceRegistry/auth/AuthProviderFactory.ts    |  45 --
 .../serviceRegistry/auth/RhhccAuthProvider.ts      |  77 ---
 .../serviceCatalog/serviceRegistryCommands.ts      |  50 --
 .../src/extension/setupDeprecationNotification.ts  |  49 --
 .../extension/setupDiagramEditorCompanionTab.ts    | 142 -----
 .../ServerlessWorkflowDiagramEditorEnvelopeApp.ts  |  44 --
 .../ServerlessWorkflowMermaidViewerEnvelopeApp.ts  |  28 -
 .../static/svg-icon-dark.png                       | Bin 656 -> 0 bytes
 .../static/svg-icon-light.png                      | Bin 362 -> 0 bytes
 .../syntaxes/JSON.tmLanguage.json                  | 213 -------
 .../syntaxes/YAML.tmLanguage.json                  | 621 ---------------------
 .../tsconfig.it-tests.json                         |  11 -
 .../tsconfig.json                                  |   9 -
 .../webpack.config.js                              |  72 ---
 .../pom.xml                                        |   7 +-
 .../internal/handlers/GetAccessorsHandler.java     |  12 +-
 .../src/textEditor/YardTextEditorController.ts     |   2 +
 .../augmentation/language/schemas/yardSchema.ts    | 187 +++++++
 .../augmentation/language/yaml/index.ts}           |  37 +-
 packages/yard-vscode-extension/package.json        |  13 +-
 pnpm-lock.yaml                                     | 339 +++++------
 repo/graph.dot                                     |  22 +-
 repo/graph.json                                    |  86 +--
 scripts/build-env/src/bin.ts                       |  20 +
 scripts/sparse-checkout/run.sh                     |   2 +-
 275 files changed, 6682 insertions(+), 8118 deletions(-)

diff --cc packages/serverless-logic-web-tools/package.json
index b80490fa23,86b1bacfcc..1368fb841f
--- a/packages/serverless-logic-web-tools/package.json
+++ b/packages/serverless-logic-web-tools/package.json
@@@ -72,7 -72,8 +74,9 @@@
      "react-if": "^4.1.4",
      "react-router": "^5.2.1",
      "react-router-dom": "^5.2.1",
+     "short-unique-id": "^4.4.4",
 +    "showdown": "^2.1.0",
+     "uuid": "^8.3.2",
      "vscode-languageserver-types": "^3.16.0",
      "yaml": "^2.0.1"
    },
diff --cc packages/serverless-logic-web-tools/src/AppConstants.ts
index 8124e259f5,0892f4e600..4b6f3ad5ac
--- a/packages/serverless-logic-web-tools/src/AppConstants.ts
+++ b/packages/serverless-logic-web-tools/src/AppConstants.ts
@@@ -15,5 -15,8 +15,9 @@@
   */
  
  export const APP_NAME = "Serverless Logic Web Tools";
 -
 +export const SERVERLESS_LOGIC_WEBTOOLS_DOCUMENTATION_URL =
 +  
"https://kiegroup.github.io/kogito-docs/serverlessworkflow/latest/tooling/serverless-logic-web-tools/serverless-logic-web-tools-overview.html";;
+ export const APP_GIT_USER = {
+   name: APP_NAME,
+   email: "",
+ };
diff --cc packages/serverless-logic-web-tools/src/editor/EditorPage.tsx
index 4fe16df52c,a0ed0c2ff9..12821815cc
--- a/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx
+++ b/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx
@@@ -42,7 -42,7 +41,8 @@@ import { EditorToolbar } from "./Editor
  import { APP_NAME } from "../AppConstants";
  import { WebToolsEmbeddedEditor, WebToolsEmbeddedEditorRef } from 
"./WebToolsEmbeddedEditor";
  import { useEditorNotifications } from "./hooks/useEditorNotifications";
+ import { useGlobalAlertsDispatchContext } from 
"../alerts/GlobalAlertsContext";
 +import { setPageTitle } from "../PageTitle";
  
  export interface Props {
    workspaceId: string;
@@@ -218,50 -218,46 +218,44 @@@ export function EditorPage(props: Props
    );
  
    return (
 -    <OnlineEditorPage>
 -      <PromiseStateWrapper
 -        promise={workspaceFilePromise}
 -        pending={<LoadingSpinner />}
 -        rejected={(errors) => <EditorPageErrorPage errors={errors} 
path={props.fileRelativePath} />}
 -        resolved={(file) => (
 -          <>
 -            <Page>
 -              <EditorToolbar workspaceFile={file.workspaceFile} 
editor={webToolsEditor?.editor} />
 -              <Divider />
 -              <EditorPageDockDrawer
 -                ref={editorPageDockRef}
 -                isEditorReady={isEditorReady}
 -                workspaceFile={file.workspaceFile}
 -                onNotificationClick={onNotificationClick}
 -                isDisabled={!webToolsEditor?.notificationHandler.isSupported}
 -              >
 -                <PageSection hasOverflowScroll={true} padding={{ default: 
"noPadding" }} aria-label="Editor Section">
 -                  <div style={{ height: "100%" }}>
 -                    {!isEditorReady && <LoadingSpinner />}
 -                    <div style={{ display: isEditorReady ? "inline" : "none" 
}}>
 -                      {embeddedEditorFile && (
 -                        <WebToolsEmbeddedEditor
 -                          uniqueFileId={uniqueFileId}
 -                          ref={webToolsEditorRef}
 -                          file={embeddedEditorFile}
 -                          workspaceFile={file.workspaceFile}
 -                          editorEnvelopeLocator={editorEnvelopeLocator}
 -                          channelType={ChannelType.ONLINE_MULTI_FILE}
 -                          locale={locale}
 -                        />
 -                      )}
 -                    </div>
 +    <PromiseStateWrapper
 +      promise={workspaceFilePromise}
 +      pending={<LoadingSpinner />}
 +      rejected={(errors) => <EditorPageErrorPage errors={errors} 
path={props.fileRelativePath} />}
 +      resolved={(file) => (
 +        <>
 +          <Page>
-             <EditorToolbar
-               workspaceFile={file.workspaceFile}
-               editor={webToolsEditor?.editor}
-               alerts={alerts}
-               alertsRef={alertsRef}
-               editorPageDock={editorPageDock}
-             />
++            <EditorToolbar workspaceFile={file.workspaceFile} 
editor={webToolsEditor?.editor} />
 +            <Divider />
 +            <EditorPageDockDrawer
 +              ref={editorPageDockRef}
 +              isEditorReady={isEditorReady}
 +              workspaceFile={file.workspaceFile}
 +              onNotificationClick={onNotificationClick}
 +              isDisabled={!webToolsEditor?.notificationHandler.isSupported}
 +            >
 +              <PageSection hasOverflowScroll={true} padding={{ default: 
"noPadding" }} aria-label="Editor Section">
 +                <div style={{ height: "100%" }}>
 +                  {!isEditorReady && <LoadingSpinner />}
 +                  <div style={{ display: isEditorReady ? "inline" : "none" }}>
 +                    {embeddedEditorFile && (
 +                      <WebToolsEmbeddedEditor
 +                        uniqueFileId={uniqueFileId}
 +                        ref={webToolsEditorRef}
 +                        file={embeddedEditorFile}
 +                        workspaceFile={file.workspaceFile}
 +                        editorEnvelopeLocator={editorEnvelopeLocator}
 +                        channelType={ChannelType.ONLINE_MULTI_FILE}
 +                        locale={locale}
 +                      />
 +                    )}
                    </div>
 -                </PageSection>
 -              </EditorPageDockDrawer>
 -            </Page>
 -          </>
 -        )}
 -      />
 -    </OnlineEditorPage>
 +                </div>
 +              </PageSection>
 +            </EditorPageDockDrawer>
 +          </Page>
 +        </>
 +      )}
 +    />
    );
  }
diff --cc packages/serverless-logic-web-tools/src/editor/EditorToolbar.tsx
index 50a4dc4635,f385ac1bd6..46ae59ab4b
--- a/packages/serverless-logic-web-tools/src/editor/EditorToolbar.tsx
+++ b/packages/serverless-logic-web-tools/src/editor/EditorToolbar.tsx
@@@ -93,15 -92,12 +91,14 @@@ import { WorkspaceStatusIndicator } fro
  import { WorkspaceKind } from 
"@kie-tools-core/workspaces-git-fs/dist/worker/api/WorkspaceOrigin";
  import { useEditorEnvelopeLocator } from 
"../envelopeLocator/EditorEnvelopeLocatorContext";
  import { UrlType, useImportableUrl } from 
"../workspace/hooks/ImportableUrlHooks";
+ import { useEnv } from "../env/EnvContext";
+ import { useGlobalAlert, useGlobalAlertsDispatchContext } from 
"../alerts/GlobalAlertsContext";
 +import { Link } from "react-router-dom";
 +import { routes } from "../navigation/Routes";
  
  export interface Props {
-   alerts: AlertsController | undefined;
-   alertsRef: (controller: AlertsController) => void;
    editor: EmbeddedEditorRef | undefined;
    workspaceFile: WorkspaceFile;
-   editorPageDock: EditorPageDockDrawerRef | undefined;
  }
  
  const showWhenSmall: ToolbarItemProps["visibility"] = {
diff --cc packages/serverless-logic-web-tools/src/editor/NewFileDropdownMenu.tsx
index 5996576438,fb59b77f64..62782c4830
--- a/packages/serverless-logic-web-tools/src/editor/NewFileDropdownMenu.tsx
+++ b/packages/serverless-logic-web-tools/src/editor/NewFileDropdownMenu.tsx
@@@ -38,7 -38,7 +37,8 @@@ import { FileTypes } from "@kie-tools-c
  import { decoder } from 
"@kie-tools-core/workspaces-git-fs/dist/encoderdecoder/EncoderDecoder";
  import { extractExtension } from 
"@kie-tools-core/workspaces-git-fs/dist/relativePath/WorkspaceFileRelativePathParser";
  import { UrlType } from "../workspace/hooks/ImportableUrlHooks";
+ import { useGlobalAlert } from "../alerts/GlobalAlertsContext";
 +import { ValidatedOptions } from "@patternfly/react-core/dist/js";
  
  const ROOT_MENU_ID = "addFileRootMenu";
  
diff --cc 
packages/serverless-logic-web-tools/src/editor/hooks/useDeployDropdownItems.tsx
index 0000000000,05183e17d4..e0f1e6be5b
mode 000000,100644..100644
--- 
a/packages/serverless-logic-web-tools/src/editor/hooks/useDeployDropdownItems.tsx
+++ 
b/packages/serverless-logic-web-tools/src/editor/hooks/useDeployDropdownItems.tsx
@@@ -1,0 -1,410 +1,411 @@@
+ /*
+  * Copyright 2021 Red Hat, Inc. and/or its affiliates.
+  *
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at
+  *
+  *        http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
+ import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
+ import { Spinner } from "@patternfly/react-core/dist/js/components/Spinner";
+ import { List, ListItem } from 
"@patternfly/react-core/dist/js/components/List";
+ import { DropdownItem } from 
"@patternfly/react-core/dist/js/components/Dropdown";
+ import { Text } from "@patternfly/react-core/dist/js/components/Text";
+ import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
+ import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
+ import { RegistryIcon, ExclamationCircleIcon } from 
"@patternfly/react-icons/dist/js/icons";
+ import { OpenshiftIcon } from 
"@patternfly/react-icons/dist/js/icons/openshift-icon";
+ import { UploadIcon } from 
"@patternfly/react-icons/dist/js/icons/upload-icon";
+ import * as React from "react";
+ import { useCallback, useMemo, useState, useEffect } from "react";
+ import { useAppI18n } from "../../i18n";
+ import { FeatureDependentOnKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/FeatureDependentOnKieSandboxExtendedServices";
+ import {
+   DependentFeature,
+   useKieSandboxExtendedServices,
+ } from "../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+ import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+ import { useOpenShift } from "../../openshift/OpenShiftContext";
+ import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
 -import { useSettings, useSettingsDispatch } from 
"../../settings/SettingsContext";
 -import { SettingsTabs } from "../../settings/SettingsModalBody";
++import { useSettings } from "../../settings/SettingsContext";
+ import { useVirtualServiceRegistryDependencies } from 
"../../virtualServiceRegistry/hooks/useVirtualServiceRegistryDependencies";
+ import { FileLabel } from "../../workspace/components/FileLabel";
+ import { ActiveWorkspace } from 
"@kie-tools-core/workspaces-git-fs/dist/model/ActiveWorkspace";
+ import { WorkspaceFile } from 
"@kie-tools-core/workspaces-git-fs/dist/context/WorkspacesContext";
+ import { useDevMode, useDevModeDispatch } from 
"../../openshift/swfDevMode/DevModeContext";
+ import { Alert, AlertActionCloseButton, AlertActionLink } from 
"@patternfly/react-core/dist/js/components/Alert";
+ import { useEnv } from "../../env/EnvContext";
+ import { useGlobalAlert } from "../../alerts/GlobalAlertsContext";
+ import { useEditor } from "../hooks/EditorContext";
+ import { isOfKind } from 
"@kie-tools-core/workspaces-git-fs/dist/constants/ExtensionHelper";
++import { useHistory } from "react-router";
++import { routes } from "../../navigation/Routes";
+ 
+ const FETCH_DEV_MODE_DEPLOYMENT_POLLING_TIME = 2000;
+ 
+ interface Props {
+   workspace: ActiveWorkspace;
+   workspaceFile: WorkspaceFile;
+ }
+ 
+ export function useDeployDropdownItems(props: Props) {
+   const { env } = useEnv();
+   const { notifications } = useEditor();
+   const { i18n } = useAppI18n();
+   const devMode = useDevMode();
+   const devModeDispatch = useDevModeDispatch();
+   const settings = useSettings();
 -  const settingsDispatch = useSettingsDispatch();
+   const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+   const openshift = useOpenShift();
+   const [canContentBeDeployed, setCanContentBeDeployed] = useState(true);
+   const { needsDependencyDeployment } = 
useVirtualServiceRegistryDependencies({
+     workspace: props.workspace,
+   });
++  const history = useHistory();
+ 
+   useEffect(() => {
+     props.workspaceFile.getFileContentsAsString().then((content) => {
+       setCanContentBeDeployed(content.trim().length > 0 && 
!notifications.some((d) => d.severity === "ERROR"));
+     });
+   }, [notifications, props.workspaceFile]);
+ 
+   const devModeUploadingAlert = useGlobalAlert(
+     useCallback(({ close }) => {
+       return (
+         <Alert
+           className="pf-u-mb-md"
+           variant="info"
+           title={
+             <>
+               <Spinner size={"sm"} />
+               &nbsp;&nbsp; Uploading files to Dev Mode...
+             </>
+           }
+           aria-live="polite"
+           data-testid="alert-dev-mode-uploading"
+           actionClose={<AlertActionCloseButton onClose={close} />}
+         />
+       );
+     }, [])
+   );
+ 
+   const devModeReadyAlert = useGlobalAlert<{ routeUrl: string; filePaths: 
string[] }>(
+     useCallback(({ close }, { routeUrl, filePaths }) => {
+       return (
+         <Alert
+           isExpandable
+           className="pf-u-mb-md"
+           variant="success"
+           title={"Your Dev Mode has been successfully updated"}
+           aria-live="polite"
+           data-testid="alert-dev-mode-ready"
+           actionClose={<AlertActionCloseButton onClose={close} />}
+           actionLinks={
+             <AlertActionLink onClick={() => window.open(routeUrl, "_blank")}>
+               {"Go to Serverless Workflow Dev UI ↗"}
+             </AlertActionLink>
+           }
+         >
+           <>
+             <Text component="p" style={{ marginBottom: "4px" }}>
+               Files that have been uploaded:
+             </Text>
+             <List>
+               {filePaths.map((p) => (
+                 <ListItem key={`uploaded-file-path-${p}`}>{p}</ListItem>
+               ))}
+             </List>
+           </>
+         </Alert>
+       );
+     }, [])
+   );
+ 
+   const uploadToDevModeSuccessAlert = useGlobalAlert(
+     useCallback(({ close }) => {
+       return (
+         <Alert
+           className="pf-u-mb-md"
+           variant="info"
+           title={
+             <>
+               <Spinner size={"sm"} />
+               &nbsp;&nbsp; Updating the Dev Mode deployment...
+             </>
+           }
+           aria-live="polite"
+           data-testid="alert-dev-mode-updating"
+           actionClose={<AlertActionCloseButton onClose={close} />}
+         />
+       );
+     }, [])
+   );
+ 
+   const uploadToDevModeErrorAlert = useGlobalAlert<{ messages: string[] }>(
+     useCallback(({ close }, { messages }) => {
+       return (
+         <Alert
+           isExpandable
+           className="pf-u-mb-md"
+           variant="warning"
+           title={"Something went wrong while uploading to the Dev Mode."}
+           aria-live="polite"
+           data-testid="alert-upload-error"
+           actionClose={<AlertActionCloseButton onClose={close} />}
+         >
+           {messages.length > 1 ? (
+             <List>
+               {messages.map((p) => (
+                 <ListItem key={`error-message-upload-${p}`}>{p}</ListItem>
+               ))}
+             </List>
+           ) : (
+             <Text component="p">{messages[0]}</Text>
+           )}
+         </Alert>
+       );
+     }, [])
+   );
+ 
+   const uploadToDevModeTimeoutErrorAlert = useGlobalAlert(
+     useCallback(({ close }) => {
+       return (
+         <Alert
+           className="pf-u-mb-md"
+           variant="warning"
+           title={
+             <>
+               Something went wrong while uploading to the Dev Mode.
+               <br />
+               Please check your Dev Mode deployment logs for more details.
+             </>
+           }
+           aria-live="polite"
+           data-testid="alert-upload-error"
+           actionClose={<AlertActionCloseButton onClose={close} />}
+         />
+       );
+     }, [])
+   );
+ 
+   const isKieSandboxExtendedServicesRunning = useMemo(
+     () => kieSandboxExtendedServices.status === 
KieSandboxExtendedServicesStatus.RUNNING,
+     [kieSandboxExtendedServices.status]
+   );
+ 
+   const isOpenShiftConnected = useMemo(
+     () => settings.openshift.status === OpenShiftInstanceStatus.CONNECTED,
+     [settings.openshift.status]
+   );
+ 
+   const isUploadToDevModeEnabled = useMemo(
+     () => devMode.isEnabled && isOfKind("sw", props.workspaceFile.name),
+     [devMode.isEnabled, props.workspaceFile.name]
+   );
+ 
+   const onSetup = useCallback(() => {
 -    settingsDispatch.open(SettingsTabs.OPENSHIFT);
 -  }, [settingsDispatch]);
++    history.push(routes.settings.openshift.path({}));
++  }, [history]);
+ 
+   const onDeploy = useCallback(() => {
+     if (isKieSandboxExtendedServicesRunning) {
+       openshift.setConfirmDeployModalOpen(true);
+       return;
+     }
+     
kieSandboxExtendedServices.setInstallTriggeredBy(DependentFeature.OPENSHIFT);
+     kieSandboxExtendedServices.setModalOpen(true);
+   }, [isKieSandboxExtendedServicesRunning, kieSandboxExtendedServices, 
openshift]);
+ 
+   const onUploadDevMode = useCallback(async () => {
+     if (isKieSandboxExtendedServicesRunning) {
+       devModeUploadingAlert.show();
+       const result = await devModeDispatch.upload({
+         targetSwfFile: props.workspaceFile,
+         allFiles: props.workspace.files,
+       });
+       devModeUploadingAlert.close();
+ 
+       if (result.success) {
+         uploadToDevModeSuccessAlert.show();
+ 
+         let attemptsLeft = 15;
+         const fetchDevModeDeploymentTask = window.setInterval(async () => {
+           const isReady = await devModeDispatch.checkHealthReady();
+           attemptsLeft--;
+           if (attemptsLeft === 0) {
+             uploadToDevModeSuccessAlert.close();
+             uploadToDevModeTimeoutErrorAlert.show();
+             window.clearInterval(fetchDevModeDeploymentTask);
+             return;
+           }
+           if (!isReady) {
+             return;
+           }
+           uploadToDevModeSuccessAlert.close();
+           devModeReadyAlert.show({ routeUrl: devMode.endpoints!.swfDevUi, 
filePaths: result.uploadedPaths });
+           window.clearInterval(fetchDevModeDeploymentTask);
+         }, FETCH_DEV_MODE_DEPLOYMENT_POLLING_TIME);
+       } else {
+         uploadToDevModeErrorAlert.show({ messages: result.messages });
+       }
+     } else {
+       
kieSandboxExtendedServices.setInstallTriggeredBy(DependentFeature.OPENSHIFT);
+       kieSandboxExtendedServices.setModalOpen(true);
+     }
+   }, [
+     isKieSandboxExtendedServicesRunning,
+     devModeUploadingAlert,
+     devModeDispatch,
+     props.workspaceFile,
+     props.workspace.files,
+     uploadToDevModeSuccessAlert,
+     devModeReadyAlert,
+     devMode.endpoints,
+     uploadToDevModeErrorAlert,
+     kieSandboxExtendedServices,
+     uploadToDevModeTimeoutErrorAlert,
+   ]);
+ 
+   return useMemo(() => {
+     return [
+       <React.Fragment key={"deploy-dropdown-items"}>
+         {props.workspace && (
+           <FeatureDependentOnKieSandboxExtendedServices isLight={false} 
position="left">
+             {isUploadToDevModeEnabled && (
+               <DropdownItem
+                 icon={<UploadIcon />}
+                 id="upload-dev-mode-button"
+                 key={`dropdown-upload-dev-mode`}
+                 component={"button"}
+                 onClick={onUploadDevMode}
+                 isDisabled={isKieSandboxExtendedServicesRunning && 
(!isOpenShiftConnected || !canContentBeDeployed)}
+                 ouiaId={"upload-to-openshift-dev-mode-dropdown-button"}
+               >
+                 {props.workspace.files.length > 1 && (
+                   <Flex flexWrap={{ default: "nowrap" }}>
+                     <FlexItem>
+                       Upload <b>{`"${props.workspace.descriptor.name}"`}</b> 
to Dev Mode
+                     </FlexItem>
+                   </Flex>
+                 )}
+                 {props.workspace.files.length === 1 && (
+                   <Flex flexWrap={{ default: "nowrap" }}>
+                     <FlexItem>
+                       Upload 
<b>{`"${props.workspace.files[0].nameWithoutExtension}"`}</b> to Dev Mode
+                     </FlexItem>
+                     <FlexItem>
+                       <b>
+                         <FileLabel 
extension={props.workspace.files[0].extension} />
+                       </b>
+                     </FlexItem>
+                   </Flex>
+                 )}
+               </DropdownItem>
+             )}
+             <DropdownItem
+               icon={<OpenshiftIcon />}
+               id="deploy-your-model-button"
+               key={`dropdown-deploy`}
+               component={"button"}
+               onClick={onDeploy}
+               isDisabled={isKieSandboxExtendedServicesRunning && 
(!isOpenShiftConnected || !canContentBeDeployed)}
+               ouiaId={"deploy-to-openshift-dropdown-button"}
+             >
+               {props.workspace.files.length > 1 && (
+                 <Flex flexWrap={{ default: "nowrap" }}>
+                   <FlexItem>
+                     Deploy models in 
<b>{`"${props.workspace.descriptor.name}"`}</b>
+                   </FlexItem>
+                 </Flex>
+               )}
+               {props.workspace.files.length === 1 && (
+                 <Flex flexWrap={{ default: "nowrap" }}>
+                   <FlexItem>
+                     Deploy 
<b>{`"${props.workspace.files[0].nameWithoutExtension}"`}</b>
+                   </FlexItem>
+                   <FlexItem>
+                     <b>
+                       <FileLabel 
extension={props.workspace.files[0].extension} />
+                     </b>
+                   </FlexItem>
+                 </Flex>
+               )}
+             </DropdownItem>
+             {needsDependencyDeployment && (
+               <>
+                 <Divider />
+                 <Tooltip 
content={i18n.deployments.virtualServiceRegistry.dependencyWarningTooltip} 
position="bottom">
+                   <DropdownItem icon={<RegistryIcon 
color="var(--pf-global--warning-color--100)" />} isDisabled>
+                     <Flex flexWrap={{ default: "nowrap" }}>
+                       <FlexItem>
+                         <Text component="small" style={{ color: 
"var(--pf-global--warning-color--200)" }}>
+                           This model has foreign workspace dependencies
+                         </Text>
+                       </FlexItem>
+                     </Flex>
+                   </DropdownItem>
+                 </Tooltip>
+               </>
+             )}
+             {!canContentBeDeployed && (
+               <>
+                 <Divider />
+                 <Tooltip
+                   content={
+                     "Models with errors or empty ones cannot be deployed. 
Check the Problems tab for more information."
+                   }
+                   position="bottom"
+                 >
+                   <DropdownItem icon={<ExclamationCircleIcon 
color="var(--pf-global--danger-color--100)" />} isDisabled>
+                     <Flex flexWrap={{ default: "nowrap" }}>
+                       <FlexItem>
+                         <Text component="small" style={{ color: 
"var(--pf-global--danger-color--300)" }}>
+                           This model cannot be deployed
+                         </Text>
+                       </FlexItem>
+                     </Flex>
+                   </DropdownItem>
+                 </Tooltip>
+               </>
+             )}
+           </FeatureDependentOnKieSandboxExtendedServices>
+         )}
+         {!isOpenShiftConnected && isKieSandboxExtendedServicesRunning && (
+           <>
+             <Divider />
+             <DropdownItem
+               id="deploy-setup-button"
+               key={`dropdown-deploy-setup`}
+               onClick={onSetup}
+               ouiaId={"setup-deploy-dropdown-button"}
+             >
+               <Button isInline={true} variant={ButtonVariant.link}>
+                 Setup...
+               </Button>
+             </DropdownItem>
+           </>
+         )}
+       </React.Fragment>,
+     ];
+   }, [
+     props.workspace,
+     onDeploy,
+     isKieSandboxExtendedServicesRunning,
+     isOpenShiftConnected,
+     canContentBeDeployed,
+     isUploadToDevModeEnabled,
+     onUploadDevMode,
+     needsDependencyDeployment,
+     i18n.deployments.virtualServiceRegistry.dependencyWarningTooltip,
+     onSetup,
+   ]);
+ }
diff --cc packages/serverless-logic-web-tools/src/home/sample/SampleCard.tsx
index aa81206b59,86e53b1dad..deed941efe
--- a/packages/serverless-logic-web-tools/src/home/sample/SampleCard.tsx
+++ b/packages/serverless-logic-web-tools/src/home/sample/SampleCard.tsx
@@@ -14,19 -14,19 +14,19 @@@
   * limitations under the License.
   */
  
 -import * as React from "react";
 -import { useMemo, useRef, useEffect } from "react";
 -import { Card, CardTitle, CardFooter, CardBody } from 
"@patternfly/react-core/dist/js/components/Card";
 -import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid";
 -import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
 -import { useRoutes } from "../../navigation/Hooks";
 -import { Link } from "react-router-dom";
 -import { Text } from "@patternfly/react-core/dist/js/components/Text";
 +import { Button, Modal, ModalVariant, Skeleton } from 
"@patternfly/react-core/dist/js";
 +import { Card, CardBody, CardTitle } from 
"@patternfly/react-core/dist/js/components/Card";
  import { Label, LabelProps } from 
"@patternfly/react-core/dist/js/components/Label";
 -import { FolderIcon, FileIcon, MonitoringIcon } from 
"@patternfly/react-icons/dist/js/icons";
+ import { Sample, SampleCategory } from "./SampleApi";
 +import { Text } from "@patternfly/react-core/dist/js/components/Text";
  import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
  import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
 +import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid";
 +import { FileIcon, FolderIcon, MonitoringIcon, SearchPlusIcon } from 
"@patternfly/react-icons/dist/js/icons";
 +import * as React from "react";
 +import { useCallback, useEffect, useMemo, useState } from "react";
 +import { useHistory } from "react-router-dom";
 +import { useRoutes } from "../../navigation/Hooks";
- import { Sample, SampleCategory } from "./sampleApi";
  
  const tagMap: Record<SampleCategory, { label: string; icon: 
React.ComponentClass; color: LabelProps["color"] }> = {
    ["serverless-workflow"]: {
diff --cc packages/serverless-logic-web-tools/src/home/sample/SampleConstants.ts
index e956c766d7,b9cec21a1a..2a8a289605
--- a/packages/serverless-logic-web-tools/src/home/sample/SampleConstants.ts
+++ b/packages/serverless-logic-web-tools/src/home/sample/SampleConstants.ts
@@@ -14,17 -14,12 +14,14 @@@
   * limitations under the License.
   */
  
- import { TextEditor, WebView } from "vscode-extension-tester";
++export const SAMPLE_COVERS_CACHE_FILE_PATH = "/covers.json";
 +
- /**
-  * Helper class to easen work with swf text editor.
-  * Make sure you switch to the webview's frame before creating and instance
-  * via contructor.
-  */
- export default class SwfTextEditorTestHelper {
-   constructor(private readonly webview: WebView) {}
+ export const SAMPLES_FS_MOUNT_POINT_PREFIX = "lfs_v1__samples__";
+ 
+ export const SAMPLE_DEFINITIONS_CACHE_FILE_PATH = "/definitions.json";
+ 
+ export const SAMPLE_SEARCH_KEYS = ["definition.category", "definition.title", 
"definition.description"];
  
-   public async getSwfTextEditor(): Promise<TextEditor> {
-     return Promise.resolve(new TextEditor());
-   }
- }
+ export const resolveSampleFsMountPoint = (appVersion: string) => {
+   return `${SAMPLES_FS_MOUNT_POINT_PREFIX}${appVersion}`;
+ };
diff --cc packages/serverless-logic-web-tools/src/home/sample/SamplesCatalog.tsx
index 76258ddfb2,0000000000..619bd13d4a
mode 100644,000000..100644
--- a/packages/serverless-logic-web-tools/src/home/sample/SamplesCatalog.tsx
+++ b/packages/serverless-logic-web-tools/src/home/sample/SamplesCatalog.tsx
@@@ -1,309 -1,0 +1,309 @@@
 +/*
 + * Copyright 2023 Red Hat, Inc. and/or its affiliates.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +import { Pagination, PaginationVariant, PerPageOptions, Skeleton } from 
"@patternfly/react-core/dist/js";
 +import {
 +  Dropdown,
 +  DropdownItem,
 +  DropdownSeparator,
 +  DropdownToggle,
 +} from "@patternfly/react-core/dist/js/components/Dropdown";
 +import { EmptyState, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
 +import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
 +import { SearchInput } from 
"@patternfly/react-core/dist/js/components/SearchInput";
 +import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
 +import { Title } from "@patternfly/react-core/dist/js/components/Title";
 +import { Toolbar, ToolbarContent, ToolbarItem } from 
"@patternfly/react-core/dist/js/components/Toolbar";
 +import { Gallery } from "@patternfly/react-core/dist/js/layouts/Gallery";
 +import { CubesIcon } from "@patternfly/react-icons/dist/js/icons/cubes-icon";
 +import * as React from "react";
 +import { useCallback, useEffect, useMemo, useState } from "react";
 +import { useHistory, useLocation } from "react-router";
 +import { QueryParams } from "../../navigation/Routes";
 +import { setPageTitle } from "../../PageTitle";
 +import { useQueryParam } from "../../queryParams/QueryParamsContext";
 +import { FileLabel } from "../../workspace/components/FileLabel";
 +import { useSampleDispatch } from "./hooks/SampleContext";
- import { Sample, SampleCategories, SampleCategory, SampleCoversHashtable } 
from "./sampleApi";
++import { Sample, SampleCategories, SampleCategory, SampleCoversHashtable } 
from "./SampleApi";
 +import { SampleCard } from "./SampleCard";
 +import { SampleCardSkeleton } from "./SampleCardSkeleton";
 +import { SamplesLoadError } from "./SamplesLoadError";
 +
 +type SearchParams = { searchValue: string; category?: SampleCategory };
 +
 +const PAGE_TITLE = "Samples Catalog";
 +const SAMPLE_PRIORITY: Record<SampleCategory, number> = {
 +  ["serverless-workflow"]: 1,
 +  ["dashbuilder"]: 2,
 +  ["serverless-decision"]: 3,
 +};
 +
 +const LABEL_MAP: Record<SampleCategory, JSX.Element> = {
 +  ["serverless-workflow"]: <FileLabel extension="sw.yaml" labelProps={{ 
isCompact: true }} />,
 +  ["dashbuilder"]: <FileLabel extension="dash.yaml" labelProps={{ isCompact: 
true }} />,
 +  ["serverless-decision"]: <FileLabel extension="yard.yaml" labelProps={{ 
isCompact: true }} />,
 +};
 +
 +const ALL_CATEGORIES_LABEL = "All categories";
 +const CARDS_PER_PAGE = 9;
 +const CATEGORY_ARRAY = Object.keys(SAMPLE_PRIORITY) as SampleCategory[];
 +
 +export const SAMPLE_CARDS_PER_PAGE_OPTIONS: PerPageOptions[] = [
 +  {
 +    title: `${CARDS_PER_PAGE}`,
 +    value: CARDS_PER_PAGE,
 +  },
 +];
 +
 +export function SamplesCatalog() {
 +  const sampleDispatch = useSampleDispatch();
 +  const [loading, setLoading] = useState<boolean>(true);
 +  const [samples, setSamples] = useState<Sample[]>([]);
 +  const [sampleCovers, setSampleCovers] = useState<SampleCoversHashtable>({});
 +  const [sampleLoadingError, setSampleLoadingError] = useState("");
 +  const [searchFilter, setSearchFilter] = useState("");
 +  const [searchParams, setSearchParams] = useState<SearchParams | 
undefined>(undefined);
 +  const [page, setPage] = React.useState(1);
 +  const [isCategoryFilterDropdownOpen, setCategoryFilterDropdownOpen] = 
useState(false);
 +  const history = useHistory();
 +  const location = useLocation();
 +
 +  const categoryFilter = useQueryParam(QueryParams.SAMPLES_CATEGORY) as 
SampleCategory;
 +
 +  const visibleSamples = useMemo(
 +    () => samples.slice((page - 1) * CARDS_PER_PAGE, page * CARDS_PER_PAGE),
 +    [samples, page]
 +  );
 +
 +  const samplesCount = useMemo(() => samples.length, [samples]);
 +
 +  const filterResultMessage = useMemo(() => {
 +    if (samplesCount === 0) {
 +      return;
 +    }
 +    const isPlural = samplesCount > 1;
 +    return `Showing ${samplesCount} sample${isPlural ? "s" : ""}`;
 +  }, [samplesCount]);
 +
 +  const selectedCategory = useMemo(() => {
 +    if (categoryFilter) {
 +      return LABEL_MAP[categoryFilter];
 +    }
 +    return ALL_CATEGORIES_LABEL;
 +  }, [categoryFilter]);
 +
 +  const setCategoryFilter = useCallback(
 +    (category?: SampleCategory) => {
 +      const searchParams = new URLSearchParams(location.search);
 +      if (category) {
 +        searchParams.set(QueryParams.SAMPLES_CATEGORY, category);
 +      } else {
 +        searchParams.delete(QueryParams.SAMPLES_CATEGORY);
 +      }
 +      const newSearchString = searchParams.toString();
 +      history.push({ search: newSearchString });
 +    },
 +    [history, location]
 +  );
 +
 +  const onSearch = useCallback(
 +    async (args: SearchParams) => {
 +      if (searchParams && args.searchValue === searchParams.searchValue && 
args.category === searchParams.category) {
 +        return;
 +      }
 +      setSearchFilter(args.searchValue);
 +      setCategoryFilter(args.category);
 +      setSearchParams(args);
 +      setPage(1);
 +      setSamples(await sampleDispatch.getSamples({ searchFilter: 
args.searchValue, categoryFilter: args.category }));
 +    },
 +    [sampleDispatch, setCategoryFilter, searchParams]
 +  );
 +
 +  useEffect(() => {
 +    if (categoryFilter && !SampleCategories.includes(categoryFilter)) {
 +      setCategoryFilter(undefined);
 +      return;
 +    }
 +
 +    onSearch({ searchValue: searchFilter, category: categoryFilter });
 +  }, [categoryFilter, onSearch, searchFilter, setCategoryFilter]);
 +
 +  useEffect(() => {
 +    if (searchParams && searchFilter === searchParams.searchValue && 
categoryFilter === searchParams.category) {
 +      return;
 +    }
 +    setSearchParams({ searchValue: searchFilter, category: categoryFilter });
 +
 +    sampleDispatch
 +      .getSamples({ categoryFilter })
 +      .then((data) => {
 +        const sortedSamples = data.sort(
 +          (a: Sample, b: Sample) => SAMPLE_PRIORITY[a.definition.category] - 
SAMPLE_PRIORITY[b.definition.category]
 +        );
 +        setSamples([...sortedSamples]);
 +      })
 +      .catch((e) => {
 +        setSampleLoadingError(e.toString());
 +      })
 +      .finally(() => {
 +        setLoading(false);
 +      });
 +  }, [sampleDispatch, categoryFilter, searchFilter, searchParams]);
 +
 +  useEffect(() => {
 +    sampleDispatch.getSampleCovers({ samples: visibleSamples, prevState: 
sampleCovers }).then(setSampleCovers);
 +    // eslint-disable-next-line react-hooks/exhaustive-deps
 +  }, [visibleSamples, sampleDispatch]);
 +
 +  const categoryFilterDropdownItems = useMemo(
 +    () => [
 +      <DropdownItem
 +        key="category-filter-all-categories"
 +        onClick={() => onSearch({ searchValue: searchFilter, category: 
undefined })}
 +      >
 +        {ALL_CATEGORIES_LABEL}
 +      </DropdownItem>,
 +      <DropdownSeparator key="category-filter-separator" />,
 +      ...CATEGORY_ARRAY.map((category: SampleCategory) => (
 +        <DropdownItem
 +          key={`category-filter-${category}`}
 +          onClick={() => onSearch({ searchValue: searchFilter, category })}
 +        >
 +          {LABEL_MAP[category]}
 +        </DropdownItem>
 +      )),
 +    ],
 +    [onSearch, searchFilter]
 +  );
 +
 +  const onSetPage = useCallback((_e, v) => {
 +    setPage(v);
 +  }, []);
 +
 +  useEffect(() => {
 +    setPageTitle([PAGE_TITLE]);
 +  }, []);
 +
 +  return (
 +    <Page>
 +      <PageSection variant={"light"}>
 +        <TextContent>
 +          <Text component={TextVariants.h1}>{PAGE_TITLE}</Text>
 +          <Text component={TextVariants.p}>Try one of our samples to start 
defining your model.</Text>
 +        </TextContent>
 +        <Toolbar style={{ paddingBottom: "0" }}>
 +          <ToolbarContent style={{ paddingLeft: "0", paddingRight: "0", 
paddingBottom: "0" }}>
 +            <ToolbarItem variant="search-filter">
 +              <SearchInput
 +                value={""}
 +                type={"search"}
 +                onChange={(_ev, value) => onSearch({ searchValue: value, 
category: categoryFilter })}
 +                onClear={() => onSearch({ searchValue: "", category: 
categoryFilter })}
 +                onFocus={() => setCategoryFilterDropdownOpen(false)}
 +                placeholder={"Find samples"}
 +                style={{ width: "400px" }}
 +                onClick={(e) => {
 +                  e.stopPropagation();
 +                }}
 +              />
 +            </ToolbarItem>
 +            <ToolbarItem>
 +              <Dropdown
 +                style={{ backgroundColor: "white" }}
 +                onSelect={() => setCategoryFilterDropdownOpen(false)}
 +                dropdownItems={categoryFilterDropdownItems}
 +                toggle={
 +                  <DropdownToggle
 +                    id="category-filter-dropdown"
 +                    onToggle={(isOpen: boolean) => 
setCategoryFilterDropdownOpen(isOpen)}
 +                  >
 +                    {selectedCategory}
 +                  </DropdownToggle>
 +                }
 +                isOpen={isCategoryFilterDropdownOpen}
 +              />
 +            </ToolbarItem>
 +            <ToolbarItem>
 +              {filterResultMessage && (
 +                <TextContent>
 +                  <Text>{filterResultMessage}</Text>
 +                </TextContent>
 +              )}
 +            </ToolbarItem>
 +            <ToolbarItem variant="pagination">
 +              {loading && <Skeleton width="200px" />}
 +              {!loading && (
 +                <Pagination
 +                  isCompact
 +                  itemCount={samplesCount}
 +                  onSetPage={onSetPage}
 +                  page={page}
 +                  perPage={CARDS_PER_PAGE}
 +                  perPageOptions={SAMPLE_CARDS_PER_PAGE_OPTIONS}
 +                  variant="top"
 +                />
 +              )}
 +            </ToolbarItem>
 +          </ToolbarContent>
 +        </Toolbar>
 +      </PageSection>
 +
 +      <PageSection isFilled>
 +        {sampleLoadingError && <SamplesLoadError 
errors={[sampleLoadingError]} />}
 +        {!sampleLoadingError && (
 +          <>
 +            {loading && <SampleCardSkeleton numberOfCards={6} />}
 +            {!loading && samplesCount === 0 && (
 +              <PageSection variant={"light"} isFilled={true} style={{ 
marginRight: "25px" }}>
 +                <EmptyState style={{ height: "350px" }}>
 +                  <EmptyStateIcon icon={CubesIcon} />
 +                  <Title headingLevel="h4" size="lg">
 +                    {"None of the available samples matched this search"}
 +                  </Title>
 +                </EmptyState>
 +              </PageSection>
 +            )}
 +            {!loading && samplesCount > 0 && (
 +              <>
 +                <Gallery hasGutter={true} minWidths={{ sm: "calc(100%/3.1 - 
16px)", default: "100%" }}>
 +                  {visibleSamples.map((sample) => (
 +                    <SampleCard
 +                      sample={sample}
 +                      key={`sample-${sample.sampleId}`}
 +                      cover={sampleCovers[sample.sampleId]}
 +                    />
 +                  ))}
 +                </Gallery>
 +                <br />
 +                <Pagination
 +                  itemCount={samplesCount}
 +                  onSetPage={onSetPage}
 +                  page={page}
 +                  perPage={CARDS_PER_PAGE}
 +                  perPageComponent="button"
 +                  perPageOptions={SAMPLE_CARDS_PER_PAGE_OPTIONS}
 +                  variant={PaginationVariant.bottom}
 +                  widgetId="bottom-example"
 +                />
 +              </>
 +            )}
 +          </>
 +        )}
 +      </PageSection>
 +    </Page>
 +  );
 +}
diff --cc 
packages/serverless-logic-web-tools/src/home/sample/hooks/SampleContext.tsx
index 65204accd1,ad3357cf41..6a197f141f
--- 
a/packages/serverless-logic-web-tools/src/home/sample/hooks/SampleContext.tsx
+++ 
b/packages/serverless-logic-web-tools/src/home/sample/hooks/SampleContext.tsx
@@@ -20,21 -20,11 +20,23 @@@ import { LocalFile } from "@kie-tools-c
  import * as React from "react";
  import { useContext, useMemo, useCallback, useState } from "react";
  import { useSettingsDispatch } from "../../../settings/SettingsContext";
 -import { fetchSampleDefinitions, fetchSampleFiles, Sample, SampleCategory } 
from "../SampleApi";
 +import {
 +  fetchSampleCover,
 +  fetchSampleDefinitions,
 +  fetchSampleFiles,
 +  Sample,
 +  SampleCategory,
 +  SampleCoversHashtable,
- } from "../sampleApi";
++} from "../SampleApi";
  import { decoder, encoder } from 
"@kie-tools-core/workspaces-git-fs/dist/encoderdecoder/EncoderDecoder";
  import Fuse from "fuse.js";
- 
- const SAMPLE_DEFINITIONS_CACHE_FILE_PATH = "/definitions.json";
- const SAMPLE_COVERS_CACHE_FILE_PATH = "/covers.json";
- const SAMPLES_FS_MOUNT_POINT = 
`lfs_v1__samples__${process.env.WEBPACK_REPLACE__version!}`;
- const SEARCH_KEYS = ["definition.category", "definition.title", 
"definition.description"];
 -import { SAMPLE_DEFINITIONS_CACHE_FILE_PATH, SAMPLE_SEARCH_KEYS, 
resolveSampleFsMountPoint } from "../SampleConstants";
++import {
++  SAMPLE_DEFINITIONS_CACHE_FILE_PATH,
++  SAMPLE_SEARCH_KEYS,
++  resolveSampleFsMountPoint,
++  SAMPLE_COVERS_CACHE_FILE_PATH,
++} from "../SampleConstants";
+ import { useEnv } from "../../../env/EnvContext";
  
  export interface SampleDispatchContextType {
    getSamples(args: { categoryFilter?: SampleCategory; searchFilter?: string 
}): Promise<Sample[]>;
diff --cc 
packages/serverless-logic-web-tools/src/homepage/recentModels/RecentModels.tsx
index c7f3120d85,0000000000..51c3119e31
mode 100644,000000..100644
--- 
a/packages/serverless-logic-web-tools/src/homepage/recentModels/RecentModels.tsx
+++ 
b/packages/serverless-logic-web-tools/src/homepage/recentModels/RecentModels.tsx
@@@ -1,267 -1,0 +1,263 @@@
 +/*
 + * Copyright 2023 Red Hat, Inc. and/or its affiliates.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *       http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +import { PromiseStateWrapper } from 
"@kie-tools-core/react-hooks/dist/PromiseState";
 +import { useController } from 
"@kie-tools-core/react-hooks/dist/useController";
 +import { useWorkspaces } from 
"@kie-tools-core/workspaces-git-fs/dist/context/WorkspacesContext";
 +import { useWorkspaceDescriptorsPromise } from 
"@kie-tools-core/workspaces-git-fs/dist/hooks/WorkspacesHooks";
 +import { WorkspaceDescriptor } from 
"@kie-tools-core/workspaces-git-fs/dist/worker/api/WorkspaceDescriptor";
 +import { Alert, AlertActionCloseButton } from 
"@patternfly/react-core/dist/js/components/Alert";
 +import { EmptyState, EmptyStateBody, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
 +import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
 +import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
 +import { Title } from "@patternfly/react-core/dist/js/components/Title";
 +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
 +import { CubesIcon } from "@patternfly/react-icons/dist/js/icons/cubes-icon";
 +import * as React from "react";
 +import { useCallback, useEffect, useMemo, useState } from "react";
- import { Alerts, AlertsController, useAlert } from "../../alerts/Alerts";
++import { useGlobalAlert } from "../../alerts/GlobalAlertsContext";
 +import { splitFiles } from "../../extension";
 +import { setPageTitle } from "../../PageTitle";
 +import { ConfirmDeleteModal } from "../../table/ConfirmDeleteModal";
 +import { defaultPerPageOptions, TablePagination } from 
"../../table/TablePagination";
 +import { TableToolbar } from "../../table/TableToolbar";
 +import { WorkspacesTable } from "./WorkspacesTable";
 +
 +const PAGE_TITLE = "Recent models";
 +
 +export function RecentModels() {
 +  const workspaceDescriptorsPromise = useWorkspaceDescriptorsPromise();
 +  const [selectedWorkspaceIds, setSelectedWorkspaceIds] = 
useState<WorkspaceDescriptor["workspaceId"][]>([]);
 +  const [isConfirmDeleteModalOpen, setIsConfirmDeleteModalOpen] = 
useState(false);
 +  const [searchValue, setSearchValue] = React.useState("");
 +  const [page, setPage] = React.useState(1);
 +  const [perPage, setPerPage] = React.useState(5);
 +  const workspaces = useWorkspaces();
 +  const [selectedFoldersCount, setSelectedFoldersCount] = useState(0);
 +  const [firstSelectedWorkspaceName, setFirstSelectedWorkspaceName] = 
useState("");
 +  const [deleteModalDataLoaded, setDeleteModalDataLoaded] = useState(false);
 +  const [deleteModalFetchError, setDeleteModalFetchError] = useState(false);
-   const [alerts, alertsRef] = useController<AlertsController>();
 +  const isSelectedWorkspacePlural = useMemo(() => selectedWorkspaceIds.length 
> 1, [selectedWorkspaceIds]);
 +
 +  const selectedElementTypesName = useMemo(() => {
 +    if (selectedWorkspaceIds.length > 1) {
 +      return selectedFoldersCount ? "workspaces" : "models";
 +    }
 +    return selectedFoldersCount ? "workspace" : "model";
 +  }, [selectedFoldersCount, selectedWorkspaceIds]);
 +
 +  const deleteModalMessage = useMemo(
 +    () => (
 +      <>
 +        Deleting {isSelectedWorkspacePlural ? "these" : "this"}{" "}
 +        <b>{isSelectedWorkspacePlural ? selectedWorkspaceIds.length : 
firstSelectedWorkspaceName}</b>{" "}
 +        {selectedElementTypesName}
 +        {selectedFoldersCount ? ` removes the ${selectedElementTypesName} and 
all the models inside.` : "."}
 +      </>
 +    ),
 +    [
 +      isSelectedWorkspacePlural,
 +      selectedWorkspaceIds,
 +      firstSelectedWorkspaceName,
 +      selectedElementTypesName,
 +      selectedFoldersCount,
 +    ]
 +  );
 +
 +  const onConfirmDeleteModalClose = useCallback(() => 
setIsConfirmDeleteModalOpen(false), []);
 +
-   const deleteSuccessAlert = useAlert<{ modelsWord: string }>(
-     alerts,
++  const deleteSuccessAlert = useGlobalAlert<{ modelsWord: string }>(
 +    useCallback(({ close }, { modelsWord }) => {
 +      return <Alert variant="success" title={`${capitalizeString(modelsWord)} 
deleted successfully`} />;
 +    }, []),
 +    { durationInSeconds: 2 }
 +  );
 +
-   const deleteErrorAlert = useAlert<{ modelsWord: string }>(
-     alerts,
++  const deleteErrorAlert = useGlobalAlert<{ modelsWord: string }>(
 +    useCallback(({ close }, { modelsWord }) => {
 +      return (
 +        <Alert
 +          variant="danger"
 +          title={`Oops, something went wrong while trying to delete the 
selected ${modelsWord}. Please refresh the page and try again. If the problem 
persists, you can try deleting site data for this application in your browser's 
settings.`}
 +          actionClose={<AlertActionCloseButton onClose={close} />}
 +        />
 +      );
 +    }, [])
 +  );
 +
 +  const onConfirmDeleteModalDelete = useCallback(
 +    async (workspaceDescriptors: WorkspaceDescriptor[]) => {
 +      const modelsWord = selectedWorkspaceIds.length > 1 ? "Models" : "Model";
 +      setIsConfirmDeleteModalOpen(false);
 +
 +      Promise.all(
 +        workspaceDescriptors
 +          .filter((w) => selectedWorkspaceIds.includes(w.workspaceId))
 +          .map((w) => workspaces.deleteWorkspace(w))
 +      )
 +        .then(() => {
 +          deleteSuccessAlert.show({ modelsWord });
 +        })
 +        .catch((e) => {
 +          console.error(e);
 +          deleteErrorAlert.show({ modelsWord });
 +        })
 +        .finally(() => {
 +          setSelectedWorkspaceIds([]);
 +        });
 +    },
 +    [selectedWorkspaceIds, workspaces, deleteErrorAlert, deleteSuccessAlert]
 +  );
 +
 +  const onWsToggle = useCallback((workspaceId: 
WorkspaceDescriptor["workspaceId"], checked: boolean) => {
 +    setSelectedWorkspaceIds((prevSelected) => {
 +      const otherSelectedIds = prevSelected.filter((r) => r !== workspaceId);
 +      return checked ? [...otherSelectedIds, workspaceId] : otherSelectedIds;
 +    });
 +  }, []);
 +
 +  const onToggleAllElements = useCallback((checked: boolean, 
workspaceDescriptors: WorkspaceDescriptor[]) => {
 +    setSelectedWorkspaceIds(checked ? workspaceDescriptors.map((e) => 
e.workspaceId) : []);
 +  }, []);
 +
 +  const onClearFilters = useCallback(() => {
 +    setSearchValue("");
 +  }, []);
 +
 +  const isWsFolder = useCallback(
 +    async (workspaceId: WorkspaceDescriptor["workspaceId"]) => {
 +      const { editableFiles, readonlyFiles } = splitFiles(await 
workspaces.getFiles({ workspaceId }));
 +      return editableFiles.length > 1 || readonlyFiles.length > 0;
 +    },
 +    [workspaces]
 +  );
 +
 +  const getWorkspaceName = useCallback(
 +    async (workspaceId: WorkspaceDescriptor["workspaceId"]) => {
 +      if (selectedWorkspaceIds.length !== 1) {
 +        return "";
 +      }
 +      const workspaceData = await workspaces.getWorkspace({ workspaceId });
 +      return (await isWsFolder(workspaceId))
 +        ? workspaceData.name
 +        : (await workspaces.getFiles({ workspaceId 
}))[0].nameWithoutExtension;
 +    },
 +    [isWsFolder, selectedWorkspaceIds, workspaces]
 +  );
 +
 +  useEffect(() => {
 +    Promise.all([
 +      Promise.all(selectedWorkspaceIds.map(isWsFolder)).then((results) => {
 +        const foldersCount = results.filter((r) => r).length;
 +        setSelectedFoldersCount(foldersCount);
 +      }),
 +      
getWorkspaceName(selectedWorkspaceIds[0]).then(setFirstSelectedWorkspaceName),
 +    ])
 +      .then(() => setDeleteModalDataLoaded(true))
 +      .catch(() => setDeleteModalFetchError(true));
 +  }, [getWorkspaceName, selectedWorkspaceIds, isWsFolder]);
 +
 +  useEffect(() => {
 +    setPageTitle([PAGE_TITLE]);
 +  }, []);
 +
 +  return (
 +    <PromiseStateWrapper
 +      promise={workspaceDescriptorsPromise}
 +      rejected={(e) => <>Error fetching workspaces: {e + ""}</>}
 +      resolved={(workspaceDescriptors: WorkspaceDescriptor[]) => {
 +        const itemCount = workspaceDescriptors.length;
 +
 +        return (
 +          <>
-             <Alerts ref={alertsRef} width={"500px"} />
 +            <Page>
 +              <PageSection variant={"light"}>
 +                <TextContent>
 +                  <Text component={TextVariants.h1}>{PAGE_TITLE}</Text>
 +                  <Text component={TextVariants.p}>
 +                    Use your recent models from GitHub Repository, a GitHub 
Gist or saved in your browser.
 +                  </Text>
 +                </TextContent>
 +              </PageSection>
 +
 +              <PageSection isFilled aria-label="workspaces-table-section">
 +                <PageSection variant={"light"} padding={{ default: 
"noPadding" }}>
 +                  {itemCount > 0 && (
 +                    <>
 +                      <TableToolbar
 +                        itemCount={itemCount}
 +                        onDeleteActionButtonClick={() => 
setIsConfirmDeleteModalOpen(true)}
 +                        onToggleAllElements={(checked) => 
onToggleAllElements(checked, workspaceDescriptors)}
 +                        searchValue={searchValue}
 +                        selectedElementsCount={selectedWorkspaceIds.length}
 +                        setSearchValue={setSearchValue}
 +                        page={page}
 +                        perPage={perPage}
 +                        perPageOptions={defaultPerPageOptions}
 +                        setPage={setPage}
 +                        setPerPage={setPerPage}
 +                      />
 +                      <WorkspacesTable
 +                        page={page}
 +                        perPage={perPage}
 +                        onClearFilters={onClearFilters}
 +                        onWsToggle={onWsToggle}
 +                        searchValue={searchValue}
 +                        selectedWorkspaceIds={selectedWorkspaceIds}
 +                        workspaceDescriptors={workspaceDescriptors}
 +                      />
 +                      <TablePagination
 +                        itemCount={itemCount}
 +                        page={page}
 +                        perPage={perPage}
 +                        perPageOptions={defaultPerPageOptions}
 +                        setPage={setPage}
 +                        setPerPage={setPerPage}
 +                        variant="bottom"
 +                      />
 +                    </>
 +                  )}
 +                  {workspaceDescriptors.length === 0 && (
 +                    <Bullseye>
 +                      <EmptyState>
 +                        <EmptyStateIcon icon={CubesIcon} />
 +                        <Title headingLevel="h4" size="lg">
 +                          {`Nothing here`}
 +                        </Title>
 +                        <EmptyStateBody>{`Start by adding a new 
model`}</EmptyStateBody>
 +                      </EmptyState>
 +                    </Bullseye>
 +                  )}
 +                </PageSection>
 +              </PageSection>
 +            </Page>
 +            <ConfirmDeleteModal
 +              isOpen={isConfirmDeleteModalOpen}
 +              onClose={onConfirmDeleteModalClose}
 +              onDelete={() => 
onConfirmDeleteModalDelete(workspaceDescriptors)}
 +              elementsTypeName={selectedElementTypesName}
 +              deleteMessage={deleteModalMessage}
 +              dataLoaded={deleteModalDataLoaded}
 +              fetchError={deleteModalFetchError}
 +            />
 +          </>
 +        );
 +      }}
 +    />
 +  );
 +}
 +
 +const capitalizeString = (value: string) => value.charAt(0).toUpperCase() + 
value.slice(1);
diff --cc 
packages/serverless-logic-web-tools/src/homepage/recentModels/workspaceFiles/WorkspaceFiles.tsx
index 9829c9dd3f,0000000000..01438e496f
mode 100644,000000..100644
--- 
a/packages/serverless-logic-web-tools/src/homepage/recentModels/workspaceFiles/WorkspaceFiles.tsx
+++ 
b/packages/serverless-logic-web-tools/src/homepage/recentModels/workspaceFiles/WorkspaceFiles.tsx
@@@ -1,307 -1,0 +1,302 @@@
 +/*
 + * Copyright 2023 Red Hat, Inc. and/or its affiliates.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *       http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +import { PromiseStateWrapper } from 
"@kie-tools-core/react-hooks/dist/PromiseState";
 +import { useController } from 
"@kie-tools-core/react-hooks/dist/useController";
 +import { useWorkspaces, WorkspaceFile } from 
"@kie-tools-core/workspaces-git-fs/dist/context/WorkspacesContext";
 +import { useWorkspacePromise } from 
"@kie-tools-core/workspaces-git-fs/dist/hooks/WorkspaceHooks";
 +import { ActiveWorkspace } from 
"@kie-tools-core/workspaces-git-fs/dist/model/ActiveWorkspace";
 +import { Breadcrumb } from "@patternfly/react-core/components/Breadcrumb";
 +import { BreadcrumbItem, Checkbox, Dropdown, DropdownToggle, ToolbarItem } 
from "@patternfly/react-core/dist/js";
 +import { Alert, AlertActionCloseButton } from 
"@patternfly/react-core/dist/js/components/Alert";
 +import { EmptyState, EmptyStateBody, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
 +import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
 +import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
 +import { Title } from "@patternfly/react-core/dist/js/components/Title";
 +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
 +import { CaretDownIcon, PlusIcon } from 
"@patternfly/react-icons/dist/js/icons";
 +import { CubesIcon } from "@patternfly/react-icons/dist/js/icons/cubes-icon";
 +import * as React from "react";
 +import { useCallback, useEffect, useMemo, useState } from "react";
 +import { useHistory } from "react-router";
- import { Alerts, AlertsController, useAlert } from "../../../alerts/Alerts";
++import { useGlobalAlert } from "../../../alerts/GlobalAlertsContext";
 +import { NewFileDropdownMenu } from "../../../editor/NewFileDropdownMenu";
 +import { splitFiles } from "../../../extension";
 +import { routes } from "../../../navigation/Routes";
 +import { setPageTitle } from "../../../PageTitle";
 +import { ConfirmDeleteModal } from "../../../table/ConfirmDeleteModal";
 +import { defaultPerPageOptions, TablePagination } from 
"../../../table/TablePagination";
 +import { TableToolbar } from "../../../table/TableToolbar";
 +import { WorkspaceFilesTable } from "./WorkspaceFilesTable";
 +
 +export interface Props {
 +  workspaceId: string;
 +}
 +
 +export function WorkspaceFiles(props: Props) {
 +  const { workspaceId } = props;
 +  const workspacePromise = useWorkspacePromise(workspaceId);
 +  const [selectedWorkspaceFiles, setSelectedWorkspaceFiles] = 
useState<WorkspaceFile[]>([]);
 +  const [isConfirmDeleteModalOpen, setIsConfirmDeleteModalOpen] = 
useState(false);
 +  const [searchValue, setSearchValue] = React.useState("");
 +  const [page, setPage] = React.useState(1);
 +  const [perPage, setPerPage] = React.useState(5);
 +  const [isViewRoFilesChecked, setIsViewRoFilesChecked] = useState(false);
 +  const [isNewFileDropdownMenuOpen, setNewFileDropdownMenuOpen] = 
useState(false);
 +  const workspaces = useWorkspaces();
 +  const history = useHistory();
-   const [alerts, alertsRef] = useController<AlertsController>();
 +  const isSelectedWorkspaceFilesPlural = useMemo(() => 
selectedWorkspaceFiles.length > 1, [selectedWorkspaceFiles]);
 +  const selectedElementTypesName = useMemo(
 +    () => (isSelectedWorkspaceFilesPlural ? "files" : "file"),
 +    [isSelectedWorkspaceFilesPlural]
 +  );
 +
 +  const deleteModalMessage = useMemo(
 +    () => (
 +      <>
 +        Deleting {isSelectedWorkspaceFilesPlural ? "these" : "this"}{" "}
 +        <b>{isSelectedWorkspaceFilesPlural ? selectedWorkspaceFiles.length : 
selectedWorkspaceFiles[0]?.name}</b>{" "}
 +        {selectedElementTypesName}
 +      </>
 +    ),
 +    [isSelectedWorkspaceFilesPlural, selectedWorkspaceFiles, 
selectedElementTypesName]
 +  );
 +
 +  const onConfirmDeleteModalClose = useCallback(() => 
setIsConfirmDeleteModalOpen(false), []);
 +
-   const deleteSuccessAlert = useAlert<{ selectedElementTypesName: string }>(
-     alerts,
++  const deleteSuccessAlert = useGlobalAlert<{ selectedElementTypesName: 
string }>(
 +    useCallback(({ close }, { selectedElementTypesName }) => {
 +      return <Alert variant="success" 
title={`${capitalizeString(selectedElementTypesName)} deleted successfully`} />;
 +    }, []),
 +    { durationInSeconds: 2 }
 +  );
 +
-   const deleteErrorAlert = useAlert<{ selectedElementTypesName: string }>(
-     alerts,
++  const deleteErrorAlert = useGlobalAlert<{ selectedElementTypesName: string 
}>(
 +    useCallback(({ close }, { selectedElementTypesName }) => {
 +      return (
 +        <Alert
 +          variant="danger"
 +          title={`Oops, something went wrong while trying to delete the 
selected ${selectedElementTypesName}. Please refresh the page and try again. If 
the problem persists, you can try deleting site data for this application in 
your browser's settings.`}
 +          actionClose={<AlertActionCloseButton onClose={close} />}
 +        />
 +      );
 +    }, [])
 +  );
 +
 +  const onConfirmDeleteModalDelete = useCallback(
 +    async (totalFilesCount: number) => {
 +      setIsConfirmDeleteModalOpen(false);
 +
 +      if (selectedWorkspaceFiles.length === totalFilesCount) {
 +        workspaces.deleteWorkspace({ workspaceId });
 +        history.push({ pathname: routes.recentModels.path({}) });
 +        deleteSuccessAlert.show({ selectedElementTypesName });
 +        return;
 +      }
 +
 +      Promise.all(selectedWorkspaceFiles.map((file) => 
workspaces.deleteFile({ file })))
 +        .then(() => {
 +          deleteSuccessAlert.show({ selectedElementTypesName });
 +        })
 +        .catch((e) => {
 +          console.error(e);
 +          deleteErrorAlert.show({ selectedElementTypesName });
 +        })
 +        .finally(() => {
 +          setSelectedWorkspaceFiles([]);
 +        });
 +    },
 +    [
 +      selectedWorkspaceFiles,
 +      workspaces,
 +      history,
 +      workspaceId,
 +      deleteErrorAlert,
 +      deleteSuccessAlert,
 +      selectedElementTypesName,
 +    ]
 +  );
 +
 +  const onFileToggle = useCallback((workspaceFile: WorkspaceFile, checked: 
boolean) => {
 +    setSelectedWorkspaceFiles((prevSelected) => {
 +      const otherSelectedFiles = [...prevSelected.filter((f) => f !== 
workspaceFile)];
 +      return checked ? [...otherSelectedFiles, workspaceFile] : 
otherSelectedFiles;
 +    });
 +  }, []);
 +
 +  const onToggleAllElements = useCallback((checked: boolean, files: 
WorkspaceFile[]) => {
 +    setSelectedWorkspaceFiles(checked ? files : []);
 +  }, []);
 +
 +  const handleViewRoCheckboxChange = useCallback((checked: boolean) => {
 +    setIsViewRoFilesChecked(checked);
 +  }, []);
 +
 +  useEffect(() => {
 +    setSelectedWorkspaceFiles([]);
 +  }, [workspacePromise]);
 +
 +  return (
 +    <PromiseStateWrapper
 +      promise={workspacePromise}
 +      rejected={(e) => <>Error fetching workspaces: {e + ""}</>}
 +      resolved={(workspace: ActiveWorkspace) => {
 +        const allFiles = splitFiles(workspace.files);
 +        const isViewRoFilesDisabled = !allFiles.editableFiles.length || 
!allFiles.readonlyFiles.length;
 +        const isViewRoFilesCheckedInternal = isViewRoFilesDisabled ? true : 
isViewRoFilesChecked;
 +        const files = [...allFiles.editableFiles, 
...(isViewRoFilesCheckedInternal ? allFiles.readonlyFiles : [])];
 +        const filesCount = files.length;
 +        const allFilesCount = workspace.files.length;
 +
 +        setPageTitle([workspace.descriptor.name]);
 +
 +        return (
 +          <>
-             <Alerts ref={alertsRef} width={"500px"} />
 +            <Page
 +              breadcrumb={
 +                <Breadcrumb>
 +                  <BreadcrumbItem to={"#" + 
routes.recentModels.path({})}>Recent Models</BreadcrumbItem>
 +                  <BreadcrumbItem to="#" isActive>
 +                    {workspace.descriptor.name}
 +                  </BreadcrumbItem>
 +                </Breadcrumb>
 +              }
 +            >
 +              <PageSection variant={"light"}>
 +                <TextContent>
 +                  <Text component={TextVariants.h1}>Files in 
&lsquo;{workspace.descriptor.name}&rsquo;</Text>
 +                  <Text component={TextVariants.p}>
 +                    Use your recent models from GitHub Repository, a GitHub 
Gist or saved in your browser.
 +                  </Text>
 +                </TextContent>
 +              </PageSection>
 +
 +              <PageSection isFilled aria-label="workspaces-table-section">
 +                <PageSection variant={"light"} padding={{ default: 
"noPadding" }}>
 +                  {filesCount > 0 && (
 +                    <>
 +                      <TableToolbar
 +                        itemCount={filesCount}
 +                        onDeleteActionButtonClick={() => 
setIsConfirmDeleteModalOpen(true)}
 +                        onToggleAllElements={(checked) => 
onToggleAllElements(checked, files)}
 +                        searchValue={searchValue}
 +                        selectedElementsCount={selectedWorkspaceFiles.length}
 +                        setSearchValue={setSearchValue}
 +                        page={page}
 +                        perPage={perPage}
 +                        perPageOptions={defaultPerPageOptions}
 +                        setPage={setPage}
 +                        setPerPage={setPerPage}
 +                        additionalComponents={
 +                          <>
 +                            <ToolbarItem>
 +                              <Dropdown
 +                                position={"right"}
 +                                isOpen={isNewFileDropdownMenuOpen}
 +                                toggle={
 +                                  <DropdownToggle
 +                                    onToggle={setNewFileDropdownMenuOpen}
 +                                    toggleIndicator={CaretDownIcon}
 +                                    toggleVariant="primary"
 +                                  >
 +                                    <PlusIcon />
 +                                    &nbsp;&nbsp;New file
 +                                  </DropdownToggle>
 +                                }
 +                              >
 +                                <NewFileDropdownMenu
-                                   alerts={alerts}
 +                                  workspaceId={workspaceId}
 +                                  destinationDirPath={""}
 +                                  onAddFile={async (file) => {
 +                                    setNewFileDropdownMenuOpen(false);
 +                                    if (!file) {
 +                                      return;
 +                                    }
 +
 +                                    history.push({
 +                                      pathname: 
routes.workspaceWithFilePath.path({
 +                                        workspaceId: file.workspaceId,
 +                                        fileRelativePath: 
file.relativePathWithoutExtension,
 +                                        extension: file.extension,
 +                                      }),
 +                                    });
 +                                  }}
 +                                />
 +                              </Dropdown>
 +                            </ToolbarItem>
 +                            <ToolbarItem>
 +                              <Checkbox
 +                                id="viewRoFiles"
 +                                label="View readonly files"
 +                                isChecked={isViewRoFilesCheckedInternal}
 +                                isDisabled={isViewRoFilesDisabled}
 +                                onChange={handleViewRoCheckboxChange}
 +                              ></Checkbox>
 +                            </ToolbarItem>
 +                          </>
 +                        }
 +                      />
 +
 +                      <WorkspaceFilesTable
 +                        page={page}
 +                        perPage={perPage}
 +                        onFileToggle={onFileToggle}
 +                        searchValue={searchValue}
 +                        selectedWorkspaceFiles={selectedWorkspaceFiles}
 +                        totalFilesCount={allFilesCount}
 +                        workspaceFiles={files}
 +                      />
 +
 +                      <TablePagination
 +                        itemCount={filesCount}
 +                        page={page}
 +                        perPage={perPage}
 +                        perPageOptions={defaultPerPageOptions}
 +                        setPage={setPage}
 +                        setPerPage={setPerPage}
 +                        variant="bottom"
 +                      />
 +                    </>
 +                  )}
 +                  {files.length === 0 && (
 +                    <Bullseye>
 +                      <EmptyState>
 +                        <EmptyStateIcon icon={CubesIcon} />
 +                        <Title headingLevel="h4" size="lg">
 +                          {`Nothing here`}
 +                        </Title>
 +                        <EmptyStateBody>{`Start by adding a new 
model`}</EmptyStateBody>
 +                      </EmptyState>
 +                    </Bullseye>
 +                  )}
 +                </PageSection>
 +              </PageSection>
 +            </Page>
 +            <ConfirmDeleteModal
 +              isOpen={isConfirmDeleteModalOpen}
 +              onClose={onConfirmDeleteModalClose}
 +              onDelete={() => 
onConfirmDeleteModalDelete(workspace.files.length)}
 +              elementsTypeName={selectedElementTypesName}
 +              deleteMessage={deleteModalMessage}
 +            />
 +          </>
 +        );
 +      }}
 +    />
 +  );
 +}
 +
 +const capitalizeString = (value: string) => value.charAt(0).toUpperCase() + 
value.slice(1);
diff --cc 
packages/serverless-logic-web-tools/src/openshift/dropdown/OpenshiftDeploymentsDropdown.tsx
index ae3746a328,9ec9127921..caa87e3bde
--- 
a/packages/serverless-logic-web-tools/src/openshift/dropdown/OpenshiftDeploymentsDropdown.tsx
+++ 
b/packages/serverless-logic-web-tools/src/openshift/dropdown/OpenshiftDeploymentsDropdown.tsx
@@@ -29,14 -29,28 +29,30 @@@ import { useSettings, useSettingsDispat
  import { useOpenShift } from "../OpenShiftContext";
  import { OpenShiftDeploymentDropdownItem } from 
"./OpenShiftDeploymentDropdownItem";
  import { OpenShiftInstanceStatus } from "../OpenShiftInstanceStatus";
+ import { WebToolsOpenShiftDeployedModel } from "../deploy/types";
+ import { useEnv } from "../../env/EnvContext";
+ import { PromiseStateStatus, useLivePromiseState } from 
"@kie-tools-core/react-hooks/dist/PromiseState";
+ import { useDevModeDispatch } from "../swfDevMode/DevModeContext";
+ import { Skeleton } from "@patternfly/react-core/dist/js/components/Skeleton";
+ import { Holder } from "@kie-tools-core/react-hooks/dist/Holder";
+ import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+ import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
+ import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
 +import { routes } from "../../navigation/Routes";
 +import { useHistory } from "react-router";
  
+ const REFRESH_COUNTDOWN_INITIAL_VALUE_IN_SECONDS = 20;
+ 
  export function OpenshiftDeploymentsDropdown() {
+   const { env } = useEnv();
    const settings = useSettings();
    const settingsDispatch = useSettingsDispatch();
    const openshift = useOpenShift();
+   const devModeDispatch = useDevModeDispatch();
+   const [refreshCountdownInSeconds, setRefreshCountdownInSeconds] = useState(
+     REFRESH_COUNTDOWN_INITIAL_VALUE_IN_SECONDS
+   );
 +  const history = useHistory();
  
    const isConnected = useMemo(
      () => settings.openshift.status === OpenShiftInstanceStatus.CONNECTED,
@@@ -44,28 -58,71 +60,71 @@@
    );
  
    const openOpenShiftSettings = useCallback(() => {
 -    settingsDispatch.open(SettingsTabs.OPENSHIFT);
 -  }, [settingsDispatch]);
 +    history.push(routes.settings.openshift.path({}));
 +  }, [history]);
  
-   const items = useMemo(() => {
-     const common = isConnected
-       ? [
-           <DropdownItem
-             key={"dropdown-openshift-setup-as"}
-             component={"button"}
-             onClick={openOpenShiftSettings}
-             ouiaId={"setup-as-openshift-dropdown-button"}
-             description={"Change..."}
-           >
-             {`Connected to ${settings.openshift.config.namespace}`}
-           </DropdownItem>,
-           <DropdownSeparator 
key={"dropdown-openshift-separator-deployments-2"} />,
-         ]
-       : [];
- 
-     if (openshift.deployments.length === 0) {
+   const [deployments, refresh] = 
useLivePromiseState<WebToolsOpenShiftDeployedModel[]>(
+     useMemo(() => {
+       if (settings.openshift.status !== OpenShiftInstanceStatus.CONNECTED) {
+         return { error: "Can't load deployments." };
+       }
+       return async () => {
+         
setRefreshCountdownInSeconds(REFRESH_COUNTDOWN_INITIAL_VALUE_IN_SECONDS);
+         const res = await Promise.all([openshift.loadDeployments(), 
devModeDispatch.loadDeployments()]);
+         return res.flat();
+       };
+     }, [devModeDispatch, openshift, settings.openshift.status])
+   );
+ 
+   useEffect(() => {
+     if (deployments.status === PromiseStateStatus.PENDING) {
+       return;
+     }
+ 
+     const interval = window.setInterval(() => {
+       setRefreshCountdownInSeconds((prev) => prev - 1);
+     }, 1000);
+ 
+     return () => {
+       window.clearInterval(interval);
+     };
+   }, [deployments.status]);
+ 
+   useEffect(() => {
+     if (refreshCountdownInSeconds > 0) {
+       return;
+     }
+     refresh(new Holder(false));
+   }, [refresh, refreshCountdownInSeconds]);
+ 
+   const connectionItem = useMemo(
+     () => [
+       <DropdownItem
+         key={"dropdown-openshift-setup-as"}
+         component={"button"}
+         onClick={openOpenShiftSettings}
+         ouiaId={"setup-as-openshift-dropdown-button"}
+         description={"Change..."}
+       >
+         {`Connected to ${settings.openshift.config.namespace}`}
+       </DropdownItem>,
+       <DropdownSeparator key={"dropdown-openshift-separator-deployments-2"} 
/>,
+     ],
+     [openOpenShiftSettings, settings.openshift.config.namespace]
+   );
+ 
+   const deploymentItems = useMemo(() => {
+     if (deployments.status === PromiseStateStatus.PENDING) {
+       return [
+         Array.from({ length: 3 }, (_, idx) => (
+           <DropdownItem key={`deployment-skeleton-${idx}`} isDisabled={true}>
+             <Skeleton width={"80%"} style={{ marginBottom: "4px" }} />
+             <Skeleton width={"50%"} />
+           </DropdownItem>
+         )),
+       ];
+     } else if (deployments.status === PromiseStateStatus.REJECTED) {
        return [
-         ...common,
          <DropdownItem key="disabled link" isDisabled>
            <Bullseye>
              <EmptyState>
@@@ -78,30 -148,47 +150,54 @@@
          </DropdownItem>,
        ];
      } else {
+       const dropdownItems = [];
+ 
+       const [devModeDeployments, userDeployments] = deployments.data
+         .sort((a, b) => b.creationTimestamp.getTime() - 
a.creationTimestamp.getTime())
+         .reduce(
+           ([devModeDeployments, userDeployments], d: 
WebToolsOpenShiftDeployedModel) =>
+             d.devMode ? [[...devModeDeployments, d], userDeployments] : 
[devModeDeployments, [...userDeployments, d]],
+           [[] as WebToolsOpenShiftDeployedModel[], [] as 
WebToolsOpenShiftDeployedModel[]]
+         );
+ 
+       if (devModeDeployments.length > 0) {
+         dropdownItems.push(
+           <OpenShiftDeploymentDropdownItem
+             key={devModeDeployments[0].creationTimestamp.getTime()}
+             id={0}
+             deployment={devModeDeployments[0]}
+             refreshDeployments={refresh}
+           />
+         );
+ 
+         if (userDeployments.length > 0) {
+           dropdownItems.push(<DropdownSeparator 
key={"dropdown-openshift-separator-deployments-2"} />);
+         }
+       }
+ 
        return [
-         ...common,
-         openshift.deployments
-           .sort((a, b) => b.creationTimestamp.getTime() - 
a.creationTimestamp.getTime())
-           .map((deployment, i) => {
-             return (
-               <OpenShiftDeploymentDropdownItem
-                 key={deployment.creationTimestamp.getTime()}
-                 id={i}
-                 deployment={deployment}
-               />
-             );
-           }),
+         ...dropdownItems,
+         userDeployments.map((deployment, i) => {
+           return (
+             <OpenShiftDeploymentDropdownItem
+               key={deployment.creationTimestamp.getTime()}
+               id={i + 1}
+               deployment={deployment}
+               refreshDeployments={refresh}
+             />
+           );
+         }),
        ];
      }
-   }, [openshift.deployments, isConnected, openOpenShiftSettings, 
settings.openshift.config.namespace]);
+   }, [deployments.data, deployments.status, refresh]);
  
 +  const onDeploymensDropdownToggle = useCallback(() => {
 +    if (!isConnected) {
 +      history.push(routes.settings.openshift.path({}));
 +    }
 +    openshift.setDeploymentsDropdownOpen((dropdownOpen) => isConnected && 
!dropdownOpen);
 +  }, [history, isConnected, openshift]);
 +
    return (
      <>
        <Tooltip
diff --cc packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
index 10a8856bba,18497e2099..d9eaaef0ae
--- a/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
+++ b/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
@@@ -14,23 -14,30 +14,24 @@@
   * limitations under the License.
   */
  
 +import { Octokit } from "@octokit/rest";
  import * as React from "react";
 -import { useCallback, useContext, useEffect, useMemo, useState } from "react";
 +import { useContext, useEffect, useMemo, useState } from "react";
  import { getCookie, setCookie } from "../cookies";
 -import { Octokit } from "@octokit/rest";
 -import { useQueryParams } from "../queryParams/QueryParamsContext";
 -import { Modal, ModalVariant } from 
"@patternfly/react-core/dist/js/components/Modal";
 -import { SettingsModalBody, SettingsTabs } from "./SettingsModalBody";
 +import { SwfServiceCatalogStore } from "../editor/api/SwfServiceCatalogStore";
 +import { useKieSandboxExtendedServices } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
 +import { KieSandboxExtendedServicesStatus } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+ import { readDevModeEnabledConfigCookie, readOpenShiftConfigCookie } from 
"./openshift/OpenShiftSettingsConfig";
 -import { isKubernetesConnectionValid } from 
"@kie-tools-core/kubernetes-bridge/dist/service";
  import { OpenShiftInstanceStatus } from 
"../openshift/OpenShiftInstanceStatus";
  import { OpenShiftService } from 
"@kie-tools-core/kubernetes-bridge/dist/service/OpenShiftService";
 -import { useHistory } from "react-router";
 -import { QueryParams } from "../navigation/Routes";
 -import { GITHUB_AUTH_TOKEN_COOKIE_NAME } from "./github/GitHubSettingsTab";
 +import { FeaturePreviewSettingsConfig, readFeaturePreviewConfigCookie } from 
"./featurePreview/FeaturePreviewConfig";
 +import { GITHUB_AUTH_TOKEN_COOKIE_NAME } from "./github/GitHubSettings";
- import { readOpenShiftConfigCookie } from 
"./openshift/OpenShiftSettingsConfig";
  import { readServiceAccountConfigCookie, ServiceAccountSettingsConfig } from 
"./serviceAccount/ServiceAccountConfig";
  import {
    readServiceRegistryConfigCookie,
    ServiceRegistrySettingsConfig,
  } from "./serviceRegistry/ServiceRegistryConfig";
 -import { useKieSandboxExtendedServices } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
 -import { KieSandboxExtendedServicesStatus } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
 -import { SwfServiceCatalogStore } from "../editor/api/SwfServiceCatalogStore";
 -import { FeaturePreviewSettingsConfig, readFeaturePreviewConfigCookie } from 
"./featurePreview/FeaturePreviewConfig";
+ import { useEnv } from "../env/EnvContext";
  import { KubernetesConnection } from 
"@kie-tools-core/kubernetes-bridge/dist/service";
  
  export enum AuthStatus {
@@@ -117,6 -129,32 +120,7 @@@ export const SettingsContext = React.cr
  export const SettingsDispatchContext = 
React.createContext<SettingsDispatchContextType>({} as any);
  
  export function SettingsContextProvider(props: any) {
 -  const queryParams = useQueryParams();
 -  const history = useHistory();
+   const { env } = useEnv();
 -  const [isOpen, setOpen] = useState(false);
 -  const [activeTab, setActiveTab] = useState(SettingsTabs.GITHUB);
 -
 -  useEffect(() => {
 -    setOpen(queryParams.has(QueryParams.SETTINGS));
 -    setActiveTab((queryParams.get(QueryParams.SETTINGS) as SettingsTabs) ?? 
SettingsTabs.GITHUB);
 -  }, [queryParams]);
 -
 -  const open = useCallback(
 -    (activeTab = SettingsTabs.GITHUB) => {
 -      history.replace({
 -        search: queryParams.with(QueryParams.SETTINGS, activeTab).toString(),
 -      });
 -    },
 -    [history, queryParams]
 -  );
 -
 -  const close = useCallback(() => {
 -    history.replace({
 -      search: queryParams.without(QueryParams.SETTINGS).toString(),
 -    });
 -  }, [history, queryParams]);
 -
    //github
    const [githubAuthStatus, setGitHubAuthStatus] = 
useState(AuthStatus.LOADING);
    const [githubOctokit, setGitHubOctokit] = useState<Octokit>(new Octokit());
@@@ -272,8 -314,11 +274,9 @@@
        },
      };
    }, [
 -    isOpen,
 -    activeTab,
      openshiftStatus,
      openshiftConfig,
+     isOpenShiftDevModeEnabled,
      githubAuthStatus,
      githubToken,
      githubUser,
diff --cc 
packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettings.tsx
index 70e28a0b6e,0000000000..5768ffdbed
mode 100644,000000..100644
--- 
a/packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettings.tsx
+++ 
b/packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettings.tsx
@@@ -1,163 -1,0 +1,170 @@@
 +/*
 + * Copyright 2023 Red Hat, Inc. and/or its affiliates.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *        http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +import React from "react";
 +import { KubernetesConnection } from 
"@kie-tools-core/kubernetes-bridge/dist/service";
 +import { Alert } from "@patternfly/react-core/dist/js/components/Alert";
 +import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
 +import { EmptyState, EmptyStateBody, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
 +import { Modal, ModalVariant } from 
"@patternfly/react-core/dist/js/components/Modal";
 +import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
 +import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
 +import { AddCircleOIcon } from 
"@patternfly/react-icons/dist/js/icons/add-circle-o-icon";
 +import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
- import { useCallback, useEffect, useState } from "react";
++import { useCallback, useEffect, useState, useMemo } from "react";
 +import { Link } from "react-router-dom";
 +import { SETTINGS_PAGE_SECTION_TITLE } from "../SettingsContext";
 +import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
 +import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
 +import { routes } from "../../navigation/Routes";
 +import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
 +import { setPageTitle } from "../../PageTitle";
 +import { obfuscate } from "../github/GitHubSettings";
 +import { useSettings, useSettingsDispatch } from "../SettingsContext";
 +import { SettingsPageProps } from "../types";
 +import { saveConfigCookie } from "./OpenShiftSettingsConfig";
 +import { OpenShiftSettingsSimpleConfig } from 
"./OpenShiftSettingsSimpleConfig";
 +
 +const PAGE_TITLE = "OpenShift";
 +
 +export function OpenShiftSettings(props: SettingsPageProps) {
 +  const settings = useSettings();
 +  const settingsDispatch = useSettingsDispatch();
 +  const [isModalOpen, setIsModalOpen] = useState(false);
 +  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
 +
 +  const handleModalToggle = useCallback(() => {
 +    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
 +  }, []);
 +
 +  const onDisconnect = useCallback(() => {
 +    
settingsDispatch.openshift.setStatus(OpenShiftInstanceStatus.DISCONNECTED);
 +    const newConfig: KubernetesConnection = {
 +      namespace: settings.openshift.config.namespace,
 +      host: settings.openshift.config.host,
 +      token: "",
 +    };
 +    settingsDispatch.openshift.setConfig(newConfig);
 +    saveConfigCookie(newConfig);
 +  }, [settings.openshift.config, settingsDispatch.openshift]);
 +
++  const devModeEnabledLabel = useMemo(
++    () => (settings.openshift.isDevModeEnabled ? "enabled" : "disabled"),
++    [settings.openshift.isDevModeEnabled]
++  );
++
 +  useEffect(() => {
 +    setPageTitle([SETTINGS_PAGE_SECTION_TITLE, PAGE_TITLE]);
 +  }, []);
 +
 +  return (
 +    <Page>
 +      <PageSection variant={"light"} isWidthLimited>
 +        <TextContent>
 +          <Text component={TextVariants.h1}>{PAGE_TITLE}</Text>
 +          <Text component={TextVariants.p}>
 +            Data you provide here is necessary for deploying models you 
design to your OpenShift instance.
 +            <br />
 +            All information is locally stored in your browser and never 
shared with anyone.
 +          </Text>
 +        </TextContent>
 +      </PageSection>
 +
 +      <PageSection>
 +        {kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.RUNNING && (
 +          <>
 +            <Alert
 +              variant="danger"
 +              title={
 +                <Text>
 +                  Connect to{" "}
 +                  <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>KIE Sandbox 
Extended Services</Link>{" "}
 +                  before configuring your OpenShift instance
 +                </Text>
 +              }
 +              aria-live="polite"
 +              isInline
 +            >
 +              KIE Sandbox Extended Services is necessary for proxying 
Serverless Logic Web Tools requests to OpenShift,
 +              thus making it possible to deploy models.
 +            </Alert>
 +            <br />
 +          </>
 +        )}
 +        <PageSection variant={"light"}>
 +          {settings.openshift.status === OpenShiftInstanceStatus.CONNECTED ? (
 +            <EmptyState>
 +              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
 +              <TextContent>
 +                <Text component={"h2"}>{"You're connected to 
OpenShift."}</Text>
 +              </TextContent>
 +              <EmptyStateBody>
 +                Deploying models is <b>enabled</b>.
 +                <br />
++                Uploading models to Dev Mode is <b>{devModeEnabledLabel}</b>.
++                <br />
 +                <b>Token: </b>
 +                <i>{obfuscate(settings.openshift.config.token)}</i>
 +                <br />
 +                <b>Host: </b>
 +                <i>{settings.openshift.config.host}</i>
 +                <br />
 +                <b>Namespace (project): </b>
 +                <i>{settings.openshift.config.namespace}</i>
 +                <br />
 +                <br />
 +                <Button variant={ButtonVariant.tertiary} 
onClick={onDisconnect}>
 +                  Disconnect
 +                </Button>
 +              </EmptyStateBody>
 +            </EmptyState>
 +          ) : (
 +            <EmptyState>
 +              <EmptyStateIcon icon={AddCircleOIcon} />
 +              <TextContent>
 +                <Text component={"h2"}>You are not connected to 
OpenShift.</Text>
 +              </TextContent>
 +              <EmptyStateBody>
 +                You currently have no OpenShift connections. <br />
 +                <br />
 +                <Button variant={ButtonVariant.primary} 
onClick={handleModalToggle} data-testid="add-connection-button">
 +                  Add connection
 +                </Button>
 +              </EmptyStateBody>
 +            </EmptyState>
 +          )}
 +        </PageSection>
 +      </PageSection>
 +
 +      {props.pageContainerRef.current && (
 +        <Modal
 +          title="Add connection"
 +          isOpen={
 +            isModalOpen &&
 +            kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.STOPPED &&
 +            (settings.openshift.status === 
OpenShiftInstanceStatus.DISCONNECTED ||
 +              settings.openshift.status === OpenShiftInstanceStatus.EXPIRED)
 +          }
 +          onClose={handleModalToggle}
 +          variant={ModalVariant.large}
 +          appendTo={props.pageContainerRef.current || document.body}
 +        >
 +          <OpenShiftSettingsSimpleConfig />
 +        </Modal>
 +      )}
 +    </Page>
 +  );
 +}
diff --cc 
packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettingsSimpleConfig.tsx
index c3de7692a6,b4e4d3d280..e9333adc72
--- 
a/packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettingsSimpleConfig.tsx
+++ 
b/packages/serverless-logic-web-tools/src/settings/openshift/OpenShiftSettingsSimpleConfig.tsx
@@@ -23,23 -24,21 +23,25 @@@ import { Text } from "@patternfly/react
  import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
  import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
  import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 -import { useCallback, useEffect, useState } from "react";
 +import * as React from "react";
 +import { useCallback, useEffect, useState, useContext } from "react";
 +import { Link } from "react-router-dom";
  import { useAppI18n } from "../../i18n";
+ import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
+ import { EMPTY_CONFIG, saveConfigCookie, saveDevModeEnabledConfigCookie } 
from "./OpenShiftSettingsConfig";
  import {
    isKubernetesConnectionValid,
    KubernetesConnection,
    KubernetesConnectionStatus,
  } from "@kie-tools-core/kubernetes-bridge/dist/service";
+ import { useSettings, useSettingsDispatch } from "../SettingsContext";
  import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
  import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
 -import { SettingsTabs } from "../SettingsModalBody";
+ import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
+ import { DEV_MODE_FEATURE_NAME } from 
"../../openshift/swfDevMode/DevModeConstants";
 +import { routes } from "../../navigation/Routes";
- import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
 +import { QuickStartIds } from "../../quickstarts-data";
- import { useSettings, useSettingsDispatch } from "../SettingsContext";
- import { EMPTY_CONFIG, saveConfigCookie } from "./OpenShiftSettingsConfig";
 +import { QuickStartContext, QuickStartContextValues } from 
"@patternfly/quickstarts";
  
  enum FormValiationOptions {
    INITIAL = "INITIAL",
@@@ -56,7 -55,7 +58,8 @@@ export function OpenShiftSettingsSimple
    const [isConfigValidated, setConfigValidated] = 
useState(FormValiationOptions.INITIAL);
    const [isConnecting, setConnecting] = useState(false);
    const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+   const [isDevModeConfigEnabled, setDevModeConfigEnabled] = 
useState(settings.openshift.isDevModeEnabled);
 +  const qsContext = useContext<QuickStartContextValues>(QuickStartContext);
  
    useEffect(() => {
      setConfig(settings.openshift.config);
@@@ -306,19 -326,39 +318,51 @@@
                </Button>
              </InputGroupText>
            </InputGroup>
 +          <br />
 +          <Button
 +            isInline={true}
 +            key="quickstart"
 +            variant="link"
 +            onClick={() => {
 +              
qsContext.setActiveQuickStartID?.(QuickStartIds.OpenShiftIntegrationQuickStart);
 +              setTimeout(() => 
qsContext.setQuickStartTaskNumber?.(QuickStartIds.OpenShiftIntegrationQuickStart,
 1), 0);
 +            }}
 +          >
 +            Need help getting started? Follow our quickstart guide.
 +          </Button>
          </FormGroup>
+         <FormGroup
+           label={DEV_MODE_FEATURE_NAME}
+           labelIcon={
+             <Popover
+               bodyContent={
+                 "Automatically spins up a deployment running Quarkus in dev 
mode, making it quick to try model changes"
+               }
+             >
+               <button
+                 type="button"
+                 aria-label="More info for Dev Mode field"
+                 onClick={(e) => e.preventDefault()}
+                 aria-describedby="dev-mode-field"
+                 className="pf-c-form__group-label-help"
+               >
+                 <HelpIcon noVerticalAlign />
+               </button>
+             </Popover>
+           }
+           isRequired
+           fieldId="dev-mode-field"
+         >
+           <Checkbox
+             id="enable-dev-mode-checkbox"
+             label="Enable Dev Mode"
+             description={
+               "Be sure to set up at least 4GB of ram for your OpenShift 
deployments, otherwise, the Dev Mode deployment may run into issues."
+             }
+             isChecked={isDevModeConfigEnabled}
+             onChange={onEnableDevModeConfigChanged}
+           />
+         </FormGroup>
          <ActionGroup>
            <Button
              id="openshift-config-save-button"
diff --cc 
packages/serverless-logic-web-tools/src/settings/storage/StorageSettings.tsx
index ccba6c851f,0000000000..4996d1f571
mode 100644,000000..100644
--- 
a/packages/serverless-logic-web-tools/src/settings/storage/StorageSettings.tsx
+++ 
b/packages/serverless-logic-web-tools/src/settings/storage/StorageSettings.tsx
@@@ -1,199 -1,0 +1,195 @@@
 +/*
 + * Copyright 2023 Red Hat, Inc. and/or its affiliates.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *        http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +import React from "react";
 +import { useController } from 
"@kie-tools-core/react-hooks/dist/useController";
 +import { Alert, AlertActionCloseButton, Button } from 
"@patternfly/react-core/dist/js";
 +import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
 +import { Form } from "@patternfly/react-core/dist/js/components/Form";
 +import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
 +import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
 +import { useCallback, useEffect, useState } from "react";
- import { Alerts, AlertsController, useAlert } from "../../alerts/Alerts";
 +import { APP_NAME } from "../../AppConstants";
 +import { routes } from "../../navigation/Routes";
 +import { setPageTitle } from "../../PageTitle";
 +import { ConfirmDeleteModal } from "../../table/ConfirmDeleteModal";
 +import { SETTINGS_PAGE_SECTION_TITLE } from "../SettingsContext";
 +import { deleteAllCookies } from "../../cookies";
 +import { isBrowserChromiumBased } from 
"../../workspace/startupBlockers/SupportedBrowsers";
 +import { useHistory } from "react-router";
++import { useGlobalAlert } from "../../alerts/GlobalAlertsContext";
 +
 +const PAGE_TITLE = "Storage";
 +/**
 + * delete alert delay in seconds before reloading the app.
 + */
 +const DELETE_ALERT_DELAY = 5;
 +
 +/**
 + * Delete all indexed DBs
 + */
 +const deleteAllIndexedDBs = async () => {
 +  Promise.all(
 +    (await indexedDB.databases()).filter((db) => db.name).map(async (db) => 
indexedDB.deleteDatabase(db.name!))
 +  );
 +};
 +
 +function Timer(props: { delay: number }) {
 +  const [delay, setDelay] = useState(props.delay);
 +
 +  useEffect(() => {
 +    const timer = setInterval(() => {
 +      setDelay((prevDelay) => prevDelay - 1);
 +    }, 1000);
 +
 +    return () => {
 +      clearInterval(timer);
 +    };
 +  }, []);
 +
 +  return <>{delay}</>;
 +}
 +
 +export function StorageSettings() {
 +  const [isDeleteCookiesChecked, setIsDeleteCookiesChecked] = useState(false);
 +  const [isDeleteLocalStorageChecked, setIsDeleteLocalStorageChecked] = 
useState(false);
 +  const [isConfirmDeleteModalOpen, setIsConfirmDeleteModalOpen] = 
useState(false);
-   const [alerts, alertsRef] = useController<AlertsController>();
 +  const history = useHistory();
 +
 +  const toggleConfirmModal = useCallback(() => {
 +    setIsConfirmDeleteModalOpen((isOpen) => !isOpen);
 +  }, []);
 +
-   const deleteSuccessAlert = useAlert(
-     alerts,
++  const deleteSuccessAlert = useGlobalAlert(
 +    useCallback(({ close }) => {
 +      setTimeout(() => {
 +        window.location.href = window.location.origin + 
window.location.pathname;
 +      }, DELETE_ALERT_DELAY * 1000);
 +      return (
 +        <Alert
 +          variant="success"
 +          title={
 +            <>
 +              Data deleted successfully. <br />
 +              You will be redirected to the home page in <Timer 
delay={DELETE_ALERT_DELAY} /> seconds
 +            </>
 +          }
 +        />
 +      );
 +    }, [])
 +  );
 +
-   const deleteErrorAlert = useAlert(
-     alerts,
++  const deleteErrorAlert = useGlobalAlert(
 +    useCallback(({ close }) => {
 +      return (
 +        <Alert
 +          variant="danger"
 +          title={`Oops, something went wrong while trying to delete the 
selected data. Please refresh the page and try again. If the problem persists, 
you can try deleting site data for this application in your browser's 
settings.`}
 +          actionClose={<AlertActionCloseButton onClose={close} />}
 +        />
 +      );
 +    }, [])
 +  );
 +
 +  const onConfirmDeleteModalDelete = useCallback(async () => {
 +    toggleConfirmModal();
 +
 +    try {
 +      await deleteAllIndexedDBs();
 +      if (isDeleteLocalStorageChecked) {
 +        localStorage.clear();
 +      }
 +      if (isDeleteCookiesChecked) {
 +        deleteAllCookies();
 +      }
 +      deleteSuccessAlert.show();
 +    } catch (e) {
 +      deleteErrorAlert.show();
 +    }
 +  }, [toggleConfirmModal, deleteSuccessAlert, isDeleteLocalStorageChecked, 
deleteErrorAlert, isDeleteCookiesChecked]);
 +
 +  useEffect(() => {
 +    if (!isBrowserChromiumBased()) {
 +      history.replace(routes.settings.home.path({}));
 +    }
 +    setPageTitle([SETTINGS_PAGE_SECTION_TITLE, PAGE_TITLE]);
 +  }, [history]);
 +
 +  return (
 +    <>
-       <Alerts ref={alertsRef} width={"500px"} />
 +      <Page>
 +        <PageSection variant={"light"} isWidthLimited>
 +          <TextContent>
 +            <Text component={TextVariants.h1}>{PAGE_TITLE}</Text>
 +            <Text component={TextVariants.p}>
 +              Here, you have the ability to completely erase all stored data 
in your browser.
 +              <br />
 +              Safely delete your cookies, modules, settings and all 
information locally stored in your browser, giving a
 +              fresh start to {APP_NAME}.
 +            </Text>
 +          </TextContent>
 +        </PageSection>
 +
 +        <PageSection>
 +          <PageSection variant={"light"}>
 +            <Form>
 +              <Checkbox
 +                id="delete-indexedDB"
 +                label="Storage"
 +                description={"Delete all databases. You will lose all your 
modules and workspaces."}
 +                isChecked
 +                isDisabled
 +              />
 +              <Alert
 +                variant="warning"
 +                isInline
 +                title="By selecting the cookies and local storage, all your 
saved settings will be permanently erased."
 +              >
 +                <br />
 +                <Checkbox
 +                  id="delete-cookies"
 +                  label="Cookies"
 +                  description={"Delete all cookies."}
 +                  isChecked={isDeleteCookiesChecked}
 +                  onChange={setIsDeleteCookiesChecked}
 +                />
 +                <br />
 +                <Checkbox
 +                  id="delete-localStorage"
 +                  label="LocalStorage"
 +                  description={"Delete all localStorage information."}
 +                  isChecked={isDeleteLocalStorageChecked}
 +                  onChange={setIsDeleteLocalStorageChecked}
 +                />
 +              </Alert>
 +            </Form>
 +            <br />
 +            <Button variant="danger" onClick={toggleConfirmModal}>
 +              Delete data
 +            </Button>
 +          </PageSection>
 +        </PageSection>
 +        <ConfirmDeleteModal
 +          isOpen={isConfirmDeleteModalOpen}
 +          onClose={toggleConfirmModal}
 +          onDelete={onConfirmDeleteModalDelete}
 +          elementsTypeName="data"
 +          deleteMessage="By deleting this data will permanently erase your 
stored information."
 +        />
 +      </Page>
 +    </>
 +  );
 +}
diff --cc 
packages/serverless-logic-web-tools/src/workspace/components/NewWorkspaceFromSample.tsx
index 500a06bd09,1c1b81bb4c..1083f71a90
--- 
a/packages/serverless-logic-web-tools/src/workspace/components/NewWorkspaceFromSample.tsx
+++ 
b/packages/serverless-logic-web-tools/src/workspace/components/NewWorkspaceFromSample.tsx
@@@ -24,9 -24,10 +24,9 @@@ import { Spinner } from "@patternfly/re
  import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
  import { QueryParams } from "../../navigation/Routes";
  import { useQueryParam } from "../../queryParams/QueryParamsContext";
 -import { OnlineEditorPage } from "../../pageTemplate/OnlineEditorPage";
  import { PageSection } from "@patternfly/react-core/dist/js/components/Page";
  import { EditorPageErrorPage } from "../../editor/EditorPageErrorPage";
- import { KIE_SAMPLES_REPO } from "../../home/sample/sampleApi";
+ import { KIE_SAMPLES_REPO } from "../../home/sample/SampleApi";
  import { useSampleDispatch } from "../../home/sample/hooks/SampleContext";
  
  export function NewWorkspaceFromSample() {
diff --cc pnpm-lock.yaml
index e676671d44,541f19f201..4c0ea5231d
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@@ -6101,9 -6120,12 +6126,15 @@@ importers
        react-router-dom:
          specifier: ^5.2.1
          version: 5.3.0([email protected])
+       short-unique-id:
+         specifier: ^4.4.4
+         version: 4.4.4
 +      showdown:
 +        specifier: ^2.1.0
 +        version: 2.1.0
+       uuid:
+         specifier: ^8.3.2
+         version: 8.3.2
        vscode-languageserver-types:
          specifier: ^3.16.0
          version: 3.17.2
@@@ -31829,14 -31734,12 +31777,20 @@@ packages
      dev: true
      optional: true
  
+   /[email protected]:
+     resolution:
+       { integrity: 
sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw==
 }
+     hasBin: true
+     dev: false
+ 
 +  /[email protected]:
 +    resolution:
 +      { integrity: 
sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
 }
 +    hasBin: true
 +    dependencies:
 +      commander: 9.4.1
 +    dev: false
 +
    /[email protected]:
      resolution:
        { integrity: 
sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
 }


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

Reply via email to