Skip to content

Commit dd2038e

Browse files
Merge pull request #1020 from thoraxe/first-time
First time user experience
2 parents 52f5d99 + cfedf79 commit dd2038e

File tree

7 files changed

+85
-2
lines changed

7 files changed

+85
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ dist/
55
.env
66
gui_test_screenshots
77
.nodeenv
8+
.playwright-mcp

locales/en/plugin__lightspeed-console-plugin.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"Not authorized": "Not authorized",
7272
"OpenShift Lightspeed authentication failed. Contact your system administrator for more information.": "OpenShift Lightspeed authentication failed. Contact your system administrator for more information.",
7373
"OpenShift Lightspeed chat history": "OpenShift Lightspeed chat history",
74+
"OpenShift Lightspeed is now available to help you with your OpenShift questions and tasks. Try asking about deployments, troubleshooting, best practices, or any other OpenShift-related topics. This notice will disappear once you minimize the chat.": "OpenShift Lightspeed is now available to help you with your OpenShift questions and tasks. Try asking about deployments, troubleshooting, best practices, or any other OpenShift-related topics. This notice will disappear once you minimize the chat.",
7475
"OpenShift Lightspeed uses AI technology to help answer your questions. Do not include personal information or other sensitive information in your input. Interactions may be used to improve Red Hat's products or services.": "OpenShift Lightspeed uses AI technology to help answer your questions. Do not include personal information or other sensitive information in your input. Interactions may be used to improve Red Hat's products or services.",
7576
"Please retry or contact support if the issue persists.": "Please retry or contact support if the issue persists.",
7677
"Preview attachment": "Preview attachment",
@@ -90,6 +91,7 @@
9091
"Uploaded file is not valid YAML": "Uploaded file is not valid YAML",
9192
"Uploaded file is too large. Max size is {{max}} MB.": "Uploaded file is too large. Max size is {{max}} MB.",
9293
"Waiting for OpenShift Lightspeed service": "Waiting for OpenShift Lightspeed service",
94+
"Welcome to OpenShift Lightspeed!": "Welcome to OpenShift Lightspeed!",
9395
"You can preview and optionally edit the code displayed in the modal before attaching it to your prompt.": "You can preview and optionally edit the code displayed in the modal before attaching it to your prompt.",
9496
"You can select a container and specify the most recent number of lines of its log file to include as an attachment for detailed troubleshooting and analysis.": "You can select a container and specify the most recent number of lines of its log file to include as an attachment for detailed troubleshooting and analysis.",
9597
"You can specify the most recent number of events from this resource to include as an attachment for detailed troubleshooting and analysis.": "You can specify the most recent number of events from this resource to include as an attachment for detailed troubleshooting and analysis.",

