Skip to content

Commit

Permalink
Rationalize AppLayout state, and add Shortcuts
Browse files Browse the repository at this point in the history
Ctrl + Alt + M: quick model setup
Ctrl + Alt + P: preferences
  • Loading branch information
enricoros committed Nov 2, 2023
1 parent a283d03 commit e9ec136
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 109 deletions.
6 changes: 3 additions & 3 deletions src/apps/chat/components/applayout/ChatDrawerItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import FileUploadIcon from '@mui/icons-material/FileUpload';

import { OpenAIIcon } from '~/common/components/icons/OpenAIIcon';
import { closeLayoutDrawerMenu } from '~/common/layout/store-applayout';
import { closeLayoutDrawer } from '~/common/layout/store-applayout';
import { useChatStore } from '~/common/state/store-chats';
import { useUIPreferencesStore } from '~/common/state/store-ui';

Expand Down Expand Up @@ -51,13 +51,13 @@ export function ChatDrawerItems(props: {
setActiveConversationId(topNewConversationId);
else
createConversation();
closeLayoutDrawerMenu();
closeLayoutDrawer();
};

const handleConversationActivate = React.useCallback((conversationId: string, closeMenu: boolean) => {
setActiveConversationId(conversationId);
if (closeMenu)
closeLayoutDrawerMenu();
closeLayoutDrawer();
}, [setActiveConversationId]);

const handleConversationDelete = React.useCallback((conversationId: string) => {
Expand Down
12 changes: 5 additions & 7 deletions src/apps/chat/components/applayout/ChatMenuItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import FileDownloadIcon from '@mui/icons-material/FileDownload';
import ForkRightIcon from '@mui/icons-material/ForkRight';
import SettingsSuggestIcon from '@mui/icons-material/SettingsSuggest';

import { setLayoutMenuAnchor } from '~/common/layout/store-applayout';
import { closeLayoutMenu } from '~/common/layout/store-applayout';
import { useUICounter, useUIPreferencesStore } from '~/common/state/store-ui';


Expand All @@ -32,32 +32,30 @@ export function ChatMenuItems(props: {
// derived state
const disabled = !props.conversationId || props.isConversationEmpty;

const closeContextMenu = () => setLayoutMenuAnchor(null);

const handleSystemMessagesToggle = () => setShowSystemMessages(!showSystemMessages);

const handleConversationExport = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
closeContextMenu();
closeLayoutMenu();
props.onExportConversation(!disabled ? props.conversationId : null);
shareTouch();
};

const handleConversationDuplicate = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
closeContextMenu();
closeLayoutMenu();
props.conversationId && props.onDuplicateConversation(props.conversationId);
};

const handleConversationFlatten = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
closeContextMenu();
closeLayoutMenu();
props.conversationId && props.onFlattenConversation(props.conversationId);
};

const handleToggleMessageSelectionMode = (e: React.MouseEvent) => {
e.stopPropagation();
closeContextMenu();
closeLayoutMenu();
props.setIsMessageSelectionMode(!props.isMessageSelectionMode);
};

Expand Down
18 changes: 10 additions & 8 deletions src/apps/chat/components/applayout/useLLMDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import * as React from 'react';
import { shallow } from 'zustand/shallow';

import { ListItemButton, ListItemDecorator } from '@mui/joy';
import { ListItemButton, ListItemDecorator, Tooltip } from '@mui/joy';
import BuildCircleIcon from '@mui/icons-material/BuildCircle';
import SettingsIcon from '@mui/icons-material/Settings';

import { DLLM, DLLMId, DModelSourceId, useModelsStore } from '~/modules/llms/store-llms';

import { AppBarDropdown, DropdownItems } from '~/common/layout/AppBarDropdown';
import { useUIStateStore } from '~/common/state/store-ui';
import { KeyStroke } from '~/common/components/KeyStroke';
import { openLayoutLLMOptions, openLayoutModelsSetup } from '~/common/layout/store-applayout';


function AppBarLLMDropdown(props: {
Expand All @@ -34,9 +35,8 @@ function AppBarLLMDropdown(props: {

const handleChatLLMChange = (_event: any, value: DLLMId | null) => value && props.setLlmId(value);

const handleOpenLLMOptions = () => props.llmId && useUIStateStore.getState().openLLMOptions(props.llmId);
const handleOpenLLMOptions = () => props.llmId && openLayoutLLMOptions(props.llmId);

const handleOpenModelsSetup = () => useUIStateStore.getState().openModelsSetup();

return (
<AppBarDropdown
Expand All @@ -52,10 +52,12 @@ function AppBarLLMDropdown(props: {
</ListItemButton>
)}

<ListItemButton key='menu-llms' onClick={handleOpenModelsSetup}>
<ListItemDecorator><BuildCircleIcon color='success' /></ListItemDecorator>
Models
</ListItemButton>
<Tooltip title={<KeyStroke combo='Ctrl + Alt + M' />}>
<ListItemButton key='menu-llms' onClick={openLayoutModelsSetup}>
<ListItemDecorator><BuildCircleIcon color='success' /></ListItemDecorator>
Models
</ListItemButton>
</Tooltip>

</>}
/>
Expand Down
10 changes: 6 additions & 4 deletions src/apps/chat/components/composer/Composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ import { ContentReducer } from '~/modules/aifn/summarize/ContentReducer';
import { LLMOptionsOpenAI } from '~/modules/llms/vendors/openai/openai.vendor';
import { useChatLLM } from '~/modules/llms/store-llms';

import { KeyStroke } from '~/common/components/KeyStroke';
import { SpeechResult, useSpeechRecognition } from '~/common/components/useSpeechRecognition';
import { countModelTokens } from '~/common/util/token-counter';
import { extractFilePathsWithCommonRadix } from '~/common/util/dropTextUtils';
import { hideOnDesktop, hideOnMobile } from '~/common/theme';
import { htmlTableToMarkdown } from '~/common/util/htmlTableToMarkdown';
import { launchAppCall } from '~/common/routes';
import { openLayoutPreferences } from '~/common/layout/store-applayout';
import { pdfToText } from '~/common/util/pdfToText';
import { useChatStore } from '~/common/state/store-chats';
import { useGlobalShortcut } from '~/common/components/useGlobalShortcut';
import { useUIPreferencesStore, useUIStateStore } from '~/common/state/store-ui';
import { useUIPreferencesStore } from '~/common/state/store-ui';

import { CameraCaptureButton } from './CameraCaptureButton';
import { ChatModeId, useComposerStartupText } from './store-composer';
Expand Down Expand Up @@ -88,11 +90,11 @@ const pasteClipboardLegend =
<Box sx={{ p: 1, lineHeight: 2 }}>
<b>Paste as 📚 Markdown attachment</b><br />
Also converts Code and Tables<br />
Ctrl + Shift + V
<KeyStroke combo='Ctrl + Shift + V' />
</Box>;

const MicButton = (props: { variant: VariantProp, color: ColorPaletteProp, onClick: () => void, sx?: SxProps }) =>
<Tooltip title='Ctrl + M' placement='top'>
<Tooltip title={<KeyStroke combo='Ctrl + M' />} placement='top'>
<IconButton variant={props.variant} color={props.color} onClick={props.onClick} sx={props.sx}>
<MicIcon />
</IconButton>
Expand Down Expand Up @@ -189,7 +191,7 @@ export function Composer(props: {

const handleCallClicked = () => props.conversationId && systemPurposeId && launchAppCall(props.conversationId, systemPurposeId);

const handleDrawOptionsClicked = () => useUIStateStore.getState().openSettings(2);
const handleDrawOptionsClicked = () => openLayoutPreferences(2);


const handleToggleChatMode = (event: React.MouseEvent<HTMLAnchorElement>) =>
Expand Down
4 changes: 2 additions & 2 deletions src/apps/link/AppChatLinkDrawerItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useChatLinkItems } from '../chat/trade/store-sharing';

import { Brand } from '~/common/brand';
import { Link } from '~/common/components/Link';
import { closeLayoutDrawerMenu } from '~/common/layout/store-applayout';
import { closeLayoutDrawer } from '~/common/layout/store-applayout';
import { getChatLinkRelativePath, getHomeLink } from '~/common/routes';


Expand All @@ -27,7 +27,7 @@ export function AppChatLinkDrawerItems() {
return <>

<MenuItem
onClick={closeLayoutDrawerMenu}
onClick={closeLayoutDrawer}
component={Link} href={getHomeLink()} noLinkStyle
>
<ListItemDecorator><ArrowBackIcon /></ListItemDecorator>
Expand Down
7 changes: 3 additions & 4 deletions src/apps/models-modal/LLMOptionsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import { DLLMId, useModelsStore } from '~/modules/llms/store-llms';

import { GoodModal } from '~/common/components/GoodModal';
import { useUIStateStore } from '~/common/state/store-ui';
import { closeLayoutLLMOptions } from '~/common/layout/store-applayout';

import { VendorLLMOptions } from './VendorLLMOptions';

Expand All @@ -20,7 +20,6 @@ export function LLMOptionsModal(props: { id: DLLMId }) {
const [showDetails, setShowDetails] = React.useState(false);

// external state
const closeLLMOptions = useUIStateStore(state => state.closeLLMOptions);
const {
llm,
removeLLM, updateLLM,
Expand Down Expand Up @@ -49,14 +48,14 @@ export function LLMOptionsModal(props: { id: DLLMId }) {

const handleLlmDelete = () => {
removeLLM(llm.id);
closeLLMOptions();
closeLayoutLLMOptions();
};

return (

<GoodModal
title={<><b>{llm.label}</b> options</>}
open={!!props.id} onClose={closeLLMOptions}
open={!!props.id} onClose={closeLayoutLLMOptions}
startButton={
<Button variant='plain' color='neutral' onClick={handleLlmDelete} startDecorator={<DeleteOutlineIcon />}>
Delete
Expand Down
7 changes: 2 additions & 5 deletions src/apps/models-modal/ModelsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,19 @@ import { DLLM, DModelSourceId, useModelsStore } from '~/modules/llms/store-llms'
import { IModelVendor } from '~/modules/llms/vendors/IModelVendor';
import { findVendorById } from '~/modules/llms/vendors/vendor.registry';

import { useUIStateStore } from '~/common/state/store-ui';
import { openLayoutLLMOptions } from '~/common/layout/store-applayout';


function ModelItem(props: { llm: DLLM, vendor: IModelVendor, chipChat: boolean, chipFast: boolean, chipFunc: boolean }) {

// external state
const openLLMOptions = useUIStateStore(state => state.openLLMOptions);

// derived
const llm = props.llm;
const label = llm.label;
const tooltip = `${llm._source.label}${llm.description ? ' - ' + llm.description : ''} - ${llm.contextTokens?.toLocaleString() || 'unknown tokens size'}`;

return (
<ListItem>
<ListItemButton onClick={() => openLLMOptions(llm.id)} sx={{ alignItems: 'center', gap: 1 }}>
<ListItemButton onClick={() => openLayoutLLMOptions(llm.id)} sx={{ alignItems: 'center', gap: 1 }}>

{/* Model Name */}
<Tooltip title={tooltip}>
Expand Down
12 changes: 7 additions & 5 deletions src/apps/models-modal/ModelsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { shallow } from 'zustand/shallow';
import { Checkbox, Divider } from '@mui/joy';

import { GoodModal } from '~/common/components/GoodModal';
import { useUIStateStore } from '~/common/state/store-ui';
import { closeLayoutModelsSetup, openLayoutModelsSetup, useLayoutModelsSetup } from '~/common/layout/store-applayout';
import { useGlobalShortcut } from '~/common/components/useGlobalShortcut';

import { DModelSourceId, useModelsStore } from '~/modules/llms/store-llms';
import { createModelSourceForDefaultVendor } from '~/modules/llms/vendors/vendor.registry';
Expand All @@ -22,11 +23,12 @@ export function ModelsModal(props: { suspendAutoModelsSetup?: boolean }) {
const [showAllSources, setShowAllSources] = React.useState<boolean>(false);

// external state
const { modelsSetupOpen, openModelsSetup, closeModelsSetup, llmOptionsId } = useUIStateStore();
const [modelsSetupOpen, llmOptionsId] = useLayoutModelsSetup();
const { modelSources, llmCount } = useModelsStore(state => ({
modelSources: state.sources,
llmCount: state.llms.length,
}), shallow);
useGlobalShortcut('m', true, true, openLayoutModelsSetup);

// auto-select the first source - note: we could use a useEffect() here, but this is more efficient
// also note that state-persistence is unneeded
Expand All @@ -39,8 +41,8 @@ export function ModelsModal(props: { suspendAutoModelsSetup?: boolean }) {
// if no sources at startup, open the modal
React.useEffect(() => {
if (!selectedSourceId && !props.suspendAutoModelsSetup)
openModelsSetup();
}, [selectedSourceId, openModelsSetup, props.suspendAutoModelsSetup]);
openLayoutModelsSetup();
}, [selectedSourceId, props.suspendAutoModelsSetup]);

// add the default source on cold - will require setup
React.useEffect(() => {
Expand All @@ -61,7 +63,7 @@ export function ModelsModal(props: { suspendAutoModelsSetup?: boolean }) {
checked={showAllSources} onChange={() => setShowAllSources(all => !all)}
/> : undefined
}
open={modelsSetupOpen} onClose={closeModelsSetup}
open onClose={closeLayoutModelsSetup}
>

<ModelsSourceSelector selectedSourceId={selectedSourceId} setSelectedSourceId={setSelectedSourceId} />
Expand Down
18 changes: 10 additions & 8 deletions src/apps/settings-modal/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import * as React from 'react';

import { Button, Divider, Tab, TabList, TabPanel, Tabs, useTheme } from '@mui/joy';
import { Button, Divider, Tab, TabList, TabPanel, Tabs } from '@mui/joy';
import { tabClasses } from '@mui/joy/Tab';
import BuildCircleIcon from '@mui/icons-material/BuildCircle';

import { ElevenlabsSettings } from '~/modules/elevenlabs/ElevenlabsSettings';
import { ProdiaSettings } from '~/modules/prodia/ProdiaSettings';

import { GoodModal } from '~/common/components/GoodModal';
import { useUIStateStore } from '~/common/state/store-ui';
import { closeLayoutPreferences, openLayoutModelsSetup, openLayoutPreferences, useLayoutPreferencesTab } from '~/common/layout/store-applayout';
import { useGlobalShortcut } from '~/common/components/useGlobalShortcut';

import { ToolsSettings } from './ToolsSettings';
import { UISettings } from './UISettings';
Expand All @@ -19,18 +20,19 @@ import { UISettings } from './UISettings';
* persisted on the client via localStorage.
*/
export function SettingsModal() {

// external state
const theme = useTheme();
const { settingsOpenTab, closeSettings, openModelsSetup } = useUIStateStore();
const settingsTabIndex = useLayoutPreferencesTab();
useGlobalShortcut('p', true, true, openLayoutPreferences);

const tabFixSx = { fontFamily: theme.fontFamily.body, flex: 1, p: 0, m: 0 };
const tabFixSx = { fontFamily: 'body', flex: 1, p: 0, m: 0 };

return (
<GoodModal
title='Preferences' strongerTitle
open={!!settingsOpenTab} onClose={closeSettings}
open={!!settingsTabIndex} onClose={closeLayoutPreferences}
startButton={
<Button variant='soft' color='success' onClick={openModelsSetup} startDecorator={<BuildCircleIcon />} sx={{
<Button variant='soft' color='success' onClick={openLayoutModelsSetup} startDecorator={<BuildCircleIcon />} sx={{
'--Icon-fontSize': 'var(--joy-fontSize-xl2)',
}}>
Models
Expand All @@ -41,7 +43,7 @@ export function SettingsModal() {

{/*<Divider />*/}

<Tabs aria-label='Settings tabbed menu' defaultValue={settingsOpenTab}>
<Tabs aria-label='Settings tabbed menu' defaultValue={settingsTabIndex}>
<TabList
variant='soft'
disableUnderline
Expand Down
6 changes: 3 additions & 3 deletions src/apps/settings-modal/UISettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import WidthNormalIcon from '@mui/icons-material/WidthNormal';
import WidthWideIcon from '@mui/icons-material/WidthWide';

import { Link } from '~/common/components/Link';
import { closeLayoutPreferences } from '~/common/layout/store-applayout';
import { hideOnMobile, settingsGap } from '~/common/theme';
import { isPwa } from '~/common/util/pwaUtils';
import { useUIPreferencesStore, useUIStateStore } from '~/common/state/store-ui';
import { useUIPreferencesStore } from '~/common/state/store-ui';


// configuration
Expand All @@ -37,7 +38,6 @@ export function UISettings() {
showPurposeFinder: state.showPurposeFinder, setShowPurposeFinder: state.setShowPurposeFinder,
zenMode: state.zenMode, setZenMode: state.setZenMode,
}), shallow);
const { closeSettings } = useUIStateStore(state => ({ closeSettings: state.closeSettings }), shallow);

const handleCenterModeChange = (event: React.ChangeEvent<HTMLInputElement>) => setCenterMode(event.target.value as 'narrow' | 'wide' | 'full' || 'wide');

Expand Down Expand Up @@ -123,7 +123,7 @@ export function UISettings() {

<FormControl orientation='horizontal' sx={{ justifyContent: 'space-between' }}>
<Box>
<FormLabel component={Link} href='/labs' onClick={closeSettings}>
<FormLabel component={Link} href='/labs' onClick={closeLayoutPreferences}>
<u>Experiments</u>
<InfoOutlinedIcon sx={{ mx: 0.5 }} />
</FormLabel>
Expand Down
22 changes: 22 additions & 0 deletions src/common/components/KeyStroke.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';

import { Chip } from '@mui/joy';

/**
* Shows a shortcut combo in a nicely presented dark box.
*/
export function KeyStroke(props: { combo: string }) {
return (
<Chip variant='solid' color='neutral'>
{props.combo}
</Chip>
// <Box sx={{
// position: 'relative', display: 'inline-block', px: 1, py: 0.5,
// bg: 'rgba(0,0,0,0.75)', color: 'white', borderRadius: 1,
// fontSize: 12, fontWeight: 500, lineHeight: 1, whiteSpace: 'nowrap',
// }}>
// <Box sx={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', bg: 'rgba(0,0,0,0.5)', borderRadius: 1 }} />
// {props.combo}
// </Box>
);
}
Loading

0 comments on commit e9ec136

Please sign in to comment.