支持文件和变更区域的根目录快捷操作
This commit is contained in:
@@ -1120,7 +1120,7 @@ export function FileWorkspacePanel() {
|
|||||||
path: diffListContext.path,
|
path: diffListContext.path,
|
||||||
branch: diffListContext.branch,
|
branch: diffListContext.branch,
|
||||||
})
|
})
|
||||||
: diffListContext.path
|
: (activeFileTab.description ?? diffListContext.path)
|
||||||
|
|
||||||
const handleOpenDiff = async (path: string) => {
|
const handleOpenDiff = async (path: string) => {
|
||||||
if (diffListContext.kind === "commit") {
|
if (diffListContext.kind === "commit") {
|
||||||
|
|||||||
@@ -1701,6 +1701,22 @@ export function FileTreeTab() {
|
|||||||
return baseName(folder.path)
|
return baseName(folder.path)
|
||||||
}, [folder?.path, t])
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (!isFileTreeTabActive) return
|
if (!isFileTreeTabActive) return
|
||||||
void fetchTree()
|
void fetchTree()
|
||||||
@@ -2009,45 +2025,128 @@ export function FileTreeTab() {
|
|||||||
onSelect={handleTreeSelect}
|
onSelect={handleTreeSelect}
|
||||||
>
|
>
|
||||||
{folder?.path && (
|
{folder?.path && (
|
||||||
<FileTreeFolder
|
<ContextMenu>
|
||||||
path={FILE_TREE_ROOT_PATH}
|
<ContextMenuTrigger asChild>
|
||||||
name={rootNodeName}
|
<FileTreeFolder
|
||||||
className="font-medium"
|
path={FILE_TREE_ROOT_PATH}
|
||||||
>
|
name={rootNodeName}
|
||||||
{nodes.map((node) => (
|
className="font-medium"
|
||||||
<RenderNode
|
>
|
||||||
key={node.path}
|
{nodes.map((node) => (
|
||||||
node={node}
|
<RenderNode
|
||||||
expandedPaths={expandedPaths}
|
key={node.path}
|
||||||
workspacePath={folder.path}
|
node={node}
|
||||||
activeSessionTabId={activeSessionTabId}
|
expandedPaths={expandedPaths}
|
||||||
gitEnabled={gitEnabled}
|
workspacePath={folder.path}
|
||||||
gitStatusByPath={gitStatusByPath}
|
activeSessionTabId={activeSessionTabId}
|
||||||
gitChangedDirPaths={gitChangedDirPaths}
|
gitEnabled={gitEnabled}
|
||||||
gitignoreIgnoredPaths={gitignoreIgnoredPaths}
|
gitStatusByPath={gitStatusByPath}
|
||||||
ancestorGitignoreIgnored={false}
|
gitChangedDirPaths={gitChangedDirPaths}
|
||||||
onOpenFilePreview={(path) => {
|
gitignoreIgnoredPaths={gitignoreIgnoredPaths}
|
||||||
void openFilePreview(path)
|
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)
|
{t("reloadFromDisk")}
|
||||||
}}
|
</ContextMenuItem>
|
||||||
onOpenDirDiff={(path) => {
|
<ContextMenuSub>
|
||||||
void openWorkingTreeDiff(path, { mode: "overview" })
|
<ContextMenuSubTrigger>
|
||||||
}}
|
{t("openIn")}
|
||||||
onOpenCommitWindow={handleOpenCommitWindow}
|
</ContextMenuSubTrigger>
|
||||||
onRequestCompareWithBranch={
|
<ContextMenuSubContent>
|
||||||
handleRequestCompareWithBranch
|
<ContextMenuItem
|
||||||
}
|
onSelect={() => {
|
||||||
onRequestRollback={handleRequestRollback}
|
void revealItemInDir(folder.path)
|
||||||
onOpenDirInTerminal={handleOpenDirInTerminal}
|
}}
|
||||||
onRequestAddToVcs={handleAddToVcs}
|
>
|
||||||
onRequestRename={handleRequestRename}
|
{systemExplorerLabel}
|
||||||
onRequestDelete={handleRequestDelete}
|
</ContextMenuItem>
|
||||||
onRefresh={fetchTree}
|
<ContextMenuItem
|
||||||
/>
|
onSelect={() => {
|
||||||
))}
|
void handleOpenDirInTerminal(
|
||||||
</FileTreeFolder>
|
folder.path,
|
||||||
|
rootNodeName
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("openInTerminal")}
|
||||||
|
</ContextMenuItem>
|
||||||
|
</ContextMenuSubContent>
|
||||||
|
</ContextMenuSub>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
)}
|
)}
|
||||||
</FileTree>
|
</FileTree>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1236,15 +1236,60 @@ export function GitChangesTab() {
|
|||||||
expanded={expandedTrackedPaths}
|
expanded={expandedTrackedPaths}
|
||||||
onExpandedChange={setExpandedTrackedPaths}
|
onExpandedChange={setExpandedTrackedPaths}
|
||||||
>
|
>
|
||||||
<FileTreeFolder
|
<ContextMenu>
|
||||||
path={TRACKED_ROOT_PATH}
|
<ContextMenuTrigger asChild>
|
||||||
name={folderName}
|
<FileTreeFolder
|
||||||
suffix={`(${trackedChanges.length})`}
|
path={TRACKED_ROOT_PATH}
|
||||||
suffixClassName="text-muted-foreground/45"
|
name={folderName}
|
||||||
title={folderName}
|
suffix={`(${trackedChanges.length})`}
|
||||||
>
|
suffixClassName="text-muted-foreground/45"
|
||||||
{trackedTreeNodes.map(renderTrackedNode)}
|
title={folderName}
|
||||||
</FileTreeFolder>
|
>
|
||||||
|
{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>
|
</FileTree>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
@@ -1284,15 +1329,60 @@ export function GitChangesTab() {
|
|||||||
expanded={expandedUntrackedPaths}
|
expanded={expandedUntrackedPaths}
|
||||||
onExpandedChange={setExpandedUntrackedPaths}
|
onExpandedChange={setExpandedUntrackedPaths}
|
||||||
>
|
>
|
||||||
<FileTreeFolder
|
<ContextMenu>
|
||||||
path={UNTRACKED_ROOT_PATH}
|
<ContextMenuTrigger asChild>
|
||||||
name={folderName}
|
<FileTreeFolder
|
||||||
suffix={`(${untrackedChanges.length})`}
|
path={UNTRACKED_ROOT_PATH}
|
||||||
suffixClassName="text-muted-foreground/45"
|
name={folderName}
|
||||||
title={folderName}
|
suffix={`(${untrackedChanges.length})`}
|
||||||
>
|
suffixClassName="text-muted-foreground/45"
|
||||||
{untrackedTreeNodes.map(renderUntrackedNode)}
|
title={folderName}
|
||||||
</FileTreeFolder>
|
>
|
||||||
|
{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>
|
</FileTree>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -440,10 +440,14 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
|
|||||||
const mode = options?.mode ?? "auto"
|
const mode = options?.mode ?? "auto"
|
||||||
|
|
||||||
if (mode === "overview") {
|
if (mode === "overview") {
|
||||||
|
const isRoot = path === "."
|
||||||
|
const displayPath = isRoot ? folderPath : path
|
||||||
const encodedPath = encodeURIComponent(path)
|
const encodedPath = encodeURIComponent(path)
|
||||||
const tabId = `diff:working-overview:${encodedPath}`
|
const tabId = `diff:working-overview:${encodedPath}`
|
||||||
const title = t("diffTitleFile", { name: fileName(path) })
|
const title = t("diffTitleFile", {
|
||||||
const description = path
|
name: fileName(displayPath ?? path),
|
||||||
|
})
|
||||||
|
const description = displayPath ?? path
|
||||||
upsertLoadingTab(
|
upsertLoadingTab(
|
||||||
loadingTab(tabId, "diff", title, description, path, "diff")
|
loadingTab(tabId, "diff", title, description, path, "diff")
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user