fix(chat): restore desktop editor file-open in PendingChangesBar (#981)
* fix(chat): restore desktop editor file-open in PendingChangesBar (#979) Commit d1553ba removed the runtime?.editor branch from handleOpenFile, breaking file-click in VS Code and Electron desktop runtimes. Restore the 3-branch logic: editor.openDiff(patch) → editor.openFile() → openContextDiff() web fallback. Display paths remain relative. * fix(chat): route non-git changed files to file view in desktop DiffView requires a git repository to display diffs. In desktop (Electron/Tauri), runtime.editor is unavailable, so non-git files fell through to openContextDiff which shows "Not a git repository". Route non-git files to openContextFile instead, which works without git. Git-tracked files continue to use openContextDiff. * feat(chat): per-turn changes dropdown for non-git; self-sufficient git sync in bar - PendingChangesBar seeds git store + listens to onGitRefreshHint; works without RightSidebarTabs (fixes VS Code where bar never rendered). - Bar is git-only now; non-git shows per-turn dropdown at end of completed assistant turns. - Dropdown uses base-ui Popover for collision-aware position; icon-only collapse with tooltips at narrow container widths. - Extract shared helpers (changedFiles.ts), popover list (ChangedFilesList.tsx), styles (changedFilesPopover.ts). --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
be65a9bd1f
commit
81591430a1
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { FileTypeIcon } from '@/components/icons/FileTypeIcon';
|
||||
import { type ChangedFileEntry, getDisplayPath, getFileStats } from './changedFiles';
|
||||
|
||||
interface ChangedFilesListProps {
|
||||
files: ChangedFileEntry[];
|
||||
currentDirectory: string;
|
||||
onOpenFile: (file: ChangedFileEntry) => void;
|
||||
}
|
||||
|
||||
export const ChangedFilesList: React.FC<ChangedFilesListProps> = ({ files, currentDirectory, onOpenFile }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 typography-ui-label font-medium text-muted-foreground">
|
||||
<span>Changed files</span>
|
||||
<span className="typography-meta tabular-nums">{files.length}</span>
|
||||
</div>
|
||||
|
||||
<div className="max-h-[260px] overflow-y-auto">
|
||||
{files.map((file, index) => {
|
||||
const { fileName, dirPart } = getDisplayPath(file, currentDirectory);
|
||||
const stats = getFileStats(file);
|
||||
|
||||
return (
|
||||
<button
|
||||
key={`${file.path}:${index}`}
|
||||
type="button"
|
||||
className="relative flex w-full cursor-pointer items-center gap-2 rounded-lg px-2 py-1 typography-ui-label outline-hidden select-none text-left hover:bg-interactive-hover"
|
||||
title={`Open ${file.path}`}
|
||||
onClick={() => onOpenFile(file)}
|
||||
>
|
||||
<FileTypeIcon filePath={file.path} className="h-3.5 w-3.5 flex-shrink-0" />
|
||||
<span className="min-w-0 flex-1 flex items-baseline overflow-hidden" title={file.path}>
|
||||
{dirPart ? (
|
||||
<>
|
||||
<span
|
||||
className="min-w-0 truncate text-muted-foreground"
|
||||
style={{ direction: 'rtl', textAlign: 'left' }}
|
||||
>
|
||||
{dirPart}
|
||||
</span>
|
||||
<span className="flex-shrink-0">
|
||||
<span className="text-muted-foreground">/</span>
|
||||
<span className="text-foreground">{fileName}</span>
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<span className="truncate text-foreground">{fileName}</span>
|
||||
)}
|
||||
</span>
|
||||
{(stats.additions > 0 || stats.deletions > 0) ? (
|
||||
<span className="flex-shrink-0 inline-flex items-baseline gap-1 text-[0.75rem] tabular-nums">
|
||||
{stats.additions > 0 ? <span style={{ color: 'var(--status-success)' }}>+{stats.additions}</span> : null}
|
||||
{stats.deletions > 0 ? <span style={{ color: 'var(--status-error)' }}>-{stats.deletions}</span> : null}
|
||||
</span>
|
||||
) : null}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user