Skip to content

Commit

Permalink
Fixing Copilot Chat UI bugs (microsoft#981)
Browse files Browse the repository at this point in the history
### Motivation and Context
<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->
This PR contains CSS clean-up and fixes for a number of UI bugs.

Changes include: 
- ChatWindow no longer overflows out of window view
- Scrollbars show up as necessary in ChatHistory and ChatList

![image](https://github.com/microsoft/semantic-kernel/assets/125500434/d87f4f7f-f01d-49c1-ace6-bcc11ed3984d)
- Check for valid .env file on start, error screen showed if variables
aren't populated.
-
  • Loading branch information
teresaqhoang authored May 13, 2023
1 parent b64450d commit 5b9b820
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 190 deletions.
4 changes: 3 additions & 1 deletion samples/apps/copilot-chat-app/webapp/env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
REACT_APP_BACKEND_URI=https://localhost:40443/
REACT_APP_AAD_AUTHORITY=https://login.microsoftonline.com/common
REACT_APP_AAD_CLIENT_ID=
REACT_APP_AAD_CLIENT_ID=

# If you add any new variables, make sure you update the variables list in the checkEnv.ts file as well.
68 changes: 32 additions & 36 deletions samples/apps/copilot-chat-app/webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,18 @@ import { RootState } from './redux/app/store';
import { removeAlert } from './redux/features/app/appSlice';
import { CopilotChatTokens } from './styles';

const useClasses = makeStyles({
export const useClasses = makeStyles({
container: {
...shorthands.overflow('hidden'),
display: 'flex',
flexDirection: 'column',
width: '100%',
height: '100vh',
},
content: {
Flex: 'auto',
},
header: {
backgroundColor: CopilotChatTokens.backgroundColor,
width: '100%',
height: '5.5%',
height: '48px',
color: '#FFF',
display: 'flex',
'& h1': {
Expand Down Expand Up @@ -119,37 +117,35 @@ const App: FC = () => {
/>
</div>
</div>
<div className={classes.content}>
{alerts &&
Object.keys(alerts).map((key) => {
const alert = alerts[key];
return (
<Alert
intent={alert.type}
action={{
icon: (
<Dismiss16Regular
aria-label="dismiss message"
onClick={() => onDismissAlert(key)}
color="black"
/>
),
}}
key={key}
>
{alert.message}
</Alert>
);
})}
{appState === AppState.ProbeForBackend && (
<BackendProbe
uri={process.env.REACT_APP_BACKEND_URI as string}
onBackendFound={() => setAppState(AppState.LoadingChats)}
/>
)}
{appState === AppState.LoadingChats && <Spinner labelPosition="below" label="Loading Chats" />}
{appState === AppState.Chat && <ChatView />}
</div>
{alerts &&
Object.keys(alerts).map((key) => {
const alert = alerts[key];
return (
<Alert
intent={alert.type}
action={{
icon: (
<Dismiss16Regular
aria-label="dismiss message"
onClick={() => onDismissAlert(key)}
color="black"
/>
),
}}
key={key}
>
{alert.message}
</Alert>
);
})}
{appState === AppState.ProbeForBackend && (
<BackendProbe
uri={process.env.REACT_APP_BACKEND_URI as string}
onBackendFound={() => setAppState(AppState.LoadingChats)}
/>
)}
{appState === AppState.LoadingChats && <Spinner labelPosition="below" label="Loading Chats" />}
{appState === AppState.Chat && <ChatView />}
</div>
</AuthenticatedTemplate>
</div>
Expand Down
14 changes: 14 additions & 0 deletions samples/apps/copilot-chat-app/webapp/src/checkEnv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const getMissingEnvVariables = () => {
// Should be aligned with variables defined in env.example
const envVariables = ['REACT_APP_BACKEND_URI', 'REACT_APP_AAD_AUTHORITY', 'REACT_APP_AAD_CLIENT_ID'];

const missingVariables = [];

for (const variable of envVariables) {
if (!process.env[variable]) {
missingVariables.push(variable);
}
}

return missingVariables;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { ChatStatus } from './ChatStatus';

const useClasses = makeStyles({
root: {
...shorthands.gap(tokens.spacingVerticalM),
display: 'flex',
flexDirection: 'column',
...shorthands.gap(tokens.spacingVerticalM),
maxWidth: '900px',
width: '100%',
justifySelf: 'center',
},
content: {},
item: {
display: 'flex',
flexDirection: 'column',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const useClasses = makeStyles({
display: 'flex',
flexDirection: 'column',
...shorthands.margin(0, '72px'),
alignContent: 'stretch',
},
typingIndicator: {
height: '28px',
Expand All @@ -38,7 +37,7 @@ const useClasses = makeStyles({
width: '100%',
},
textarea: {
height: '70px',
maxHeight: '80px',
},
controls: {
display: 'flex',
Expand All @@ -52,7 +51,7 @@ const useClasses = makeStyles({
functional: {
display: 'flex',
flexDirection: 'row',
}
},
});

interface ChatInputProps {
Expand Down Expand Up @@ -81,8 +80,7 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
if (recognizer) return;
void (async () => {
var response = await speechService.validSpeechKeyAsync();
if(response.isSuccess)
{
if (response.isSuccess) {
const newRecognizer = await speechService.getSpeechRecognizerAsyncWithValidKey(response);
setRecognizer(newRecognizer);
}
Expand Down Expand Up @@ -115,7 +113,7 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
account!.homeAccountId!,
selectedId,
documentFile,
await AuthHelper.getSKaaSAccessToken(instance)
await AuthHelper.getSKaaSAccessToken(instance),
);
dispatch(addAlert({ message: 'Document uploaded successfully', type: AlertType.Success }));
} catch (e: any) {
Expand Down Expand Up @@ -191,16 +189,26 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
type="file"
ref={documentFileRef}
style={{ display: 'none' }}
accept='.txt,.pdf'
accept=".txt,.pdf"
multiple={false}
onChange={() => importDocument()}
/>
<Button disabled={ documentImporting } appearance="transparent" icon={<AttachRegular />} onClick={() => selectDocument()} />
<Button
disabled={documentImporting}
appearance="transparent"
icon={<AttachRegular />}
onClick={() => selectDocument()}
/>
{documentImporting && <Spinner size="tiny" />}
</div>
<div className={classes.essentials}>
{recognizer && (
<Button appearance="transparent" disabled={isListening} icon={<MicRegular />} onClick={() => handleSpeech()} />
<Button
appearance="transparent"
disabled={isListening}
icon={<MicRegular />}
onClick={() => handleSpeech()}
/>
)}
<Button appearance="transparent" icon={<SendRegular />} onClick={() => handleSubmit(value)} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@ const log = debug(Constants.debug.root).extend('chat-room');

const useClasses = makeStyles({
root: {
height: '94.5%',
...shorthands.overflow('hidden'),
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
gridTemplateColumns: '1fr',
gridTemplateRows: '1fr auto',
gridTemplateAreas: "'history' 'input'",
height: '100%',
},
scroll: {
overflowY: 'auto',
},
history: {
...shorthands.gridArea('history'),
...shorthands.padding(tokens.spacingVerticalM),
overflowY: 'auto',
display: 'grid',
marginLeft: '40px',
paddingRight: '40px',
display: 'flex',
justifyContent: 'center',
},
input: {
...shorthands.gridArea('input'),
...shorthands.padding(tokens.spacingVerticalM),
},
});
Expand Down Expand Up @@ -113,8 +114,10 @@ export const ChatRoom: React.FC = () => {

return (
<div className={classes.root}>
<div ref={scrollViewTargetRef} className={classes.history}>
<ChatHistory audience={audience} messages={messages} onGetResponse={handleSubmit} />
<div ref={scrollViewTargetRef} className={classes.scroll}>
<div ref={scrollViewTargetRef} className={classes.history}>
<ChatHistory audience={audience} messages={messages} onGetResponse={handleSubmit} />
</div>
<div>
<div ref={scrollTargetRef} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,59 +26,34 @@ import { ShareBotMenu } from './ShareBotMenu';

const useClasses = makeStyles({
root: {
height: '100%',
display: 'grid',
gridTemplateColumns: '1fr',
gridTemplateRows: 'auto 1fr',
gridTemplateAreas: "'header' 'content'",
display: 'flex',
flexDirection: 'column',
width: '-webkit-fill-available',
backgroundColor: '#F5F5F5',
boxShadow: 'rgb(0 0 0 / 25%) 0 0.2rem 0.4rem -0.075rem',
},
header: {
...shorthands.gridArea('header'),
...shorthands.borderBottom('1px', 'solid', 'rgb(0 0 0 / 10%)'),
...shorthands.padding(tokens.spacingVerticalS, tokens.spacingHorizontalM),
backgroundColor: tokens.colorNeutralBackground4,
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
...shorthands.borderBottom('1px', 'solid', 'rgb(0 0 0 / 10%)'),
},
headerContent: {
...shorthands.padding(tokens.spacingVerticalS, tokens.spacingHorizontalM),
display: 'grid',
gridTemplateColumns: '1fr auto',
gridTemplateRows: '1fr',
gridTemplateAreas: "'title controls'",
boxSizing: 'border-box',
width: '100%',
justifyContent: 'space-between',
},
title: {
...shorthands.gridArea('title'),
...shorthands.gap(tokens.spacingHorizontalM),
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
},
controls: {
...shorthands.gridArea('controls'),
...shorthands.gap(tokens.spacingHorizontalM),
alignItems: 'right',
display: 'flex',
flexDirection: 'row',
},
content: {
...shorthands.gridArea('content'),
overflowY: 'auto',
},
contentOuter: {
height: '100%',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
},
contentInner: {
width: '100%',
},
});

export const ChatWindow: React.FC = () => {
Expand Down Expand Up @@ -125,42 +100,37 @@ export const ChatWindow: React.FC = () => {
return (
<div className={classes.root}>
<div className={classes.header}>
<div className={classes.headerContent}>
<div className={classes.title}>
<Persona
key={'SK Bot'}
size="medium"
avatar={{ image: { src: conversations[selectedId].botProfilePicture }}}
presence={{ status: 'available' }}
<div className={classes.title}>
<Persona
key={'SK Bot'}
size="medium"
avatar={{ image: { src: conversations[selectedId].botProfilePicture } }}
presence={{ status: 'available' }}
/>
{isEditing ? (
<Input value={title} onChange={onTitleChange} id={title} />
) : (
<Label size="large" weight="semibold">
{chatName}
</Label>
)}
<Tooltip
content={isEditing ? 'Save conversation name' : 'Edit conversation name'}
relationship="label"
>
<Button
icon={isEditing ? <Save24Regular /> : <EditRegular />}
appearance="transparent"
onClick={onEdit}
disabled={title === undefined || !title}
/>
{isEditing ? (
<Input value={title} onChange={onTitleChange} id={title} />
) : (
<Label size="large" weight="semibold">
{chatName}
</Label>
)}
<Tooltip content={isEditing ? "Save conversation name" : "Edit conversation name"} relationship="label">
<Button
icon={isEditing ? <Save24Regular /> : <EditRegular />}
appearance="transparent"
onClick={onEdit}
disabled={title === undefined || !title}
/>
</Tooltip>
</div>
<div className={classes.controls}>
<ShareBotMenu chatId={selectedId} chatTitle={title || ''} />
</div>
</Tooltip>
</div>
</div>
<div className={classes.content}>
<div className={classes.contentOuter}>
<div className={classes.contentInner}>
<ChatRoom />
</div>
<div className={classes.controls}>
<ShareBotMenu chatId={selectedId} chatTitle={title || ''} />
</div>
</div>
<ChatRoom />
</div>
);
};
Loading

0 comments on commit 5b9b820

Please sign in to comment.