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 db67ee42b83b2a09a5110d66c1c94c7b9da62366
Author: Fabrizio Antonangeli <[email protected]>
AuthorDate: Wed Jan 25 20:08:55 2023 +0100

    KOGITO-8323: Refactor Settings according to UX redesign (#1404)
    
    * KOGITO-8147 Refactor the app bar and menu according to UX redesign
    
    * refactor to function style
    
    * remove new home page
    
    * remove old home page
    
    * Updated OnlineEditorPage.tsx
    
    * Add Settings routes and Settings Nav sidebar
    
    * GitHubSettings page wip
    
    * Rename 
packages/serverless-logic-sandbox/src/settings/github/GitHubSettingsTab.tsx -> 
packages/serverless-logic-sandbox/src/settings/github/GitHubSettings.tsx
    
    * GitHubSettings page
    
    * Removed quickstart link after branching
    
    * add KieSandboxExtendedServicesSettings route
    
    * Fix expand content when sidebar is collapsed
    
    * Moved new settings routes to src/newSettings
    
    * Completing the new settings folder
    
    * WIP OpenShiftSettings
    
    * OpenShiftSettings page
    
    * Fix "setup" modal hidden by "add connection" modal
    
    * Fix: Can't perform a React state update on an unmounted component
    
    * Mv ServiceAccountSettingsTab -> ServiceAccountSettings
    
    * ServiceAccountSettings
    
    * R 
packages/serverless-logic-sandbox/src/newSettings/serviceRegistry/ServiceRegistrySettingsTab.tsx
 -> 
packages/serverless-logic-sandbox/src/newSettings/serviceRegistry/ServiceRegistrySettings.tsx
    
    * Refactor ServiceRegistrySettings
    
    * R 
packages/serverless-logic-sandbox/src/newSettings/kafka/ApacheKafkaSettingsTab.tsx
 -> 
packages/serverless-logic-sandbox/src/newSettings/kafka/ApacheKafkaSettings.tsx
    
    * Refactor ApacheKafkaSettings
    
    * R 
packages/serverless-logic-sandbox/src/newSettings/featurePreview/FeaturePreviewSettingsTab.tsx
 -> 
packages/serverless-logic-sandbox/src/newSettings/featurePreview/FeaturePreviewSettings.tsx
    
    * Refactor FeaturePreviewSettings
    
    * Sidebar title same as OpenShift Console
    
    * deleted:    
packages/serverless-logic-sandbox/src/newSettings/SettingsModalBody.tsx
    removed settings modal related code
    
    * Fix Copyright
    
    * Add check not to show the loading in modal if we are in settings route
    
    * Removed unnecessary code for input focus
    
    * Code review
    
    * Fixed issues after merge conflicts
    
    * Fix issue after merge
    
    Co-authored-by: Xaiofeng Bai <[email protected]>
---
 packages/serverless-logic-web-tools/src/App.tsx    |   2 +
 .../src/homepage/pageTemplate/OnlineEditorPage.tsx |  16 +-
 .../src/navigation/Routes.ts                       |  12 +
 .../src/navigation/RoutesSwitch.tsx                |   6 +-
 .../src/newSettings/SettingsButton.tsx             |  35 +++
 .../{settings => newSettings}/SettingsContext.tsx  |  73 +----
 .../KieSandboxExtendedServicesSettings.tsx         | 273 ++++++++++++++++++
 .../featurePreview/FeaturePreviewConfig.tsx        |  42 +++
 .../featurePreview/FeaturePreviewSettings.tsx      |  72 +++++
 .../src/newSettings/github/GitHubSettings.tsx      | 239 +++++++++++++++
 .../src/newSettings/github/Hooks.tsx               |  34 +++
 .../src/newSettings/kafka/ApacheKafkaSettings.tsx  | 297 +++++++++++++++++++
 .../src/newSettings/kafka/KafkaSettingsConfig.tsx  |  70 +++++
 .../newSettings/openshift/OpenShiftSettings.tsx    | 151 ++++++++++
 .../openshift/OpenShiftSettingsConfig.tsx          |  58 ++++
 .../openshift/OpenShiftSettingsSimpleConfig.tsx    | 319 +++++++++++++++++++++
 .../src/newSettings/routes/SettingsPageRoutes.tsx  |  59 ++++
 .../serviceAccount/ServiceAccountConfig.tsx        |  66 +++++
 .../serviceAccount/ServiceAccountSettings.tsx      | 307 ++++++++++++++++++++
 .../serviceRegistry/ServiceRegistryConfig.tsx      |  66 +++++
 .../serviceRegistry/ServiceRegistrySettings.tsx    | 305 ++++++++++++++++++++
 .../src/newSettings/uiNav/SettingsPageNav.tsx      |  75 +++++
 .../src/settings/SettingsContext.tsx               |  14 +-
 .../static/resources/style.css                     |  12 +
 24 files changed, 2533 insertions(+), 70 deletions(-)

diff --git a/packages/serverless-logic-web-tools/src/App.tsx 
b/packages/serverless-logic-web-tools/src/App.tsx
index 540822c69c..eb5d51eb35 100644
--- a/packages/serverless-logic-web-tools/src/App.tsx
+++ b/packages/serverless-logic-web-tools/src/App.tsx
@@ -24,6 +24,7 @@ import { NavigationContextProvider } from 
"./navigation/NavigationContextProvide
 import { RoutesSwitch } from "./navigation/RoutesSwitch";
 import { OpenShiftContextProvider } from 
"./openshift/OpenShiftContextProvider";
 import { SettingsContextProvider } from "./settings/SettingsContext";
+import { SettingsContextProvider as NewSettingsContextProvider } from 
"./newSettings/SettingsContext";
 import { VirtualServiceRegistryContextProvider } from 
"./virtualServiceRegistry/VirtualServiceRegistryContextProvider";
 import { WorkspacesContextProvider } from 
"@kie-tools-core/workspaces-git-fs/dist/context/WorkspacesContextProvider";
 
@@ -35,6 +36,7 @@ export const App = () => (
       [EnvContextProvider, {}],
       [KieSandboxExtendedServicesContextProvider, {}],
       [SettingsContextProvider, {}],
+      [NewSettingsContextProvider, {}],
       [WorkspacesContextProvider, { workspacesSharedWorkerScriptUrl: 
"workspace/worker/sharedWorker.js" }],
       [OpenShiftContextProvider, {}],
       [VirtualServiceRegistryContextProvider, {}],
diff --git 
a/packages/serverless-logic-web-tools/src/homepage/pageTemplate/OnlineEditorPage.tsx
 
b/packages/serverless-logic-web-tools/src/homepage/pageTemplate/OnlineEditorPage.tsx
index 6f13f1ae49..7f55b5605a 100644
--- 
a/packages/serverless-logic-web-tools/src/homepage/pageTemplate/OnlineEditorPage.tsx
+++ 
b/packages/serverless-logic-web-tools/src/homepage/pageTemplate/OnlineEditorPage.tsx
@@ -32,7 +32,7 @@ import {
   SkipToContent,
 } from "@patternfly/react-core";
 import { Page } from "@patternfly/react-core/dist/js/components/Page";
-import { useHistory } from "react-router";
+import { useHistory, useRouteMatch } from "react-router";
 import { KieSandboxExtendedServicesIcon } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesIcon";
 import { useRoutes } from "../../navigation/Hooks";
 import { OpenshiftDeploymentsDropdown } from 
"../../openshift/dropdown/OpenshiftDeploymentsDropdown";
@@ -40,6 +40,7 @@ import { SettingsButton } from 
"../../settings/SettingsButton";
 import { HomePageNav } from "../uiNav/HomePageNav";
 import { useLocation } from "react-router-dom";
 import { useState } from "react";
+import { SettingsPageNav } from "../../newSettings/uiNav/SettingsPageNav";
 import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
 import { ExclamationIcon, BarsIcon } from 
"@patternfly/react-icons/dist/js/icons";
 
@@ -47,6 +48,7 @@ export function OnlineEditorPage(props: { children?: 
React.ReactNode }) {
   const history = useHistory();
   const routes = useRoutes();
   const [isNavOpen, setIsNavOpen] = useState(true);
+  const isRouteInSettingsSection = 
useRouteMatch(routes.settings.home.path({}));
   const navToggle = () => {
     setIsNavOpen(!isNavOpen);
   };
@@ -127,9 +129,17 @@ export function OnlineEditorPage(props: { children?: 
React.ReactNode }) {
   );
   const location = useLocation();
 
-  const sidebar = (
-    <PageSidebar nav={<HomePageNav 
pathname={location.pathname}></HomePageNav>} isNavOpen={isNavOpen} theme="dark" 
/>
+  const pageNav = useMemo(
+    () =>
+      !isRouteInSettingsSection ? (
+        <HomePageNav pathname={location.pathname}></HomePageNav>
+      ) : (
+        <SettingsPageNav pathname={location.pathname}></SettingsPageNav>
+      ),
+    [location, isRouteInSettingsSection]
   );
+
+  const sidebar = <PageSidebar nav={pageNav} isNavOpen={isNavOpen} 
theme="dark" />;
   const mainContainerId = "main-content-page-layout-tertiary-nav";
 
   const pageSkipToContent = <SkipToContent href={`#${mainContainerId}`}>Skip 
to content</SkipToContent>;
diff --git a/packages/serverless-logic-web-tools/src/navigation/Routes.ts 
b/packages/serverless-logic-web-tools/src/navigation/Routes.ts
index 54189fd1c6..b62375e791 100644
--- a/packages/serverless-logic-web-tools/src/navigation/Routes.ts
+++ b/packages/serverless-logic-web-tools/src/navigation/Routes.ts
@@ -15,6 +15,7 @@
  */
 
 const IS_HASH_ROUTER = true;
+const SETTINGS_ROUTE = "/settings";
 
 export enum QueryParams {
   SETTINGS = "settings",
@@ -128,6 +129,17 @@ export const routes = {
       `/${workspaceId}/file/${fileRelativePath}${extension ? "." + extension : 
""}`
   ),
 
+  settings: {
+    home: new Route<{}>(() => SETTINGS_ROUTE),
+    github: new Route<{}>(() => `${SETTINGS_ROUTE}/github`),
+    openshift: new Route<{}>(() => `${SETTINGS_ROUTE}/openshift`),
+    kie_sandbox_extended_services: new Route<{}>(() => 
`${SETTINGS_ROUTE}/kie_sandbox_extended_services`),
+    service_account: new Route<{}>(() => `${SETTINGS_ROUTE}/serviceAccount`),
+    service_registry: new Route<{}>(() => `${SETTINGS_ROUTE}/serviceRegistry`),
+    kafka: new Route<{}>(() => `${SETTINGS_ROUTE}/kafka`),
+    feature_preview: new Route<{}>(() => `${SETTINGS_ROUTE}/featurePreview`),
+  },
+
   static: {
     sample: new Route<{ pathParams: "type" | "name" }>(({ type, name }) => 
`samples/${name}/${name}.${type}`),
     images: {
diff --git 
a/packages/serverless-logic-web-tools/src/navigation/RoutesSwitch.tsx 
b/packages/serverless-logic-web-tools/src/navigation/RoutesSwitch.tsx
index 686c59fd1b..004b9837b9 100644
--- a/packages/serverless-logic-web-tools/src/navigation/RoutesSwitch.tsx
+++ b/packages/serverless-logic-web-tools/src/navigation/RoutesSwitch.tsx
@@ -16,14 +16,16 @@
 
 import * as React from "react";
 import { useMemo } from "react";
-import { Route, Switch } from "react-router-dom";
+import { Route, Switch, useRouteMatch } from "react-router-dom";
 import { useRoutes } from "./Hooks";
 import { OnlineEditorPage } from "../homepage/pageTemplate/OnlineEditorPage";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { HomePageRoutes } from "../homepage/routes/HomePageRoutes";
+import { SettingsPageRoutes } from "../newSettings/routes/SettingsPageRoutes";
 
 export function RoutesSwitch() {
   const routes = useRoutes();
+  const isRouteInSettingsSection = 
useRouteMatch(routes.settings.home.path({}));
   const buildInfo = useMemo(() => {
     return process.env["WEBPACK_REPLACE__buildInfo"];
   }, []);
@@ -44,7 +46,7 @@ export function RoutesSwitch() {
   }) => {
     return (
       <OnlineEditorPage>
-        <HomePageRoutes />
+        {!isRouteInSettingsSection ? <HomePageRoutes /> : <SettingsPageRoutes 
/>}
         {buildInfo && (
           <div className={"kie-tools--build-info"}>
             <Label>{buildInfo}</Label>
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/SettingsButton.tsx 
b/packages/serverless-logic-web-tools/src/newSettings/SettingsButton.tsx
new file mode 100644
index 0000000000..7b1cde4e00
--- /dev/null
+++ b/packages/serverless-logic-web-tools/src/newSettings/SettingsButton.tsx
@@ -0,0 +1,35 @@
+/*
+ * 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 * as React from "react";
+import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
+import { CogIcon } from "@patternfly/react-icons/dist/js/icons/cog-icon";
+import { useSettingsDispatch } from "./SettingsContext";
+import { Link } from "react-router-dom";
+import { useRoutes } from "../navigation/Hooks";
+
+export function SettingsButton() {
+  const settingsDispatch = useSettingsDispatch();
+  const routes = useRoutes();
+
+  return (
+    <Link to={routes.settings.home.path({})}>
+      <Button variant={ButtonVariant.plain} aria-label="Settings" 
className={"kie-tools--masthead-hoverable-dark"}>
+        <CogIcon />
+      </Button>
+    </Link>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx 
b/packages/serverless-logic-web-tools/src/newSettings/SettingsContext.tsx
similarity index 84%
copy from packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
copy to packages/serverless-logic-web-tools/src/newSettings/SettingsContext.tsx
index 242e71c961..76a2eeb0bf 100644
--- a/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
+++ b/packages/serverless-logic-web-tools/src/newSettings/SettingsContext.tsx
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2023 Red Hat, Inc. and/or its affiliates.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,30 +14,25 @@
  * limitations under the License.
  */
 
+import { OpenShiftConnection } from 
"@kie-tools-core/openshift/dist/service/OpenShiftConnection";
+import { OpenShiftService } from 
"@kie-tools-core/openshift/dist/service/OpenShiftService";
+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 { readOpenShiftConfigCookie } from 
"./openshift/OpenShiftSettingsConfig";
-import { OpenShiftConnection } from 
"@kie-tools-core/openshift/dist/service/OpenShiftConnection";
+import { SwfServiceCatalogStore } from "../editor/api/SwfServiceCatalogStore";
+import { useKieSandboxExtendedServices } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
 import { OpenShiftInstanceStatus } from "../openshift/OpenShiftInstanceStatus";
-import { OpenShiftService } from 
"@kie-tools-core/openshift/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 { KafkaSettingsConfig, readKafkaConfigCookie } from 
"./kafka/KafkaSettingsConfig";
+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";
 
 export enum AuthStatus {
   SIGNED_OUT,
@@ -69,8 +64,6 @@ export class ExtendedServicesConfig {
 }
 
 export interface SettingsContextType {
-  isOpen: boolean;
-  activeTab: SettingsTabs;
   openshift: {
     status: OpenShiftInstanceStatus;
     config: OpenShiftConnection;
@@ -99,8 +92,6 @@ export interface SettingsContextType {
 }
 
 export interface SettingsDispatchContextType {
-  open: (activeTab?: SettingsTabs) => void;
-  close: () => void;
   openshift: {
     service: OpenShiftService;
     setStatus: React.Dispatch<React.SetStateAction<OpenShiftInstanceStatus>>;
@@ -132,31 +123,6 @@ export const SettingsContext = 
React.createContext<SettingsContextType>({} as an
 export const SettingsDispatchContext = 
React.createContext<SettingsDispatchContextType>({} as any);
 
 export function SettingsContextProvider(props: any) {
-  const queryParams = useQueryParams();
-  const history = useHistory();
-  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());
@@ -256,8 +222,6 @@ export function SettingsContextProvider(props: any) {
 
   const dispatch = useMemo(() => {
     return {
-      open,
-      close,
       openshift: {
         service: openshiftService,
         setStatus: setOpenshiftStatus,
@@ -285,10 +249,8 @@ export function SettingsContextProvider(props: any) {
       },
     };
   }, [
-    close,
     githubAuthService,
     githubOctokit,
-    open,
     openshiftService,
     kieSandboxExtendedServices.saveNewConfig,
     serviceCatalogStore,
@@ -296,8 +258,6 @@ export function SettingsContextProvider(props: any) {
 
   const value = useMemo(() => {
     return {
-      isOpen,
-      activeTab,
       openshift: {
         status: openshiftStatus,
         config: openshiftConfig,
@@ -325,8 +285,6 @@ export function SettingsContextProvider(props: any) {
       },
     };
   }, [
-    isOpen,
-    activeTab,
     openshiftStatus,
     openshiftConfig,
     githubAuthStatus,
@@ -342,14 +300,7 @@ export function SettingsContextProvider(props: any) {
 
   return (
     <SettingsContext.Provider value={value}>
-      <SettingsDispatchContext.Provider value={dispatch}>
-        {githubAuthStatus !== AuthStatus.LOADING && <>{props.children}</>}
-        <Modal title="Settings" isOpen={isOpen} onClose={close} 
variant={ModalVariant.large}>
-          <div style={{ height: "calc(100vh * 0.5)" }} 
className={"kie-tools--settings-modal-content"}>
-            <SettingsModalBody />
-          </div>
-        </Modal>
-      </SettingsDispatchContext.Provider>
+      <SettingsDispatchContext.Provider 
value={dispatch}>{props.children}</SettingsDispatchContext.Provider>
     </SettingsContext.Provider>
   );
 }
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/extendedServices/KieSandboxExtendedServicesSettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/extendedServices/KieSandboxExtendedServicesSettings.tsx
new file mode 100644
index 0000000000..4e163afd88
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/extendedServices/KieSandboxExtendedServicesSettings.tsx
@@ -0,0 +1,273 @@
+/*
+ * 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 { Modal, ModalVariant } from "@patternfly/react-core";
+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 { ActionGroup, Form, FormAlert, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup, InputGroupText } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
+import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
+import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
+import { AddCircleOIcon } from "@patternfly/react-icons";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { ExtendedServicesConfig, useSettings, useSettingsDispatch } from 
"../../settings/SettingsContext";
+
+export function KieSandboxExtendedServicesSettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+  const [config, setConfig] = 
useState(settings.kieSandboxExtendedServices.config);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+
+  const isCurrentConfigValid = useMemo(
+    () => config.host.trim().length > 0 && config.buildUrl().trim().length > 0,
+    [config]
+  );
+
+  const onClearHost = useCallback(() => setConfig(new 
ExtendedServicesConfig("", config.port)), [config]);
+  const onClearPort = useCallback(() => setConfig(new 
ExtendedServicesConfig(config.host, "")), [config]);
+
+  const onHostChanged = useCallback(
+    (newValue: string) => setConfig(new ExtendedServicesConfig(newValue, 
config.port)),
+    [config]
+  );
+  const onPortChanged = useCallback(
+    (newValue: string) => setConfig(new ExtendedServicesConfig(config.host, 
newValue)),
+    [config]
+  );
+
+  const onConnect = useCallback(() => {
+    settingsDispatch.kieSandboxExtendedServices.setConfig(config);
+  }, [settingsDispatch.kieSandboxExtendedServices, config]);
+
+  const onReset = useCallback(() => {
+    const emptyConfig = new ExtendedServicesConfig("", "");
+    setConfig(emptyConfig);
+    settingsDispatch.kieSandboxExtendedServices.setConfig(emptyConfig);
+  }, [settingsDispatch.kieSandboxExtendedServices]);
+
+  const handleModalToggle = useCallback(() => {
+    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
+  }, []);
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>KIE Sandbox Extended 
Services</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for proxying Serverless Logic 
Web Tools requests to OpenShift, thus
+            making it possible to deploy models.
+            <br /> All information is locally stored in your browser and never 
shared with anyone.
+          </Text>
+        </TextContent>
+      </PageSection>
+
+      <PageSection isFilled>
+        <PageSection variant={"light"}>
+          {kieSandboxExtendedServices.status === 
KieSandboxExtendedServicesStatus.RUNNING ? (
+            <EmptyState>
+              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
+              <TextContent>
+                <Text component={"h2"}>You are connect to the KIE Sandbox 
Extended Services.</Text>
+              </TextContent>
+              <EmptyStateBody>
+                Deploying models is <b>enabled</b>.
+                <br />
+                <b>URL: </b>
+                <i>{config.buildUrl()}</i>
+                <br />
+                <br />
+                <Button variant={ButtonVariant.secondary} onClick={onReset}>
+                  Reset
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          ) : (
+            <>
+              <EmptyState>
+                <EmptyStateIcon icon={AddCircleOIcon} />
+                <TextContent>
+                  <Text component={"h2"}>You are not connected to KIE Sandbox 
Extended Services.</Text>
+                </TextContent>
+                <EmptyStateBody>
+                  You currently have no KIE Sandbox Extended Services 
connections.{" "}
+                  <a
+                    onClick={() => {
+                      
kieSandboxExtendedServices.setInstallTriggeredBy(undefined);
+                      kieSandboxExtendedServices.setModalOpen(true);
+                    }}
+                  >
+                    Click to setup
+                  </a>
+                  <br />
+                  <br />
+                  <Button
+                    variant={ButtonVariant.primary}
+                    onClick={handleModalToggle}
+                    data-testid="add-connection-button"
+                  >
+                    Add connection
+                  </Button>
+                </EmptyStateBody>
+              </EmptyState>
+            </>
+          )}
+        </PageSection>
+      </PageSection>
+
+      <Modal
+        title="Add connection"
+        isOpen={
+          isModalOpen &&
+          kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.RUNNING &&
+          !kieSandboxExtendedServices.isModalOpen
+        }
+        onClose={handleModalToggle}
+        variant={ModalVariant.large}
+      >
+        <Form>
+          <FormAlert>
+            <Alert
+              variant="danger"
+              title={
+                <Text>
+                  You are not connected to KIE Sandbox Extended Services.{" "}
+                  <a
+                    onClick={() => {
+                      
kieSandboxExtendedServices.setInstallTriggeredBy(undefined);
+                      kieSandboxExtendedServices.setModalOpen(true);
+                    }}
+                  >
+                    Click to setup
+                  </a>
+                </Text>
+              }
+              aria-live="polite"
+              isInline
+            />
+          </FormAlert>
+          <PageSection variant={"light"} isFilled={true} style={{ height: 
"100%" }}>
+            <FormGroup
+              label={"Host"}
+              labelIcon={
+                <Popover bodyContent={"The host associated with the KIE 
Sandbox Extended Services URL instance."}>
+                  <button
+                    type="button"
+                    aria-label="More info for host field"
+                    onClick={(e) => e.preventDefault()}
+                    aria-describedby="host-server-field"
+                    className="pf-c-form__group-label-help"
+                  >
+                    <HelpIcon noVerticalAlign />
+                  </button>
+                </Popover>
+              }
+              isRequired
+              fieldId="host-server-field"
+            >
+              <InputGroup className="pf-u-mt-sm">
+                <TextInput
+                  autoComplete={"off"}
+                  isRequired
+                  type="text"
+                  id="host-server-field"
+                  name="host-server-field"
+                  aria-label="Host field"
+                  aria-describedby="host-server-field-helper"
+                  value={config.host}
+                  onChange={onHostChanged}
+                  tabIndex={1}
+                  data-testid="host-text-field"
+                />
+                <InputGroupText>
+                  <Button isSmall variant="plain" aria-label="Clear host 
button" onClick={onClearHost}>
+                    <TimesIcon />
+                  </Button>
+                </InputGroupText>
+              </InputGroup>
+            </FormGroup>
+            <FormGroup
+              label={"Port"}
+              labelIcon={
+                <Popover
+                  bodyContent={"The port number associated with the KIE 
Sandbox Extended Services URL instance."}
+                >
+                  <button
+                    type="button"
+                    aria-label="More info for port field"
+                    onClick={(e) => e.preventDefault()}
+                    aria-describedby="port-field"
+                    className="pf-c-form__group-label-help"
+                  >
+                    <HelpIcon noVerticalAlign />
+                  </button>
+                </Popover>
+              }
+              isRequired
+              fieldId="port-field"
+            >
+              <InputGroup className="pf-u-mt-sm">
+                <TextInput
+                  autoComplete={"off"}
+                  isRequired
+                  type="text"
+                  id="port-field"
+                  name="port-field"
+                  aria-label="Port field"
+                  aria-describedby="port-field-helper"
+                  value={config.port}
+                  onChange={onPortChanged}
+                  tabIndex={2}
+                  data-testid="port-text-field"
+                />
+                <InputGroupText>
+                  <Button isSmall variant="plain" aria-label="Clear port 
button" onClick={onClearPort}>
+                    <TimesIcon />
+                  </Button>
+                </InputGroupText>
+              </InputGroup>
+            </FormGroup>
+            <ActionGroup>
+              <Button
+                isDisabled={!isCurrentConfigValid}
+                id="kie-sandbox-extended-services-config-connect-button"
+                key="connect"
+                variant="primary"
+                onClick={onConnect}
+                data-testid="connect-config-button"
+              >
+                Connect
+              </Button>
+              <Button key="cancel" variant="link" onClick={handleModalToggle} 
data-testid="connect-cancel-button">
+                Connect
+              </Button>
+            </ActionGroup>
+          </PageSection>
+        </Form>
+      </Modal>
+    </Page>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewConfig.tsx
new file mode 100644
index 0000000000..36cce4c180
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewConfig.tsx
@@ -0,0 +1,42 @@
+/*
+ * 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 { getCookie, makeCookieName, setCookie } from "../../cookies";
+
+export const FEATURE_PREVIEW_STUNNER_ENABLED_COOKIE_NAME = 
makeCookieName("feature-preview", "stunner-enabled");
+
+export interface FeaturePreviewSettingsConfig {
+  stunnerEnabled: boolean;
+}
+
+export const DEFAULT_CONFIG: FeaturePreviewSettingsConfig = {
+  stunnerEnabled: true,
+};
+
+export function readFeaturePreviewConfigCookie(): FeaturePreviewSettingsConfig 
{
+  const stunnerEnabledCookie = 
getCookie(FEATURE_PREVIEW_STUNNER_ENABLED_COOKIE_NAME);
+  return {
+    stunnerEnabled: stunnerEnabledCookie ? stunnerEnabledCookie === "true" : 
DEFAULT_CONFIG.stunnerEnabled,
+  };
+}
+
+export function saveStunnerEnabledCookie(isEnabled: boolean): void {
+  setCookie(FEATURE_PREVIEW_STUNNER_ENABLED_COOKIE_NAME, String(isEnabled));
+}
+
+export function saveConfigCookie(config: FeaturePreviewSettingsConfig): void {
+  saveStunnerEnabledCookie(config.stunnerEnabled);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewSettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewSettings.tsx
new file mode 100644
index 0000000000..4b28dc3182
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/featurePreview/FeaturePreviewSettings.tsx
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as React from "react";
+import { 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 { useSettings, useSettingsDispatch } from "../SettingsContext";
+import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
+import { saveConfigCookie } from "./FeaturePreviewConfig";
+
+export function FeaturePreviewSettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const [config, setConfig] = useState(settings.featurePreview.config);
+  const [stunnerEnabled, setStunnerEnabled] = useState(config.stunnerEnabled);
+
+  useEffect(() => {
+    settingsDispatch.featurePreview.setConfig(config);
+    saveConfigCookie(config);
+  }, [config, settingsDispatch.featurePreview]);
+
+  const onStunnerEnabledChanged = useCallback(
+    (isEnabled: boolean) => {
+      setStunnerEnabled(isEnabled);
+      setConfig({ ...config, stunnerEnabled: isEnabled });
+    },
+    [config]
+  );
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>Feature Preview</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for configuring the preview of 
features that are not fully supported yet.
+            <br /> All information is locally stored in your browser and never 
shared with anyone.
+          </Text>
+        </TextContent>
+      </PageSection>
+
+      <PageSection>
+        <PageSection variant={"light"}>
+          <Form>
+            <Checkbox
+              id="feature-preview-enable-stunner"
+              label="Kogito Serverless Workflow Visualization"
+              description={"Enable/disable Kogito Serverless Workflow 
Visualization for JSON files."}
+              isChecked={stunnerEnabled}
+              onChange={onStunnerEnabledChanged}
+            />
+          </Form>
+        </PageSection>
+      </PageSection>
+    </Page>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/github/GitHubSettings.tsx 
b/packages/serverless-logic-web-tools/src/newSettings/github/GitHubSettings.tsx
new file mode 100644
index 0000000000..bd3be0578f
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/github/GitHubSettings.tsx
@@ -0,0 +1,239 @@
+/*
+ * 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 { Modal, ModalVariant } from "@patternfly/react-core";
+import { Button, ButtonVariant } from 
"@patternfly/react-core/dist/js/components/Button";
+import { EmptyState, EmptyStateBody, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
+import { Form, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { Spinner } from "@patternfly/react-core/dist/js/components/Spinner";
+import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
+import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
+import { AddCircleOIcon } from "@patternfly/react-icons";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import { ExclamationTriangleIcon } from 
"@patternfly/react-icons/dist/js/icons/exclamation-triangle-icon";
+import { ExternalLinkAltIcon } from 
"@patternfly/react-icons/dist/js/icons/external-link-alt-icon";
+import { GithubIcon } from "@patternfly/react-icons/dist/js/icons/github-icon";
+import * as React from "react";
+import { useCallback, useMemo, useRef, useState } from "react";
+import { makeCookieName } from "../../cookies";
+import { AuthStatus, useSettings, useSettingsDispatch } from 
"../../settings/SettingsContext";
+
+export const GITHUB_OAUTH_TOKEN_SIZE = 40;
+export const GITHUB_TOKENS_URL = "https://github.com/settings/tokens";;
+export const GITHUB_TOKENS_HOW_TO_URL =
+  
"https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line";;
+export const GITHUB_AUTH_TOKEN_COOKIE_NAME = makeCookieName("github", 
"oauth-token");
+
+export enum GitHubSignInOption {
+  PERSONAL_ACCESS_TOKEN,
+  OAUTH,
+}
+
+enum GitHubTokenScope {
+  GIST = "gist",
+  REPO = "repo",
+}
+
+export function GitHubSettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+
+  const [potentialGitHubToken, setPotentialGitHubToken] = useState<string | 
undefined>(undefined);
+  const [isGitHubTokenValid, setIsGitHubTokenValid] = useState(true);
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const tokenInput = useRef<HTMLInputElement>(null);
+
+  const githubTokenValidated = useMemo(() => {
+    return isGitHubTokenValid ? "default" : "error";
+  }, [isGitHubTokenValid]);
+
+  const githubTokenHelperText = useMemo(() => {
+    return isGitHubTokenValid ? undefined : "Invalid token. Check if it has 
the 'repo' scope.";
+  }, [isGitHubTokenValid]);
+
+  const githubTokenToDisplay = useMemo(() => {
+    return obfuscate(potentialGitHubToken ?? settings.github.token) ?? "";
+  }, [settings.github, potentialGitHubToken]);
+
+  const handleModalToggle = useCallback(() => {
+    setPotentialGitHubToken(undefined);
+    setIsGitHubTokenValid(true);
+    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
+  }, []);
+
+  const onPasteGitHubToken = useCallback(
+    (e) => {
+      const token = e.clipboardData.getData("text/plain").slice(0, 
GITHUB_OAUTH_TOKEN_SIZE);
+      setPotentialGitHubToken(token);
+      settingsDispatch.github.authService
+        .authenticate(token)
+        .then(() => handleModalToggle())
+        .catch(() => setIsGitHubTokenValid(false));
+    },
+    [settingsDispatch.github.authService, handleModalToggle]
+  );
+
+  const onSignOutFromGitHub = useCallback(() => {
+    settingsDispatch.github.authService.reset();
+    setPotentialGitHubToken(undefined);
+  }, [settingsDispatch.github.authService]);
+
+  return (
+    <Page>
+      <PageSection variant={"light"}>
+        <TextContent>
+          <Text component={TextVariants.h1}>GitHub</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for creating repositories 
containing models you design, and syncing
+            changes with GitHub.
+            <br />
+            All information is locally stored in your browser and never shared 
with anyone.
+          </Text>
+        </TextContent>
+      </PageSection>
+
+      <PageSection isFilled>
+        <PageSection variant={"light"}>
+          {settings.github.authStatus === AuthStatus.TOKEN_EXPIRED && (
+            <EmptyState>
+              <EmptyStateIcon icon={ExclamationTriangleIcon} />
+              <TextContent>
+                <Text component={"h2"}>GitHub Token expired</Text>
+              </TextContent>
+              <EmptyStateBody>
+                <TextContent>Reset your token to sign in with GitHub 
again.</TextContent>
+              </EmptyStateBody>
+              <br />
+              <Button variant={ButtonVariant.secondary} 
onClick={onSignOutFromGitHub}>
+                Reset
+              </Button>
+            </EmptyState>
+          )}
+          {settings.github.authStatus === AuthStatus.LOADING && (
+            <EmptyState>
+              <EmptyStateIcon icon={GithubIcon} />
+              <TextContent>
+                <Text component={"h2"}>Signing in with GitHub</Text>
+              </TextContent>
+              <br />
+              <br />
+              <Spinner />
+            </EmptyState>
+          )}
+          {settings.github.authStatus === AuthStatus.SIGNED_IN && (
+            <EmptyState>
+              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
+              <TextContent>
+                <Text component={"h2"}>{"You're signed in with GitHub."}</Text>
+              </TextContent>
+              <EmptyStateBody>
+                Gists are 
<b>{settings.github.scopes?.includes(GitHubTokenScope.GIST) ? "enabled" : 
"disabled"}.</b>
+                <br />
+                Private repositories are{" "}
+                <b>{settings.github.scopes?.includes(GitHubTokenScope.REPO) ? 
"enabled" : "disabled"}.</b>
+                <br />
+                <b>Token: </b>
+                <i>{obfuscate(settings.github.token)}</i>
+                <br />
+                <b>User: </b>
+                <i>{settings.github.user?.login}</i>
+                <br />
+                <b>Scope: </b>
+                <i>{settings.github.scopes?.join(", ") || "(none)"}</i>
+              </EmptyStateBody>
+              <br />
+              <Button variant={ButtonVariant.secondary} 
onClick={onSignOutFromGitHub}>
+                Sign out
+              </Button>
+            </EmptyState>
+          )}
+          {settings.github.authStatus === AuthStatus.SIGNED_OUT && (
+            <EmptyState>
+              <EmptyStateIcon icon={AddCircleOIcon} />
+              <TextContent>
+                <Text component={"h2"}>{"No access token"}</Text>
+              </TextContent>
+              <EmptyStateBody>
+                You currently have no tokens to display. Access tokens allow 
you for creating repositories containing
+                models you design, and syncing changes with GitHub.
+              </EmptyStateBody>
+              <Button variant={ButtonVariant.primary} 
onClick={handleModalToggle}>
+                Add access token
+              </Button>
+            </EmptyState>
+          )}
+        </PageSection>
+      </PageSection>
+
+      <Modal
+        title="Create new token"
+        isOpen={isModalOpen && settings.github.authStatus !== 
AuthStatus.LOADING}
+        onClose={handleModalToggle}
+        variant={ModalVariant.large}
+      >
+        <Form onSubmit={(e) => e.preventDefault()}>
+          <h3>
+            <a href={GITHUB_TOKENS_URL} target={"_blank"} rel="noopener 
noreferrer">
+              Create a new token&nbsp;&nbsp;
+              <ExternalLinkAltIcon />
+            </a>
+          </h3>
+          <FormGroup
+            isRequired={true}
+            helperTextInvalid={githubTokenHelperText}
+            validated={githubTokenValidated}
+            label={"Token"}
+            fieldId={"github-pat"}
+            helperText={"Your token must include the 'repo' scope."}
+          >
+            <InputGroup>
+              <TextInput
+                ref={tokenInput}
+                autoComplete={"off"}
+                id="token-input"
+                name="tokenInput"
+                aria-describedby="token-text-input-helper"
+                placeholder={"Paste your GitHub token here"}
+                maxLength={GITHUB_OAUTH_TOKEN_SIZE}
+                validated={githubTokenValidated}
+                value={githubTokenToDisplay}
+                onPaste={onPasteGitHubToken}
+                tabIndex={1}
+              />
+            </InputGroup>
+          </FormGroup>
+          <br />
+        </Form>
+      </Modal>
+    </Page>
+  );
+}
+
+export function obfuscate(token?: string) {
+  if (!token) {
+    return undefined;
+  }
+
+  if (token.length <= 8) {
+    return token;
+  }
+
+  const stars = new Array(token.length - 8).join("*");
+  const pieceToObfuscate = token.substring(4, token.length - 4);
+  return token.replace(pieceToObfuscate, stars);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/github/Hooks.tsx 
b/packages/serverless-logic-web-tools/src/newSettings/github/Hooks.tsx
new file mode 100644
index 0000000000..f05fde5cd4
--- /dev/null
+++ b/packages/serverless-logic-web-tools/src/newSettings/github/Hooks.tsx
@@ -0,0 +1,34 @@
+/*
+ * 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 { useMemo } from "react";
+import { AuthStatus, useSettings } from "../SettingsContext";
+
+export function useGitHubAuthInfo() {
+  const settings = useSettings();
+  return useMemo(() => {
+    if (settings.github.authStatus !== AuthStatus.SIGNED_IN) {
+      return undefined;
+    }
+
+    return {
+      name: settings.github.user!.name,
+      email: settings.github.user!.email,
+      username: settings.github.user!.login,
+      password: settings.github.token!,
+    };
+  }, [settings.github]);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/kafka/ApacheKafkaSettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/kafka/ApacheKafkaSettings.tsx
new file mode 100644
index 0000000000..7df8cb63dd
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/kafka/ApacheKafkaSettings.tsx
@@ -0,0 +1,297 @@
+/*
+ * 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 { Modal, ModalVariant } from "@patternfly/react-core";
+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 { ActionGroup, Form, FormAlert, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup, InputGroupText } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
+import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
+import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
+import { AddCircleOIcon } from "@patternfly/react-icons";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import { Link } from "react-router-dom";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { routes } from "../../navigation/Routes";
+import { useSettings, useSettingsDispatch } from "../SettingsContext";
+import { EMPTY_CONFIG, isKafkaConfigValid, resetConfigCookie, saveConfigCookie 
} from "./KafkaSettingsConfig";
+
+export function ApacheKafkaSettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const [config, setConfig] = useState(settings.apacheKafka.config);
+  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+  const [isModalOpen, setIsModalOpen] = useState(false);
+
+  const handleModalToggle = useCallback(() => {
+    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
+  }, []);
+
+  const isExtendedServicesRunning = useMemo(
+    () => kieSandboxExtendedServices.status === 
KieSandboxExtendedServicesStatus.RUNNING,
+    [kieSandboxExtendedServices.status]
+  );
+
+  const isStoredConfigValid = useMemo(
+    () => isExtendedServicesRunning && 
isKafkaConfigValid(settings.apacheKafka.config),
+    [isExtendedServicesRunning, settings.apacheKafka.config]
+  );
+
+  const isCurrentConfigValid = useMemo(
+    () => isExtendedServicesRunning && isKafkaConfigValid(config),
+    [isExtendedServicesRunning, config]
+  );
+
+  const onClearBootstraServer = useCallback(() => setConfig({ ...config, 
bootstrapServer: "" }), [config]);
+  const onClearTopic = useCallback(() => setConfig({ ...config, topic: "" }), 
[config]);
+
+  const onBootstrapServerChanged = useCallback(
+    (newValue: string) => setConfig({ ...config, bootstrapServer: newValue }),
+    [config]
+  );
+
+  const onTopicChanged = useCallback((newValue: string) => setConfig({ 
...config, topic: newValue }), [config]);
+
+  const onReset = useCallback(() => {
+    setConfig(EMPTY_CONFIG);
+    settingsDispatch.apacheKafka.setConfig(EMPTY_CONFIG);
+    resetConfigCookie();
+  }, [settingsDispatch.apacheKafka]);
+
+  const onApply = useCallback(() => {
+    settingsDispatch.apacheKafka.setConfig(config);
+    saveConfigCookie(config);
+  }, [config, settingsDispatch.apacheKafka]);
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>Streams for Apache Kafka</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for connecting serverless 
deployments with your Streams for Apache Kafka
+            instance through a KafkaSource.
+            <br /> All information is locally stored in your browser and never 
shared with anyone.
+          </Text>
+        </TextContent>
+      </PageSection>
+
+      <PageSection>
+        {!isExtendedServicesRunning && (
+          <>
+            <Alert
+              variant="danger"
+              title={
+                <Text>
+                  Connect to{" "}
+                  <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>KIE Sandbox 
Extended Services</Link>{" "}
+                  before configuring your Streams for Apache Kafka instance
+                </Text>
+              }
+              aria-live="polite"
+              isInline
+            >
+              KIE Sandbox Extended Services is necessary for connecting 
serverless deployments with your Streams for
+              Apache Kafka instance through a KafkaSource.
+            </Alert>
+            <br />
+          </>
+        )}
+        <PageSection variant={"light"}>
+          {isStoredConfigValid ? (
+            <EmptyState>
+              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
+              <TextContent>
+                <Text component={"h2"}>{"Your Streams for Apache Kafka 
information is set."}</Text>
+              </TextContent>
+              <EmptyStateBody>
+                Deploying models with a KafkaSource attached to the service is 
<b>enabled</b>.
+                <br />
+                <b>Bootstrap server: </b>
+                <i>{config.bootstrapServer}</i>
+                <br />
+                <b>Topic: </b>
+                <i>{config.topic}</i>
+                <br />
+                <br />
+                <Button variant={ButtonVariant.tertiary} onClick={onReset}>
+                  Reset
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          ) : (
+            <EmptyState>
+              <EmptyStateIcon icon={AddCircleOIcon} />
+              <TextContent>
+                <Text component={"h2"}>No Streams for Apache Kafka information 
yet</Text>
+              </TextContent>
+              <EmptyStateBody>
+                To get started, add a Streams for Apache Kafka information.
+                <br />
+                <br />
+                <Button variant={ButtonVariant.primary} 
onClick={handleModalToggle} data-testid="add-connection-button">
+                  Add Streams for Apache Kafka
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          )}
+        </PageSection>
+      </PageSection>
+
+      <Modal
+        title="Add Streams for Apache Kafka"
+        isOpen={
+          isModalOpen &&
+          kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.STOPPED &&
+          !isStoredConfigValid
+        }
+        onClose={handleModalToggle}
+        variant={ModalVariant.large}
+      >
+        <Form>
+          {!isExtendedServicesRunning && (
+            <FormAlert>
+              <Alert
+                variant="danger"
+                title={
+                  <Text>
+                    Connect to{" "}
+                    <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>
+                      KIE Sandbox Extended Services
+                    </Link>{" "}
+                    before configuring your Streams for Apache Kafka instance
+                  </Text>
+                }
+                aria-live="polite"
+                isInline
+              />
+            </FormAlert>
+          )}
+          <FormGroup
+            label={"Bootstrap Server"}
+            labelIcon={
+              <Popover bodyContent={"The bootstrap server associated with your 
Streams for Apache Kafka instance."}>
+                <button
+                  type="button"
+                  aria-label="More info for bootstrap server field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="bootstrap-server-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="bootstrap-server-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="bootstrap-server-field"
+                name="bootstrap-server-field"
+                aria-label="Bootstrap server field"
+                aria-describedby="bootstrap-server-field-helper"
+                value={config.bootstrapServer}
+                onChange={onBootstrapServerChanged}
+                tabIndex={1}
+                data-testid="bootstrap-server-text-field"
+              />
+              <InputGroupText>
+                <Button
+                  isSmall
+                  variant="plain"
+                  aria-label="Clear bootstrap server button"
+                  onClick={onClearBootstraServer}
+                >
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <FormGroup
+            label={"Topic"}
+            labelIcon={
+              <Popover bodyContent={"The topic that messages will flow in."}>
+                <button
+                  type="button"
+                  aria-label="More info for topic field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="topic-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="topic-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="topic-field"
+                name="topic-field"
+                aria-label="Topic field"
+                aria-describedby="topic-field-helper"
+                value={config.topic}
+                onChange={onTopicChanged}
+                tabIndex={2}
+                data-testid="topic-text-field"
+              />
+              <InputGroupText>
+                <Button isSmall variant="plain" aria-label="Clear topic 
button" onClick={onClearTopic}>
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <TextContent>
+            <Text component={TextVariants.p}>
+              <b>Note</b>: You must also provide{" "}
+              <Link to={routes.settings.service_account.path({})}>Service 
Account</Link> so the connection with your
+              Streams for Apache Kafka instance can be properly established.
+            </Text>
+          </TextContent>
+          <ActionGroup>
+            <Button
+              isDisabled={!isCurrentConfigValid}
+              id="apache-kafka-config-apply-button"
+              key="save"
+              variant="primary"
+              onClick={onApply}
+              data-testid="apply-config-button"
+            >
+              Apply
+            </Button>
+          </ActionGroup>
+        </Form>
+      </Modal>
+    </Page>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/kafka/KafkaSettingsConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/kafka/KafkaSettingsConfig.tsx
new file mode 100644
index 0000000000..dde86edea1
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/kafka/KafkaSettingsConfig.tsx
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { makeCookieName, getCookie, setCookie } from "../../cookies";
+
+export const KAFKA_BOOTSTRAP_SERVER_COOKIE_NAME = makeCookieName("kafka", 
"bootstrap-server");
+export const KAFKA_TOPIC_COOKIE_NAME = makeCookieName("kafka", "topic");
+
+export interface KafkaSettingsConfig {
+  bootstrapServer: string;
+  topic: string;
+}
+
+export const EMPTY_CONFIG: KafkaSettingsConfig = {
+  bootstrapServer: "",
+  topic: "",
+};
+
+export function isKafkaConfigValid(config: KafkaSettingsConfig): boolean {
+  return isBootstrapServerValid(config.bootstrapServer) && 
isTopicValid(config.topic);
+}
+
+export function isBootstrapServerValid(bootstrapServer: string): boolean {
+  return bootstrapServer !== undefined && bootstrapServer.trim().length > 0;
+}
+
+export function isOAuthEndpointUriValid(oauthEndpointUri: string): boolean {
+  return oauthEndpointUri !== undefined && oauthEndpointUri.trim().length > 0;
+}
+
+export function isTopicValid(topic: string): boolean {
+  return topic !== undefined && topic.trim().length > 0;
+}
+
+export function readKafkaConfigCookie(): KafkaSettingsConfig {
+  return {
+    bootstrapServer: getCookie(KAFKA_BOOTSTRAP_SERVER_COOKIE_NAME) ?? "",
+    topic: getCookie(KAFKA_TOPIC_COOKIE_NAME) ?? "",
+  };
+}
+
+export function resetConfigCookie(): void {
+  saveConfigCookie(EMPTY_CONFIG);
+}
+
+export function saveBootstrapServerCookie(bootstrapServer: string): void {
+  setCookie(KAFKA_BOOTSTRAP_SERVER_COOKIE_NAME, bootstrapServer);
+}
+
+export function saveTopicCookie(topic: string): void {
+  setCookie(KAFKA_TOPIC_COOKIE_NAME, topic);
+}
+
+export function saveConfigCookie(config: KafkaSettingsConfig): void {
+  saveBootstrapServerCookie(config.bootstrapServer);
+  saveTopicCookie(config.topic);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettings.tsx
new file mode 100644
index 0000000000..8454b667cd
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettings.tsx
@@ -0,0 +1,151 @@
+/*
+ * 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 { OpenShiftConnection } from 
"@kie-tools-core/openshift/dist/service/OpenShiftConnection";
+import { Modal, ModalVariant } from "@patternfly/react-core";
+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 { 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";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import * as React from "react";
+import { useCallback, useState } from "react";
+import { Link } from "react-router-dom";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { routes } from "../../navigation/Routes";
+import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
+import { obfuscate } from "../github/GitHubSettings";
+import { useSettings, useSettingsDispatch } from "../SettingsContext";
+import { saveConfigCookie } from "./OpenShiftSettingsConfig";
+import { OpenShiftSettingsSimpleConfig } from 
"./OpenShiftSettingsSimpleConfig";
+
+export function OpenShiftSettings() {
+  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: OpenShiftConnection = {
+      namespace: settings.openshift.config.namespace,
+      host: settings.openshift.config.host,
+      token: "",
+    };
+    settingsDispatch.openshift.setConfig(newConfig);
+    saveConfigCookie(newConfig);
+  }, [settings.openshift.config, settingsDispatch.openshift]);
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>OpenShift</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 />
+                <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>
+
+      <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}
+      >
+        <OpenShiftSettingsSimpleConfig />
+      </Modal>
+    </Page>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsConfig.tsx
new file mode 100644
index 0000000000..26ffc405ea
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsConfig.tsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { OpenShiftConnection } from 
"@kie-tools-core/openshift/dist/service/OpenShiftConnection";
+import { makeCookieName, getCookie, setCookie } from "../../cookies";
+
+export const OPENSHIFT_NAMESPACE_COOKIE_NAME = makeCookieName("openshift", 
"namespace");
+export const OPENSHIFT_HOST_COOKIE_NAME = makeCookieName("openshift", "host");
+export const OPENSHIFT_TOKEN_COOKIE_NAME = makeCookieName("openshift", 
"token");
+
+export const EMPTY_CONFIG: OpenShiftConnection = {
+  namespace: "",
+  host: "",
+  token: "",
+};
+
+export function readOpenShiftConfigCookie(): OpenShiftConnection {
+  return {
+    namespace: getCookie(OPENSHIFT_NAMESPACE_COOKIE_NAME) ?? "",
+    host: getCookie(OPENSHIFT_HOST_COOKIE_NAME) ?? "",
+    token: getCookie(OPENSHIFT_TOKEN_COOKIE_NAME) ?? "",
+  };
+}
+
+export function resetConfigCookie(): void {
+  saveConfigCookie(EMPTY_CONFIG);
+}
+
+export function saveNamespaceCookie(namespace: string): void {
+  setCookie(OPENSHIFT_NAMESPACE_COOKIE_NAME, namespace);
+}
+
+export function saveHostCookie(host: string): void {
+  setCookie(OPENSHIFT_HOST_COOKIE_NAME, host);
+}
+
+export function saveTokenCookie(token: string): void {
+  setCookie(OPENSHIFT_TOKEN_COOKIE_NAME, token);
+}
+
+export function saveConfigCookie(config: OpenShiftConnection): void {
+  saveNamespaceCookie(config.namespace);
+  saveHostCookie(config.host);
+  saveTokenCookie(config.token);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsSimpleConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsSimpleConfig.tsx
new file mode 100644
index 0000000000..4069b01132
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/openshift/OpenShiftSettingsSimpleConfig.tsx
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+  isOpenShiftConnectionValid,
+  OpenShiftConnection,
+} from "@kie-tools-core/openshift/dist/service/OpenShiftConnection";
+import { Alert } from "@patternfly/react-core/dist/js/components/Alert";
+import { Button } from "@patternfly/react-core/dist/js/components/Button";
+import { ActionGroup, Form, FormAlert, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup, InputGroupText } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
+import { Text } from "@patternfly/react-core/dist/js/components/Text";
+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 * as React from "react";
+import { useCallback, useEffect, useState } from "react";
+import { Link } from "react-router-dom";
+import { useAppI18n } from "../../i18n";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { routes } from "../../navigation/Routes";
+import { OpenShiftInstanceStatus } from 
"../../openshift/OpenShiftInstanceStatus";
+import { useSettings, useSettingsDispatch } from "../SettingsContext";
+import { EMPTY_CONFIG, saveConfigCookie } from "./OpenShiftSettingsConfig";
+
+enum FormValiationOptions {
+  INITIAL = "INITIAL",
+  INVALID = "INVALID",
+  CONNECTION_ERROR = "CONNECTION_ERROR",
+  CONFIG_EXPIRED = "CONFIG_EXPIRED",
+}
+
+export function OpenShiftSettingsSimpleConfig() {
+  const { i18n } = useAppI18n();
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const [config, setConfig] = useState(settings.openshift.config);
+  const [isConfigValidated, setConfigValidated] = 
useState(FormValiationOptions.INITIAL);
+  const [isConnecting, setConnecting] = useState(false);
+  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+
+  useEffect(() => {
+    setConfig(settings.openshift.config);
+    setConfigValidated(
+      settings.openshift.status === OpenShiftInstanceStatus.EXPIRED
+        ? FormValiationOptions.CONFIG_EXPIRED
+        : FormValiationOptions.INITIAL
+    );
+  }, [settings.openshift.config, settings.openshift.status]);
+
+  const resetConfig = useCallback(
+    (config: OpenShiftConnection) => {
+      setConfigValidated(
+        settings.openshift.status === OpenShiftInstanceStatus.EXPIRED && 
config !== EMPTY_CONFIG
+          ? FormValiationOptions.CONFIG_EXPIRED
+          : FormValiationOptions.INITIAL
+      );
+      setConnecting(false);
+      setConfig(config);
+    },
+    [settings.openshift.status]
+  );
+
+  const onConnect = useCallback(async () => {
+    if (isConnecting) {
+      return;
+    }
+
+    if (!isOpenShiftConnectionValid(config)) {
+      setConfigValidated(FormValiationOptions.INVALID);
+      return;
+    }
+
+    setConnecting(true);
+    const isConfigOk = await 
settingsDispatch.openshift.service.isConnectionEstablished(config);
+
+    setConnecting(false);
+
+    if (!isConfigOk) {
+      setConfigValidated(FormValiationOptions.CONNECTION_ERROR);
+      return;
+    }
+
+    saveConfigCookie(config);
+    settingsDispatch.openshift.setConfig(config);
+    resetConfig(config);
+    settingsDispatch.openshift.setStatus(OpenShiftInstanceStatus.CONNECTED);
+  }, [config, isConnecting, resetConfig, settingsDispatch.openshift]);
+
+  const onClearHost = useCallback(() => setConfig({ ...config, host: "" }), 
[config]);
+  const onClearNamespace = useCallback(() => setConfig({ ...config, namespace: 
"" }), [config]);
+  const onClearToken = useCallback(() => setConfig({ ...config, token: "" }), 
[config]);
+
+  const onHostChanged = useCallback(
+    (newValue: string) => {
+      setConfig({ ...config, host: newValue });
+    },
+    [config]
+  );
+
+  const onNamespaceChanged = useCallback(
+    (newValue: string) => {
+      setConfig({ ...config, namespace: newValue });
+    },
+    [config]
+  );
+
+  const onTokenChanged = useCallback(
+    (newValue: string) => {
+      setConfig({ ...config, token: newValue });
+    },
+    [config]
+  );
+
+  return (
+    <>
+      <Form>
+        {kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.RUNNING && (
+          <FormAlert>
+            <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
+            />
+          </FormAlert>
+        )}
+        {isConfigValidated === FormValiationOptions.INVALID && (
+          <FormAlert>
+            <Alert
+              variant="danger"
+              title={i18n.openshift.configModal.validationError}
+              aria-live="polite"
+              isInline
+              data-testid="alert-validation-error"
+            />
+          </FormAlert>
+        )}
+        {isConfigValidated === FormValiationOptions.CONNECTION_ERROR && (
+          <FormAlert>
+            <Alert
+              variant="danger"
+              title={i18n.openshift.configModal.connectionError}
+              aria-live="polite"
+              isInline
+              data-testid="alert-connection-error"
+            />
+          </FormAlert>
+        )}
+        {isConfigValidated === FormValiationOptions.CONFIG_EXPIRED && (
+          <FormAlert>
+            <Alert
+              variant="warning"
+              title={i18n.openshift.configModal.configExpiredWarning}
+              aria-live="polite"
+              isInline
+              data-testid="alert-config-expired-warning"
+            />
+          </FormAlert>
+        )}
+        <FormGroup
+          label={i18n.terms.namespace}
+          labelIcon={
+            <Popover bodyContent={i18n.openshift.configModal.namespaceInfo}>
+              <button
+                type="button"
+                aria-label="More info for namespace field"
+                onClick={(e) => e.preventDefault()}
+                aria-describedby="namespace-field"
+                className="pf-c-form__group-label-help"
+              >
+                <HelpIcon noVerticalAlign />
+              </button>
+            </Popover>
+          }
+          isRequired
+          fieldId="namespace-field"
+        >
+          <InputGroup className="pf-u-mt-sm">
+            <TextInput
+              autoComplete={"off"}
+              isRequired
+              type="text"
+              id="namespace-field"
+              name="namespace-field"
+              aria-label="Namespace field"
+              aria-describedby="namespace-field-helper"
+              value={config.namespace}
+              onChange={onNamespaceChanged}
+              isDisabled={isConnecting}
+              tabIndex={1}
+              data-testid="namespace-text-field"
+            />
+            <InputGroupText>
+              <Button isSmall variant="plain" aria-label="Clear namespace 
button" onClick={onClearNamespace}>
+                <TimesIcon />
+              </Button>
+            </InputGroupText>
+          </InputGroup>
+        </FormGroup>
+        <FormGroup
+          label={i18n.terms.host}
+          labelIcon={
+            <Popover bodyContent={i18n.openshift.configModal.hostInfo}>
+              <button
+                type="button"
+                aria-label="More info for host field"
+                onClick={(e) => e.preventDefault()}
+                aria-describedby="host-field"
+                className="pf-c-form__group-label-help"
+              >
+                <HelpIcon noVerticalAlign />
+              </button>
+            </Popover>
+          }
+          isRequired
+          fieldId="host-field"
+        >
+          <InputGroup className="pf-u-mt-sm">
+            <TextInput
+              autoComplete={"off"}
+              isRequired
+              type="text"
+              id="host-field"
+              name="host-field"
+              aria-label="Host field"
+              aria-describedby="host-field-helper"
+              value={config.host}
+              onChange={onHostChanged}
+              isDisabled={isConnecting}
+              tabIndex={2}
+              data-testid="host-text-field"
+            />
+            <InputGroupText>
+              <Button isSmall variant="plain" aria-label="Clear host button" 
onClick={onClearHost}>
+                <TimesIcon />
+              </Button>
+            </InputGroupText>
+          </InputGroup>
+        </FormGroup>
+        <FormGroup
+          label={i18n.terms.token}
+          labelIcon={
+            <Popover bodyContent={i18n.openshift.configModal.tokenInfo}>
+              <button
+                type="button"
+                aria-label="More info for token field"
+                onClick={(e) => e.preventDefault()}
+                aria-describedby="token-field"
+                className="pf-c-form__group-label-help"
+              >
+                <HelpIcon noVerticalAlign />
+              </button>
+            </Popover>
+          }
+          isRequired
+          fieldId="token-field"
+        >
+          <InputGroup className="pf-u-mt-sm">
+            <TextInput
+              autoComplete={"off"}
+              isRequired
+              type="text"
+              id="token-field"
+              name="token-field"
+              aria-label="Token field"
+              aria-describedby="token-field-helper"
+              value={config.token}
+              onChange={onTokenChanged}
+              isDisabled={isConnecting}
+              tabIndex={3}
+              data-testid="token-text-field"
+            />
+            <InputGroupText>
+              <Button isSmall variant="plain" aria-label="Clear token button" 
onClick={onClearToken}>
+                <TimesIcon />
+              </Button>
+            </InputGroupText>
+          </InputGroup>
+        </FormGroup>
+        <ActionGroup>
+          <Button
+            id="openshift-config-save-button"
+            key="save"
+            variant="primary"
+            onClick={onConnect}
+            data-testid="save-config-button"
+            isLoading={isConnecting}
+            isDisabled={kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.RUNNING}
+            spinnerAriaValueText={isConnecting ? "Loading" : undefined}
+          >
+            {isConnecting ? "Connecting" : "Connect"}
+          </Button>
+        </ActionGroup>
+      </Form>
+    </>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/routes/SettingsPageRoutes.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/routes/SettingsPageRoutes.tsx
new file mode 100644
index 0000000000..56f678e3b0
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/routes/SettingsPageRoutes.tsx
@@ -0,0 +1,59 @@
+/*
+ * 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 { Redirect, Switch } from "react-router";
+import { Route } from "react-router-dom";
+import { useRoutes } from "../../navigation/Hooks";
+import { GitHubSettings } from "../github/GitHubSettings";
+import { KieSandboxExtendedServicesSettings } from 
"../extendedServices/KieSandboxExtendedServicesSettings";
+import { FeaturePreviewSettings } from 
"../featurePreview/FeaturePreviewSettings";
+import { ApacheKafkaSettings } from "../kafka/ApacheKafkaSettings";
+import { OpenShiftSettings } from "../openshift/OpenShiftSettings";
+import { ServiceAccountSettings } from 
"../serviceAccount/ServiceAccountSettings";
+import { ServiceRegistrySettings } from 
"../serviceRegistry/ServiceRegistrySettings";
+
+export function SettingsPageRoutes() {
+  const routes = useRoutes();
+  return (
+    <Switch>
+      <Route path={routes.settings.github.path({})}>
+        <GitHubSettings />
+      </Route>
+      <Route path={routes.settings.kie_sandbox_extended_services.path({})}>
+        <KieSandboxExtendedServicesSettings />
+      </Route>
+      <Route path={routes.settings.openshift.path({})}>
+        <OpenShiftSettings />
+      </Route>
+      <Route path={routes.settings.service_account.path({})}>
+        <ServiceAccountSettings />
+      </Route>
+      <Route path={routes.settings.service_registry.path({})}>
+        <ServiceRegistrySettings />
+      </Route>
+      <Route path={routes.settings.kafka.path({})}>
+        <ApacheKafkaSettings />
+      </Route>
+      <Route path={routes.settings.feature_preview.path({})}>
+        <FeaturePreviewSettings />
+      </Route>
+      <Route>
+        <Redirect to={routes.settings.github.path({})} />
+      </Route>
+    </Switch>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountConfig.tsx
new file mode 100644
index 0000000000..1b9bb2d77a
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountConfig.tsx
@@ -0,0 +1,66 @@
+/*
+ * 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 { makeCookieName, getCookie, setCookie } from "../../cookies";
+
+export const SERVICE_ACCOUNT_CLIENT_ID_COOKIE_NAME = 
makeCookieName("service-account", "client-id");
+export const SERVICE_ACCOUNT_CLIENT_SECRET_COOKIE_NAME = 
makeCookieName("service-account", "client-secret");
+
+export interface ServiceAccountSettingsConfig {
+  clientId: string;
+  clientSecret: string;
+}
+
+export const EMPTY_CONFIG: ServiceAccountSettingsConfig = {
+  clientId: "",
+  clientSecret: "",
+};
+
+export function isServiceAccountConfigValid(config: 
ServiceAccountSettingsConfig): boolean {
+  return isClientIdValid(config.clientId) && 
isClientSecretValid(config.clientSecret);
+}
+
+export function isClientIdValid(clientId: string): boolean {
+  return clientId !== undefined && clientId.trim().length > 0;
+}
+
+export function isClientSecretValid(clientSecret: string): boolean {
+  return clientSecret !== undefined && clientSecret.trim().length > 0;
+}
+
+export function readServiceAccountConfigCookie(): ServiceAccountSettingsConfig 
{
+  return {
+    clientId: getCookie(SERVICE_ACCOUNT_CLIENT_ID_COOKIE_NAME) ?? "",
+    clientSecret: getCookie(SERVICE_ACCOUNT_CLIENT_SECRET_COOKIE_NAME) ?? "",
+  };
+}
+
+export function resetConfigCookie(): void {
+  saveConfigCookie(EMPTY_CONFIG);
+}
+
+export function saveClientIdCookie(clientId: string): void {
+  setCookie(SERVICE_ACCOUNT_CLIENT_ID_COOKIE_NAME, clientId);
+}
+
+export function saveClientSecretCookie(clientSecret: string): void {
+  setCookie(SERVICE_ACCOUNT_CLIENT_SECRET_COOKIE_NAME, clientSecret);
+}
+
+export function saveConfigCookie(config: ServiceAccountSettingsConfig): void {
+  saveClientIdCookie(config.clientId);
+  saveClientSecretCookie(config.clientSecret);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountSettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountSettings.tsx
new file mode 100644
index 0000000000..5b7ebde91e
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/serviceAccount/ServiceAccountSettings.tsx
@@ -0,0 +1,307 @@
+/*
+ * 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 { Modal, ModalVariant } from "@patternfly/react-core";
+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 { ActionGroup, Form, FormAlert, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup, InputGroupText } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
+import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
+import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
+import { AddCircleOIcon } from "@patternfly/react-icons";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import { Link } from "react-router-dom";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { routes } from "../../navigation/Routes";
+import { useSettings, useSettingsDispatch } from "../SettingsContext";
+import { EMPTY_CONFIG, isServiceAccountConfigValid, resetConfigCookie, 
saveConfigCookie } from "./ServiceAccountConfig";
+
+export function ServiceAccountSettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const [config, setConfig] = useState(settings.serviceAccount.config);
+  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+  const [isModalOpen, setIsModalOpen] = useState(false);
+
+  const handleModalToggle = useCallback(() => {
+    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
+  }, []);
+
+  const isExtendedServicesRunning = useMemo(
+    () => kieSandboxExtendedServices.status === 
KieSandboxExtendedServicesStatus.RUNNING,
+    [kieSandboxExtendedServices.status]
+  );
+
+  const isStoredConfigValid = useMemo(
+    () => isExtendedServicesRunning && 
isServiceAccountConfigValid(settings.serviceAccount.config),
+    [isExtendedServicesRunning, settings.serviceAccount.config]
+  );
+
+  const isCurrentConfigValid = useMemo(
+    () => isExtendedServicesRunning && isServiceAccountConfigValid(config),
+    [config, isExtendedServicesRunning]
+  );
+
+  const onClearClientId = useCallback(() => setConfig({ ...config, clientId: 
"" }), [config]);
+  const onClearClientSecret = useCallback(() => setConfig({ ...config, 
clientSecret: "" }), [config]);
+
+  const onClientIdChanged = useCallback(
+    (newValue: string) => {
+      setConfig({ ...config, clientId: newValue });
+    },
+    [config]
+  );
+
+  const onClientSecretChanged = useCallback(
+    (newValue: string) => {
+      setConfig({ ...config, clientSecret: newValue });
+    },
+    [config]
+  );
+
+  const onReset = useCallback(() => {
+    setConfig(EMPTY_CONFIG);
+    settingsDispatch.serviceAccount.setConfig(EMPTY_CONFIG);
+    resetConfigCookie();
+  }, [settingsDispatch.serviceAccount]);
+
+  const onApply = useCallback(() => {
+    settingsDispatch.serviceAccount.setConfig(config);
+    saveConfigCookie(config);
+  }, [config, settingsDispatch.serviceAccount]);
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>Service Account</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for uploading Open API specs 
associated with models you design to your
+            Service Registry instance and also connecting deployments with 
your Streams for Apache Kafka 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 Service Account instance
+                </Text>
+              }
+              aria-live="polite"
+              isInline
+            >
+              KIE Sandbox Extended Services is necessary for uploading Open 
API specs associated with models you design
+              to your Service Registry instance and also connecting 
deployments with your Streams for Apache Kafka
+              instance.
+            </Alert>
+            <br />
+          </>
+        )}
+        <PageSection variant={"light"}>
+          {isStoredConfigValid ? (
+            <EmptyState>
+              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
+              <TextContent>
+                <Text component={"h2"}>{"Your Service Account information is 
set."}</Text>
+              </TextContent>
+              <EmptyStateBody>
+                Accessing your Service Registry and Streams for Apache Kafka 
is <b>enabled</b>.
+                <br />
+                <b>Client ID: </b>
+                <i>{config.clientId}</i>
+                <br />
+                <b>Client secret: </b>
+                <i>{obfuscate(config.clientSecret)}</i>
+                <br />
+                <br />
+                <Button variant={ButtonVariant.tertiary} onClick={onReset}>
+                  Reset
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          ) : (
+            <EmptyState>
+              <EmptyStateIcon icon={AddCircleOIcon} />
+              <TextContent>
+                <Text component={"h2"}>No Service Accounts yet</Text>
+              </TextContent>
+              <EmptyStateBody>
+                To get started, add a service account.
+                <br />
+                <br />
+                <Button variant={ButtonVariant.primary} 
onClick={handleModalToggle} data-testid="add-connection-button">
+                  Add service account
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          )}
+        </PageSection>
+      </PageSection>
+
+      <Modal
+        title="Add Service Account"
+        isOpen={
+          isModalOpen &&
+          kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.STOPPED &&
+          !isStoredConfigValid
+        }
+        onClose={handleModalToggle}
+        variant={ModalVariant.large}
+      >
+        <Form>
+          {!isExtendedServicesRunning && (
+            <FormAlert>
+              <Alert
+                variant="danger"
+                title={
+                  <Text>
+                    Connect to{" "}
+                    <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>
+                      KIE Sandbox Extended Services
+                    </Link>{" "}
+                    before configuring your Service Account
+                  </Text>
+                }
+                aria-live="polite"
+                isInline
+              />
+            </FormAlert>
+          )}
+          <FormGroup
+            label={"Client ID"}
+            labelIcon={
+              <Popover bodyContent={"Client ID"}>
+                <button
+                  type="button"
+                  aria-label="More info for client id field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="client-id-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="client-id-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="client-id-field"
+                name="client-id-field"
+                aria-label="Client ID field"
+                aria-describedby="client-id-field-helper"
+                value={config.clientId}
+                onChange={onClientIdChanged}
+                tabIndex={1}
+                data-testid="client-id-text-field"
+              />
+              <InputGroupText>
+                <Button isSmall variant="plain" aria-label="Clear client id 
button" onClick={onClearClientId}>
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <FormGroup
+            label={"Client Secret"}
+            labelIcon={
+              <Popover bodyContent={"Client Secret"}>
+                <button
+                  type="button"
+                  aria-label="More info for client secret field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="client-secret-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="client-secret-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="client-secret-field"
+                name="client-secret-field"
+                aria-label="Client secret field"
+                aria-describedby="client-secret-field-helper"
+                value={config.clientSecret}
+                onChange={onClientSecretChanged}
+                tabIndex={2}
+                data-testid="client-secret-text-field"
+              />
+              <InputGroupText>
+                <Button isSmall variant="plain" aria-label="Clear client 
secret button" onClick={onClearClientSecret}>
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <ActionGroup>
+            <Button
+              isDisabled={!isCurrentConfigValid}
+              id="service-account-config-apply-button"
+              key="save"
+              variant="primary"
+              onClick={onApply}
+              data-testid="apply-config-button"
+            >
+              Apply
+            </Button>
+          </ActionGroup>
+        </Form>
+      </Modal>
+    </Page>
+  );
+}
+
+export function obfuscate(token?: string) {
+  if (!token) {
+    return undefined;
+  }
+
+  if (token.length <= 10) {
+    return new Array(10).join("*");
+  }
+
+  const stars = new Array(token.length - 4).join("*");
+  const pieceToObfuscate = token.substring(0, token.length - 4);
+  return token.replace(pieceToObfuscate, stars);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistryConfig.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistryConfig.tsx
new file mode 100644
index 0000000000..49dad4fe02
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistryConfig.tsx
@@ -0,0 +1,66 @@
+/*
+ * 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 { getCookie, makeCookieName, setCookie } from "../../cookies";
+
+export const SERVICE_REGISTRY_NAME_COOKIE_NAME = 
makeCookieName("service-registry", "name");
+export const SERVICE_REGISTRY_CORE_REGISTRY_API_COOKIE_NAME = 
makeCookieName("service-registry", "core-registry-api");
+
+export interface ServiceRegistrySettingsConfig {
+  name: string;
+  coreRegistryApi: string;
+}
+
+export const EMPTY_CONFIG: ServiceRegistrySettingsConfig = {
+  name: "",
+  coreRegistryApi: "",
+};
+
+export function isServiceRegistryConfigValid(config: 
ServiceRegistrySettingsConfig): boolean {
+  return isNameValid(config.name) && 
isCoreRegistryApiValid(config.coreRegistryApi);
+}
+
+export function isNameValid(name: string): boolean {
+  return name !== undefined && name.trim().length > 0;
+}
+
+export function isCoreRegistryApiValid(coreRegistryApi: string): boolean {
+  return coreRegistryApi !== undefined && coreRegistryApi.trim().length > 0;
+}
+
+export function readServiceRegistryConfigCookie(): 
ServiceRegistrySettingsConfig {
+  return {
+    name: getCookie(SERVICE_REGISTRY_NAME_COOKIE_NAME) ?? "",
+    coreRegistryApi: getCookie(SERVICE_REGISTRY_CORE_REGISTRY_API_COOKIE_NAME) 
?? "",
+  };
+}
+
+export function resetConfigCookie(): void {
+  saveConfigCookie(EMPTY_CONFIG);
+}
+
+export function saveNameCookie(name: string): void {
+  setCookie(SERVICE_REGISTRY_NAME_COOKIE_NAME, name);
+}
+
+export function saveCoreRegistryApiCookie(coreRegistryApi: string): void {
+  setCookie(SERVICE_REGISTRY_CORE_REGISTRY_API_COOKIE_NAME, coreRegistryApi);
+}
+
+export function saveConfigCookie(config: ServiceRegistrySettingsConfig): void {
+  saveNameCookie(config.name);
+  saveCoreRegistryApiCookie(config.coreRegistryApi);
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistrySettings.tsx
 
b/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistrySettings.tsx
new file mode 100644
index 0000000000..2a4f4e5bfc
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/serviceRegistry/ServiceRegistrySettings.tsx
@@ -0,0 +1,305 @@
+/*
+ * 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 { Modal, ModalVariant } from "@patternfly/react-core";
+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 { ActionGroup, Form, FormAlert, FormGroup } from 
"@patternfly/react-core/dist/js/components/Form";
+import { InputGroup, InputGroupText } from 
"@patternfly/react-core/dist/js/components/InputGroup";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
+import { Text, TextContent, TextVariants } from 
"@patternfly/react-core/dist/js/components/Text";
+import { TextInput } from 
"@patternfly/react-core/dist/js/components/TextInput";
+import { AddCircleOIcon } from "@patternfly/react-icons";
+import { CheckCircleIcon } from 
"@patternfly/react-icons/dist/js/icons/check-circle-icon";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import { Link } from "react-router-dom";
+import { useKieSandboxExtendedServices } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesContext";
+import { KieSandboxExtendedServicesStatus } from 
"../../kieSandboxExtendedServices/KieSandboxExtendedServicesStatus";
+import { routes } from "../../navigation/Routes";
+import { useSettings, useSettingsDispatch } from "../SettingsContext";
+import {
+  EMPTY_CONFIG,
+  isServiceRegistryConfigValid,
+  resetConfigCookie,
+  saveConfigCookie,
+} from "./ServiceRegistryConfig";
+
+export function ServiceRegistrySettings() {
+  const settings = useSettings();
+  const settingsDispatch = useSettingsDispatch();
+  const [config, setConfig] = useState(settings.serviceRegistry.config);
+  const kieSandboxExtendedServices = useKieSandboxExtendedServices();
+  const [isModalOpen, setIsModalOpen] = useState(false);
+
+  const handleModalToggle = useCallback(() => {
+    setIsModalOpen((prevIsModalOpen) => !prevIsModalOpen);
+  }, []);
+
+  const isExtendedServicesRunning = useMemo(
+    () => kieSandboxExtendedServices.status === 
KieSandboxExtendedServicesStatus.RUNNING,
+    [kieSandboxExtendedServices.status]
+  );
+
+  const isStoredConfigValid = useMemo(
+    () => isExtendedServicesRunning && 
isServiceRegistryConfigValid(settings.serviceRegistry.config),
+    [isExtendedServicesRunning, settings.serviceRegistry.config]
+  );
+
+  const isCurrentConfigValid = useMemo(
+    () => isExtendedServicesRunning && isServiceRegistryConfigValid(config),
+    [isExtendedServicesRunning, config]
+  );
+
+  const onClearName = useCallback(() => setConfig({ ...config, name: "" }), 
[config]);
+
+  const onClearCoreRegistryApi = useCallback(() => setConfig({ ...config, 
coreRegistryApi: "" }), [config]);
+
+  const onNameChanged = useCallback((newValue: string) => setConfig({ 
...config, name: newValue }), [config]);
+
+  const onCoreRegistryApiChanged = useCallback(
+    (newValue: string) => setConfig({ ...config, coreRegistryApi: newValue }),
+    [config]
+  );
+
+  const onReset = useCallback(() => {
+    setConfig(EMPTY_CONFIG);
+    settingsDispatch.serviceRegistry.setConfig(EMPTY_CONFIG);
+    resetConfigCookie();
+  }, [settingsDispatch.serviceRegistry]);
+
+  const onApply = useCallback(() => {
+    settingsDispatch.serviceRegistry.setConfig(config);
+    saveConfigCookie(config);
+  }, [config, settingsDispatch.serviceRegistry]);
+
+  return (
+    <Page>
+      <PageSection variant={"light"} isWidthLimited>
+        <TextContent>
+          <Text component={TextVariants.h1}>Service Registry</Text>
+          <Text component={TextVariants.p}>
+            Data you provide here is necessary for uploading Open API specs 
associated with models you design to your
+            Service Registry instance.
+            <br /> All information is locally stored in your browser and never 
shared with anyone.
+          </Text>
+        </TextContent>
+      </PageSection>
+
+      <PageSection>
+        {!isExtendedServicesRunning && (
+          <>
+            <Alert
+              variant="danger"
+              title={
+                <Text>
+                  Connect to{" "}
+                  <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>KIE Sandbox 
Extended Services</Link>{" "}
+                  before configuring your Service Registry instance
+                </Text>
+              }
+              aria-live="polite"
+              isInline
+            >
+              KIE Sandbox Extended Services is necessary for uploading Open 
API specs associated with models you design
+              to your Service Registry instance.
+            </Alert>
+            <br />
+          </>
+        )}
+        <PageSection variant={"light"}>
+          {isStoredConfigValid ? (
+            <EmptyState>
+              <EmptyStateIcon icon={CheckCircleIcon} 
color={"var(--pf-global--success-color--100)"} />
+              <TextContent>
+                <Text component={"h2"}>{"Your Service Registry information is 
set."}</Text>
+              </TextContent>
+              <EmptyStateBody>
+                Uploading OpenAPI specs when deploying models is 
<b>enabled</b>.
+                <br />
+                <b>Service Registry Name: </b>
+                <i>{config.name}</i>
+                <br />
+                <b>Core Registry Api: </b>
+                <i>{config.coreRegistryApi}</i>
+                <br />
+                <br />
+                <Button variant={ButtonVariant.tertiary} onClick={onReset}>
+                  Reset
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          ) : (
+            <EmptyState>
+              <EmptyStateIcon icon={AddCircleOIcon} />
+              <TextContent>
+                <Text component={"h2"}>No Service Registry yet</Text>
+              </TextContent>
+              <EmptyStateBody>
+                To get started, add a service registry.
+                <br />
+                <br />
+                <Button variant={ButtonVariant.primary} 
onClick={handleModalToggle} data-testid="add-connection-button">
+                  Add service registry
+                </Button>
+              </EmptyStateBody>
+            </EmptyState>
+          )}
+        </PageSection>
+      </PageSection>
+
+      <Modal
+        title="Add Service Registry"
+        isOpen={
+          isModalOpen &&
+          kieSandboxExtendedServices.status !== 
KieSandboxExtendedServicesStatus.STOPPED &&
+          !isStoredConfigValid
+        }
+        onClose={handleModalToggle}
+        variant={ModalVariant.large}
+      >
+        <Form>
+          {!isExtendedServicesRunning && (
+            <FormAlert>
+              <Alert
+                variant="danger"
+                title={
+                  <Text>
+                    Connect to{" "}
+                    <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>
+                      KIE Sandbox Extended Services
+                    </Link>{" "}
+                    before configuring your Service Registry instance
+                  </Text>
+                }
+                aria-live="polite"
+                isInline
+              />
+            </FormAlert>
+          )}
+          <FormGroup
+            label={"Name"}
+            labelIcon={
+              <Popover
+                bodyContent={"Name to identify your Service Registry instance 
across the Serverless Logic Web Tools."}
+              >
+                <button
+                  type="button"
+                  aria-label="More info for name field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="name-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="name-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="name-field"
+                name="name-field"
+                aria-label="Name field"
+                aria-describedby="name-field-helper"
+                value={config.name}
+                onChange={onNameChanged}
+                tabIndex={1}
+                data-testid="name-text-field"
+              />
+              <InputGroupText>
+                <Button isSmall variant="plain" aria-label="Clear name button" 
onClick={onClearName}>
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <FormGroup
+            label={"Core Registry API"}
+            labelIcon={
+              <Popover bodyContent={"Core Registry API URL associated with 
your Service Registry instance."}>
+                <button
+                  type="button"
+                  aria-label="More info for core registry api field"
+                  onClick={(e) => e.preventDefault()}
+                  aria-describedby="core-registry-api-field"
+                  className="pf-c-form__group-label-help"
+                >
+                  <HelpIcon noVerticalAlign />
+                </button>
+              </Popover>
+            }
+            isRequired
+            fieldId="core-registry-api-field"
+          >
+            <InputGroup className="pf-u-mt-sm">
+              <TextInput
+                autoComplete={"off"}
+                isRequired
+                type="text"
+                id="core-registry-api-field"
+                name="core-registry-api-field"
+                aria-label="Core Registry API field"
+                aria-describedby="core-registry-api-field-helper"
+                value={config.coreRegistryApi}
+                onChange={onCoreRegistryApiChanged}
+                tabIndex={2}
+                data-testid="core-registry-api-text-field"
+              />
+              <InputGroupText>
+                <Button
+                  isSmall
+                  variant="plain"
+                  aria-label="Clear core registry api button"
+                  onClick={onClearCoreRegistryApi}
+                >
+                  <TimesIcon />
+                </Button>
+              </InputGroupText>
+            </InputGroup>
+          </FormGroup>
+          <TextContent>
+            <Text component={TextVariants.p}>
+              <b>Note</b>: You must also provide{" "}
+              <Link to={routes.settings.service_account.path({})}>Service 
Account</Link> so the connection with your
+              Service Registry instance can be properly established.
+            </Text>
+          </TextContent>
+          <ActionGroup>
+            <Button
+              isDisabled={!isCurrentConfigValid}
+              id="service-registry-config-apply-button"
+              key="save"
+              variant="primary"
+              onClick={onApply}
+              data-testid="apply-config-button"
+            >
+              Apply
+            </Button>
+          </ActionGroup>
+        </Form>
+      </Modal>
+    </Page>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/newSettings/uiNav/SettingsPageNav.tsx 
b/packages/serverless-logic-web-tools/src/newSettings/uiNav/SettingsPageNav.tsx
new file mode 100644
index 0000000000..2d0ef44cdd
--- /dev/null
+++ 
b/packages/serverless-logic-web-tools/src/newSettings/uiNav/SettingsPageNav.tsx
@@ -0,0 +1,75 @@
+/*
+ * 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 { Nav, NavItem, NavList } from "@patternfly/react-core";
+import * as React from "react";
+import { Link } from "react-router-dom";
+import { useRoutes } from "../../navigation/Hooks";
+
+export function SettingsPageNav(props: { pathname: string }) {
+  const routes = useRoutes();
+
+  return (
+    <>
+      <div className="chr-c-app-title">Settings</div>
+      <Nav aria-label="Global NAV" theme="dark">
+        <NavList>
+          <NavItem itemId={0} key={`Settings-github-nav`} 
isActive={props.pathname === routes.settings.github.path({})}>
+            <Link to={routes.settings.github.path({})}>GitHub</Link>
+          </NavItem>
+          <NavItem
+            itemId={0}
+            key={`Settings-kie_sandbox_extended_services-nav`}
+            isActive={props.pathname === 
routes.settings.kie_sandbox_extended_services.path({})}
+          >
+            <Link 
to={routes.settings.kie_sandbox_extended_services.path({})}>KIE Sandbox 
Extended Services</Link>
+          </NavItem>
+          <NavItem
+            itemId={0}
+            key={`Settings-openshift-nav`}
+            isActive={props.pathname === routes.settings.openshift.path({})}
+          >
+            <Link to={routes.settings.openshift.path({})}>OpenShift</Link>
+          </NavItem>
+          <NavItem
+            itemId={0}
+            key={`Settings-service_account-nav`}
+            isActive={props.pathname === 
routes.settings.service_account.path({})}
+          >
+            <Link to={routes.settings.service_account.path({})}>Service 
Account</Link>
+          </NavItem>
+          <NavItem
+            itemId={0}
+            key={`Settings-service_registry-nav`}
+            isActive={props.pathname === 
routes.settings.service_registry.path({})}
+          >
+            <Link to={routes.settings.service_registry.path({})}>Service 
Registry</Link>
+          </NavItem>
+          <NavItem itemId={0} key={`Settings-kafka-nav`} 
isActive={props.pathname === routes.settings.kafka.path({})}>
+            <Link to={routes.settings.kafka.path({})}>Streams for Apache 
Kafka</Link>
+          </NavItem>
+          <NavItem
+            itemId={0}
+            key={`Settings-feature_preview-nav`}
+            isActive={props.pathname === 
routes.settings.feature_preview.path({})}
+          >
+            <Link to={routes.settings.feature_preview.path({})}>Feature 
Preview</Link>
+          </NavItem>
+        </NavList>
+      </Nav>
+    </>
+  );
+}
diff --git 
a/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx 
b/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
index 242e71c961..2abccb1650 100644
--- a/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
+++ b/packages/serverless-logic-web-tools/src/settings/SettingsContext.tsx
@@ -25,8 +25,8 @@ import { readOpenShiftConfigCookie } from 
"./openshift/OpenShiftSettingsConfig";
 import { OpenShiftConnection } from 
"@kie-tools-core/openshift/dist/service/OpenShiftConnection";
 import { OpenShiftInstanceStatus } from "../openshift/OpenShiftInstanceStatus";
 import { OpenShiftService } from 
"@kie-tools-core/openshift/dist/service/OpenShiftService";
-import { useHistory } from "react-router";
-import { QueryParams } from "../navigation/Routes";
+import { useHistory, useRouteMatch } from "react-router";
+import { QueryParams, routes } from "../navigation/Routes";
 import { GITHUB_AUTH_TOKEN_COOKIE_NAME } from "./github/GitHubSettingsTab";
 import { KafkaSettingsConfig, readKafkaConfigCookie } from 
"./kafka/KafkaSettingsConfig";
 import { readServiceAccountConfigCookie, ServiceAccountSettingsConfig } from 
"./serviceAccount/ServiceAccountConfig";
@@ -136,6 +136,7 @@ export function SettingsContextProvider(props: any) {
   const history = useHistory();
   const [isOpen, setOpen] = useState(false);
   const [activeTab, setActiveTab] = useState(SettingsTabs.GITHUB);
+  const isRouteInSettingsSection = 
useRouteMatch(routes.settings.home.path({}));
 
   useEffect(() => {
     setOpen(queryParams.has(QueryParams.SETTINGS));
@@ -343,8 +344,13 @@ export function SettingsContextProvider(props: any) {
   return (
     <SettingsContext.Provider value={value}>
       <SettingsDispatchContext.Provider value={dispatch}>
-        {githubAuthStatus !== AuthStatus.LOADING && <>{props.children}</>}
-        <Modal title="Settings" isOpen={isOpen} onClose={close} 
variant={ModalVariant.large}>
+        {(isRouteInSettingsSection || githubAuthStatus !== AuthStatus.LOADING) 
&& <>{props.children}</>}
+        <Modal
+          title="Settings"
+          isOpen={!isRouteInSettingsSection && isOpen}
+          onClose={close}
+          variant={ModalVariant.large}
+        >
           <div style={{ height: "calc(100vh * 0.5)" }} 
className={"kie-tools--settings-modal-content"}>
             <SettingsModalBody />
           </div>
diff --git a/packages/serverless-logic-web-tools/static/resources/style.css 
b/packages/serverless-logic-web-tools/static/resources/style.css
index f6ecff2555..b54a7c8b6e 100644
--- a/packages/serverless-logic-web-tools/static/resources/style.css
+++ b/packages/serverless-logic-web-tools/static/resources/style.css
@@ -652,3 +652,15 @@ section.kie-tools--settings-tab {
 .pf-c-masthead__main::before {
   display: none;
 }
+
+.chr-c-app-title {
+  color: #fff;
+  padding: var(--pf-global--spacer--md) var(--pf-global--spacer--sm) 
var(--pf-global--spacer--md)
+    var(--pf-global--spacer--lg);
+  width: 100%;
+  border-bottom: var(--pf-global--spacer--xs) solid 
var(--pf-global--Color--300);
+  font-weight: var(--pf-global--FontWeight--semi-bold);
+  white-space: normal;
+  text-align: left;
+  font-size: 17px;
+}


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

Reply via email to