mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
ui changes
This commit is contained in:
parent
c87d1886cd
commit
eefa9648c4
8 changed files with 245 additions and 118 deletions
|
|
@ -78,7 +78,6 @@
|
||||||
|
|
||||||
/* styles for all containers used by void */
|
/* styles for all containers used by void */
|
||||||
.void-scope {
|
.void-scope {
|
||||||
background-color: var(--vscode-editor-background);
|
|
||||||
--scrollbar-vertical-width: 8px;
|
--scrollbar-vertical-width: 8px;
|
||||||
--scrollbar-horizontal-height: 6px;
|
--scrollbar-horizontal-height: 6px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { URI } from '../../../../../../../base/common/uri.js'
|
||||||
import { FileSymlink, LucideIcon, RotateCw, Terminal } from 'lucide-react'
|
import { FileSymlink, LucideIcon, RotateCw, Terminal } from 'lucide-react'
|
||||||
import { Check, X, Square, Copy, Play, } from 'lucide-react'
|
import { Check, X, Square, Copy, Play, } from 'lucide-react'
|
||||||
import { getBasename, ListableToolItem, ToolChildrenWrapper } from '../sidebar-tsx/SidebarChat.js'
|
import { getBasename, ListableToolItem, ToolChildrenWrapper } from '../sidebar-tsx/SidebarChat.js'
|
||||||
|
import { PlacesType, VariantType } from 'react-tooltip'
|
||||||
|
|
||||||
enum CopyButtonText {
|
enum CopyButtonText {
|
||||||
Idle = 'Copy',
|
Idle = 'Copy',
|
||||||
|
|
@ -31,13 +32,13 @@ export const IconShell1 = ({ onClick, Icon, disabled, className, ...props }: Ico
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onClick?.(e);
|
onClick?.(e);
|
||||||
}}
|
}}
|
||||||
|
// border border-void-border-1 rounded
|
||||||
className={`
|
className={`
|
||||||
size-[22px]
|
size-[18px]
|
||||||
p-[4px]
|
p-[2px]
|
||||||
flex items-center justify-center
|
flex items-center justify-center
|
||||||
text-sm bg-void-bg-3 text-void-fg-1
|
text-sm bg-void-bg-3 text-void-fg-3
|
||||||
hover:brightness-110
|
hover:brightness-110
|
||||||
border border-void-border-1 rounded
|
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed
|
disabled:opacity-50 disabled:cursor-not-allowed
|
||||||
${className}
|
${className}
|
||||||
`}
|
`}
|
||||||
|
|
@ -92,13 +93,14 @@ export const CopyButton = ({ codeStr }: { codeStr: string }) => {
|
||||||
return <IconShell1
|
return <IconShell1
|
||||||
Icon={copyButtonText === CopyButtonText.Copied ? Check : copyButtonText === CopyButtonText.Error ? X : Copy}
|
Icon={copyButtonText === CopyButtonText.Copied ? Check : copyButtonText === CopyButtonText.Error ? X : Copy}
|
||||||
onClick={onCopy}
|
onClick={onCopy}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Copy' })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const JumpToFileButton = ({ uri }: { uri: URI | 'current' }) => {
|
export const JumpToFileButton = ({ uri, ...props }: { uri: URI | 'current' } & React.ButtonHTMLAttributes<HTMLButtonElement>) => {
|
||||||
const accessor = useAccessor()
|
const accessor = useAccessor()
|
||||||
const commandService = accessor.get('ICommandService')
|
const commandService = accessor.get('ICommandService')
|
||||||
|
|
||||||
|
|
@ -108,6 +110,8 @@ export const JumpToFileButton = ({ uri }: { uri: URI | 'current' }) => {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
commandService.executeCommand('vscode.open', uri, { preview: true })
|
commandService.executeCommand('vscode.open', uri, { preview: true })
|
||||||
}}
|
}}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Goto file' })}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
return jumpToFileButton
|
return jumpToFileButton
|
||||||
|
|
@ -120,7 +124,6 @@ export const JumpToTerminalButton = ({ onClick }: { onClick: () => void }) => {
|
||||||
<IconShell1
|
<IconShell1
|
||||||
Icon={Terminal}
|
Icon={Terminal}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className="text-void-fg-1"
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -174,16 +177,18 @@ export const useApplyButtonState = ({ applyBoxId, uri }: { applyBoxId: string, u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const StatusIndicator = ({ color, title, className }: { color: 'green' | 'orange' | 'dark' | null, title?: React.ReactNode, className?: string }) => {
|
type IndicatorColor = 'green' | 'orange' | 'dark' | 'yellow' | null
|
||||||
|
export const StatusIndicator = ({ indicatorColor, title, className, ...props }: { indicatorColor: IndicatorColor, title?: React.ReactNode, className?: string } & React.HTMLAttributes<HTMLDivElement>) => {
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-row text-void-fg-3 text-xs items-center gap-1 ${className}`}>
|
<div className={`flex flex-row text-void-fg-3 text-xs items-center gap-1 ${className}`} {...props}>
|
||||||
{title && <span>{title}</span>}
|
{title && <span className='opacity-80'>{title}</span>}
|
||||||
<div
|
<div
|
||||||
className={` size-1.5 rounded-full border
|
className={` size-1.5 rounded-full border
|
||||||
${color === 'dark' ? 'bg-void-bg-3 border-void-border-1' :
|
${indicatorColor === 'dark' ? 'bg-void-bg-3 border-void-border-1' :
|
||||||
color === 'orange' ? 'bg-orange-500 border-orange-500 shadow-[0_0_4px_0px_rgba(234,88,12,0.6)]' :
|
indicatorColor === 'orange' ? 'bg-orange-500 border-orange-500 shadow-[0_0_4px_0px_rgba(234,88,12,0.6)]' :
|
||||||
color === 'green' ? 'bg-green-500 border-green-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' :
|
indicatorColor === 'green' ? 'bg-green-500 border-green-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' :
|
||||||
'bg-void-border-1 border-void-border-1'
|
indicatorColor === 'yellow' ? 'bg-yellow-500 border-yellow-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' :
|
||||||
|
'bg-void-border-1 border-void-border-1'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
/>
|
/>
|
||||||
|
|
@ -191,7 +196,15 @@ export const StatusIndicator = ({ color, title, className }: { color: 'green' |
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' }) => {
|
const tooltipPropsForApplyBlock = ({ tooltipName, color = undefined, position = 'top-end', offset = undefined }: { tooltipName: string, color?: IndicatorColor, position?: PlacesType, offset?: number }) => ({
|
||||||
|
'data-tooltip-id': color === 'orange' ? `void-tooltip-orange` : color === 'green' ? 'void-tooltip-green' : 'void-tooltip',
|
||||||
|
'data-tooltip-place': position as PlacesType,
|
||||||
|
'data-tooltip-content': `${tooltipName}`,
|
||||||
|
'data-tooltip-offset': offset,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' } & React.HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
|
||||||
const { currStreamState } = useApplyButtonState({ applyBoxId, uri })
|
const { currStreamState } = useApplyButtonState({ applyBoxId, uri })
|
||||||
|
|
||||||
|
|
@ -202,7 +215,19 @@ export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId:
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
const statusIndicatorHTML = <StatusIndicator className='mx-2' color={color} />
|
const tooltipName = (
|
||||||
|
currStreamState === 'idle-no-changes' ? 'Done' :
|
||||||
|
currStreamState === 'streaming' ? 'Applying' :
|
||||||
|
currStreamState === 'idle-has-changes' ? 'Done' : // also 'Done'? 'Applied' looked bad
|
||||||
|
''
|
||||||
|
)
|
||||||
|
|
||||||
|
const statusIndicatorHTML = <StatusIndicator
|
||||||
|
key={currStreamState}
|
||||||
|
className='mx-2'
|
||||||
|
indicatorColor={color}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName, color, position: 'top', offset: 12 })}
|
||||||
|
/>
|
||||||
return statusIndicatorHTML
|
return statusIndicatorHTML
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,11 +292,22 @@ export const ApplyButtonsHTML = ({ codeStr, applyBoxId, reapplyIcon, uri }: { co
|
||||||
|
|
||||||
|
|
||||||
if (currStreamState === 'streaming') {
|
if (currStreamState === 'streaming') {
|
||||||
return <IconShell1 Icon={Square} onClick={onInterrupt} />
|
return <IconShell1
|
||||||
|
|
||||||
|
Icon={Square}
|
||||||
|
onClick={onInterrupt}
|
||||||
|
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Stop' })}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currStreamState === 'idle-no-changes') {
|
if (currStreamState === 'idle-no-changes') {
|
||||||
return <IconShell1 Icon={reapplyIcon ? RotateCw : Play} onClick={onClickSubmit} />
|
|
||||||
|
return <IconShell1
|
||||||
|
Icon={reapplyIcon ? RotateCw : Play}
|
||||||
|
onClick={onClickSubmit}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: reapplyIcon ? 'Reapply' : 'Apply' })}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currStreamState === 'idle-has-changes') {
|
if (currStreamState === 'idle-has-changes') {
|
||||||
|
|
@ -283,12 +319,12 @@ export const ApplyButtonsHTML = ({ codeStr, applyBoxId, reapplyIcon, uri }: { co
|
||||||
<IconShell1
|
<IconShell1
|
||||||
Icon={X}
|
Icon={X}
|
||||||
onClick={onReject}
|
onClick={onReject}
|
||||||
className="text-red-600"
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Reject file' })}
|
||||||
/>
|
/>
|
||||||
<IconShell1
|
<IconShell1
|
||||||
Icon={Check}
|
Icon={Check}
|
||||||
onClick={onAccept}
|
onClick={onAccept}
|
||||||
className="text-green-600"
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Accept file' })}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ import { getModelCapabilities, getIsReasoningEnabledState } from '../../../../co
|
||||||
import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X } from 'lucide-react';
|
import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X } from 'lucide-react';
|
||||||
import { ChatMessage, CheckpointEntry, StagingSelectionItem, ToolMessage } from '../../../../common/chatThreadServiceTypes.js';
|
import { ChatMessage, CheckpointEntry, StagingSelectionItem, ToolMessage } from '../../../../common/chatThreadServiceTypes.js';
|
||||||
import { ToolCallParams, ToolName, toolNames, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js';
|
import { ToolCallParams, ToolName, toolNames, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js';
|
||||||
import { ApplyButtonsHTML, CopyButton, JumpToFileButton, JumpToTerminalButton, StatusIndicator, StatusIndicatorForApplyButton, useApplyButtonState } from '../markdown/ApplyBlockHoverButtons.js';
|
import { ApplyButtonsHTML, CopyButton, IconShell1, JumpToFileButton, JumpToTerminalButton, StatusIndicator, StatusIndicatorForApplyButton, useApplyButtonState } from '../markdown/ApplyBlockHoverButtons.js';
|
||||||
import { IsRunningType } from '../../../chatThreadService.js';
|
import { IsRunningType } from '../../../chatThreadService.js';
|
||||||
import { acceptAllBg, acceptBorder, buttonFontSize, buttonTextColor, rejectAllBg, rejectBg, rejectBorder } from '../../../../common/helpers/colors.js';
|
import { acceptAllBg, acceptBorder, buttonFontSize, buttonTextColor, rejectAllBg, rejectBg, rejectBorder } from '../../../../common/helpers/colors.js';
|
||||||
|
import { PlacesType } from 'react-tooltip';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -391,6 +392,9 @@ export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Re
|
||||||
${disabled ? 'bg-vscode-disabled-fg cursor-default' : 'bg-white cursor-pointer'}
|
${disabled ? 'bg-vscode-disabled-fg cursor-default' : 'bg-white cursor-pointer'}
|
||||||
${className}
|
${className}
|
||||||
`}
|
`}
|
||||||
|
// data-tooltip-id='void-tooltip'
|
||||||
|
// data-tooltip-content={'Send'}
|
||||||
|
// data-tooltip-place='left'
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<IconArrowUp size={DEFAULT_BUTTON_SIZE} className="stroke-[2] p-[2px]" />
|
<IconArrowUp size={DEFAULT_BUTTON_SIZE} className="stroke-[2] p-[2px]" />
|
||||||
|
|
@ -955,25 +959,32 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhost, _scr
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<EditSymbol
|
|
||||||
size={18}
|
<div
|
||||||
className={`
|
className="absolute -top-1 -right-1 translate-x-0 -translate-y-0 z-1"
|
||||||
absolute -top-1 -right-1
|
// data-tooltip-id='void-tooltip'
|
||||||
translate-x-0 -translate-y-0
|
// data-tooltip-content='Edit message'
|
||||||
cursor-pointer z-1
|
// data-tooltip-place='left'
|
||||||
p-[2px]
|
>
|
||||||
bg-void-bg-1 border border-void-border-1 rounded-md
|
<EditSymbol
|
||||||
transition-opacity duration-200 ease-in-out
|
size={18}
|
||||||
${isHovered || (isFocused && mode === 'edit') ? 'opacity-100' : 'opacity-0'}
|
className={`
|
||||||
`}
|
cursor-pointer
|
||||||
onClick={() => {
|
p-[2px]
|
||||||
if (mode === 'display') {
|
bg-void-bg-1 border border-void-border-1 rounded-md
|
||||||
onOpenEdit()
|
transition-opacity duration-200 ease-in-out
|
||||||
} else if (mode === 'edit') {
|
${isHovered || (isFocused && mode === 'edit') ? 'opacity-100' : 'opacity-0'}
|
||||||
onCloseEdit()
|
`}
|
||||||
}
|
onClick={() => {
|
||||||
}}
|
if (mode === 'display') {
|
||||||
/>
|
onOpenEdit()
|
||||||
|
} else if (mode === 'edit') {
|
||||||
|
onCloseEdit()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -1240,7 +1251,7 @@ const ToolRequestAcceptRejectButtons = () => {
|
||||||
<button
|
<button
|
||||||
onClick={onAccept}
|
onClick={onAccept}
|
||||||
className={`
|
className={`
|
||||||
px-4 py-1.5
|
px-2 py-1
|
||||||
bg-[var(--vscode-button-background)]
|
bg-[var(--vscode-button-background)]
|
||||||
text-[var(--vscode-button-foreground)]
|
text-[var(--vscode-button-foreground)]
|
||||||
hover:bg-[var(--vscode-button-hoverBackground)]
|
hover:bg-[var(--vscode-button-hoverBackground)]
|
||||||
|
|
@ -1256,7 +1267,7 @@ const ToolRequestAcceptRejectButtons = () => {
|
||||||
<button
|
<button
|
||||||
onClick={onReject}
|
onClick={onReject}
|
||||||
className={`
|
className={`
|
||||||
px-4 py-1.5
|
px-2 py-1
|
||||||
bg-[var(--vscode-button-secondaryBackground)]
|
bg-[var(--vscode-button-secondaryBackground)]
|
||||||
text-[var(--vscode-button-secondaryForeground)]
|
text-[var(--vscode-button-secondaryForeground)]
|
||||||
hover:bg-[var(--vscode-button-secondaryHoverBackground)]
|
hover:bg-[var(--vscode-button-secondaryHoverBackground)]
|
||||||
|
|
@ -1271,7 +1282,7 @@ const ToolRequestAcceptRejectButtons = () => {
|
||||||
const autoApproveToggle = (
|
const autoApproveToggle = (
|
||||||
<div className="flex items-center ml-2 gap-x-1">
|
<div className="flex items-center ml-2 gap-x-1">
|
||||||
<VoidSwitch
|
<VoidSwitch
|
||||||
size="xs"
|
size="xxs"
|
||||||
value={voidSettingsState.globalSettings.autoApprove}
|
value={voidSettingsState.globalSettings.autoApprove}
|
||||||
onChange={onToggleAutoApprove}
|
onChange={onToggleAutoApprove}
|
||||||
/>
|
/>
|
||||||
|
|
@ -2002,17 +2013,24 @@ const CommandBarInChat = () => {
|
||||||
const chatThreadsState = useChatThreadsState()
|
const chatThreadsState = useChatThreadsState()
|
||||||
const chatThreadsStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId)
|
const chatThreadsStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId)
|
||||||
|
|
||||||
const [isFileDetailsOpened, setFileDetailsOpened] = useState(false);
|
const [fileDetailsOpenedState, setFileDetailsOpenedState] = useState<'auto-opened' | 'auto-closed' | 'user-opened' | 'user-closed'>('auto-closed');
|
||||||
|
const isFileDetailsOpened = fileDetailsOpenedState === 'auto-opened' || fileDetailsOpenedState === 'user-opened';
|
||||||
|
|
||||||
|
|
||||||
// close the file details if there are no files
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFileDetailsOpened && numFilesChanged === 0) {
|
// close the file details if there are no files
|
||||||
setFileDetailsOpened(false)
|
// this converts 'user-closed' to 'auto-closed'
|
||||||
|
if (numFilesChanged === 0) {
|
||||||
|
setFileDetailsOpenedState('auto-closed')
|
||||||
}
|
}
|
||||||
}, [isFileDetailsOpened, numFilesChanged, setFileDetailsOpened])
|
// open the file details if it hasnt been closed
|
||||||
|
if (numFilesChanged > 0 && fileDetailsOpenedState !== 'user-closed') {
|
||||||
|
setFileDetailsOpenedState('auto-opened')
|
||||||
|
}
|
||||||
|
}, [fileDetailsOpenedState, setFileDetailsOpenedState, numFilesChanged])
|
||||||
|
|
||||||
|
|
||||||
const isFinishedMakingThreadChanges = chatThreadsStreamState && !chatThreadsStreamState.isRunning && numFilesChanged !== 0
|
const isFinishedMakingThreadChanges = numFilesChanged !== 0 && (chatThreadsStreamState ? !chatThreadsStreamState.isRunning : true)
|
||||||
|
|
||||||
// ======== status of agent ========
|
// ======== status of agent ========
|
||||||
// This icon answers the question "is the LLM doing work on this thread?"
|
// This icon answers the question "is the LLM doing work on this thread?"
|
||||||
|
|
@ -2022,13 +2040,13 @@ const CommandBarInChat = () => {
|
||||||
// dark = Done
|
// dark = Done
|
||||||
|
|
||||||
const threadStatus = (
|
const threadStatus = (
|
||||||
chatThreadsStreamState?.isRunning === 'awaiting_user' ? { title: 'Needs Approval', color: 'orange', } as const
|
chatThreadsStreamState?.isRunning === 'awaiting_user' ? { title: 'Needs Approval', color: 'yellow', } as const
|
||||||
: chatThreadsStreamState?.isRunning ? { title: 'Running', color: 'green', } as const
|
: chatThreadsStreamState?.isRunning ? { title: 'Running', color: 'orange', } as const
|
||||||
: { title: 'Done', color: 'dark', } as const
|
: { title: 'Done', color: 'dark', } as const
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
const threadStatusHTML = <StatusIndicator color={threadStatus.color} title={threadStatus.title} />
|
const threadStatusHTML = <StatusIndicator className='mx-1' indicatorColor={threadStatus.color} title={threadStatus.title} />
|
||||||
|
|
||||||
|
|
||||||
// ======== info about changes ========
|
// ======== info about changes ========
|
||||||
|
|
@ -2037,29 +2055,21 @@ const CommandBarInChat = () => {
|
||||||
// popup info about each change (each with num changes + acceptall + rejectall of their own)
|
// popup info about each change (each with num changes + acceptall + rejectall of their own)
|
||||||
|
|
||||||
const numFilesChangedStr = numFilesChanged === 0 ? 'No files with changes'
|
const numFilesChangedStr = numFilesChanged === 0 ? 'No files with changes'
|
||||||
: `${sortedCommandBarURIs.length} file${numFilesChanged === 1 ? '' : 's'} changed`
|
: `${sortedCommandBarURIs.length} file${numFilesChanged === 1 ? '' : 's'} with changes`
|
||||||
|
|
||||||
const acceptAllButton = (
|
|
||||||
<AcceptAllButtonWrapper
|
|
||||||
text="Accept All"
|
|
||||||
className="text-xs"
|
|
||||||
onClick={() => {
|
|
||||||
sortedCommandBarURIs.forEach(uri => {
|
|
||||||
editCodeService.acceptOrRejectAllDiffAreas({
|
|
||||||
uri,
|
|
||||||
removeCtrlKs: true,
|
|
||||||
behavior: "accept",
|
|
||||||
_addToHistory: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
const rejectAllButton = (
|
|
||||||
<RejectAllButtonWrapper
|
|
||||||
text="Reject All"
|
const acceptRejectAllButtons = <div
|
||||||
className="text-xs"
|
// do this with opacity so that the height remains the same at all times
|
||||||
|
className={`flex items-center gap-0.5
|
||||||
|
${isFinishedMakingThreadChanges ? '' : 'opacity-0 pointer-events-none'}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconShell1 // RejectAllButtonWrapper
|
||||||
|
// text="Reject All"
|
||||||
|
// className="text-xs"
|
||||||
|
Icon={X}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
sortedCommandBarURIs.forEach(uri => {
|
sortedCommandBarURIs.forEach(uri => {
|
||||||
editCodeService.acceptOrRejectAllDiffAreas({
|
editCodeService.acceptOrRejectAllDiffAreas({
|
||||||
|
|
@ -2067,16 +2077,35 @@ const CommandBarInChat = () => {
|
||||||
removeCtrlKs: true,
|
removeCtrlKs: true,
|
||||||
behavior: "reject",
|
behavior: "reject",
|
||||||
_addToHistory: true,
|
_addToHistory: true,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
|
data-tooltip-id='void-tooltip'
|
||||||
|
data-tooltip-place='top'
|
||||||
|
data-tooltip-content='Reject all'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconShell1 // AcceptAllButtonWrapper
|
||||||
|
// text="Accept All"
|
||||||
|
// className="text-xs"
|
||||||
|
Icon={Check}
|
||||||
|
onClick={() => {
|
||||||
|
sortedCommandBarURIs.forEach(uri => {
|
||||||
|
editCodeService.acceptOrRejectAllDiffAreas({
|
||||||
|
uri,
|
||||||
|
removeCtrlKs: true,
|
||||||
|
behavior: "accept",
|
||||||
|
_addToHistory: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
data-tooltip-id='void-tooltip'
|
||||||
|
data-tooltip-place='top'
|
||||||
|
data-tooltip-content='Accept all'
|
||||||
/>
|
/>
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
const acceptRejectAllButtons = isFinishedMakingThreadChanges && <div className='flex items-center gap-1'>
|
|
||||||
{acceptAllButton}
|
|
||||||
{rejectAllButton}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2092,44 +2121,60 @@ const CommandBarInChat = () => {
|
||||||
|
|
||||||
const fileStatus = (isFinishedMakingFileChanges
|
const fileStatus = (isFinishedMakingFileChanges
|
||||||
? { title: 'Done', color: 'dark', } as const
|
? { title: 'Done', color: 'dark', } as const
|
||||||
: { title: 'Running', color: 'green', } as const
|
: { title: 'Running', color: 'orange', } as const
|
||||||
)
|
)
|
||||||
|
|
||||||
const acceptButton = <AcceptAllButtonWrapper
|
|
||||||
text="Accept"
|
|
||||||
className="text-xs"
|
|
||||||
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "accept", _addToHistory: true, }) }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
const rejectButton = <RejectAllButtonWrapper
|
|
||||||
text="Reject"
|
|
||||||
className="text-xs"
|
|
||||||
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "reject", _addToHistory: true, }) }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
const fileNameHTML = <div
|
const fileNameHTML = <div
|
||||||
className="flex items-center gap-1.5 hover:brightness-125 transition-all duration-200 cursor-pointer"
|
className="flex items-center gap-1.5 text-void-fg-3 hover:brightness-125 transition-all duration-200 cursor-pointer"
|
||||||
onClick={() => commandService.executeCommand('vscode.open', uri, { preview: true })}
|
onClick={() => commandService.executeCommand('vscode.open', uri, { preview: true })}
|
||||||
>
|
>
|
||||||
<FileIcon size={14} className="text-void-fg-3" />
|
{/* <FileIcon size={14} className="text-void-fg-3" /> */}
|
||||||
<span className="text-void-fg-2">{basename}</span>
|
<span className="text-void-fg-3">{basename}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
const detailsContent = <>
|
|
||||||
<span className="text-void-fg-3">{numDiffs} change{numDiffs !== 1 ? 's' : ''}</span>
|
|
||||||
</>
|
|
||||||
|
|
||||||
const acceptRejectButtons = isFinishedMakingFileChanges && <div className='flex gap-1'>
|
|
||||||
{acceptButton}
|
|
||||||
{rejectButton}
|
const detailsContent = <div className='flex px-4'>
|
||||||
|
<span className="text-void-fg-3 opacity-80">{numDiffs} diff{numDiffs !== 1 ? 's' : ''}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
const fileStatusHTML = <StatusIndicator color={fileStatus.color} title={fileStatus.title} />
|
const acceptRejectButtons = <div
|
||||||
|
// do this with opacity so that the height remains the same at all times
|
||||||
|
className={`flex
|
||||||
|
${isFinishedMakingThreadChanges ? '' : 'opacity-0 pointer-events-none'}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<JumpToFileButton
|
||||||
|
uri={uri}
|
||||||
|
data-tooltip-id='void-tooltip'
|
||||||
|
data-tooltip-place='top'
|
||||||
|
data-tooltip-content='Goto file'
|
||||||
|
/>
|
||||||
|
<IconShell1 // RejectAllButtonWrapper
|
||||||
|
Icon={X}
|
||||||
|
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "reject", _addToHistory: true, }); }}
|
||||||
|
data-tooltip-id='void-tooltip'
|
||||||
|
data-tooltip-place='top'
|
||||||
|
data-tooltip-content='Reject file'
|
||||||
|
|
||||||
|
/>
|
||||||
|
<IconShell1 // AcceptAllButtonWrapper
|
||||||
|
Icon={Check}
|
||||||
|
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "accept", _addToHistory: true, }); }}
|
||||||
|
data-tooltip-id='void-tooltip'
|
||||||
|
data-tooltip-place='top'
|
||||||
|
data-tooltip-content='Accept file'
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
const fileStatusHTML = <StatusIndicator className='mx-1' indicatorColor={fileStatus.color} title={fileStatus.title} />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// name, details
|
// name, details
|
||||||
<div key={i} className="flex justify-between items-center gap-2">
|
<div key={i} className="flex justify-between items-center">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center">
|
||||||
{fileNameHTML}
|
{fileNameHTML}
|
||||||
{detailsContent}
|
{detailsContent}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -2145,7 +2190,7 @@ const CommandBarInChat = () => {
|
||||||
const fileDetailsButton = (
|
const fileDetailsButton = (
|
||||||
<button
|
<button
|
||||||
className={`flex items-center gap-1 rounded ${numFilesChanged === 0 ? 'cursor-pointer' : 'cursor-pointer hover:brightness-125 transition-all duration-200'}`}
|
className={`flex items-center gap-1 rounded ${numFilesChanged === 0 ? 'cursor-pointer' : 'cursor-pointer hover:brightness-125 transition-all duration-200'}`}
|
||||||
onClick={() => setFileDetailsOpened(!isFileDetailsOpened)}
|
onClick={() => isFileDetailsOpened ? setFileDetailsOpenedState('user-closed') : setFileDetailsOpenedState('user-opened')}
|
||||||
type='button'
|
type='button'
|
||||||
disabled={numFilesChanged === 0}
|
disabled={numFilesChanged === 0}
|
||||||
>
|
>
|
||||||
|
|
@ -2171,8 +2216,8 @@ const CommandBarInChat = () => {
|
||||||
flex w-full rounded-t-lg bg-void-bg-3
|
flex w-full rounded-t-lg bg-void-bg-3
|
||||||
text-void-fg-3 text-xs text-nowrap
|
text-void-fg-3 text-xs text-nowrap
|
||||||
|
|
||||||
overflow-hidden transition-all duration-200 ease-in-out origin-top
|
overflow-hidden transition-all duration-200 ease-in-out
|
||||||
${isFileDetailsOpened ? 'max-h-32' : 'max-h-0'}
|
${isFileDetailsOpened ? 'max-h-24' : 'max-h-0'}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{fileDetailsContent}
|
{fileDetailsContent}
|
||||||
|
|
@ -2183,7 +2228,8 @@ const CommandBarInChat = () => {
|
||||||
className={`
|
className={`
|
||||||
select-none
|
select-none
|
||||||
flex w-full rounded-t-lg bg-void-bg-3
|
flex w-full rounded-t-lg bg-void-bg-3
|
||||||
text-void-fg-4 text-xs text-nowrap
|
text-void-fg-3 text-xs text-nowrap
|
||||||
|
border-t border-l border-r border-zinc-300/10
|
||||||
|
|
||||||
px-2 py-1
|
px-2 py-1
|
||||||
justify-between
|
justify-between
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,20 @@ const VoidSelectionHelper = ({ rerenderKey }: VoidSelectionHelperProps) => {
|
||||||
>
|
>
|
||||||
Disable Suggestions?
|
Disable Suggestions?
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{dividerHTML}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className='
|
||||||
|
flex items-center px-0.5
|
||||||
|
cursor-pointer
|
||||||
|
'
|
||||||
|
onClick={() => {
|
||||||
|
setClickState('init');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVertical className="w-4" />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
return <div className='
|
return <div className='
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@ import { WarningBox } from './WarningBox.js'
|
||||||
import { os } from '../../../../common/helpers/systemInfo.js'
|
import { os } from '../../../../common/helpers/systemInfo.js'
|
||||||
import { IconLoading, IconX } from '../sidebar-tsx/SidebarChat.js'
|
import { IconLoading, IconX } from '../sidebar-tsx/SidebarChat.js'
|
||||||
import { getModelCapabilities, getProviderCapabilities, ollamaRecommendedModels, VoidStaticModelInfo } from '../../../../common/modelCapabilities.js'
|
import { getModelCapabilities, getProviderCapabilities, ollamaRecommendedModels, VoidStaticModelInfo } from '../../../../common/modelCapabilities.js'
|
||||||
import { ToolCallType, AnthropicReasoning } from '../../../../common/sendLLMMessageTypes.js'
|
|
||||||
import { IconShell1, StatusIndicatorForApplyButton } from '../markdown/ApplyBlockHoverButtons.js'
|
|
||||||
|
|
||||||
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
|
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { Tooltip } from 'react-tooltip';
|
import { Tooltip } from 'react-tooltip';
|
||||||
import 'react-tooltip/dist/react-tooltip.css';
|
import 'react-tooltip/dist/react-tooltip.css';
|
||||||
|
import { useIsDark } from '../util/services.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a configured global tooltip component with consistent styling
|
* Creates a configured global tooltip component with consistent styling
|
||||||
|
|
@ -13,6 +14,10 @@ import 'react-tooltip/dist/react-tooltip.css';
|
||||||
* 2. Add data-tooltip-id="void-tooltip" and data-tooltip-content="Your tooltip text" to any element
|
* 2. Add data-tooltip-id="void-tooltip" and data-tooltip-content="Your tooltip text" to any element
|
||||||
*/
|
*/
|
||||||
export const VoidTooltip = () => {
|
export const VoidTooltip = () => {
|
||||||
|
|
||||||
|
|
||||||
|
const isDark = useIsDark()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
// use native colors so we don't have to worry about @@void-scope styles
|
// use native colors so we don't have to worry about @@void-scope styles
|
||||||
|
|
@ -39,15 +44,30 @@ export const VoidTooltip = () => {
|
||||||
<>
|
<>
|
||||||
<style>
|
<style>
|
||||||
{`
|
{`
|
||||||
|
#void-tooltip, #void-tooltip-orange, #void-tooltip-green {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
#void-tooltip {
|
#void-tooltip {
|
||||||
background-color: var(--vscode-editor-background);
|
background-color: var(--vscode-editor-background);
|
||||||
color: var(--vscode-input-foreground);
|
color: var(--vscode-input-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
|
#void-tooltip-orange {
|
||||||
font-size: 10px;
|
background-color: #F6762A;
|
||||||
padding: 0px 8px;
|
color: white;
|
||||||
border-radius: 6px;
|
}
|
||||||
z-index: 9999;
|
|
||||||
|
#void-tooltip-green {
|
||||||
|
background-color: #228B22;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-tooltip-arrow {
|
||||||
|
z-index: -1 !important; /* Keep arrow behind content (somehow this isnt done automatically) */
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -55,7 +75,20 @@ export const VoidTooltip = () => {
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id="void-tooltip"
|
id="void-tooltip"
|
||||||
border='1px solid var(--vscode-commandCenter-border)'
|
// border='1px solid var(--vscode-editorGroup-border)'
|
||||||
|
border='1px solid rgba(100,100,100,.2)'
|
||||||
|
opacity={1}
|
||||||
|
delayShow={50}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
id="void-tooltip-orange"
|
||||||
|
border='1px solid rgba(200,200,200,.3)'
|
||||||
|
opacity={1}
|
||||||
|
delayShow={50}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
id="void-tooltip-green"
|
||||||
|
border='1px solid rgba(200,200,200,.3)'
|
||||||
opacity={1}
|
opacity={1}
|
||||||
delayShow={50}
|
delayShow={50}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], opt
|
||||||
|
|
||||||
export const modelFilterOfFeatureName: { [featureName in FeatureName]: { filter: (o: ModelSelection, opts: { chatMode: ChatMode }) => boolean; emptyMessage: null | { message: string, priority: 'always' | 'fallback' } } } = {
|
export const modelFilterOfFeatureName: { [featureName in FeatureName]: { filter: (o: ModelSelection, opts: { chatMode: ChatMode }) => boolean; emptyMessage: null | { message: string, priority: 'always' | 'fallback' } } } = {
|
||||||
'Autocomplete': { filter: (o) => getModelCapabilities(o.providerName, o.modelName).supportsFIM, emptyMessage: { message: 'No models support FIM', priority: 'always' } },
|
'Autocomplete': { filter: (o) => getModelCapabilities(o.providerName, o.modelName).supportsFIM, emptyMessage: { message: 'No models support FIM', priority: 'always' } },
|
||||||
'Chat': { filter: (o, { chatMode }) => chatMode === 'normal' ? true : !!getModelCapabilities(o.providerName, o.modelName).supportsTools, emptyMessage: { message: 'No models support tool use', priority: 'fallback' } },
|
'Chat': { filter: o => true, emptyMessage: null, },
|
||||||
'Ctrl+K': { filter: o => true, emptyMessage: null, },
|
'Ctrl+K': { filter: o => true, emptyMessage: null, },
|
||||||
'Apply': { filter: o => true, emptyMessage: null, },
|
'Apply': { filter: o => true, emptyMessage: null, },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ const newOpenAICompatibleSDK = ({ settingsOfProvider, providerName, includeInPay
|
||||||
}
|
}
|
||||||
else if (providerName === 'gemini') {
|
else if (providerName === 'gemini') {
|
||||||
const thisConfig = settingsOfProvider[providerName]
|
const thisConfig = settingsOfProvider[providerName]
|
||||||
return new OpenAI({ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai', apiKey: thisConfig.apiKey, ...commonPayloadOpts })
|
return new OpenAI({ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/', apiKey: thisConfig.apiKey, ...commonPayloadOpts })
|
||||||
}
|
}
|
||||||
else if (providerName === 'deepseek') {
|
else if (providerName === 'deepseek') {
|
||||||
const thisConfig = settingsOfProvider[providerName]
|
const thisConfig = settingsOfProvider[providerName]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue