diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx index ba8f6f63999..982bccb896a 100644 --- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -7,15 +7,13 @@ import React, { KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState import { useAccessor, useChatThreadsState, useChatThreadsStreamState, useSettingsState } from '../util/services.js'; -import { TextAreaFns, VoidInputBox2 } from '../util/inputs.js'; +import { TextAreaFns } from '../util/inputs.js'; import { PastThreadsList } from './SidebarThreadSelector.js'; import { VoidChatArea, ButtonSubmit, ButtonStop } from './composer/VoidChatArea.js'; import { SelectedFiles } from './composer/SelectedFiles.js'; import { scrollToBottom } from './composer/ScrollToBottomContainer.js'; -import { ContextUsageBar } from './composer/ContextUsageBar.js'; -import { CommandBarInChat } from './composer/CommandBarInChat.js'; import { ChatMessageList } from './composer/ChatMessageList.js'; -import { StagingContextChips } from './composer/StagingContextChips.js'; +import { ComposerInputSection } from './composer/ComposerInputSection.js'; import { useContextUsage } from './composer/useContextUsage.js'; import { resolveAtReferencesInMessage } from '../../../../common/resolveAtReferences.js'; import { handleSlashCommand } from './composer/handleSlashCommand.js'; @@ -31,8 +29,6 @@ import ErrorBoundary from './ErrorBoundary.js'; import { useImageAttachments } from '../util/useImageAttachments.js'; import { usePDFAttachments } from '../util/usePDFAttachments.js'; import { useTranslation } from '../util/useTranslation.js'; -import { PDFAttachmentList } from '../util/PDFAttachmentList.js'; -import { ImageAttachmentList } from '../util/ImageAttachmentList.js'; import { IconX, IconWarning, IconLoading, TypingCursor } from './shared/icons.js'; import { getBasename, getFolderName, getRelative, voidOpenFileFn } from './shared/pathUtils.js'; import { ToolChildrenWrapper, CodeChildren, ListableToolItem } from './tools/ToolPrimitives.js'; @@ -260,117 +256,55 @@ export const SidebarChat = () => { scrollToBottomCallback={scrollToBottomCallback} /> - const inputChatArea = onSubmit()} - onAbort={onAbort} - isStreaming={isActivelyStreaming} - isDisabled={isDisabled} - showSelections={true} - // showProspectiveSelections={previousMessagesHTML.length === 0} - selections={selections} - setSelections={setSelections} - onClickAnywhere={() => { textAreaRef.current?.focus() }} - imageAttachments={ - imageAttachments.length > 0 ? ( - <> - - {imageValidationError && ( -
- {imageValidationError.message} -
- )} - - ) : null - } - onImagePaste={addImages} - onImageDrop={addImages} - onPDFDrop={addPDFs} - pdfAttachments={ - pdfAttachments.length > 0 ? ( - <> - - {pdfValidationError && ( -
- {pdfValidationError} -
- )} - - ) : null - } - > - { chatThreadsService.setCurrentlyFocusedMessageIdx(undefined) }} - ref={textAreaRef} - fnsRef={textAreaFnsRef} - multiline={true} - /> - - {/* Context chips for current selections */} - { chatThreadsService.popStagingSelections(1) }} + const composerInputProps = { + onSubmit: () => onSubmit(), + onAbort, + isStreaming: isActivelyStreaming, + isDisabled, + selections, + setSelections, + textAreaRef, + textAreaFnsRef, + onChangeText, + onKeyDown, + onInputFocus: () => { chatThreadsService.setCurrentlyFocusedMessageIdx(undefined) }, + onRemoveStagingLast: () => { chatThreadsService.popStagingSelections(1) }, + imageAttachments, + removeImage, + retryImage, + cancelImage, + focusedImageIndex, + setFocusedImageIndex, + imageValidationError, + addImages, + pdfAttachments, + removePDF, + retryPDF, + cancelPDF, + focusedPDFIndex, + setFocusedPDFIndex, + pdfValidationError, + addPDFs, + modelSel, + contextTotal, + contextBudget, + contextPct, + }; + + const landingPageInput = ( + + ); + + const threadPageInput = ( + - -
- + ); const isLandingPage = previousMessages.length === 0 - - const threadPageInput =
-
- -
-
- {inputChatArea} - - {/* Context usage indicator */} - {modelSel ? ( - - ) : null} -
-
- - const landingPageInput =
-
- {inputChatArea} - {modelSel ? ( - - ) : null} -
-
- const landingPageContent = ( +
+ {message} +
+); + +export type ComposerInputAreaProps = { + onSubmit: () => void; + onAbort: () => void; + isStreaming: boolean; + isDisabled: boolean; + selections: StagingSelectionItem[]; + setSelections: (selections: StagingSelectionItem[]) => void; + textAreaRef: RefObject; + textAreaFnsRef: RefObject; + onChangeText: (value: string) => void; + onKeyDown: (e: KeyboardEvent) => void; + onInputFocus: () => void; + onRemoveStagingLast: () => void; + imageAttachments: ChatImageAttachment[]; + removeImage: (id: string) => void; + retryImage: (id: string) => Promise; + cancelImage: (id: string) => void; + focusedImageIndex: number | null; + setFocusedImageIndex: (index: number | null) => void; + imageValidationError: ImageValidationError | null; + addImages: (files: File[]) => Promise; + pdfAttachments: ChatPDFAttachment[]; + removePDF: (id: string) => void; + retryPDF: (id: string) => Promise; + cancelPDF: (id: string) => void; + focusedPDFIndex: number | null; + setFocusedPDFIndex: (index: number | null) => void; + pdfValidationError: string | null; + addPDFs: (files: File[]) => Promise; +}; + +export const ComposerInputArea = ({ + onSubmit, + onAbort, + isStreaming, + isDisabled, + selections, + setSelections, + textAreaRef, + textAreaFnsRef, + onChangeText, + onKeyDown, + onInputFocus, + onRemoveStagingLast, + imageAttachments, + removeImage, + retryImage, + cancelImage, + focusedImageIndex, + setFocusedImageIndex, + imageValidationError, + addImages, + pdfAttachments, + removePDF, + retryPDF, + cancelPDF, + focusedPDFIndex, + setFocusedPDFIndex, + pdfValidationError, + addPDFs, +}: ComposerInputAreaProps) => ( + { textAreaRef.current?.focus() }} + imageAttachments={ + imageAttachments.length > 0 ? ( + <> + + {imageValidationError ? ( + + ) : null} + + ) : null + } + onImagePaste={addImages} + onImageDrop={addImages} + onPDFDrop={addPDFs} + pdfAttachments={ + pdfAttachments.length > 0 ? ( + <> + + {pdfValidationError ? ( + + ) : null} + + ) : null + } + > + + + +); diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx new file mode 100644 index 00000000000..2b71ec26bcb --- /dev/null +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx @@ -0,0 +1,62 @@ +/*-------------------------------------------------------------------------------------- + * Copyright 2025 Glass Devtools, Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. + *--------------------------------------------------------------------------------------*/ + +import React from 'react'; +import { CommandBarInChat } from './CommandBarInChat.js'; +import { ContextUsageBar } from './ContextUsageBar.js'; +import { ComposerInputArea, ComposerInputAreaProps } from './ComposerInputArea.js'; +import { ModelSelection } from '../../../../common/cortexideSettingsTypes.js'; + +type ComposerInputSectionProps = ComposerInputAreaProps & { + variant: 'landing' | 'thread'; + threadKey?: string; + modelSel: ModelSelection | null | undefined; + contextTotal: number; + contextBudget: number; + contextPct: number; +}; + +export const ComposerInputSection = ({ + variant, + threadKey, + modelSel, + contextTotal, + contextBudget, + contextPct, + ...inputProps +}: ComposerInputSectionProps) => { + const inputArea = ; + const contextBar = modelSel ? ( + + ) : null; + + if (variant === 'thread') { + return ( +
+
+ +
+
+ {inputArea} + {contextBar} +
+
+ ); + } + + return ( +
+
+ {inputArea} + {contextBar} +
+
+ ); +};