diff --git a/.eslintrc.json b/.eslintrc.json
index 6d62c78893..c908e6055f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -6,6 +6,7 @@
"node": true
},
"parserOptions": {
+ "ecmaVersion": "latest",
"project": [
"apps/*/tsconfig.eslint.json",
"libs/*/tsconfig.eslint.json",
@@ -21,6 +22,9 @@
"ignorePatterns": [
"apps/*/build",
"libs/*/build",
- "tools/*/build"
+ "tools/*/build",
+ "apps/*/dist",
+ "libs/*/dist",
+ "tools/*/dist"
]
}
diff --git a/.gitignore b/.gitignore
index 795c698c66..d12bece289 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,8 +38,3 @@ package-lock.json
!.yarn/releases
!.yarn/sdks
!.yarn/versions
-
-# Ignored apps
-apps/*
-!apps/assisted-ui
-!apps/assisted-disconnected-ui
diff --git a/apps/assisted-chatbot/.eslintrc.cjs b/apps/assisted-chatbot/.eslintrc.cjs
new file mode 100644
index 0000000000..96e1ba897f
--- /dev/null
+++ b/apps/assisted-chatbot/.eslintrc.cjs
@@ -0,0 +1,39 @@
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ overrides: [
+ {
+ files: ['./vite.config.ts'],
+ extends: ['@openshift-assisted/eslint-config'],
+ env: {
+ browser: false,
+ },
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ },
+ rules: {
+ 'no-console': 'off',
+ },
+ },
+ {
+ files: ['./src/**/*.{ts,tsx}'],
+ extends: ['@openshift-assisted/eslint-config', 'plugin:react/jsx-runtime'],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ },
+ rules: {
+ 'no-restricted-imports': [
+ 'error',
+ {
+ paths: [
+ {
+ name: 'react-i18next',
+ importNames: ['useTranslation'],
+ message: 'Import `useTranslation` from `@openshift-assisted/ui-lib/common` instead',
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+};
diff --git a/apps/assisted-chatbot/README.md b/apps/assisted-chatbot/README.md
new file mode 100644
index 0000000000..19f40a01b2
--- /dev/null
+++ b/apps/assisted-chatbot/README.md
@@ -0,0 +1,19 @@
+# Assisted Installer Chatbot UI
+
+This is a federated module for
+[Astro Virtual Assistant UI](https://github.com/RedHatInsights/astro-virtual-assistant-frontend)
+
+## Run the project
+
+1. Run the Astro
+ 1. For now you need to use my fork which can load this new assisted chatbot module - clone the
+ repo
+ [Astro fork](https://github.com/rawagner/astro-virtual-assistant-frontend/tree/chatbot_app)
+ 2. run `npm install`
+ 3. start the Astro `npm run start`
+2. Run the Assisted Chatbot
+
+ 1. run `yarn start:assisted_chatbot:static`
+
+3. Open [c.rh.c](https://prod.foo.redhat.com:1337/). The chatbot will appear on the bottom left
+ corner. You should be able to choose Assisted Installer chatbot
diff --git a/apps/assisted-chatbot/deploy/frontend.yaml b/apps/assisted-chatbot/deploy/frontend.yaml
new file mode 100644
index 0000000000..26ec5fb965
--- /dev/null
+++ b/apps/assisted-chatbot/deploy/frontend.yaml
@@ -0,0 +1,34 @@
+---
+apiVersion: v1
+kind: Template
+metadata:
+ name: assisted-installer-ui-chatbot
+objects:
+ - apiVersion: cloud.redhat.com/v1alpha1
+ kind: Frontend
+ metadata:
+ name: assisted-installer-ui-chatbot
+ spec:
+ feoConfigEnabled: true
+ envName: ${ENV_NAME}
+ title: Assisted Installer UI Chatbot
+ deploymentRepo: https://github.com/openshift-assisted/assisted-installer-ui
+ frontend:
+ paths:
+ - /apps/assisted-installer-ui-chatbot
+ API:
+ versions:
+ - v1
+ image: ${IMAGE}:${IMAGE_TAG}
+ module:
+ manifestLocation: '/apps/assisted-installer-ui-chatbot/fed-mods.json'
+ moduleConfig:
+ ssoScopes:
+ - rhfull
+parameters:
+ - name: ENV_NAME
+ required: true
+ - name: IMAGE_TAG
+ required: true
+ - name: IMAGE
+ value: quay.io/app-sre/assisted-installer-ui-chatbot
diff --git a/apps/assisted-chatbot/fec.config.js b/apps/assisted-chatbot/fec.config.js
new file mode 100644
index 0000000000..b9cc13eda1
--- /dev/null
+++ b/apps/assisted-chatbot/fec.config.js
@@ -0,0 +1,29 @@
+const path = require('path');
+const { insights } = require('./package.json');
+const moduleName = insights.appname.replace(/-(\w)/g, (_, match) => match.toUpperCase());
+
+module.exports = {
+ appUrl: '/openshift/assisted-installer-ui-chatbot',
+ appEntry: path.resolve(__dirname, './src/AppEntry.tsx'),
+ debug: true,
+ useProxy: true,
+ proxyVerbose: true,
+ stripAllPfStyles: true,
+ sassPrefix: `.${moduleName}`,
+ interceptChromeConfig: false,
+ plugins: [],
+ hotReload: process.env.HOT === 'true',
+ nodeModulesDirectories: '../../node_modules',
+ moduleFederation: {
+ exposes: {
+ './ChatbotMessageEntry': path.resolve(
+ __dirname,
+ './src/components/ChatbotMessageEntry/ChatbotMessageEntry.tsx',
+ ),
+ './useAsyncChatbot': path.resolve(__dirname, './src/hooks/useAsyncChatbot.tsx'),
+ },
+ },
+ routes: {
+ '/apps/assisted-installer-ui-chatbot': { host: 'http://localhost:8003' },
+ },
+};
diff --git a/apps/assisted-chatbot/package.json b/apps/assisted-chatbot/package.json
new file mode 100644
index 0000000000..0ad1d5aaec
--- /dev/null
+++ b/apps/assisted-chatbot/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@openshift-assisted/assisted-installer-ui-chatbot",
+ "version": "1.0.0",
+ "main": "index.js",
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=7.0.0"
+ },
+ "scripts": {
+ "build": "fec build",
+ "check_types": "yarn run -T tsc --noEmit",
+ "clean": "yarn run -T rimraf node_modules dist .cache",
+ "patch:hosts": "fec patch-etc-hosts",
+ "format": "yarn run -T prettier --cache --check . \"!dist\"",
+ "fix-code-style": "yarn lint --fix && yarn format --write",
+ "lint": "yarn run -T eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache .",
+ "start": "HOT=true fec dev --clouddotEnv=prod --uiEnv=stable",
+ "start:static": "fec static --port=7003 --config ../../node_modules/@redhat-cloud-services/frontend-components-config/bin/prod.webpack.config.js",
+ "static": "fec static",
+ "postinstall": "ts-patch install"
+ },
+ "dependencies": {
+ "@openshift-assisted/chatbot": "workspace:*",
+ "@patternfly/chatbot": "6.4.1",
+ "@patternfly/patternfly": "6.4.0",
+ "@patternfly/react-core": "6.4.0",
+ "@patternfly/react-icons": "6.4.0",
+ "@patternfly/react-styles": "6.4.0",
+ "@patternfly/react-tokens": "6.4.0",
+ "@redhat-cloud-services/ai-client-common": "^0.13.0",
+ "@redhat-cloud-services/ai-client-state": "^0.15.0",
+ "@redhat-cloud-services/frontend-components": "^7.0.0",
+ "axios": ">=0.22.0 <2.0.0",
+ "i18next": "^20.4.0",
+ "parse-url": "^9.2.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-i18next": "^11.11.4",
+ "react-router-dom-v5-compat": "^6.21.2"
+ },
+ "devDependencies": {
+ "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3",
+ "@redhat-cloud-services/frontend-components-config": "^6.0.17",
+ "@redhat-cloud-services/tsc-transform-imports": "^1.0.4",
+ "@tsconfig/vite-react": "^1.0.1",
+ "@types/react": "18.2.37",
+ "@types/react-dom": "^18.2.0",
+ "rimraf": "^5.0.5",
+ "ts-patch": "^3.0.2",
+ "typescript": "^5.2.2"
+ },
+ "insights": {
+ "appname": "assisted-installer-ui-chatbot"
+ }
+}
diff --git a/apps/assisted-chatbot/src/AppEntry.tsx b/apps/assisted-chatbot/src/AppEntry.tsx
new file mode 100644
index 0000000000..36b8364c6e
--- /dev/null
+++ b/apps/assisted-chatbot/src/AppEntry.tsx
@@ -0,0 +1,9 @@
+// Minimal entry point for fec dev server
+// This module only exposes federated components, no standalone app
+import React from 'react';
+
+const AppEntry: React.FC = () => {
+ return null;
+};
+
+export default AppEntry;
diff --git a/apps/assisted-chatbot/src/assets/Ask_Red_Hat_OFFICIAL-whitebackground.svg b/apps/assisted-chatbot/src/assets/Ask_Red_Hat_OFFICIAL-whitebackground.svg
new file mode 100644
index 0000000000..c7e17f1341
--- /dev/null
+++ b/apps/assisted-chatbot/src/assets/Ask_Red_Hat_OFFICIAL-whitebackground.svg
@@ -0,0 +1,33 @@
+
diff --git a/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.css b/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.css
new file mode 100644
index 0000000000..d5301f90be
--- /dev/null
+++ b/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.css
@@ -0,0 +1,3 @@
+.ai-async-message-skeleton--slow {
+ --pf-v6-c-skeleton--after--AnimationDuration: 3.6s;
+}
diff --git a/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.tsx b/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.tsx
new file mode 100644
index 0000000000..ae48875f53
--- /dev/null
+++ b/apps/assisted-chatbot/src/components/AsyncMessagePlaceholder/AsyncMessagePlaceholder.tsx
@@ -0,0 +1,35 @@
+import { Skeleton } from '@patternfly/react-core';
+import './AsyncMessagePlaceholder.css';
+
+export const AsyncMessagePlaceholder = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/apps/assisted-chatbot/src/components/ChatbotMessageEntry/ChatbotMessageEntry.tsx b/apps/assisted-chatbot/src/components/ChatbotMessageEntry/ChatbotMessageEntry.tsx
new file mode 100644
index 0000000000..5e025270ba
--- /dev/null
+++ b/apps/assisted-chatbot/src/components/ChatbotMessageEntry/ChatbotMessageEntry.tsx
@@ -0,0 +1,35 @@
+import * as React from 'react';
+import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
+import { MessageEntry, MessageEntryProps } from '@openshift-assisted/chatbot';
+import { getBaseUrl } from '../../config';
+
+const ChatbotMessageEntry = (
+ props: Omit,
+) => {
+ const { chromeHistory, ...chrome } = useChrome();
+
+ const onApiCall = React.useCallback(async (input, init) => {
+ const userToken = await chrome.auth.getToken();
+ const api = new URL(getBaseUrl());
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+ return fetch(`https://assisted-chat.${api.hostname}${input}`, {
+ ...(init || {}),
+ headers: {
+ ...(init?.headers || {}),
+ ...(userToken ? { Authorization: `Bearer ${userToken}` } : {}),
+ },
+ });
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const openClusterDetails = React.useCallback(
+ (id) => {
+ chromeHistory.push(`/openshift/assisted-installer/clusters/${id}`);
+ },
+ [chromeHistory],
+ );
+
+ return ;
+};
+
+export default ChatbotMessageEntry;
diff --git a/apps/assisted-chatbot/src/config.ts b/apps/assisted-chatbot/src/config.ts
new file mode 100644
index 0000000000..b419f4897b
--- /dev/null
+++ b/apps/assisted-chatbot/src/config.ts
@@ -0,0 +1,38 @@
+const envs: { [key: string]: string } = {
+ integration: 'https://api.integration.openshift.com',
+ staging: 'https://api.stage.openshift.com',
+ production: 'https://api.openshift.com',
+};
+
+const ENV_OVERRIDE_LOCALSTORAGE_KEY = 'ocmOverridenEnvironment';
+
+const parseEnvQueryParam = (): string | undefined => {
+ const queryParams = new URLSearchParams(window.location.search);
+ const envVal = queryParams.get('env');
+ return envVal && envs[envVal] ? envVal : undefined;
+};
+
+export const getBaseUrl = (): string => {
+ let envOverrideStorageItem: string | null = null;
+ try {
+ envOverrideStorageItem = localStorage.getItem(ENV_OVERRIDE_LOCALSTORAGE_KEY);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.warn('failed to get override item', e);
+ }
+ const queryEnv = parseEnvQueryParam() || envOverrideStorageItem;
+ if (queryEnv && envs[queryEnv]) {
+ try {
+ localStorage.setItem(ENV_OVERRIDE_LOCALSTORAGE_KEY, queryEnv);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.warn('failed to store override item', e);
+ }
+ return envs[queryEnv];
+ }
+ const defaultEnv =
+ window.location.host.includes('dev') || window.location.host.includes('foo')
+ ? 'staging'
+ : 'production';
+ return envs[defaultEnv];
+};
diff --git a/apps/assisted-chatbot/src/hooks/useAsyncChatbot.tsx b/apps/assisted-chatbot/src/hooks/useAsyncChatbot.tsx
new file mode 100644
index 0000000000..30344aea92
--- /dev/null
+++ b/apps/assisted-chatbot/src/hooks/useAsyncChatbot.tsx
@@ -0,0 +1,171 @@
+import React from 'react';
+import { createClientStateManager } from '@redhat-cloud-services/ai-client-state';
+import { Message as MessageType } from '@redhat-cloud-services/ai-client-state';
+import {
+ LightSpeedCoreAdditionalProperties,
+ LightspeedClient,
+} from '@redhat-cloud-services/lightspeed-client';
+import { ScalprumComponent, ScalprumComponentProps } from '@scalprum/react-core';
+
+import { Models, StateManagerConfiguration, UseManagerHook } from '../types';
+import ARH_BOT_ICON from '../assets/Ask_Red_Hat_OFFICIAL-whitebackground.svg';
+import { AsyncMessagePlaceholder } from '../components/AsyncMessagePlaceholder/AsyncMessagePlaceholder';
+import { Message } from '@patternfly/chatbot';
+import { getBaseUrl } from '../config';
+import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
+
+type LightspeedMessage = ScalprumComponentProps<
+ Record,
+ {
+ message: MessageType;
+ avatar: string;
+ conversationId: string | undefined;
+ }
+>;
+
+const AsyncMessageError = () => (
+
+);
+
+const LSCMessageEntry = ({
+ message,
+ avatar,
+ conversationId,
+}: {
+ message: MessageType;
+ avatar: string;
+ conversationId: string;
+}) => {
+ const messageProps: LightspeedMessage = {
+ message,
+ avatar: message.role === 'user' ? avatar : ARH_BOT_ICON,
+ scope: 'assistedInstallerApp',
+ module: './ChatbotMessageEntry',
+ fallback: null,
+ conversationId,
+ };
+ return (
+ }
+ fallback={}
+ />
+ );
+};
+
+const useIsAuthenticated = () => {
+ const chrome = useChrome();
+ const [isLoading, setIsLoading] = React.useState(true);
+ const [isAuthenticated, setIsAuthenticated] = React.useState(false);
+
+ React.useEffect(() => {
+ void (async () => {
+ const api = new URL(getBaseUrl());
+ const token = await chrome.auth.getToken();
+ try {
+ const response = await fetch(`https://assisted-chat.${api.hostname}/v1/conversations`, {
+ method: 'GET',
+ headers: token
+ ? {
+ Authorization: `Bearer ${token}`,
+ }
+ : {},
+ });
+ setIsAuthenticated(response.ok);
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error('Error checking authentication:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ })();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ return {
+ isAuthenticated,
+ isLoading,
+ };
+};
+
+const useStateManager = (): UseManagerHook => {
+ const chrome = useChrome();
+ const { isAuthenticated, isLoading } = useIsAuthenticated();
+ const manager = React.useMemo(() => {
+ const api = new URL(getBaseUrl());
+ const client = new LightspeedClient({
+ baseUrl: `https://assisted-chat.${api.hostname}`,
+ fetchFunction: async (input, init) => {
+ const token = await chrome.auth.getToken();
+ return fetch(input, {
+ ...init,
+ headers: {
+ ...init?.headers,
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
+ },
+ });
+ },
+ });
+ const stateManager = createClientStateManager(client);
+ const config: StateManagerConfiguration = {
+ model: Models.OAI,
+ stateManager,
+ historyManagement: true,
+ streamMessages: true,
+ modelName: 'OpenShift Assisted Installer',
+ docsUrl:
+ 'https://docs.redhat.com/en/documentation/assisted_installer_for_openshift_container_platform/2025/html/installing_openshift_container_platform_with_the_assisted_installer/index',
+ selectionTitle: 'OpenShift Assisted Installer',
+ selectionDescription:
+ 'Create, configure, and install OpenShift Container Platform clusters using the Assisted Installer.',
+ MessageEntryComponent: LSCMessageEntry,
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ handleNewChat: async (toggleDrawer) => {
+ // can't use hooks here, we are not yet within the correct React context
+ await stateManager.createNewConversation();
+ toggleDrawer(false);
+ },
+ isPreview: true,
+ welcome: {
+ buttons: [
+ {
+ title: 'Create a new OpenShift cluster',
+ value: 'Create a new OpenShift cluster',
+ },
+ {
+ title: 'List my OpenShift clusters',
+ value: 'List my OpenShift clusters',
+ },
+ {
+ title: 'List available OpenShift versions',
+ value: 'List available OpenShift versions',
+ },
+ ],
+ },
+ routes: ['/openshift/assisted-installer/*'],
+ };
+
+ return config;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ if (isLoading) {
+ return { manager: null, loading: true };
+ }
+ if (!isAuthenticated) {
+ return { manager: null, loading: false };
+ }
+
+ return { manager, loading: false };
+};
+
+export default useStateManager;
diff --git a/apps/assisted-chatbot/src/types.ts b/apps/assisted-chatbot/src/types.ts
new file mode 100644
index 0000000000..051ebd36b5
--- /dev/null
+++ b/apps/assisted-chatbot/src/types.ts
@@ -0,0 +1,49 @@
+import { StateManager } from '@redhat-cloud-services/ai-client-state';
+import { IAIClient } from '@redhat-cloud-services/ai-client-common';
+
+export enum Models {
+ ASK_RED_HAT = 'Ask Red Hat',
+ RHEL_LIGHTSPEED = 'RHEL LightSpeed',
+ VA = 'Virtual Assistant',
+ OAI = 'OpenShift assisted Installer',
+}
+
+export interface WelcomeButton {
+ /** Title for the welcome button */
+ title: string;
+ /** Optional message to display below the title */
+ message?: string;
+ /** Message to send when the button is clicked */
+ value: string;
+}
+
+export interface WelcomeConfig {
+ /** Welcome message content to display */
+ content?: string;
+ /** Optional array of interactive buttons */
+ buttons?: WelcomeButton[];
+}
+
+export type StateManagerConfiguration = {
+ model: Models;
+ historyManagement: boolean;
+ streamMessages: boolean;
+ modelName: string;
+ docsUrl: string;
+ selectionTitle: string;
+ selectionDescription: string;
+ stateManager: StateManager, S>;
+ isPreview?: boolean;
+ handleNewChat?: (toggleDrawer: (isOpen: boolean) => void) => void;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ MessageEntryComponent?: React.ComponentType;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ FooterComponent?: React.ComponentType;
+ welcome?: WelcomeConfig;
+ routes?: string[];
+};
+
+export type UseManagerHook = {
+ manager: StateManagerConfiguration | null;
+ loading: boolean;
+};
diff --git a/apps/assisted-chatbot/src/typings.d.ts b/apps/assisted-chatbot/src/typings.d.ts
new file mode 100644
index 0000000000..cdb2b1a9a2
--- /dev/null
+++ b/apps/assisted-chatbot/src/typings.d.ts
@@ -0,0 +1,4 @@
+declare module '*.svg' {
+ const content: string;
+ export default content;
+}
diff --git a/apps/assisted-chatbot/tsconfig.json b/apps/assisted-chatbot/tsconfig.json
new file mode 100644
index 0000000000..12be2ceae2
--- /dev/null
+++ b/apps/assisted-chatbot/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "sourceMap": true,
+ "moduleResolution": "node",
+ "target": "es5",
+ "allowSyntheticDefaultImports": true,
+ "noErrorTruncation": true,
+ "strict": true,
+ "rootDir": ".",
+ "skipLibCheck": true,
+ "lib": ["dom", "esnext"],
+ "module": "esnext",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true
+ },
+ "include": ["src"]
+}
diff --git a/apps/assisted-disconnected-ui/package.json b/apps/assisted-disconnected-ui/package.json
index c1dcf1ab82..54e2b21d57 100644
--- a/apps/assisted-disconnected-ui/package.json
+++ b/apps/assisted-disconnected-ui/package.json
@@ -1,14 +1,14 @@
{
"dependencies": {
"@openshift-assisted/ui-lib": "workspace:*",
- "@openshift-console/dynamic-plugin-sdk": "0.0.3",
- "@patternfly/patternfly": "6.2.3",
- "@patternfly/react-code-editor": "6.2.2",
- "@patternfly/react-core": "6.2.2",
- "@patternfly/react-icons": "6.2.2",
- "@patternfly/react-styles": "6.2.2",
- "@patternfly/react-table": "6.2.2",
- "@patternfly/react-tokens": "6.2.2",
+ "@openshift-console/dynamic-plugin-sdk": "1.0.0",
+ "@patternfly/patternfly": "6.4.0",
+ "@patternfly/react-code-editor": "6.4.0",
+ "@patternfly/react-core": "6.4.0",
+ "@patternfly/react-icons": "6.4.0",
+ "@patternfly/react-styles": "6.4.0",
+ "@patternfly/react-table": "6.4.0",
+ "@patternfly/react-tokens": "6.4.0",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/browser": "^7.119",
"axios": ">=0.22.0 <2.0.0",
@@ -21,7 +21,7 @@
"react-i18next": "^11.11.4",
"react-monaco-editor": "^0.55.0",
"react-redux": "^8.0.5",
- "react-router-dom": "^5.3.3",
+ "react-router-dom": "5.3.x",
"react-router-dom-v5-compat": "^6.21.2",
"react-tagsinput": "^3.20",
"redux": "^4",
@@ -31,18 +31,14 @@
"description": "A stand-alone web UI for the disconnected environments",
"devDependencies": {
"@tsconfig/vite-react": "^1.0.1",
- "@types/react": "17.0.x",
+ "@types/react": "18.2.37",
+ "@types/react-dom": "^18.2.0",
"@vitejs/plugin-react-swc": "^3.0.1",
"concurrently": "^8.2.2",
"nodemon": "^3.0.3",
"vite": "^5.4.21",
"vite-plugin-environment": "^1.1.3"
},
- "overrides": {
- "@patternfly/react-core": {
- "attr-accept": "2.2.2"
- }
- },
"engines": {
"node": ">=14"
},
diff --git a/apps/assisted-ui/README.md b/apps/assisted-ui/README.md
index 96c34900f8..1e3c02777d 100644
--- a/apps/assisted-ui/README.md
+++ b/apps/assisted-ui/README.md
@@ -91,14 +91,6 @@ You can build the container image by running:
$ podman build -t quay.io/edge-infrastructure/assisted-installer-ui:latest . --build-arg AIUI_APP_GIT_SHA="$(git rev-parse HEAD)" --build-arg AIUI_APP_VERSION=latest
```
-## ChatBot
-
-You can run the standalone UI with chatbot enabled. You need to be logged in via `ocm`.
-
-```
-$ AIUI_CHAT_API_URL= OCM_REFRESH_TOKEN=$(ocm token --refresh) AIUI_SSO_API_URL=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token yarn start:assisted_ui
-```
-
## Available Scripts
In the project directory, you can run:
diff --git a/apps/assisted-ui/deploy/nginx.conf b/apps/assisted-ui/deploy/nginx.conf
index 8bb6fd1652..78bcc840ed 100644
--- a/apps/assisted-ui/deploy/nginx.conf
+++ b/apps/assisted-ui/deploy/nginx.conf
@@ -14,20 +14,6 @@ location /api {
client_max_body_size 2M;
}
-location /chatbot/ {
- proxy_pass $AIUI_CHAT_API_URL;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection 'upgrade';
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- proxy_connect_timeout 120;
- proxy_send_timeout 120;
- proxy_read_timeout 120;
- send_timeout 120;
- client_max_body_size 2M;
-}
-
location /token {
proxy_pass $AIUI_SSO_API_URL;
proxy_http_version 1.1;
diff --git a/apps/assisted-ui/package.json b/apps/assisted-ui/package.json
index a00f9cc074..cc574883e4 100644
--- a/apps/assisted-ui/package.json
+++ b/apps/assisted-ui/package.json
@@ -1,18 +1,14 @@
{
"dependencies": {
- "@openshift-assisted/chatbot": "workspace:*",
"@openshift-assisted/ui-lib": "workspace:*",
- "@openshift-console/dynamic-plugin-sdk": "0.0.3",
- "@patternfly-6/patternfly": "npm:@patternfly/patternfly@6.3.1",
- "@patternfly-6/react-core": "npm:@patternfly/react-core@6.3.1",
- "@patternfly/chatbot": "6.4.0-prerelease.4",
- "@patternfly/patternfly": "6.2.3",
- "@patternfly/react-code-editor": "6.2.2",
- "@patternfly/react-core": "6.2.2",
- "@patternfly/react-icons": "6.2.2",
- "@patternfly/react-styles": "6.2.2",
- "@patternfly/react-table": "6.2.2",
- "@patternfly/react-tokens": "6.2.2",
+ "@openshift-console/dynamic-plugin-sdk": "1.0.0",
+ "@patternfly/patternfly": "6.4.0",
+ "@patternfly/react-code-editor": "6.4.0",
+ "@patternfly/react-core": "6.4.0",
+ "@patternfly/react-icons": "6.4.0",
+ "@patternfly/react-styles": "6.4.0",
+ "@patternfly/react-table": "6.4.0",
+ "@patternfly/react-tokens": "6.4.0",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/browser": "^7.119",
"axios": ">=0.22.0 <2.0.0",
@@ -25,7 +21,7 @@
"react-i18next": "^11.11.4",
"react-monaco-editor": "^0.55.0",
"react-redux": "^8.0.5",
- "react-router-dom": "^5.3.3",
+ "react-router-dom": "5.3.x",
"react-router-dom-v5-compat": "^6.21.2",
"react-tagsinput": "^3.20",
"redux": "^4",
@@ -35,16 +31,14 @@
"description": "A stand-alone web UI for the Assisted Installer",
"devDependencies": {
"@tsconfig/vite-react": "^1.0.1",
- "@types/react": "17.0.x",
+ "@types/react": "18.2.37",
+ "@types/react-dom": "^18.2.0",
+ "@types/react-router": "^5.1.x",
+ "@types/react-router-dom": "5.3.x",
"@vitejs/plugin-react-swc": "^3.0.1",
"vite": "^5.4.21",
"vite-plugin-environment": "^1.1.3"
},
- "overrides": {
- "@patternfly/react-core": {
- "attr-accept": "2.2.2"
- }
- },
"engines": {
"node": ">=14"
},
diff --git a/apps/assisted-ui/src/components/App.tsx b/apps/assisted-ui/src/components/App.tsx
index 758129b100..2fbea9eed1 100755
--- a/apps/assisted-ui/src/components/App.tsx
+++ b/apps/assisted-ui/src/components/App.tsx
@@ -4,7 +4,6 @@ import { CompatRouter, Route } from 'react-router-dom-v5-compat';
import { Page } from '@patternfly/react-core';
import * as OCM from '@openshift-assisted/ui-lib/ocm';
import { Header } from './Header';
-import ChatBot, { refreshToken } from './Chatbot';
import '../i18n';
const { HostsClusterDetailTabMock, UILibRoutes, Features, Config } = OCM;
@@ -14,10 +13,7 @@ export const App: React.FC = () => (
} isManagedSidebar defaultManagedSidebarIsOpen={false}>
- : undefined}
- >
+
} />
diff --git a/apps/assisted-ui/src/components/Chatbot.tsx b/apps/assisted-ui/src/components/Chatbot.tsx
deleted file mode 100644
index 72c9a9f80b..0000000000
--- a/apps/assisted-ui/src/components/Chatbot.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import * as React from 'react';
-import { ChatBot as AIChatBot, ChatBotWindowProps } from '@openshift-assisted/chatbot';
-import { useNavigate } from 'react-router-dom-v5-compat';
-
-import '@patternfly-6/react-core/dist/styles/base.css';
-import '@patternfly/chatbot/dist/css/main.css';
-import '@patternfly-6/patternfly/patternfly-addons.css';
-
-export const refreshToken =
- (import.meta.env.AIUI_OCM_REFRESH_TOKEN as string | undefined) || window.OCM_REFRESH_TOKEN;
-let expiration = Date.now();
-let token = '';
-
-export const getOcmToken = async () => {
- // if token expires in less than 5s, refresh it
- if (Date.now() > expiration - 5000) {
- if (!refreshToken) {
- throw new Error('No refresh token available');
- }
- const params = new URLSearchParams();
- params.append('grant_type', 'refresh_token');
- params.append('refresh_token', refreshToken || '');
- params.append('client_id', 'cloud-services');
-
- try {
- const response = await fetch('/token', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- body: params.toString(),
- });
-
- if (!response.ok) {
- throw new Error(`Token refresh failed: ${response.status}`);
- }
-
- const data = (await response.json()) as { access_token: string; expires_in: number };
- token = data.access_token;
- expiration = Date.now() + data.expires_in * 1000;
- } catch (error) {
- // eslint-disable-next-line
- console.error('Failed to refresh token:', error);
- throw error;
- }
- }
- return token;
-};
-
-const ChatBot = () => {
- const navigate = useNavigate();
- const onApiCall = React.useCallback(async (input, init) => {
- const token = await getOcmToken();
- return fetch(`/chatbot${input.toString()}`, {
- ...(init || {}),
- headers: {
- ...(init?.headers || {}),
- Authorization: `Bearer ${token}`,
- },
- });
- }, []);
-
- const openClusterDetails = React.useCallback(
- (id) => navigate(`/assisted-installer/clusters/${id}`),
- [navigate],
- );
-
- return (
-
- );
-};
-
-export default ChatBot;
diff --git a/apps/assisted-ui/vite.config.ts b/apps/assisted-ui/vite.config.ts
index 141fb2274b..7dae76efd1 100644
--- a/apps/assisted-ui/vite.config.ts
+++ b/apps/assisted-ui/vite.config.ts
@@ -48,11 +48,6 @@ export default defineConfig(async ({ mode }) => {
target: env.AIUI_APP_API_URL,
changeOrigin: true,
},
- '/chatbot': {
- target: env.AIUI_CHAT_API_URL,
- changeOrigin: true,
- rewrite: (path: string) => path.replace(/^\/chatbot/, ''),
- },
'/token': {
target: env.AIUI_SSO_API_URL,
changeOrigin: true,
diff --git a/libs/chatbot/lib/components/ChatBot/AIAlert.tsx b/libs/chatbot/lib/components/ChatBot/AIAlert.tsx
index d9187cda17..d3012c222c 100644
--- a/libs/chatbot/lib/components/ChatBot/AIAlert.tsx
+++ b/libs/chatbot/lib/components/ChatBot/AIAlert.tsx
@@ -1,4 +1,4 @@
-import { Alert, AlertActionCloseButton, Stack, StackItem } from '@patternfly-6/react-core';
+import { Alert, AlertActionCloseButton, Stack, StackItem } from '@patternfly/react-core';
import * as React from 'react';
import ExternalLink from './ExternalLink';
diff --git a/libs/chatbot/lib/components/ChatBot/BotMessage.tsx b/libs/chatbot/lib/components/ChatBot/BotMessage.tsx
index d4d1df3196..12ddd8ec18 100644
--- a/libs/chatbot/lib/components/ChatBot/BotMessage.tsx
+++ b/libs/chatbot/lib/components/ChatBot/BotMessage.tsx
@@ -2,9 +2,9 @@ import * as React from 'react';
import { Message } from '@patternfly/chatbot';
import MessageLoading from '@patternfly/chatbot/dist/cjs/Message/MessageLoading';
import { MsgProps } from './helpers';
-import { Button, Stack, StackItem } from '@patternfly-6/react-core';
+import { Button, Stack, StackItem } from '@patternfly/react-core';
import { saveAs } from 'file-saver';
-import { DownloadIcon, ExternalLinkAltIcon } from '@patternfly-6/react-icons';
+import { DownloadIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
import FeedbackForm from './FeedbackCard';
import AIAvatar from '../../assets/lightspeed-logo.svg';
diff --git a/libs/chatbot/lib/components/ChatBot/ChatBotButton.tsx b/libs/chatbot/lib/components/ChatBot/ChatBotButton.tsx
index a1d0b9b6f4..1776d9711b 100644
--- a/libs/chatbot/lib/components/ChatBot/ChatBotButton.tsx
+++ b/libs/chatbot/lib/components/ChatBot/ChatBotButton.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import { Button, Icon, Popover } from '@patternfly-6/react-core';
-import { InfoCircleIcon } from '@patternfly-6/react-icons';
+import { Button, Icon, Popover } from '@patternfly/react-core';
+import { InfoCircleIcon } from '@patternfly/react-icons';
import LightSpeedLogo from '../../assets/lightspeed-logo.svg';
diff --git a/libs/chatbot/lib/components/ChatBot/ChatBotHistory.tsx b/libs/chatbot/lib/components/ChatBot/ChatBotHistory.tsx
index 9c22aa76cd..c04e0d2931 100644
--- a/libs/chatbot/lib/components/ChatBot/ChatBotHistory.tsx
+++ b/libs/chatbot/lib/components/ChatBot/ChatBotHistory.tsx
@@ -4,9 +4,9 @@ import {
ChatbotDisplayMode,
Conversation,
} from '@patternfly/chatbot';
-import { Alert, MenuItemAction } from '@patternfly-6/react-core';
+import { Alert, MenuItemAction } from '@patternfly/react-core';
import { getErrorMessage } from './helpers';
-import { TrashAltIcon } from '@patternfly-6/react-icons';
+import { TrashAltIcon } from '@patternfly/react-icons';
import DeleteConversationModal from './DeleteConversationModal';
type ConversationHistory = { conversations: { conversation_id: string; created_at: string }[] };
diff --git a/libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx b/libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
index 79215c0d52..4d472fe04d 100644
--- a/libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
+++ b/libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
@@ -18,7 +18,7 @@ import {
MessageBox,
MessageBoxHandle,
} from '@patternfly/chatbot';
-import { Brand, EmptyState, Spinner } from '@patternfly-6/react-core';
+import { Brand, EmptyState, Spinner } from '@patternfly/react-core';
import BotMessage from './BotMessage';
import { MESSAGE_BAR_ID, botRole, userRole, MsgProps } from './helpers';
diff --git a/libs/chatbot/lib/components/ChatBot/DeleteConversationModal.tsx b/libs/chatbot/lib/components/ChatBot/DeleteConversationModal.tsx
index 1945a8ecdd..ce12c27d11 100644
--- a/libs/chatbot/lib/components/ChatBot/DeleteConversationModal.tsx
+++ b/libs/chatbot/lib/components/ChatBot/DeleteConversationModal.tsx
@@ -7,7 +7,7 @@ import {
ModalHeader,
Stack,
StackItem,
-} from '@patternfly-6/react-core';
+} from '@patternfly/react-core';
import * as React from 'react';
import { getErrorMessage } from './helpers';
import { Conversation } from '@patternfly/chatbot';
diff --git a/libs/chatbot/lib/components/ChatBot/ExternalLink.tsx b/libs/chatbot/lib/components/ChatBot/ExternalLink.tsx
index 58d6ae83df..4d80532d7a 100644
--- a/libs/chatbot/lib/components/ChatBot/ExternalLink.tsx
+++ b/libs/chatbot/lib/components/ChatBot/ExternalLink.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import { Button } from '@patternfly-6/react-core';
-import { ExternalLinkAltIcon } from '@patternfly-6/react-icons';
+import { Button } from '@patternfly/react-core';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons';
const ExternalLink = ({ href, children }: React.PropsWithChildren<{ href: string }>) => (