feat: 开发者面板页面git工具支持推送远程仓库

This commit is contained in:
2026-01-30 12:01:44 +08:00
parent 37f9faf2a4
commit 796ffcfe00
3 changed files with 72 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
import { GitBranch, GitCommit as GitCommitIcon, CornerRightUp, RotateCcw, AlertTriangle, RefreshCw, GitCommit } from 'lucide-react' import { GitBranch, GitCommit as GitCommitIcon, CornerRightUp, RotateCcw, AlertTriangle, RefreshCw, GitCommit, Upload } from 'lucide-react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator' import { Separator } from '@/components/ui/separator'
import { trpc } from '@/lib/trpc' import { trpc } from '@/lib/trpc'
@@ -73,7 +73,7 @@ export function VersionControl({ isOpen }: { isOpen: boolean }) {
const [isLoadingMore, setIsLoadingMore] = React.useState(false) const [isLoadingMore, setIsLoadingMore] = React.useState(false)
const [commitType, setCommitType] = React.useState<'normal' | 'amend' | null>(null) const [commitType, setCommitType] = React.useState<'normal' | 'amend' | null>(null)
const [confirmAction, setConfirmAction] = React.useState<{ const [confirmAction, setConfirmAction] = React.useState<{
type: 'checkout' | 'checkout-branch' | 'revert' | 'reset' type: 'checkout' | 'checkout-branch' | 'revert' | 'reset' | 'push'
commitId?: string commitId?: string
message?: string message?: string
title?: string title?: string
@@ -191,6 +191,17 @@ export function VersionControl({ isOpen }: { isOpen: boolean }) {
}, },
}) })
// 推送远程仓库mutation
const pushToRemoteMutation = trpc.devPanel!.pushToRemote.useMutation({
onSuccess: (data) => {
toast.success(data.message)
setConfirmAction(null)
},
onError: (error) => {
toast.error(error.message)
},
})
// 处理分支选择(仅用于查看历史,不切换实际分支) // 处理分支选择(仅用于查看历史,不切换实际分支)
const handleBranchChange = (branchName: string | null) => { const handleBranchChange = (branchName: string | null) => {
if (!branchName) return if (!branchName) return
@@ -306,9 +317,21 @@ export function VersionControl({ isOpen }: { isOpen: boolean }) {
resetToCommitMutation.mutate({ commitId: confirmAction.commitId }) resetToCommitMutation.mutate({ commitId: confirmAction.commitId })
} }
break break
case 'push':
pushToRemoteMutation.mutate({ branchName: selectedBranch })
break
} }
} }
// 处理推送远程仓库
const handlePushToRemote = () => {
setConfirmAction({
type: 'push',
title: '推送到远程仓库',
description: `确定要将分支 "${selectedBranch}" 的最新提交推送到远程仓库吗?`,
})
}
// 手动刷新所有数据 // 手动刷新所有数据
const handleRefresh = () => { const handleRefresh = () => {
refetchBranches() refetchBranches()
@@ -357,7 +380,7 @@ export function VersionControl({ isOpen }: { isOpen: boolean }) {
</div> </div>
</div> </div>
{/* 右半部分Commit按钮和刷新按钮 */} {/* 右半部分Commit按钮、推送按钮和刷新按钮 */}
<div className="flex items-center gap-2 flex-1 justify-end"> <div className="flex items-center gap-2 flex-1 justify-end">
<Button <Button
onClick={() => setShowCommitDialog(true)} onClick={() => setShowCommitDialog(true)}
@@ -367,6 +390,16 @@ export function VersionControl({ isOpen }: { isOpen: boolean }) {
<GitCommit className="mr-2 h-4 w-4" /> <GitCommit className="mr-2 h-4 w-4" />
</Button> </Button>
{selectedBranch && !selectedBranch.startsWith('origin/') && (
<Button
variant="outline"
onClick={handlePushToRemote}
disabled={pushToRemoteMutation.isPending}
title="推送到远程仓库"
>
<Upload className={cn("h-4 w-4", pushToRemoteMutation.isPending && "animate-pulse")} />
</Button>
)}
<Button <Button
variant="outline" variant="outline"
onClick={handleRefresh} onClick={handleRefresh}

View File

@@ -12,6 +12,7 @@ import {
resetToCommit, resetToCommit,
getCurrentBranch, getCurrentBranch,
hasUncommittedChanges, hasUncommittedChanges,
pushToRemote,
} from '@/server/utils/git-helper' } from '@/server/utils/git-helper'
@@ -224,6 +225,25 @@ export const devPanelRouter = createTRPCRouter({
}) })
} }
}), }),
/**
* 推送分支到远程仓库
*/
pushToRemote: permissionRequiredProcedure('SUPER_ADMIN_ONLY')
.input(z.object({
branchName: z.string().min(1, '分支名称不能为空'),
}))
.mutation(async ({ input }) => {
try {
await pushToRemote(input.branchName)
return { success: true, message: `已推送分支 ${input.branchName} 到远程仓库` }
} catch (error: any) {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: `推送失败: ${error.message}`,
})
}
}),
}) })
export type DevPanelRouter = typeof devPanelRouter export type DevPanelRouter = typeof devPanelRouter

View File

@@ -632,3 +632,19 @@ export async function hasUncommittedChanges(): Promise<boolean> {
return false return false
} }
} }
/**
* 推送当前分支到远程仓库
* @param branchName 分支名称
*/
export async function pushToRemote(branchName: string): Promise<void> {
try {
await execAsync(`git push origin "${branchName}"`, {
cwd: process.cwd(),
encoding: 'utf-8',
})
} catch (error) {
console.error('推送到远程仓库失败:', error)
throw new Error(`无法推送到远程仓库: ${error instanceof Error ? error.message : String(error)}`)
}
}