Skip to content

Commit

Permalink
Add shared context for assistant selector
Browse files Browse the repository at this point in the history
Allow for selection of assistant from assistant panel
  • Loading branch information
rebeccaalpert committed Nov 27, 2024
1 parent a787422 commit b150481
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 50 deletions.
30 changes: 30 additions & 0 deletions src/app/AppData/AppDataContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { CannedChatbot } from '@app/types/CannedChatbot';
import * as React from 'react';

interface AppDataContextType {
flyoutMenuSelectedChatbot?: CannedChatbot;
updateFlyoutMenuSelectedChatbot: (newChatbot: CannedChatbot) => void;
}

const AppDataContext = React.createContext<AppDataContextType | undefined>(undefined);

export const AppDataProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [flyoutMenuSelectedChatbot, setFlyoutMenuSelectedChatbot] = React.useState<CannedChatbot>();

const updateFlyoutMenuSelectedChatbot = (newChatbot: CannedChatbot) =>
setFlyoutMenuSelectedChatbot((prev) => ({ ...prev, ...newChatbot }));

return (
<AppDataContext.Provider value={{ flyoutMenuSelectedChatbot, updateFlyoutMenuSelectedChatbot }}>
{children}
</AppDataContext.Provider>
);
};

export const useAppData = () => {
const context = React.useContext(AppDataContext);
if (!context) {
throw new Error('useAppData must be used within a AppDataProvider');
}
return context;
};
23 changes: 13 additions & 10 deletions src/app/AppLayout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { BarsIcon } from '@patternfly/react-icons';
import logo from '@app/bgimages/Logo-Red_Hat-Composer_AI_Studio-A-Standard-RGB.svg';
import logoDark from '@app/bgimages/Logo-Red_Hat-Composer_AI_Studio-A-Reverse.svg';
import { SidebarWithFlyout } from '@app/SidebarWithFlyout/SidebarWithFlyout';
import { AppDataProvider } from '@app/AppData/AppDataContext';

const AppLayout: React.FunctionComponent = () => {
const [sidebarOpen, setSidebarOpen] = React.useState(true);
Expand Down Expand Up @@ -77,16 +78,18 @@ const AppLayout: React.FunctionComponent = () => {
);

return (
<Page
className="chatbot-ui-page"
mainContainerId={pageId}
masthead={masthead}
sidebar={sidebarOpen && Sidebar}
skipToContent={PageSkipToContent}
isContentFilled
>
<Outlet />
</Page>
<AppDataProvider>
<Page
className="chatbot-ui-page"
mainContainerId={pageId}
masthead={masthead}
sidebar={sidebarOpen && Sidebar}
skipToContent={PageSkipToContent}
isContentFilled
>
<Outlet />
</Page>
</AppDataProvider>
);
};

Expand Down
10 changes: 9 additions & 1 deletion src/app/BaseChatbot/BaseChatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ import userAvatar from '@app/bgimages/avatarImg.svg';
import { Source } from '@app/types/Source';
import { SourceResponse } from '@app/types/SourceResponse';
import { UserFacingFile } from '@app/types/UserFacingFile';
import { useAppData } from '@app/AppData/AppDataContext';

const BaseChatbot: React.FunctionComponent = () => {
const { chatbots } = useLoaderData() as { chatbots: CannedChatbot[] };
const { flyoutMenuSelectedChatbot } = useAppData();
const [isSendButtonDisabled, setIsSendButtonDisabled] = React.useState(true);
const [messages, setMessages] = React.useState<MessageProps[]>([]);
const [currentMessage, setCurrentMessage] = React.useState<string[]>([]);
const [currentSources, setCurrentSources] = React.useState<Source[]>();
const scrollToBottomRef = React.useRef<HTMLDivElement>(null);
const [error, setError] = React.useState<{ title: string; body: string }>();
const [announcement, setAnnouncement] = React.useState<string>();
const [currentChatbot, setCurrentChatbot] = React.useState<CannedChatbot>(chatbots[0]);
const [currentChatbot, setCurrentChatbot] = React.useState<CannedChatbot>(flyoutMenuSelectedChatbot ?? chatbots[0]);
const [controller, setController] = React.useState<AbortController>();
const [currentDate, setCurrentDate] = React.useState<Date>();
const [hasStopButton, setHasStopButton] = React.useState(false);
Expand All @@ -50,6 +52,12 @@ const BaseChatbot: React.FunctionComponent = () => {
document.title = `Red Hat Composer AI Studio | ${currentChatbot?.name}`;
}, [currentChatbot]);