src/components/GeneralPage.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import { copyToClipboard } from '../clipboard';
4646
import { ErrorType, getFetchErrorMessage } from '../error';
4747
import { AuthStatus, getRequestInitWithAuthHeader, useAuth } from '../hooks/useAuth';
4848
import { useBoolean } from '../hooks/useBoolean';
49+
import { useFirstTimeUser } from '../hooks/useFirstTimeUser';
4950
import { useIsDarkTheme } from '../hooks/useIsDarkTheme';
5051
import {
5152
attachmentsClear,
@@ -65,6 +66,7 @@ import NewChatModal from './NewChatModal';
6566
import Prompt from './Prompt';
6667
import ReadinessAlert from './ReadinessAlert';
6768
import ResponseTools from './ResponseTools';
69+
import WelcomeNotice from './WelcomeNotice';
6870

6971
import './general-page.css';
7072
import '@patternfly/chatbot/dist/css/main.css';
@@ -429,6 +431,7 @@ const GeneralPage: React.FC<GeneralPageProps> = ({ onClose, onCollapse, onExpand
429431
const conversationID: string = useSelector((s: State) => s.plugins?.ols?.get('conversationID'));
430432

431433
const [authStatus] = useAuth();
434+
const [isFirstTimeUser] = useFirstTimeUser();
432435

433436
const [isNewChatModalOpen, , openNewChatModal, closeNewChatModal] = useBoolean(false);
434437
const [isCopied, , setCopied, setNotCopied] = useBoolean(false);
@@ -566,6 +569,7 @@ const GeneralPage: React.FC<GeneralPageProps> = ({ onClose, onCollapse, onExpand
566569
</Title>
567570
<AuthAlert authStatus={authStatus} />
568571
<PrivacyAlert />
572+
{isFirstTimeUser && <WelcomeNotice />}
569573
{chatHistory.toJS().map((entry: ChatEntry, i: number) => (
570574
<ChatHistoryEntry
571575
conversationID={conversationID}

src/components/Popover.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { consoleFetchJSON } from '@openshift-console/dynamic-plugin-sdk';
77
import { getApiUrl } from '../config';
88
import { getRequestInitWithAuthHeader } from '../hooks/useAuth';
99
import { useBoolean } from '../hooks/useBoolean';
10+
import { useFirstTimeUser } from '../hooks/useFirstTimeUser';
1011
import { useHideLightspeed } from '../hooks/useHideLightspeed';
1112
import { useIsDarkTheme } from '../hooks/useIsDarkTheme';
1213
import { closeOLS, openOLS, userFeedbackDisable } from '../redux-actions';
@@ -29,6 +30,7 @@ const Popover: React.FC = () => {
2930
const [isExpanded, , expand, collapse] = useBoolean(false);
3031
const [isHidden] = useHideLightspeed();
3132
const [isDarkTheme] = useIsDarkTheme();
33+
const [isFirstTimeUser, markAsExperienced, firstTimeLoaded] = useFirstTimeUser();
3234

3335
React.useEffect(() => {
3436
consoleFetchJSON(
@@ -48,13 +50,28 @@ const Popover: React.FC = () => {
4850
});
4951
}, [dispatch]);
5052

53+
// Auto-open chat for first-time users
54+
React.useEffect(() => {
55+
if (firstTimeLoaded && isFirstTimeUser && !isOpen && !isHidden) {
56+
// Small delay to allow the page to load before opening
57+
const timer = setTimeout(() => {
58+
dispatch(openOLS());
59+
}, 500);
60+
return () => clearTimeout(timer);
61+
}
62+
}, [firstTimeLoaded, isFirstTimeUser, isOpen, isHidden, dispatch]);
63+
5164
const open = React.useCallback(() => {
5265
dispatch(openOLS());
5366
}, [dispatch]);
5467

5568
const close = React.useCallback(() => {
69+
// Mark user as experienced when they close chat for the first time
70+
if (isFirstTimeUser) {
71+
markAsExperienced();
72+
}
5673
dispatch(closeOLS());
57-
}, [dispatch]);
74+
}, [dispatch, isFirstTimeUser, markAsExperienced]);
5875

5976
if (isHidden) {
6077
return null;

src/components/WelcomeNotice.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as React from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import { Alert } from '@patternfly/react-core';
4+
5+
/**
6+
* Welcome notice component for first-time users.
7+
* Displayed inside the chat window to welcome new users and encourage them to try Lightspeed.
8+
*/
9+
const WelcomeNotice: React.FC = () => {
10+
const { t } = useTranslation('plugin__lightspeed-console-plugin');
11+
12+
return (
13+
<Alert
14+
className="ols-plugin__alert"
15+
isInline
16+
title={t('Welcome to OpenShift Lightspeed!')}
17+
variant="info"
18+
>
19+
{t(
20+
'OpenShift Lightspeed is now available to help you with your OpenShift questions and tasks. Try asking about deployments, troubleshooting, best practices, or any other OpenShift-related topics. This notice will disappear once you minimize the chat.',
21+
)}
22+
</Alert>
23+
);
24+
};
25+
26+
export default WelcomeNotice;

src/hooks/useFirstTimeUser.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useCallback } from 'react';
2+
import { useUserSettings } from '@openshift-console/dynamic-plugin-sdk';
3+
4+
/**
5+
* Simple hook to manage first-time user experience for OpenShift Lightspeed.
6+
*
7+
* This hook tracks whether the user has ever closed/minimized the chat window.
8+
* For first-time users, the chat should auto-open. Once they close it once,
9+
* it should stay closed on future page loads.
10+
*
11+
* @returns A tuple containing:
12+
* - isFirstTimeUser: boolean indicating if this is a first-time user (chat should auto-open)
13+
* - markAsExperienced: callback function to mark that user has closed chat
14+
* - isLoaded: boolean indicating if the user settings have finished loading
15+
*/
16+
export const useFirstTimeUser = (): [boolean, () => void, boolean] => {
17+
// Track if user has ever closed the chat window
18+
const [hasClosedChatBefore, setHasClosedChatBefore, isLoaded] = useUserSettings(
19+
'lightspeed.hasClosedChat',
20+
false, // Default: user hasn't closed chat yet (first-time user)
21+
true, // Sync across namespaces
22+
);
23+
24+
// Create stable callback to mark user as experienced (no longer first-time)
25+
const markAsExperienced = useCallback(() => {
26+
setHasClosedChatBefore(true);
27+
}, [setHasClosedChatBefore]);
28+
29+
// First-time user if they haven't closed chat before and settings are loaded
30+
const isFirstTimeUser = isLoaded && !hasClosedChatBefore;
31+
32+
return [isFirstTimeUser, markAsExperienced, isLoaded];
33+
};

src/hooks/useIsDarkTheme.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useUserSettings } from '@openshift-console/dynamic-plugin-sdk';
33
export const useIsDarkTheme = (): [boolean] => {
44
const [theme] = useUserSettings('console.theme', null, true);
55
return [
6-
theme === 'systemDefault'
6+
theme === 'systemDefault' || theme === null
77
? window.matchMedia?.('(prefers-color-scheme: dark)').matches
88
: theme === 'dark',
99
];

0 commit comments

Comments
 (0)