支持git冲突时弹出窗口合并代码解决冲突

This commit is contained in:
xintaofei
2026-03-14 20:55:15 +08:00
parent f503c25161
commit 4129f02985
25 changed files with 3123 additions and 51 deletions

128
src/app/merge/page.tsx Normal file
View File

@@ -0,0 +1,128 @@
"use client"
import { Suspense, useCallback, useEffect, useState } from "react"
import { useSearchParams } from "next/navigation"
import { useTranslations } from "next-intl"
import { getCurrentWindow } from "@tauri-apps/api/window"
import { Loader2 } from "lucide-react"
import { MergeWorkspace } from "@/components/merge/merge-workspace"
import { AppTitleBar } from "@/components/layout/app-title-bar"
import { AppToaster } from "@/components/ui/app-toaster"
import { getFolder } from "@/lib/tauri"
import type { FolderDetail } from "@/lib/types"
const TOAST_DURATION_MS = 6000
interface FolderLoadState {
loadedId: number | null
folder: FolderDetail | null
error: string | null
}
function MergePageInner() {
const t = useTranslations("MergePage")
const searchParams = useSearchParams()
const [state, setState] = useState<FolderLoadState>({
loadedId: null,
folder: null,
error: null,
})
const folderId = Number(searchParams.get("folderId") ?? "0")
const operation = searchParams.get("operation") ?? "merge"
const normalizedFolderId = Number.isFinite(folderId) ? folderId : 0
const hasValidFolderId = normalizedFolderId > 0
const loading = hasValidFolderId && state.loadedId !== normalizedFolderId
const folder = state.loadedId === normalizedFolderId ? state.folder : null
const error = state.loadedId === normalizedFolderId ? state.error : null
const closeWindow = useCallback(() => {
getCurrentWindow()
.close()
.catch((err) => {
console.error("[MergePage] failed to close window:", err)
})
}, [])
useEffect(() => {
if (!hasValidFolderId) return
let cancelled = false
getFolder(normalizedFolderId)
.then((detail) => {
if (!cancelled) {
setState({
loadedId: normalizedFolderId,
folder: detail,
error: null,
})
}
})
.catch((err) => {
if (!cancelled) {
setState({
loadedId: normalizedFolderId,
folder: null,
error: String(err),
})
}
})
return () => {
cancelled = true
}
}, [hasValidFolderId, normalizedFolderId])
return (
<div className="flex h-screen flex-col overflow-hidden bg-background text-foreground">
<AppTitleBar
center={
<div className="text-sm font-semibold tracking-tight">
{t("title")}
{hasValidFolderId && folder ? ` · ${folder.name}` : ""}
</div>
}
/>
<main className="flex-1 min-h-0 p-3">
{!hasValidFolderId ? (
<div className="rounded-lg border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive">
{t("invalidFolderId")}
</div>
) : loading ? (
<div className="flex h-full items-center justify-center text-sm text-muted-foreground">
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t("loadingRepo")}
</div>
) : error ? (
<div className="rounded-lg border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive">
{error}
</div>
) : folder ? (
<MergeWorkspace
folderId={normalizedFolderId}
folderPath={folder.path}
operation={operation}
onCompleted={closeWindow}
onAborted={closeWindow}
/>
) : null}
</main>
<AppToaster
position="bottom-right"
duration={TOAST_DURATION_MS}
closeButton
/>
</div>
)
}
export default function MergePage() {
return (
<Suspense>
<MergePageInner />
</Suspense>
)
}