Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ui/desktop/src/components/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@ export default function ChatInput({
)}

{/* Secondary actions and controls row below input */}
<div className="flex flex-row items-center gap-1 p-2 relative">
<div className="flex flex-wrap flex-row items-center gap-x-1 gap-y-2 p-2 relative">
{/* Directory path */}
<DirSwitcher hasMessages={messages.length > 0} className="mr-0" />
<div className="w-px h-4 bg-border-default mx-2" />
Expand Down
20 changes: 18 additions & 2 deletions ui/desktop/src/components/CheckpointActions.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useState } from 'react';
import { ResourceContent } from '../types/message';
import { useSidecar } from './SidecarLayout';

interface CheckpointActionsProps {
checkpointContent: ResourceContent;
}

export default function CheckpointActions({ checkpointContent }: CheckpointActionsProps) {
const [showDiff, setShowDiff] = useState(false);
const sidecar = useSidecar();

// Parse the checkpoint payload
let checkpointData: {
Expand All @@ -23,7 +25,21 @@ export default function CheckpointActions({ checkpointContent }: CheckpointActio
}

const handleViewDiff = () => {
setShowDiff(!showDiff);
if (sidecar && checkpointData.diff) {
// Check if diff viewer is already active
if (sidecar.activeView === 'diff') {
// If diff viewer is open, close it
sidecar.hideDiffViewer();
setShowDiff(false);
} else {
// Show diff in sidecar
sidecar.showDiffViewer(checkpointData.diff, checkpointData.file || 'File');
setShowDiff(true);
}
} else {
// Fallback to inline diff display
setShowDiff(!showDiff);
}
};

const handleRestore = async () => {
Expand Down Expand Up @@ -62,7 +78,7 @@ export default function CheckpointActions({ checkpointContent }: CheckpointActio
onClick={handleViewDiff}
className="text-xs px-2 py-1 bg-bgStandard hover:bg-bgSubtle border border-borderSubtle rounded transition-colors"
>
{showDiff ? 'Hide Diff' : 'View Diff'}
{sidecar && sidecar.activeView === 'diff' ? 'Hide Diff' : 'View Diff'}
</button>
{checkpointData.checkpoint && (
<button
Expand Down
44 changes: 26 additions & 18 deletions ui/desktop/src/components/GooseMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,24 +252,30 @@ export default function GooseMessage({
<TooltipTrigger asChild>
<button
onClick={() => {
// Find the first tool request with diff content and show its diff
const toolRequestWithDiff = toolRequests.find((toolRequest) =>
hasDiffContent(toolResponsesMap.get(toolRequest.id))
);
if (toolRequestWithDiff) {
const diffContent = extractDiffContent(
toolResponsesMap.get(toolRequestWithDiff.id)
// Check if diff viewer is already active
if (sidecar.activeView === 'diff') {
// If diff viewer is open, close it
sidecar.hideDiffViewer();
} else {
// Find the first tool request with diff content and show its diff
const toolRequestWithDiff = toolRequests.find((toolRequest) =>
hasDiffContent(toolResponsesMap.get(toolRequest.id))
);
if (diffContent) {
// Extract filename from tool arguments if available
const toolCall =
toolRequestWithDiff.toolCall.status === 'success'
? toolRequestWithDiff.toolCall.value
: null;
const args = toolCall?.arguments as Record<string, never>;
const fileName = args?.path ? String(args.path) : 'File';

sidecar.showDiffViewer(diffContent, fileName);
if (toolRequestWithDiff) {
const diffContent = extractDiffContent(
toolResponsesMap.get(toolRequestWithDiff.id)
);
if (diffContent) {
// Extract filename from tool arguments if available
const toolCall =
toolRequestWithDiff.toolCall.status === 'success'
? toolRequestWithDiff.toolCall.value
: null;
const args = toolCall?.arguments as Record<string, never>;
const fileName = args?.path ? String(args.path) : 'File';

sidecar.showDiffViewer(diffContent, fileName);
}
}
}
}}
Expand All @@ -278,7 +284,9 @@ export default function GooseMessage({
<FileDiff size={16} />
</button>
</TooltipTrigger>
<TooltipContent side="top">View diff</TooltipContent>
<TooltipContent side="top">
{sidecar.activeView === 'diff' ? 'Hide diff' : 'View diff'}
</TooltipContent>
</Tooltip>
</div>
)}
Expand Down
12 changes: 8 additions & 4 deletions ui/desktop/src/components/SidecarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ export function SidecarProvider({ children, showSidecar = true }: SidecarProvide

// Import and use the window manager hook
const { toggleWindow } = useWindowManager({
expandPercentage: 100,
maxWidthForExpansion: 2200,
expandPercentage: 60,
maxWidthForExpansion: 1200,
transitionDuration: 300,
});

Expand All @@ -323,8 +323,10 @@ export function SidecarProvider({ children, showSidecar = true }: SidecarProvide
setActiveView(view.id);
};

const hideView = () => {
const hideView = async () => {
setActiveView(null);
// Collapse window when hiding sidecar
await toggleWindow();
};

const showDiffViewer = (content: string, fileName = 'File') => {
Expand All @@ -338,10 +340,12 @@ export function SidecarProvider({ children, showSidecar = true }: SidecarProvide
showView(diffView);
};

const hideDiffViewer = () => {
const hideDiffViewer = async () => {
setViews((prev) => prev.filter((v) => v.id !== 'diff'));
if (activeView === 'diff') {
setActiveView(null);
// Collapse window when hiding diff viewer
await toggleWindow();
}
};

Expand Down
71 changes: 42 additions & 29 deletions ui/desktop/src/hooks/useWindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,6 @@ export function useWindowManager(options: WindowManagerOptions = {}): WindowMana
return;
}

// Don't resize if window is already expanded
if (windowState.isExpanded) {
console.log('Window is already expanded, skipping resize operation');
return;
}

try {
resizeInProgressRef.current = true;

Expand All @@ -191,33 +185,52 @@ export function useWindowManager(options: WindowManagerOptions = {}): WindowMana
isTransitioning: true,
}));

// Only expanding logic remains since we skip when already expanded
if (!canExpand) {
console.log('Window too wide for expansion, skipping resize');
setWindowState((prev) => ({
...prev,
isTransitioning: false,
}));
// Still mount the component even if we don't resize
setIsComponentMounted(true);
return;
}
if (windowState.isExpanded) {
// Collapse the window back to original size
console.log('Window is expanded, collapsing back to original size');

const success = await window.electron.resizeWindow(0); // 0 means reset to original size

if (success) {
setWindowState((prev) => ({
...prev,
isExpanded: false,
currentWidth: prev.originalWidth,
isTransitioning: false,
}));
} else {
throw new Error('Failed to resize window for collapse');
}
} else {
// Expand the window
if (!canExpand) {
console.log('Window too wide for expansion, skipping resize but showing sidecar');
setWindowState((prev) => ({
...prev,
isExpanded: true, // Mark as expanded even though we didn't resize
isTransitioning: false,
}));
// Still mount the component even if we don't resize
setIsComponentMounted(true);
return;
}

const success = await window.electron.resizeWindow(opts.expandPercentage);
const success = await window.electron.resizeWindow(opts.expandPercentage);

if (success) {
const newWidth = Math.floor(windowState.currentWidth * (1 + opts.expandPercentage / 100));
if (success) {
const newWidth = Math.floor(windowState.currentWidth * (1 + opts.expandPercentage / 100));

setWindowState((prev) => ({
...prev,
isExpanded: true,
currentWidth: newWidth,
isTransitioning: false,
}));
setWindowState((prev) => ({
...prev,
isExpanded: true,
currentWidth: newWidth,
isTransitioning: false,
}));

// Component will be mounted by the useEffect above
} else {
throw new Error('Failed to resize window for expansion');
// Component will be mounted by the useEffect above
} else {
throw new Error('Failed to resize window for expansion');
}
}
} catch (error) {
console.error('Error during window toggle:', error);
Expand Down