feat: improve VS Code editor chat actions
Targets active editor chat before falling back to sidebar Adds session open-in-editor action in the VS Code sidebar Uses attachment badges for VS Code file and selection context
This commit is contained in:
@@ -187,6 +187,19 @@ export const VSCodeLayout: React.FC = () => {
|
||||
void vscodeApi.executeCommand('openchamber.setActiveSession', currentSessionId, activeSessionTitle);
|
||||
}, [activeSessionTitle, currentSessionId, runtimeApis.vscode]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (viewMode !== 'editor' || !currentSessionId || !activeSessionTitle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const vscodeApi = runtimeApis.vscode;
|
||||
if (!vscodeApi) {
|
||||
return;
|
||||
}
|
||||
|
||||
void vscodeApi.executeCommand('openchamber.updateSessionEditorTitle', currentSessionId, activeSessionTitle);
|
||||
}, [activeSessionTitle, currentSessionId, runtimeApis.vscode, viewMode]);
|
||||
|
||||
// If the active session disappears (e.g., deleted), go back to sessions list
|
||||
React.useEffect(() => {
|
||||
if (viewMode === 'editor') {
|
||||
@@ -709,7 +722,7 @@ const VSCodeHeader: React.FC<VSCodeHeaderProps> = ({ title, showBack, onBack, on
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t('sessions.switcher.openAria')}
|
||||
className="flex min-w-0 flex-1 items-center rounded-md px-1 py-0.5 -my-0.5 text-left transition-colors hover:bg-interactive-hover/60 focus-visible:outline-none focus-visible:bg-interactive-hover/60"
|
||||
className="inline-flex min-w-0 max-w-full items-center rounded-md px-1 py-0.5 -my-0.5 text-left transition-colors hover:bg-interactive-hover/60 focus-visible:outline-none focus-visible:bg-interactive-hover/60"
|
||||
>
|
||||
<span className="text-sm font-medium truncate" title={title}>{title}</span>
|
||||
</button>
|
||||
@@ -717,6 +730,7 @@ const VSCodeHeader: React.FC<VSCodeHeaderProps> = ({ title, showBack, onBack, on
|
||||
) : (
|
||||
<h1 className="text-sm font-medium truncate flex-1" title={title}>{title}</h1>
|
||||
)}
|
||||
<div className="min-w-0 flex-1" />
|
||||
{onNewSession && (
|
||||
<button
|
||||
onClick={onNewSession}
|
||||
|
||||
@@ -32,6 +32,7 @@ import { useI18n } from '@/lib/i18n';
|
||||
import { parseMultiRunSessionTitle } from '@/lib/multirun/title';
|
||||
import { MultiRunFusionDialog } from '@/components/multirun/MultiRunFusionDialog';
|
||||
import { FusionIcon } from '@/components/icons/FusionIcon';
|
||||
import { RuntimeAPIContext } from '@/contexts/runtimeAPIContext';
|
||||
|
||||
type Folder = { id: string; name: string; sessionIds: string[] };
|
||||
|
||||
@@ -261,19 +262,25 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
const isMinimalMode = displayMode === 'minimal';
|
||||
const isVSCode = React.useMemo(() => isVSCodeRuntime(), []);
|
||||
const isElectron = React.useMemo(() => canUseElectronDesktopIPC(), []);
|
||||
const runtimeApis = React.useContext(RuntimeAPIContext);
|
||||
const revealOnHoverClass = isVSCode
|
||||
? 'group-hover:opacity-100 group-hover:pointer-events-auto'
|
||||
: 'group-hover:opacity-100 group-hover:pointer-events-auto group-focus-within:opacity-100 group-focus-within:pointer-events-auto';
|
||||
const hideOnHoverClass = isVSCode
|
||||
? 'group-hover:opacity-0'
|
||||
: 'group-hover:opacity-0 group-focus-within:opacity-0';
|
||||
const showOpenInEditorAction = isVSCode;
|
||||
const showQuickArchiveAction = !archivedBucket && !mobileVariant;
|
||||
const revealPaddingClass = isMinimalMode
|
||||
? (isVSCode
|
||||
? 'group-hover:pr-2'
|
||||
: 'group-hover:pr-2 group-focus-within:pr-2')
|
||||
: (isVSCode
|
||||
? (showQuickArchiveAction ? 'group-hover:pr-12' : 'group-hover:pr-5')
|
||||
? (showQuickArchiveAction && showOpenInEditorAction
|
||||
? 'group-hover:pr-18'
|
||||
: showQuickArchiveAction || showOpenInEditorAction
|
||||
? 'group-hover:pr-12'
|
||||
: 'group-hover:pr-5')
|
||||
: (showQuickArchiveAction ? 'group-hover:pr-12 group-focus-within:pr-12' : 'group-hover:pr-5 group-focus-within:pr-5'));
|
||||
const alwaysActionPaddingClass = showQuickArchiveAction ? 'pr-13' : 'pr-7';
|
||||
const suppressNextSelectRef = React.useRef(false);
|
||||
@@ -609,6 +616,22 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
handleDeleteSession(session, { archivedBucket });
|
||||
};
|
||||
|
||||
const handleOpenInEditorPointerDown = (event: React.PointerEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleOpenInEditorMouseDown = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleOpenInEditorClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
void runtimeApis?.vscode?.executeCommand('openchamber.openSessionInEditor', session.id, sessionTitle);
|
||||
};
|
||||
|
||||
const handleRowSelect = (event?: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (suppressNextSelectRef.current) {
|
||||
suppressNextSelectRef.current = false;
|
||||
@@ -936,6 +959,29 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{showOpenInEditorAction ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'inline-flex items-center justify-center rounded-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 transition-opacity',
|
||||
isMinimalMode && !alwaysShowActions ? 'h-4 w-4' : 'h-6 w-6',
|
||||
)}
|
||||
aria-label={t('sessions.sidebar.session.actions.openInEditor')}
|
||||
onPointerDown={handleOpenInEditorPointerDown}
|
||||
onMouseDown={handleOpenInEditorMouseDown}
|
||||
onClick={handleOpenInEditorClick}
|
||||
onKeyDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<Icon name="external-link" className={cn(isMinimalMode && !alwaysShowActions ? 'h-2.5 w-2.5' : 'h-3.5 w-3.5')} />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left" sideOffset={8}>
|
||||
{t('sessions.sidebar.session.actions.openInEditor')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<DropdownMenu open={isMenuOpen} onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user