mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 18:51:59 +00:00
Cody: Add some recipes buttons to the welcome message (#54277)
This adds three recipes to the welcome chat message in VScode to help users get started. Fixes issue #54232 . ## Test plan Open Cody. A new chat now has buttons. Clicking the buttons starts those recipes. --------- Co-authored-by: Beatrix <beatrix@sourcegraph.com>
This commit is contained in:
parent
9e78e1c4cd
commit
a7a1db2bb6
@ -3,9 +3,16 @@ import { Message } from '../../sourcegraph-api'
|
||||
|
||||
import { TranscriptJSON } from '.'
|
||||
|
||||
export interface ChatButton {
|
||||
label: string
|
||||
action: string
|
||||
onClick: (action: string) => void
|
||||
}
|
||||
|
||||
export interface ChatMessage extends Message {
|
||||
displayText?: string
|
||||
contextFiles?: ContextFile[]
|
||||
buttons?: ChatButton[]
|
||||
}
|
||||
|
||||
export interface InteractionMessage extends Message {
|
||||
|
||||
@ -3,7 +3,7 @@ import React, { useCallback, useMemo, useState } from 'react'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { ChatContextStatus } from '@sourcegraph/cody-shared/src/chat/context'
|
||||
import { ChatMessage } from '@sourcegraph/cody-shared/src/chat/transcript/messages'
|
||||
import { ChatButton, ChatMessage } from '@sourcegraph/cody-shared/src/chat/transcript/messages'
|
||||
import { isDefined } from '@sourcegraph/common'
|
||||
|
||||
import { FileLinkProps } from './chat/ContextFiles'
|
||||
@ -32,6 +32,7 @@ interface ChatProps extends ChatClassNames {
|
||||
fileLinkComponent: React.FunctionComponent<FileLinkProps>
|
||||
helpMarkdown?: string
|
||||
afterMarkdown?: string
|
||||
gettingStartedButtons?: ChatButton[]
|
||||
className?: string
|
||||
EditButtonContainer?: React.FunctionComponent<EditButtonProps>
|
||||
editButtonOnSubmit?: (text: string) => void
|
||||
@ -46,6 +47,7 @@ interface ChatProps extends ChatClassNames {
|
||||
abortMessageInProgressComponent?: React.FunctionComponent<{ onAbortMessageInProgress: () => void }>
|
||||
onAbortMessageInProgress?: () => void
|
||||
isCodyEnabled: boolean
|
||||
ChatButtonComponent?: React.FunctionComponent<ChatButtonProps>
|
||||
}
|
||||
|
||||
interface ChatClassNames extends TranscriptItemClassNames {
|
||||
@ -54,6 +56,12 @@ interface ChatClassNames extends TranscriptItemClassNames {
|
||||
chatInputClassName?: string
|
||||
}
|
||||
|
||||
export interface ChatButtonProps {
|
||||
label: string
|
||||
action: string
|
||||
onClick: (action: string) => void
|
||||
}
|
||||
|
||||
export interface ChatUITextAreaProps {
|
||||
className: string
|
||||
rows: number
|
||||
@ -113,6 +121,7 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
|
||||
fileLinkComponent,
|
||||
helpMarkdown,
|
||||
afterMarkdown,
|
||||
gettingStartedButtons,
|
||||
className,
|
||||
codeBlocksCopyButtonClassName,
|
||||
codeBlocksInsertButtonClassName,
|
||||
@ -138,6 +147,7 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
|
||||
abortMessageInProgressComponent: AbortMessageInProgressButton,
|
||||
onAbortMessageInProgress = () => {},
|
||||
isCodyEnabled,
|
||||
ChatButtonComponent,
|
||||
}) => {
|
||||
const [inputRows, setInputRows] = useState(5)
|
||||
const [historyIndex, setHistoryIndex] = useState(inputHistory.length)
|
||||
@ -230,10 +240,11 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
|
||||
{
|
||||
speaker: 'assistant',
|
||||
displayText: welcomeText({ helpMarkdown, afterMarkdown }),
|
||||
buttons: gettingStartedButtons,
|
||||
},
|
||||
...transcript,
|
||||
],
|
||||
[helpMarkdown, afterMarkdown, transcript]
|
||||
[helpMarkdown, afterMarkdown, gettingStartedButtons, transcript]
|
||||
)
|
||||
|
||||
return (
|
||||
@ -268,6 +279,7 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
|
||||
copyButtonOnSubmit={copyButtonOnSubmit}
|
||||
submitButtonComponent={SubmitButton}
|
||||
chatInputClassName={chatInputClassName}
|
||||
ChatButtonComponent={ChatButtonComponent}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import classNames from 'classnames'
|
||||
import { ChatMessage } from '@sourcegraph/cody-shared/src/chat/transcript/messages'
|
||||
|
||||
import {
|
||||
ChatButtonProps,
|
||||
ChatUITextAreaProps,
|
||||
EditButtonProps,
|
||||
FeedbackButtonsProps,
|
||||
@ -32,6 +33,7 @@ export const Transcript: React.FunctionComponent<
|
||||
feedbackButtonsOnSubmit?: (text: string) => void
|
||||
copyButtonOnSubmit?: CopyButtonProps['copyButtonOnSubmit']
|
||||
submitButtonComponent?: React.FunctionComponent<ChatUISubmitButtonProps>
|
||||
ChatButtonComponent?: React.FunctionComponent<ChatButtonProps>
|
||||
} & TranscriptItemClassNames
|
||||
> = React.memo(function TranscriptContent({
|
||||
transcript,
|
||||
@ -54,6 +56,7 @@ export const Transcript: React.FunctionComponent<
|
||||
copyButtonOnSubmit,
|
||||
submitButtonComponent,
|
||||
chatInputClassName,
|
||||
ChatButtonComponent,
|
||||
}) {
|
||||
const transcriptContainerRef = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
@ -116,6 +119,7 @@ export const Transcript: React.FunctionComponent<
|
||||
showFeedbackButtons={index > 0 && transcript.length - index === 1}
|
||||
submitButtonComponent={submitButtonComponent}
|
||||
chatInputClassName={chatInputClassName}
|
||||
ChatButtonComponent={ChatButtonComponent}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
@ -136,6 +140,7 @@ export const Transcript: React.FunctionComponent<
|
||||
copyButtonOnSubmit={copyButtonOnSubmit}
|
||||
submitButtonComponent={submitButtonComponent}
|
||||
chatInputClassName={chatInputClassName}
|
||||
ChatButtonComponent={ChatButtonComponent}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
FeedbackButtonsProps,
|
||||
CopyButtonProps,
|
||||
ChatUISubmitButtonProps,
|
||||
ChatButtonProps,
|
||||
} from '../Chat'
|
||||
|
||||
import { BlinkingCursor } from './BlinkingCursor'
|
||||
@ -52,6 +53,7 @@ export const TranscriptItem: React.FunctionComponent<
|
||||
submitButtonComponent?: React.FunctionComponent<ChatUISubmitButtonProps>
|
||||
abortMessageInProgressComponent?: React.FunctionComponent<{ onAbortMessageInProgress: () => void }>
|
||||
onAbortMessageInProgress?: () => void
|
||||
ChatButtonComponent?: React.FunctionComponent<ChatButtonProps>
|
||||
} & TranscriptItemClassNames
|
||||
> = React.memo(function TranscriptItemContent({
|
||||
message,
|
||||
@ -75,6 +77,7 @@ export const TranscriptItem: React.FunctionComponent<
|
||||
copyButtonOnSubmit,
|
||||
submitButtonComponent: SubmitButton,
|
||||
chatInputClassName,
|
||||
ChatButtonComponent,
|
||||
}) {
|
||||
const [formInput, setFormInput] = useState<string>(message.displayText ?? '')
|
||||
const textarea =
|
||||
@ -168,6 +171,9 @@ export const TranscriptItem: React.FunctionComponent<
|
||||
<BlinkingCursor />
|
||||
) : null}
|
||||
</div>
|
||||
{message.buttons?.length && ChatButtonComponent && (
|
||||
<div className={styles.actions}>{message.buttons.map(ChatButtonComponent)}</div>
|
||||
)}
|
||||
{showFeedbackButtons &&
|
||||
FeedbackButtonsContainer &&
|
||||
feedbackButtonsOnSubmit &&
|
||||
|
||||
@ -299,6 +299,18 @@ export class ChatViewProvider implements vscode.WebviewViewProvider, vscode.Disp
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'chat-button': {
|
||||
switch (message.action) {
|
||||
case 'explain-code-high-level':
|
||||
case 'find-code-smells':
|
||||
case 'generate-unit-test':
|
||||
void this.executeRecipe(message.action)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
this.sendErrorToWebview('Invalid request type from Webview')
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ export type WebviewMessage =
|
||||
| { command: 'insert'; text: string }
|
||||
| { command: 'auth'; type: 'signin' | 'signout' | 'support' | 'app' | 'callback'; endpoint?: string }
|
||||
| { command: 'abort' }
|
||||
| { command: 'chat-button'; action: string }
|
||||
|
||||
/**
|
||||
* A message sent from the extension host to the webview.
|
||||
|
||||
@ -97,6 +97,11 @@ body[data-vscode-theme-kind='vscode-high-contrast'] .transcript-item:not(.human-
|
||||
color: var(--vscode-problemsWarningIcon-foreground);
|
||||
}
|
||||
|
||||
.chat-button {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.feedback-buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -6,6 +6,7 @@ import classNames from 'classnames'
|
||||
import { ChatContextStatus } from '@sourcegraph/cody-shared/src/chat/context'
|
||||
import { ChatMessage } from '@sourcegraph/cody-shared/src/chat/transcript/messages'
|
||||
import {
|
||||
ChatButtonProps,
|
||||
Chat as ChatUI,
|
||||
ChatUISubmitButtonProps,
|
||||
ChatUISuggestionButtonProps,
|
||||
@ -89,6 +90,13 @@ export const Chat: React.FunctionComponent<React.PropsWithChildren<ChatboxProps>
|
||||
[vscodeAPI]
|
||||
)
|
||||
|
||||
const onChatButtonClick = useCallback(
|
||||
(which: string) => {
|
||||
vscodeAPI.postMessage({ command: 'chat-button', action: which })
|
||||
},
|
||||
[vscodeAPI]
|
||||
)
|
||||
|
||||
return (
|
||||
<ChatUI
|
||||
messageInProgress={messageInProgress}
|
||||
@ -128,7 +136,15 @@ export const Chat: React.FunctionComponent<React.PropsWithChildren<ChatboxProps>
|
||||
// down here to render cody is disabled on the instance nicely.
|
||||
isCodyEnabled={true}
|
||||
codyNotEnabledNotice={undefined}
|
||||
helpMarkdown="See [Getting Started](command:cody.welcome) for help and tips."
|
||||
helpMarkdown="See [Getting Started](command:cody.welcome) for help and tips.
|
||||
|
||||
To get started, select some code and run one of Cody's recipes:"
|
||||
gettingStartedButtons={[
|
||||
{ label: 'Explain code (high level)', action: 'explain-code-high-level', onClick: onChatButtonClick },
|
||||
{ label: 'Smell code', action: 'find-code-smells', onClick: onChatButtonClick },
|
||||
{ label: 'Generate a unit test', action: 'generate-unit-test', onClick: onChatButtonClick },
|
||||
]}
|
||||
ChatButtonComponent={ChatButton}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -149,6 +165,12 @@ const AbortMessageInProgress: React.FunctionComponent<AbortMessageInProgressProp
|
||||
</div>
|
||||
)
|
||||
|
||||
const ChatButton: React.FunctionComponent<ChatButtonProps> = ({ label, action, onClick }) => (
|
||||
<VSCodeButton type="button" onClick={() => onClick(action)} className={styles.chatButton}>
|
||||
{label}
|
||||
</VSCodeButton>
|
||||
)
|
||||
|
||||
const TextArea: React.FunctionComponent<ChatUITextAreaProps> = ({
|
||||
className,
|
||||
rows,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user