diff --git a/.eslintrc b/.eslintrc index d315386999..c173037fa1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,7 +12,7 @@ "@typescript-eslint/no-explicit-any": "off", "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ - "warn", // or "error" + "error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", diff --git a/cypress.config.ts b/cypress.config.ts index 2212db215a..c352b8d4e4 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -8,13 +8,14 @@ export default defineConfig({ bundler: 'vite' } }, + viewportWidth: 1200, e2e: { supportFile: false, defaultCommandTimeout: 10000, video: false, baseUrl: 'http://127.0.0.1:8000', - setupNodeEvents(on, config) { + setupNodeEvents(on) { on('task', { log(message) { console.log(message); diff --git a/cypress/e2e/conversations/spec.cy.ts b/cypress/e2e/conversations/spec.cy.ts index a739171225..8b87a69eba 100644 --- a/cypress/e2e/conversations/spec.cy.ts +++ b/cypress/e2e/conversations/spec.cy.ts @@ -20,10 +20,13 @@ describe('Conversations', () => { cy.intercept('GET', '/project/settings', { statusCode: 200, body: { - ui: {}, + ui: { + show_readme_as_default: true + }, userEnv: [], dataPersistence: true, - markdown: 'foo' + markdown: 'foo', + chatProfiles: [] } }).as('getSettings'); diff --git a/frontend/src/components/organisms/chat/index.tsx b/frontend/src/components/organisms/chat/index.tsx index 3ebe2af49b..5cc98b52bf 100644 --- a/frontend/src/components/organisms/chat/index.tsx +++ b/frontend/src/components/organisms/chat/index.tsx @@ -133,8 +133,8 @@ const Chat = () => { [askUser, user, replyMessage] ); - const tasklist = tasklists.at(-1); - const enableMultiModalUpload = !disabled && pSettings?.features.multi_modal; + const tasklist = tasklists[tasklists.length - 1]; + const enableMultiModalUpload = !disabled && pSettings?.features?.multi_modal; return ( { ) : null} - - {error && ( - - Could not reach the server. - + + + Could not reach the server. + + )} + - {!messages.length && pSettings?.ui.show_readme_as_default ? ( ) : ( diff --git a/frontend/src/components/organisms/chat/inputBox/UploadButton.tsx b/frontend/src/components/organisms/chat/inputBox/UploadButton.tsx index cd8fa72856..5e41f6f3ba 100644 --- a/frontend/src/components/organisms/chat/inputBox/UploadButton.tsx +++ b/frontend/src/components/organisms/chat/inputBox/UploadButton.tsx @@ -30,7 +30,7 @@ const UploadButton = ({ options: { noDrag: true } }); - if (!upload || !pSettings?.features.multi_modal) return null; + if (!upload || !pSettings?.features?.multi_modal) return null; const { getRootProps, getInputProps, uploading } = upload; return ( diff --git a/frontend/src/components/organisms/conversationsHistory/sidebar/OpenChatHistoryButton.tsx b/frontend/src/components/organisms/conversationsHistory/sidebar/OpenChatHistoryButton.tsx new file mode 100644 index 0000000000..6fdc0ef725 --- /dev/null +++ b/frontend/src/components/organisms/conversationsHistory/sidebar/OpenChatHistoryButton.tsx @@ -0,0 +1,48 @@ +import { useRecoilState } from 'recoil'; + +import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight'; +import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; + +import { settingsState } from 'state/settings'; + +const OpenChatHistoryButton = ({ mode }: { mode: 'mobile' | 'desktop' }) => { + const [settings, setSettings] = useRecoilState(settingsState); + const isDesktop = mode === 'desktop'; + + return !settings.isChatHistoryOpen ? ( + + theme.palette.background.paper + }} + onClick={() => + setSettings((prev) => ({ + ...prev, + isChatHistoryOpen: true + })) + } + > + + + + ) : null; +}; + +export default OpenChatHistoryButton; diff --git a/frontend/src/components/organisms/conversationsHistory/sidebar/index.tsx b/frontend/src/components/organisms/conversationsHistory/sidebar/index.tsx index fed44e0149..9b13775849 100644 --- a/frontend/src/components/organisms/conversationsHistory/sidebar/index.tsx +++ b/frontend/src/components/organisms/conversationsHistory/sidebar/index.tsx @@ -4,8 +4,6 @@ import { useEffect, useRef, useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft'; -import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight'; -import Box from '@mui/material/Box'; import Drawer from '@mui/material/Drawer'; import IconButton from '@mui/material/IconButton'; import Stack from '@mui/material/Stack'; @@ -20,6 +18,7 @@ import { conversationsHistoryState } from 'state/conversations'; import { projectSettingsState } from 'state/project'; +import { settingsState } from 'state/settings'; import { accessTokenState } from 'state/user'; import { ConversationsHistoryList } from './ConversationsHistoryList'; @@ -31,15 +30,15 @@ const BATCH_SIZE = 20; let _scrollTop = 0; const _ConversationsHistorySidebar = () => { - const isMobile = useMediaQuery('(max-width:800px)'); + const isMobile = useMediaQuery('(max-width:66rem)'); const [conversations, setConversations] = useRecoilState( conversationsHistoryState ); const accessToken = useRecoilValue(accessTokenState); const filters = useRecoilValue(conversationsFiltersState); + const [settings, setSettings] = useRecoilState(settingsState); - const [open, setOpen] = useState(true); const [shouldLoadMore, setShouldLoadMore] = useState(false); const [error, setError] = useState(undefined); const [prevFilters, setPrevFilters] = @@ -98,10 +97,17 @@ const _ConversationsHistorySidebar = () => { } }; + const setChatHistoryOpen = (open: boolean) => + setSettings((prev) => ({ ...prev, isChatHistoryOpen: open })); + useEffect(() => { if (ref.current) { ref.current.scrollTop = _scrollTop; } + + if (isMobile) { + setChatHistoryOpen(false); + } }, []); useEffect(() => { @@ -135,7 +141,7 @@ const _ConversationsHistorySidebar = () => { { onScroll: handleScroll }} sx={{ - width: open ? DRAWER_WIDTH : 0, + width: settings.isChatHistoryOpen ? DRAWER_WIDTH : 0, '& .MuiDrawer-paper': { position: 'inherit', gap: 1, @@ -171,8 +177,8 @@ const _ConversationsHistorySidebar = () => { > Chat History - setOpen(false)}> - + setChatHistoryOpen(false)}> + @@ -186,25 +192,6 @@ const _ConversationsHistorySidebar = () => { /> ) : null} - - theme.palette.background.paper - }} - onClick={() => setOpen(true)} - > - - - ); }; diff --git a/frontend/src/components/organisms/header.tsx b/frontend/src/components/organisms/header.tsx index 5d4a4d7a68..7b489cde82 100644 --- a/frontend/src/components/organisms/header.tsx +++ b/frontend/src/components/organisms/header.tsx @@ -10,9 +10,7 @@ import { IconButton, Menu, Stack, - Theme, - Toolbar, - useTheme + Toolbar } from '@mui/material'; import useMediaQuery from '@mui/material/useMediaQuery'; @@ -23,8 +21,12 @@ import UserButton from 'components/atoms/buttons/userButton'; import { Logo } from 'components/atoms/logo'; import NewChatButton from 'components/molecules/newChatButton'; +import { useAuth } from 'hooks/auth'; + import { projectSettingsState } from 'state/project'; +import OpenChatHistoryButton from './conversationsHistory/sidebar/OpenChatHistoryButton'; + interface INavItem { to: string; label: string; @@ -58,12 +60,13 @@ function NavItem({ to, label }: INavItem) { } interface NavProps { + dataPersistence?: boolean; hasReadme?: boolean; } -function Nav({ hasReadme }: NavProps) { +function Nav({ dataPersistence, hasReadme }: NavProps) { const location = useLocation(); - const theme = useTheme(); + const { isAuthenticated } = useAuth(); const [open, setOpen] = useState(false); const ref = useRef(); @@ -73,8 +76,7 @@ function Nav({ hasReadme }: NavProps) { anchorEl = ref.current; } - const matches = useMediaQuery(theme.breakpoints.down('md')); - + const isMobile = useMediaQuery('(max-width: 66rem)'); const tabs = [{ to: '/', label: 'Chat' }]; if (hasReadme) { @@ -82,7 +84,7 @@ function Nav({ hasReadme }: NavProps) { } const nav = ( - + {tabs.map((t) => { const active = location.pathname === t.to; return ( @@ -94,7 +96,7 @@ function Nav({ hasReadme }: NavProps) { ); - if (matches) { + if (isMobile) { return ( <> + {isAuthenticated && dataPersistence ? ( + + ) : null} theme.breakpoints.down('md')); + const matches = useMediaQuery('(max-width: 66rem)'); return ( @@ -153,9 +158,12 @@ export default function Header() { borderBottomColor: (theme) => theme.palette.divider }} > - + {!matches ? : null} -