React.useEffect(() => {
if (flyoutMenuSelectedChatbot) {
setCurrentChatbot(flyoutMenuSelectedChatbot);
}
}, [flyoutMenuSelectedChatbot]);

React.useEffect(() => {
document.title = `Red Hat Composer AI Studio | ${currentChatbot?.name}${announcement ? ` - ${announcement}` : ''}`;
}, [announcement]);

Check warning on line 63 in src/app/BaseChatbot/BaseChatbot.tsx

View workflow job for this annotation

GitHub Actions / Lint

React Hook React.useEffect has a missing dependency: 'currentChatbot?.name'. Either include it or remove the dependency array
Expand Down
42 changes: 20 additions & 22 deletions src/app/FlyoutForm/FlyoutForm.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { FlyoutError } from '@app/FlyoutError/FlyoutError';
import { FlyoutFooter } from '@app/FlyoutFooter/FlyoutFooter';
import { FlyoutHeader } from '@app/FlyoutHeader.tsx/FlyoutHeader';
import { FlyoutStartScreen } from '@app/FlyoutStartScreen/FlyoutStartScreen';
import { useFlyoutWizard } from '@app/FlyoutWizard/FlyoutWizardContext';
import { ErrorObject } from '@app/types/ErrorObject';
import {
Dropdown,
DropdownItem,
DropdownList,
FileUpload,
//Dropdown,
//DropdownItem,
//DropdownList,
//FileUpload,
Form,
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
MenuToggle,
MenuToggleElement,
//MenuToggle,
//MenuToggleElement,
TextArea,
TextInput,
} from '@patternfly/react-core';
Expand All @@ -29,25 +28,25 @@ interface FlyoutFormProps {
export const FlyoutForm: React.FunctionComponent<FlyoutFormProps> = ({ header, hideFlyout }: FlyoutFormProps) => {
const [title, setTitle] = React.useState('');
const [displayName, setDisplayName] = React.useState('');
const [model, setModel] = React.useState('');
//const [model, setModel] = React.useState('');
const [instructions, setInstructions] = React.useState('');
const [icon, setIcon] = React.useState('');
const [filename, setFilename] = React.useState('');
//const [icon, setIcon] = React.useState('');
//const [filename, setFilename] = React.useState('');
const [error, setError] = React.useState<ErrorObject>();
const { nextStep, prevStep } = useFlyoutWizard();

const llmConnectionId = '66edae13e03073de9ef24204'; // how do i get these
const llmConnectionId = '66edae13e03073de9ef24204'; // fixme how do i get these
const retrieverConnectionId = '66f3fbffd7e04770c03ee123';

const handleFileInputChange = (_, file: File) => {
/*const handleFileInputChange = (_, file: File) => {
setFilename(file.name);
};
};*/

const handleClear = () => {
/*const handleClear = () => {
setFilename('');
setIcon('');
};
const [isOpen, setIsOpen] = React.useState(false);
};*/
// const [isOpen, setIsOpen] = React.useState(false);

const handleTitleChange = (_event, title: string) => {
setTitle(title);
Expand All @@ -57,21 +56,21 @@ export const FlyoutForm: React.FunctionComponent<FlyoutFormProps> = ({ header, h
setDisplayName(name);
};

const handleModelChange = (_event, value: string | number | undefined) => {
/*const handleModelChange = (_event, value: string | number | undefined) => {
if (value && typeof value === 'string') {
setModel(value);
return;
}
setModel('');
};
};*/

const handleInstructionsChange = (_event, instructions: string) => {
setInstructions(instructions);
};

const onToggleClick = () => {
/* const onToggleClick = () => {
setIsOpen(!isOpen);
};
};*/

const createAssistant = async () => {
const url =
Expand All @@ -95,12 +94,12 @@ export const FlyoutForm: React.FunctionComponent<FlyoutFormProps> = ({ header, h
});

if (!response.ok) {
// fixme use error handling used elsewhere
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
return data;
console.log('Assistant created successfully:', data);
} catch (error) {
if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
setError({ title: 'Error creating assistant', body: error.message });
Expand All @@ -113,7 +112,6 @@ export const FlyoutForm: React.FunctionComponent<FlyoutFormProps> = ({ header, h

const onClick = async () => {
const data = await createAssistant();
console.log(data);
if (data) {
nextStep();
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/FlyoutHeader.tsx/FlyoutHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TimesIcon } from '@patternfly/react-icons';
import * as React from 'react';

interface FlyoutHeaderProps {
title: string;
title: string | React.ReactNode;
hideFlyout: () => void;
}
export const FlyoutHeader: React.FunctionComponent<FlyoutHeaderProps> = ({ title, hideFlyout }: FlyoutHeaderProps) => {
Expand Down
22 changes: 13 additions & 9 deletions src/app/FlyoutList/FlyoutList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useAppData } from '@app/AppData/AppDataContext';
import { FlyoutFooter } from '@app/FlyoutFooter/FlyoutFooter';
import { FlyoutHeader } from '@app/FlyoutHeader.tsx/FlyoutHeader';
import { FlyoutLoading } from '@app/FlyoutLoading/FlyoutLoading';
Expand All @@ -23,7 +24,8 @@ export const FlyoutList: React.FunctionComponent<FlyoutListProps> = ({
const [items, setItems] = React.useState<CannedChatbot[]>([]);
const [filteredItems, setFilteredItems] = React.useState<CannedChatbot[]>([]);
const [isLoading, setIsLoading] = React.useState(true);
const { nextStep, prevStep } = useFlyoutWizard();
const { nextStep } = useFlyoutWizard();
const { updateFlyoutMenuSelectedChatbot } = useAppData();
const header = (
<div className="title-with-label">
{title} <Label variant="outline">{items.length}</Label>
Expand All @@ -41,7 +43,6 @@ export const FlyoutList: React.FunctionComponent<FlyoutListProps> = ({
}

const data = await response.json();
console.log('Assistants', data);
setItems(data);
setFilteredItems(data);
setIsLoading(false);
Expand All @@ -52,8 +53,7 @@ export const FlyoutList: React.FunctionComponent<FlyoutListProps> = ({
};

const loadAssistants = async () => {
const data = await getAssistants();
console.log(data);
await getAssistants();
};

React.useEffect(() => {
Expand All @@ -72,13 +72,17 @@ export const FlyoutList: React.FunctionComponent<FlyoutListProps> = ({
);
};

const onSelectActiveItem = () => {};
const activeItemId = '1';
const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, value) => {
console.log(value);
if (filteredItems.length > 0) {
const newChatbot = items.filter((item) => item.name === value)[0];
console.log(newChatbot);
updateFlyoutMenuSelectedChatbot(newChatbot);
}
};

const findMatchingItems = (targetValue: string) => {
const matchingElements = items.filter((item) => item.displayName.toLowerCase().includes(targetValue.toLowerCase()));

console.log(matchingElements);
return matchingElements;
};

Expand All @@ -103,7 +107,7 @@ export const FlyoutList: React.FunctionComponent<FlyoutListProps> = ({
onChange={(_event, value) => handleTextInputChange(value)}
placeholder={`Search ${typeWordPlural}...`}
/>
<Menu className="flyout-list-menu" isPlain onSelect={onSelectActiveItem} activeItemId={activeItemId}>
<Menu className="flyout-list-menu" isPlain onSelect={onSelect}>
<MenuContent>
{filteredItems.length > 0 ? (
buildMenu()
Expand Down
2 changes: 1 addition & 1 deletion src/app/FlyoutWizard/FlyoutWizard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useFlyoutWizard } from './FlyoutWizardContext';
import * as React from 'react';
import { useFlyoutWizard } from './FlyoutWizardContext';

export const FlyoutWizard: React.FC<{ steps: React.ReactNode[] }> = ({ steps }) => {
const { currentStep } = useFlyoutWizard();
Expand Down
7 changes: 1 addition & 6 deletions src/app/FlyoutWizard/FlyoutWizardContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,21 @@ import * as React from 'react';

interface FlyoutWizardContextType {
currentStep: number;
data: any;
nextStep: () => void;
prevStep: () => void;
goToStep: (step: number) => void;
updateData: (newData: any) => void;
}

const FlyoutWizardContext = React.createContext<FlyoutWizardContextType | undefined>(undefined);

export const FlyoutWizardProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [currentStep, setCurrentStep] = React.useState(0);
const [data, setData] = React.useState({});

const nextStep = () => setCurrentStep((prev) => prev + 1);
const prevStep = () => setCurrentStep((prev) => prev - 1);
const goToStep = (step: number) => setCurrentStep(step);
const updateData = (newData: any) => setData((prev) => ({ ...prev, ...newData }));

return (
<FlyoutWizardContext.Provider value={{ currentStep, data, nextStep, prevStep, goToStep, updateData }}>
<FlyoutWizardContext.Provider value={{ currentStep, nextStep, prevStep, goToStep }}>
{children}
</FlyoutWizardContext.Provider>
);
Expand Down

0 comments on commit b150481

Please sign in to comment.