支持文件和变更区域的根目录快捷操作

This commit is contained in:
xintaofei
2026-03-13 21:50:15 +08:00
parent bf14a99168
commit 3376974d0f
4 changed files with 252 additions and 59 deletions

View File

@@ -1120,7 +1120,7 @@ export function FileWorkspacePanel() {
path: diffListContext.path,
branch: diffListContext.branch,
})
: diffListContext.path
: (activeFileTab.description ?? diffListContext.path)
const handleOpenDiff = async (path: string) => {
if (diffListContext.kind === "commit") {

View File

@@ -1701,6 +1701,22 @@ export function FileTreeTab() {
return baseName(folder.path)
}, [folder?.path, t])
const systemExplorerLabel =
typeof navigator === "undefined"
? t("openInFileManager")
: (() => {
const platform =
`${navigator.platform} ${navigator.userAgent}`.toLowerCase()
if (platform.includes("mac")) return t("openInFinder")
if (platform.includes("win")) return t("openInExplorer")
return t("openInFileManager")
})()
const rootTarget: FileActionTarget = useMemo(
() => ({ kind: "dir", path: "", name: rootNodeName }),
[rootNodeName]
)
useEffect(() => {
if (!isFileTreeTabActive) return
void fetchTree()
@@ -2009,45 +2025,128 @@ export function FileTreeTab() {
onSelect={handleTreeSelect}
>
{folder?.path && (
<FileTreeFolder
path={FILE_TREE_ROOT_PATH}
name={rootNodeName}
className="font-medium"
>
{nodes.map((node) => (
<RenderNode
key={node.path}
node={node}
expandedPaths={expandedPaths}
workspacePath={folder.path}
activeSessionTabId={activeSessionTabId}
gitEnabled={gitEnabled}
gitStatusByPath={gitStatusByPath}
gitChangedDirPaths={gitChangedDirPaths}
gitignoreIgnoredPaths={gitignoreIgnoredPaths}
ancestorGitignoreIgnored={false}
onOpenFilePreview={(path) => {
void openFilePreview(path)
<ContextMenu>
<ContextMenuTrigger asChild>
<FileTreeFolder
path={FILE_TREE_ROOT_PATH}
name={rootNodeName}
className="font-medium"
>
{nodes.map((node) => (
<RenderNode
key={node.path}
node={node}
expandedPaths={expandedPaths}
workspacePath={folder.path}
activeSessionTabId={activeSessionTabId}
gitEnabled={gitEnabled}
gitStatusByPath={gitStatusByPath}
gitChangedDirPaths={gitChangedDirPaths}
gitignoreIgnoredPaths={gitignoreIgnoredPaths}
ancestorGitignoreIgnored={false}
onOpenFilePreview={(path) => {
void openFilePreview(path)
}}
onOpenFileDiff={(path) => {
void openWorkingTreeDiff(path)
}}
onOpenDirDiff={(path) => {
void openWorkingTreeDiff(path, {
mode: "overview",
})
}}
onOpenCommitWindow={handleOpenCommitWindow}
onRequestCompareWithBranch={
handleRequestCompareWithBranch
}
onRequestRollback={handleRequestRollback}
onOpenDirInTerminal={handleOpenDirInTerminal}
onRequestAddToVcs={handleAddToVcs}
onRequestRename={handleRequestRename}
onRequestDelete={handleRequestDelete}
onRefresh={fetchTree}
/>
))}
</FileTreeFolder>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuSub>
<ContextMenuSubTrigger disabled={!gitEnabled}>
{t("git")}
</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem
onSelect={() => handleOpenCommitWindow()}
disabled={!gitEnabled}
>
{t("actions.commitCode")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => void handleAddToVcs(rootTarget)}
disabled={!gitEnabled}
>
{t("actions.addToVcs")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() =>
void openWorkingTreeDiff(".", {
mode: "overview",
})
}
disabled={!gitEnabled}
>
{tCommon("viewDiff")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() =>
handleRequestCompareWithBranch(rootTarget)
}
disabled={!gitEnabled}
>
{t("compareWithBranch")}
</ContextMenuItem>
<ContextMenuItem
variant="destructive"
onSelect={() => handleRequestRollback(rootTarget)}
disabled={!gitEnabled}
>
{t("actions.rollback")}
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuItem
onSelect={() => {
void fetchTree()
}}
onOpenFileDiff={(path) => {
void openWorkingTreeDiff(path)
}}
onOpenDirDiff={(path) => {
void openWorkingTreeDiff(path, { mode: "overview" })
}}
onOpenCommitWindow={handleOpenCommitWindow}
onRequestCompareWithBranch={
handleRequestCompareWithBranch
}
onRequestRollback={handleRequestRollback}
onOpenDirInTerminal={handleOpenDirInTerminal}
onRequestAddToVcs={handleAddToVcs}
onRequestRename={handleRequestRename}
onRequestDelete={handleRequestDelete}
onRefresh={fetchTree}
/>
))}
</FileTreeFolder>
>
{t("reloadFromDisk")}
</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>
{t("openIn")}
</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem
onSelect={() => {
void revealItemInDir(folder.path)
}}
>
{systemExplorerLabel}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
void handleOpenDirInTerminal(
folder.path,
rootNodeName
)
}}
>
{t("openInTerminal")}
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
</ContextMenuContent>
</ContextMenu>
)}
</FileTree>
</div>

View File

@@ -1236,15 +1236,60 @@ export function GitChangesTab() {
expanded={expandedTrackedPaths}
onExpandedChange={setExpandedTrackedPaths}
>
<FileTreeFolder
path={TRACKED_ROOT_PATH}
name={folderName}
suffix={`(${trackedChanges.length})`}
suffixClassName="text-muted-foreground/45"
title={folderName}
>
{trackedTreeNodes.map(renderTrackedNode)}
</FileTreeFolder>
<ContextMenu>
<ContextMenuTrigger asChild>
<FileTreeFolder
path={TRACKED_ROOT_PATH}
name={folderName}
suffix={`(${trackedChanges.length})`}
suffixClassName="text-muted-foreground/45"
title={folderName}
>
{trackedTreeNodes.map(renderTrackedNode)}
</FileTreeFolder>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
onSelect={() => {
handleOpenCommitWindow()
}}
>
{t("actions.commitCode")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
void openWorkingTreeDiff(".", {
mode: "overview",
})
}}
>
{tCommon("viewDiff")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
handleRequestRollback({
kind: "dir",
path: "",
name: folderName,
})
}}
variant="destructive"
>
{t("actions.rollback")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
void handleAddToVcs({
kind: "dir",
path: "",
name: folderName,
})
}}
>
{t("actions.addToVcs")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</FileTree>
</section>
)}
@@ -1284,15 +1329,60 @@ export function GitChangesTab() {
expanded={expandedUntrackedPaths}
onExpandedChange={setExpandedUntrackedPaths}
>
<FileTreeFolder
path={UNTRACKED_ROOT_PATH}
name={folderName}
suffix={`(${untrackedChanges.length})`}
suffixClassName="text-muted-foreground/45"
title={folderName}
>
{untrackedTreeNodes.map(renderUntrackedNode)}
</FileTreeFolder>
<ContextMenu>
<ContextMenuTrigger asChild>
<FileTreeFolder
path={UNTRACKED_ROOT_PATH}
name={folderName}
suffix={`(${untrackedChanges.length})`}
suffixClassName="text-muted-foreground/45"
title={folderName}
>
{untrackedTreeNodes.map(renderUntrackedNode)}
</FileTreeFolder>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
onSelect={() => {
handleOpenCommitWindow()
}}
>
{t("actions.commitCode")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
void openWorkingTreeDiff(".", {
mode: "overview",
})
}}
>
{tCommon("viewDiff")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
handleRequestRollback({
kind: "dir",
path: "",
name: folderName,
})
}}
variant="destructive"
>
{t("actions.rollback")}
</ContextMenuItem>
<ContextMenuItem
onSelect={() => {
void handleAddToVcs({
kind: "dir",
path: "",
name: folderName,
})
}}
>
{t("actions.addToVcs")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</FileTree>
</section>
)}

View File

@@ -440,10 +440,14 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
const mode = options?.mode ?? "auto"
if (mode === "overview") {
const isRoot = path === "."
const displayPath = isRoot ? folderPath : path
const encodedPath = encodeURIComponent(path)
const tabId = `diff:working-overview:${encodedPath}`
const title = t("diffTitleFile", { name: fileName(path) })
const description = path
const title = t("diffTitleFile", {
name: fileName(displayPath ?? path),
})
const description = displayPath ?? path
upsertLoadingTab(
loadingTab(tabId, "diff", title, description, path, "diff")
)