From 4caad25380e6b23d51a586f59b54fd7d8099bf1e Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Fri, 2 Aug 2024 18:04:52 -0300 Subject: [PATCH] Cody Web: Update Cody Web to 0.3.6 [React version] (#64254) Closes https://linear.app/sourcegraph/issue/SRCH-720/new-chat-button-in-side-panel-view Closes https://linear.app/sourcegraph/issue/SRCH-808/chat-history-in-side-panel-view This PR does a few things - Updates Cody Web to 0.3.6 (this includes improvements around mentions UI, web url mention support, etc) - Adds "create new chat" button to the sidebar cody chat UI - Adds history chats UI to the sidebar cody chat UI (note that in GA we will rely on the new Tabs UI, this history UI is just a temporal solution for the Sourcegraph Aug release, in sep GA release it will be improved) ## Test plan - General manual checks on Cody Web. - Check that you can create a new chat from the sidebar chat UI - Check that you can select chats from the history panel from the sidebar chat UI ## Changelog --- .../chat-history-list/ChatHistoryList.tsx | 25 +++++-- .../NewCodySidebar.module.scss | 18 +++++ .../new-cody-sidebar/NewCodySidebar.tsx | 70 +++++++++++++++++-- .../NewCodySidebarWebChat.module.scss | 9 +++ .../NewCodySidebarWebChat.tsx | 53 ++++++++++++-- package.json | 2 +- pnpm-lock.yaml | 8 ++- 7 files changed, 165 insertions(+), 20 deletions(-) create mode 100644 client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.module.scss diff --git a/client/web/src/cody/chat/new-chat/components/chat-history-list/ChatHistoryList.tsx b/client/web/src/cody/chat/new-chat/components/chat-history-list/ChatHistoryList.tsx index b1828a3fcda..5d9b3e886b2 100644 --- a/client/web/src/cody/chat/new-chat/components/chat-history-list/ChatHistoryList.tsx +++ b/client/web/src/cody/chat/new-chat/components/chat-history-list/ChatHistoryList.tsx @@ -25,6 +25,7 @@ export interface ChatExportResult { interface ChatHistoryListProps { chats: ChatExportResult[] isSelectedChat: (chat: ChatExportResult) => boolean + withCreationButton?: boolean className?: string onChatSelect: (chat: ChatExportResult) => void onChatDelete: (chat: ChatExportResult) => void @@ -32,7 +33,15 @@ interface ChatHistoryListProps { } export const ChatHistoryList: FC = props => { - const { chats, isSelectedChat, className, onChatSelect, onChatDelete, onChatCreate } = props + const { + chats, + isSelectedChat, + withCreationButton = true, + className, + onChatSelect, + onChatDelete, + onChatCreate, + } = props const sortedChats = useMemo(() => { try { @@ -65,12 +74,14 @@ export const ChatHistoryList: FC = props => { onDelete={() => onChatDelete(chat)} /> ))} -
- -
+ {withCreationButton && ( +
+ +
+ )} ) } diff --git a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.module.scss b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.module.scss index b492efeb236..5a49c688a98 100644 --- a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.module.scss +++ b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.module.scss @@ -14,4 +14,22 @@ font-size: 0.875rem; background-color: var(--input-bg); border-bottom: 1px solid var(--border-color-2); + + &--main { + display: flex; + align-items: center; + flex-shrink: 0; + gap: 0.5rem; + } + + &--actions { + display: flex; + align-items: center; + gap: 0.5rem; + } + + &--logo { + display: flex; + align-items: center; + } } diff --git a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.tsx b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.tsx index 4b7590e1dff..c57144ed601 100644 --- a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.tsx +++ b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebar.tsx @@ -1,10 +1,11 @@ -import { Suspense, type FC } from 'react' +import { Suspense, type FC, useRef, useCallback, useState } from 'react' -import { mdiClose } from '@mdi/js' +import { mdiClose, mdiPlus, mdiArrowLeft, mdiHistory } from '@mdi/js' import { CodyLogo } from '@sourcegraph/cody-ui' +import type { CodyWebChatContextClient } from '@sourcegraph/cody-web' import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent' -import { Alert, Button, H4, Icon, LoadingSpinner, ProductStatusBadge } from '@sourcegraph/wildcard' +import { Alert, Button, H4, Icon, LoadingSpinner, ProductStatusBadge, Tooltip } from '@sourcegraph/wildcard' import styles from './NewCodySidebar.module.scss' @@ -25,16 +26,67 @@ interface NewCodySidebarProps { export const NewCodySidebar: FC = props => { const { repository, filePath, isAuthorized, onClose } = props + const [chatMode, setChatMode] = useState<'chat' | 'history'>('chat') + const codyClientRef = useRef() + + const handleShowHistory = (): void => { + setChatMode('history') + } + + const handleShowChat = (): void => { + setChatMode('chat') + } + + const handleCreateNewChat = async (): Promise => { + if (codyClientRef.current) { + await codyClientRef.current.createNewChat() + setChatMode('chat') + } + } + + const handleSelectChat = (): void => { + setChatMode('chat') + } + + const handleClientCreation = useCallback((client: CodyWebChatContextClient): void => { + codyClientRef.current = client + }, []) + return (
-
+
+ {chatMode === 'history' && ( + + + + )} + + {chatMode === 'chat' && ( + + + + )} + + + + +
+ + Cody
-
+ + @@ -48,7 +100,13 @@ export const NewCodySidebar: FC = props => {
} > - + )} diff --git a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.module.scss b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.module.scss new file mode 100644 index 00000000000..1d0d3bf0d80 --- /dev/null +++ b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.module.scss @@ -0,0 +1,9 @@ +.chat-history { + padding: 0.5rem; + overflow: auto; + height: 100%; +} + +.hidden { + display: none; +} diff --git a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.tsx b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.tsx index 668f1de736c..c5e7d6f3ed1 100644 --- a/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.tsx +++ b/client/web/src/cody/sidebar/new-cody-sidebar/NewCodySidebarWebChat.tsx @@ -1,13 +1,23 @@ import { type FC, memo, useCallback, useMemo } from 'react' +import classNames from 'classnames' import { useLocation } from 'react-router-dom' -import { CodyWebChatProvider, type InitialContext } from '@sourcegraph/cody-web' +import { + CodyWebChatProvider, + type InitialContext, + type CodyWebChatContextClient, + CodyWebHistory, +} from '@sourcegraph/cody-web' import { SourcegraphURL } from '@sourcegraph/common' -import { useLocalStorage } from '@sourcegraph/wildcard' +import { Text, useLocalStorage } from '@sourcegraph/wildcard' import { getTelemetrySourceClient } from '../../../telemetry' +import { ChatHistoryList } from '../../chat/new-chat/components/chat-history-list/ChatHistoryList' import { ChatUi } from '../../chat/new-chat/components/chat-ui/ChatUi' +import { Skeleton } from '../../chat/new-chat/components/skeleton/Skeleton' + +import styles from './NewCodySidebarWebChat.module.scss' interface Repository { id: string @@ -17,10 +27,13 @@ interface Repository { interface NewCodySidebarWebChatProps { filePath?: string repository: Repository + mode: 'chat' | 'history' + onChatSelect?: () => void + onClientCreated?: (client: CodyWebChatContextClient) => void } export const NewCodySidebarWebChat: FC = memo(function CodyWebChat(props) { - const { filePath, repository } = props + const { filePath, repository, onChatSelect, onClientCreated, mode } = props const location = useLocation() const [contextToChatIds, setContextToChatIds] = useLocalStorage>( @@ -64,8 +77,40 @@ export const NewCodySidebarWebChat: FC = memo(functi customHeaders={window.context.xhrHeaders} telemetryClientName={getTelemetrySourceClient()} onNewChatCreated={handleNewChatCreated} + onClientCreated={onClientCreated} > - + + +
+ + {history => ( +
+ {history.loading && ( + <> + + + + + )} + {history.error && Error: {history.error.message}} + + {!history.loading && !history.error && ( + { + onChatSelect?.() + history.selectChat(chat) + }} + onChatDelete={history.deleteChat} + onChatCreate={history.createNewChat} + /> + )} +
+ )} +
+
) }) diff --git a/package.json b/package.json index 81b728fa094..bfa20d17d6d 100644 --- a/package.json +++ b/package.json @@ -309,7 +309,7 @@ "@reach/visually-hidden": "^0.16.0", "@react-aria/live-announcer": "^3.1.0", "@sentry/browser": "^7.8.1", - "@sourcegraph/cody-web": "^0.3.4", + "@sourcegraph/cody-web": "^0.3.6", "@sourcegraph/extension-api-classes": "^1.1.0", "@stripe/react-stripe-js": "^2.7.0", "@stripe/stripe-js": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55de5163ce1..d100a962f04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,8 +146,8 @@ importers: specifier: ^7.8.1 version: 7.8.1 '@sourcegraph/cody-web': - specifier: ^0.3.4 - version: 0.3.4 + specifier: ^0.3.6 + version: 0.3.6 '@sourcegraph/extension-api-classes': specifier: ^1.1.0 version: 1.1.0(sourcegraph@client+extension-api) @@ -9724,6 +9724,10 @@ packages: resolution: {integrity: sha512-g9wXZcQTrPBrxE3Pm6A3ip57diIEQAwBEqy16gCoN7DIwI9YYsP47svXxwgJmF6JS0XEA33Ah9k3RbRfoMadKg==} dev: false + /@sourcegraph/cody-web@0.3.6: + resolution: {integrity: sha512-xFOjcdv7pITMg6AIN3VJxzXCdKk4nszQkuobbsqJeJwIA4sRljU+Zv6qLstzY5kQgCFu8KoYs9aAofAg3KFD0A==} + dev: false + /@sourcegraph/eslint-config@0.37.1(@testing-library/dom@8.13.0)(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-3G0d3OUgifaADfd27Bdk/kSpECj21BfQ6srbYMY/HVWOv/N8AVuFWNwUMT4Y4slt026RXO5XcwoZhfnaskr5hQ==} dependencies: