Skip to content

Commit 586bd5f

Browse files
authored
feat(web): enhance code editor functionality (#1945)
- 添加支持 EditCLMode 和 skip_build 参数 - 新增 Change List 模式选择功能,支持强制创建新 CL 或尝试复用已有 CL - 新增跳过自动构建选项,允许提交时跳过 Cl 构建流程 - 更新 favicon 图标资源
1 parent 1435f4e commit 586bd5f

File tree

3 files changed

+362
-30
lines changed

3 files changed

+362
-30
lines changed

moon/apps/web/components/CodeView/BlobView/BlobEditor.tsx

Lines changed: 123 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import toast from 'react-hot-toast'
88
import { Button } from '@gitmono/ui/Button'
99
import { Dialog } from '@gitmono/ui/Dialog'
1010

11+
import { usePostClList } from '@/hooks/CL/usePostClList'
1112
import { useDiffPreview } from '@/hooks/useDiffPreview'
1213
import { useGetCurrentUser } from '@/hooks/useGetCurrentUser'
1314
import { useUpdateBlob } from '@/hooks/useUpdateBlob'
@@ -21,13 +22,21 @@ interface BlobEditorProps {
2122
}
2223

2324
type ViewMode = 'edit' | 'preview'
25+
type CLModeType = 'force_create' | 'try_reuse'
26+
27+
interface ClList {
28+
id: string
29+
link: string
30+
title: string
31+
author: string
32+
}
2433

2534
export default function BlobEditor({ fileContent, filePath, fileName, onCancel }: BlobEditorProps) {
2635
const { data: currentUser } = useGetCurrentUser()
2736

2837
const updateBlobMutation = useUpdateBlob()
2938
const diffPreviewMutation = useDiffPreview()
30-
39+
const { mutate: fetchClList } = usePostClList()
3140
const [content, setContent] = useState(fileContent)
3241

3342
const [editedFileName, setEditedFileName] = useState(fileName)
@@ -36,6 +45,11 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
3645

3746
const [viewMode, setViewMode] = useState<ViewMode>('edit')
3847

48+
const [clOpenList, setClOpenList] = useState<ClList[]>([])
49+
const [selectedClMode, setSelectedClMode] = useState<CLModeType>('force_create')
50+
const [selectedClLink, setSelectedClLink] = useState<string | null>(null)
51+
const [skipBuild, setSkipBuild] = useState(false)
52+
3953
const [diffResult, setDiffResult] = useState<any>(null)
4054
const [fileDiffMetadata, setFileDiffMetadata] = useState<FileDiffMetadata | null>(null)
4155

@@ -87,7 +101,6 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
87101
if (patches.length > 0 && patches[0].files.length > 0) {
88102
let metadata = patches[0].files[0]
89103

90-
// 设置文件名和语言
91104
if (!metadata.name) {
92105
metadata = { ...metadata, name: editedFileName }
93106
}
@@ -107,15 +120,49 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
107120
return
108121
}
109122
setIsCommitDialogOpen(true)
110-
}, [hasChanges])
123+
setSelectedClMode('force_create')
124+
setSelectedClLink(null)
125+
setSkipBuild(false)
126+
127+
fetchClList(
128+
{
129+
data: {
130+
pagination: { page: 1, per_page: 100 },
131+
additional: {
132+
asc: true,
133+
status: 'open'
134+
}
135+
}
136+
},
137+
{
138+
onSuccess: (response) => {
139+
const data = response.data
140+
const items = data?.items || []
141+
142+
setClOpenList(
143+
items.map((item: any) => ({
144+
id: item.id || '',
145+
link: item.link || '',
146+
title: item.title || '',
147+
author: item.author || ''
148+
}))
149+
)
150+
}
151+
}
152+
)
153+
}, [fetchClList, hasChanges])
111154

112155
const handleSave = useCallback(async () => {
156+
const mode = selectedClMode === 'force_create' ? 'force_create' : { try_reuse: selectedClLink }
157+
113158
await updateBlobMutation.mutateAsync({
114159
path: fullEditedPath,
115160
content: content,
116161
commit_message: commitDescription ? `${commitMessage}\n\n${commitDescription}` : commitMessage,
117162
author_email: currentUser?.email,
118-
author_username: currentUser?.username
163+
author_username: currentUser?.username,
164+
mode: mode,
165+
skip_build: skipBuild
119166
})
120167

121168
setIsCommitDialogOpen(false)
@@ -128,9 +175,22 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
128175
commitMessage,
129176
currentUser?.email,
130177
currentUser?.username,
178+
selectedClMode,
179+
selectedClLink,
180+
skipBuild,
131181
onCancel
132182
])
133183

184+
const handleDialogClose = useCallback((open: boolean) => {
185+
setIsCommitDialogOpen(open)
186+
if (!open) {
187+
setSelectedClMode('force_create')
188+
setSelectedClLink(null)
189+
setSkipBuild(false)
190+
setClOpenList([])
191+
}
192+
}, [])
193+
134194
const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
135195
setContent(e.target.value)
136196

@@ -286,7 +346,7 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
286346
</div>
287347
</div>
288348

289-
<Dialog.Root open={isCommitDialogOpen} onOpenChange={setIsCommitDialogOpen}>
349+
<Dialog.Root open={isCommitDialogOpen} onOpenChange={handleDialogClose}>
290350
<Dialog.Content>
291351
<Dialog.CloseButton />
292352
<Dialog.Header>
@@ -317,15 +377,68 @@ export default function BlobEditor({ fileContent, filePath, fileName, onCancel }
317377
disabled={updateBlobMutation.isPending}
318378
/>
319379
</div>
380+
381+
<div className='flex flex-col gap-2'>
382+
<label className='text-sm font-medium text-gray-700'>Change List Mode *</label>
383+
<select
384+
value={selectedClMode}
385+
onChange={(e) => {
386+
const mode = e.target.value as CLModeType
387+
388+
setSelectedClMode(mode)
389+
if (mode === 'force_create') {
390+
setSelectedClLink(null)
391+
}
392+
// 切换到 try_reuse 时不自动选择,保持为 null
393+
}}
394+
className='w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500'
395+
disabled={updateBlobMutation.isPending}
396+
>
397+
<option value='try_reuse'>Try reuse existing CL</option>
398+
<option value='force_create'>Create new CL</option>
399+
</select>
400+
</div>
401+
402+
{selectedClMode === 'try_reuse' && (
403+
<div className='flex flex-col gap-2'>
404+
<label className='text-sm font-medium text-gray-700'>Select Change List</label>
405+
<select
406+
value={selectedClLink || ''}
407+
onChange={(e) => setSelectedClLink(e.target.value || null)}
408+
className='w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500'
409+
disabled={updateBlobMutation.isPending}
410+
>
411+
<option value=''>Auto select or create new</option>
412+
{clOpenList.map((cl) => (
413+
<option key={cl.link} value={cl.link}>
414+
{cl.link} - {cl.title} ({cl.author})
415+
</option>
416+
))}
417+
</select>
418+
<p className='text-xs text-gray-500'>
419+
If no CL is selected, the system will automatically search for an existing open CL or create a new one
420+
</p>
421+
</div>
422+
)}
423+
424+
<div className='flex items-center gap-2'>
425+
<input
426+
type='checkbox'
427+
id='skipBuild'
428+
checked={skipBuild}
429+
onChange={(e) => setSkipBuild(e.target.checked)}
430+
className='h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500'
431+
disabled={updateBlobMutation.isPending}
432+
/>
433+
<label htmlFor='skipBuild' className='text-sm font-medium text-gray-700'>
434+
Skip automatic build after commit
435+
</label>
436+
</div>
320437
</div>
321438

322439
<Dialog.Footer>
323440
<Dialog.TrailingActions>
324-
<Button
325-
variant='flat'
326-
onClick={() => setIsCommitDialogOpen(false)}
327-
disabled={updateBlobMutation.isPending}
328-
>
441+
<Button variant='flat' onClick={() => handleDialogClose(false)} disabled={updateBlobMutation.isPending}>
329442
Cancel
330443
</Button>
331444
<Button onClick={handleSave} disabled={updateBlobMutation.isPending || !commitMessage.trim()}>

moon/apps/web/public/favicon.ico

16.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)