Skip to content

Commit 7c8650f

Browse files
feat: 启动 AI 功能优化
- 去掉“生成项目文档”选项,点击“启动 AI”直接弹出对话框 - 添加仓库分支选择功能,调用 API 获取分支列表 - 添加项目名称和仓库地址展示(只读输入框样式) - internal 平台不显示分支选择框,branch 传空字符串 - 使用 project.full_name 字段获取仓库名称 - 优先选择 main/master 分支,无则选择第一个 - 添加分支加载状态显示 - 去掉对话框子标题和上下边距 - 分支选择框撑满一行,宽度与上方输入框一致 - 修复生成项目文档对话框的构建错误 Co-authored-by: monkeycode-ai <monkeycode-ai@chaitin.com>
1 parent 31e797a commit 7c8650f

File tree

4 files changed

+245
-48
lines changed

4 files changed

+245
-48
lines changed

frontend/src/api/Api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,8 @@ export interface DomainProject {
827827
created_at?: number;
828828
/** 项目描述 */
829829
description?: string;
830+
/** 仓库 full_name */
831+
full_name?: string;
830832
/** 项目关联的 git identity id */
831833
git_identity_id?: string;
832834
/** 项目ID */

frontend/src/components/console/project/generate-doc-dialog.tsx

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,113 @@
1-
import { ConstsCliName, ConstsTaskSubType, ConstsTaskType } from "@/api/Api"
1+
import { ConstsCliName, ConstsTaskSubType, ConstsTaskType, ConstsGitPlatform, type DomainProject, type DomainBranch } from "@/api/Api"
22
import { useCommonData } from "@/components/console/data-provider"
33
import { Button } from "@/components/ui/button"
4-
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
4+
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
5+
import { Input } from "@/components/ui/input"
6+
import { Label } from "@/components/ui/label"
7+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
58
import { Spinner } from "@/components/ui/spinner"
69
import { packAndUploadFilesAsZip, selectHost, selectImage, selectModel } from "@/utils/common"
710
import { apiRequest } from "@/utils/requestUtils"
811
import { IconSparkles } from "@tabler/icons-react"
9-
import { useState } from "react"
12+
import { useState, useEffect } from "react"
1013
import { toast } from "sonner"
1114

1215
interface GenerateDocDialogProps {
1316
open: boolean
1417
onOpenChange: (open: boolean) => void
1518
projectId: string
1619
projectName: string
20+
project?: DomainProject
1721
}
1822

1923
export default function GenerateDocDialog({
2024
open,
2125
onOpenChange,
2226
projectId,
23-
projectName
27+
projectName,
28+
project
2429
}: GenerateDocDialogProps) {
2530
const [selectedFiles, setSelectedFiles] = useState<File[]>([])
2631
const [submitting, setSubmitting] = useState<boolean>(false)
32+
const [branches, setBranches] = useState<string[]>([])
33+
const [selectedBranch, setSelectedBranch] = useState<string>('')
34+
const [loadingBranches, setLoadingBranches] = useState<boolean>(false)
2735
const { images, models, hosts } = useCommonData()
2836

37+
const fetchBranches = async () => {
38+
if (!project?.git_identity_id || !project?.repo_url) {
39+
return
40+
}
41+
42+
// internal 平台不需要获取分支列表
43+
if (project.platform === ConstsGitPlatform.GitPlatformInternal) {
44+
setSelectedBranch('')
45+
setBranches([])
46+
return
47+
}
48+
49+
setLoadingBranches(true)
50+
51+
try {
52+
// 直接使用 full_name 字段
53+
const escapedRepoFullName = project?.full_name || ''
54+
55+
if (!escapedRepoFullName) {
56+
toast.error('无法获取仓库信息')
57+
setLoadingBranches(false)
58+
return
59+
}
60+
61+
// URL 编码仓库名称
62+
const encodedRepoName = encodeURIComponent(escapedRepoFullName)
63+
64+
await apiRequest('v1UsersGitIdentitiesBranchesDetail', {}, [project.git_identity_id, encodedRepoName], (resp) => {
65+
if (resp.code === 0 && resp.data) {
66+
const branchList = resp.data.map((b: DomainBranch) => b.name || '').filter(Boolean)
67+
setBranches(branchList)
68+
69+
// 优先选择 main 或 master,否则选择第一个
70+
if (branchList.includes('main')) {
71+
setSelectedBranch('main')
72+
} else if (branchList.includes('master')) {
73+
setSelectedBranch('master')
74+
} else if (branchList.length > 0) {
75+
setSelectedBranch(branchList[0])
76+
}
77+
} else {
78+
toast.error('获取分支列表失败: ' + resp.message)
79+
}
80+
})
81+
} catch (error) {
82+
console.error('Fetch branches error:', error)
83+
toast.error('获取分支列表失败')
84+
} finally {
85+
setLoadingBranches(false)
86+
}
87+
}
88+
89+
useEffect(() => {
90+
if (open) {
91+
fetchBranches()
92+
}
93+
}, [open, project])
94+
2995
const handleOpenChange = (open: boolean) => {
3096
onOpenChange(open)
3197
if (!open) {
3298
// 重置表单状态
3399
setSelectedFiles([])
100+
setSelectedBranch('')
101+
setBranches([])
34102
}
35103
}
36104

37105
const handleSubmit = async () => {
106+
if (project?.platform !== ConstsGitPlatform.GitPlatformInternal && !selectedBranch) {
107+
toast.error('请选择分支')
108+
return
109+
}
110+
38111
setSubmitting(true)
39112

40113
let repoInfo: { zip_url?: string; repo_filename?: string } = {}
@@ -68,6 +141,7 @@ export default function GenerateDocDialog({
68141
},
69142
extra: {
70143
project_id: projectId,
144+
branch: project?.platform === ConstsGitPlatform.GitPlatformInternal ? '' : selectedBranch,
71145
},
72146
task_type: ConstsTaskType.TaskTypeDesign,
73147
sub_type: ConstsTaskSubType.TaskSubTypeGenerateDocs,
@@ -89,10 +163,43 @@ export default function GenerateDocDialog({
89163
<DialogContent>
90164
<DialogHeader>
91165
<DialogTitle>生成项目文档</DialogTitle>
92-
<DialogDescription>
93-
AI 将根据你的需求为你生成项目架构设计文档
94-
</DialogDescription>
95166
</DialogHeader>
167+
168+
<div className="space-y-4 py-4">
169+
<div className="space-y-2">
170+
<Label>仓库地址</Label>
171+
<Input
172+
value={project?.repo_url || '-'}
173+
readOnly
174+
className="bg-muted"
175+
/>
176+
</div>
177+
{(project?.platform !== ConstsGitPlatform.GitPlatformInternal) && (
178+
<div className="space-y-2">
179+
<Label>选择分支</Label>
180+
<Select value={selectedBranch} onValueChange={setSelectedBranch} disabled={loadingBranches || branches.length === 0}>
181+
<SelectTrigger>
182+
{loadingBranches ? (
183+
<div className="flex items-center gap-2">
184+
<Spinner className="size-4" />
185+
<span>加载中...</span>
186+
</div>
187+
) : (
188+
<SelectValue placeholder="请选择分支" />
189+
)}
190+
</SelectTrigger>
191+
<SelectContent>
192+
{branches.map((branch) => (
193+
<SelectItem key={branch} value={branch}>
194+
{branch}
195+
</SelectItem>
196+
))}
197+
</SelectContent>
198+
</Select>
199+
</div>
200+
)}
201+
</div>
202+
96203
<DialogFooter>
97204
<Button
98205
onClick={handleSubmit}
@@ -106,4 +213,3 @@ export default function GenerateDocDialog({
106213
</Dialog>
107214
)
108215
}
109-

frontend/src/components/console/project/project-info.tsx

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { type DomainProject } from "@/api/Api"
22
import { useCommonData } from "@/components/console/data-provider"
33
import EditCollaboratorsDialog from "@/components/console/project/edit-collaborators"
44
import EditProjectNameDialog from "@/components/console/project/edit-project-name"
5-
import GenerateDocDialog from "@/components/console/project/generate-doc-dialog"
65
import StartDevelopTaskDialog from "@/components/console/project/start-develop-task-dialog"
76
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"
87
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
@@ -11,7 +10,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
1110
import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "@/components/ui/item"
1211
import { isProjectRepoUnbound } from "@/utils/project"
1312
import { apiRequest } from "@/utils/requestUtils"
14-
import { IconBook, IconBrandGithub, IconLoader, IconPencil, IconSparkles, IconTrash, IconUsers } from "@tabler/icons-react"
13+
import { IconBrandGithub, IconLoader, IconPencil, IconSparkles, IconTrash, IconUsers } from "@tabler/icons-react"
1514
import { MoreVertical } from "lucide-react"
1615
import { useState } from "react"
1716
import { useNavigate } from "react-router-dom"
@@ -32,7 +31,6 @@ const ProjectInfo = ({
3231
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
3332
const [deletingProject, setDeletingProject] = useState<DomainProject | undefined>(undefined)
3433
const [deleteLoading, setDeleteLoading] = useState(false)
35-
const [emptyDocDialogOpen, setEmptyDocDialogOpen] = useState(false)
3634
const [conversationDialogOpen, setConversationDialogOpen] = useState(false)
3735
const navigate = useNavigate()
3836
const { projects, reloadProjects } = useCommonData()
@@ -79,11 +77,6 @@ const ProjectInfo = ({
7977
setDeleteLoading(false)
8078
}
8179

82-
const handleGenerateDoc = () => {
83-
if (!project) return
84-
setEmptyDocDialogOpen(true)
85-
}
86-
8780
const handleStartConversation = () => {
8881
if (!project || isRepoUnbound) return
8982
setConversationDialogOpen(true)
@@ -118,24 +111,16 @@ const ProjectInfo = ({
118111
</ItemContent>
119112
<ItemActions>
120113

121-
<DropdownMenu>
122-
<DropdownMenuTrigger asChild>
123-
<Button variant="secondary" size="sm" disabled={isRepoUnbound}>
124-
<IconSparkles className="size-4" />
125-
启动 AI
126-
</Button>
127-
</DropdownMenuTrigger>
128-
<DropdownMenuContent align="end">
129-
<DropdownMenuItem onClick={handleStartConversation}>
130-
<IconSparkles />
131-
发起对话
132-
</DropdownMenuItem>
133-
<DropdownMenuItem onClick={handleGenerateDoc}>
134-
<IconBook />
135-
生成项目文档
136-
</DropdownMenuItem>
137-
</DropdownMenuContent>
138-
</DropdownMenu>
114+
<Button
115+
variant="secondary"
116+
size="sm"
117+
disabled={isRepoUnbound}
118+
onClick={handleStartConversation}
119+
>
120+
<IconSparkles className="size-4" />
121+
启动 AI
122+
</Button>
123+
139124
<DropdownMenu>
140125
<DropdownMenuTrigger asChild>
141126
<Button variant="ghost" size="icon-sm">
@@ -200,13 +185,6 @@ const ProjectInfo = ({
200185
</AlertDialogContent>
201186
</AlertDialog>
202187

203-
<GenerateDocDialog
204-
open={emptyDocDialogOpen}
205-
onOpenChange={setEmptyDocDialogOpen}
206-
projectId={project?.id || ''}
207-
projectName={project?.name || ''}
208-
/>
209-
210188
<StartDevelopTaskDialog
211189
open={conversationDialogOpen}
212190
onOpenChange={setConversationDialogOpen}

0 commit comments

Comments
 (0)