Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"node": true
},
"parserOptions": {
"ecmaVersion": "latest",
"project": [
"apps/*/tsconfig.eslint.json",
"libs/*/tsconfig.eslint.json",
Expand All @@ -21,6 +22,9 @@
"ignorePatterns": [
"apps/*/build",
"libs/*/build",
"tools/*/build"
"tools/*/build",
"apps/*/dist",
"libs/*/dist",
"tools/*/dist"
]
}
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,3 @@ package-lock.json
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Ignored apps
apps/*
!apps/assisted-ui
!apps/assisted-disconnected-ui
39 changes: 39 additions & 0 deletions apps/assisted-chatbot/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -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',
},
],
},
],
},
},
],
};
19 changes: 19 additions & 0 deletions apps/assisted-chatbot/README.md
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions apps/assisted-chatbot/deploy/frontend.yaml
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions apps/assisted-chatbot/fec.config.js
Original file line number Diff line number Diff line change
@@ -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' },
},
};
55 changes: 55 additions & 0 deletions apps/assisted-chatbot/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
9 changes: 9 additions & 0 deletions apps/assisted-chatbot/src/AppEntry.tsx
Original file line number Diff line number Diff line change
@@ -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;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.ai-async-message-skeleton--slow {
--pf-v6-c-skeleton--after--AnimationDuration: 3.6s;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Skeleton } from '@patternfly/react-core';
import './AsyncMessagePlaceholder.css';

export const AsyncMessagePlaceholder = () => (
<div className="pf-v6-u-display-flex pf-v6-u-align-items-flex-start pf-v6-u-p-md">
<div className="pf-v6-u-mr-md">
<Skeleton
shape="circle"
width="2.5rem"
height="2.5rem"
className="ai-async-message-skeleton--slow"
screenreaderText="Loading user avatar"
/>
</div>
<div className="pf-v6-u-flex-1">
<div className="pf-v6-u-mb-xs">
<Skeleton
width="6rem"
height="0.875rem"
className="ai-async-message-skeleton--slow"
screenreaderText="Loading message timestamp"
/>
</div>
<div className="pf-v6-u-mb-xs">
<Skeleton width="85%" height="1rem" screenreaderText="Loading message content" />
</div>
<div className="pf-v6-u-mb-xs">
<Skeleton width="70%" height="1rem" screenreaderText="Loading message content" />
</div>
<div>
<Skeleton width="55%" height="1rem" screenreaderText="Loading message content" />
</div>
</div>
</div>
);
Original file line number Diff line number Diff line change
@@ -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<MessageEntryProps, 'onApiCall' | 'openClusterDetails'>,
) => {
const { chromeHistory, ...chrome } = useChrome();

const onApiCall = React.useCallback<MessageEntryProps['onApiCall']>(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<MessageEntryProps['openClusterDetails']>(
(id) => {
chromeHistory.push(`/openshift/assisted-installer/clusters/${id}`);
},
[chromeHistory],
);

return <MessageEntry onApiCall={onApiCall} openClusterDetails={openClusterDetails} {...props} />;
};

export default ChatbotMessageEntry;
38 changes: 38 additions & 0 deletions apps/assisted-chatbot/src/config.ts
Original file line number Diff line number Diff line change
@@ -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];
};
Loading
Loading