"use client" import React, { useState, useEffect, useRef } from "react" import { FileCode, Save, X, AlertCircle, CheckCircle2, AlertTriangle } from "lucide-react" import Editor from "@monaco-editor/react" import * as yaml from "js-yaml" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" import { toast } from "sonner" import { useTheme } from "next-themes" import type { ScanEngine } from "@/types/engine.types" interface EngineEditDialogProps { engine: ScanEngine | null open: boolean onOpenChange: (open: boolean) => void onSave?: (engineId: number, yamlContent: string) => Promise } /** * 引擎配置编辑弹窗 * 使用 Monaco Editor 提供 VSCode 级别的编辑体验 */ export function EngineEditDialog({ engine, open, onOpenChange, onSave, }: EngineEditDialogProps) { const [yamlContent, setYamlContent] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) const [hasChanges, setHasChanges] = useState(false) const [isEditorReady, setIsEditorReady] = useState(false) const [yamlError, setYamlError] = useState<{ message: string; line?: number; column?: number } | null>(null) const { theme } = useTheme() const editorRef = useRef(null) // 生成示例 YAML 配置 const generateSampleYaml = (engine: ScanEngine) => { return `# 引擎名称: ${engine.name} # ==================== 子域名发现 ==================== subdomain_discovery: tools: subfinder: enabled: true timeout: 600 # 10 分钟(必需) amass_passive: enabled: true timeout: 600 # 10 分钟(必需) amass_active: enabled: true timeout: 1800 # 30 分钟(必需) sublist3r: enabled: true timeout: 900 # 15 分钟(必需) oneforall: enabled: true timeout: 1200 # 20 分钟(必需) # ==================== 端口扫描 ==================== port_scan: tools: naabu_active: enabled: true timeout: auto # 自动计算 threads: 5 top-ports: 100 rate: 10 naabu_passive: enabled: true timeout: auto # ==================== 站点扫描 ==================== site_scan: tools: httpx: enabled: true timeout: auto # 自动计算 # ==================== 目录扫描 ==================== directory_scan: tools: ffuf: enabled: true timeout: auto # 自动计算超时时间 wordlist: ~/Desktop/dirsearch_dicc.txt # 词表文件路径(必需) delay: 0.1-2.0 threads: 10 request_timeout: 10 match_codes: 200,201,301,302,401,403 # ==================== URL 获取 ==================== url_fetch: tools: waymore: enabled: true timeout: auto katana: enabled: true timeout: auto depth: 5 threads: 10 rate-limit: 30 random-delay: 1 retry: 2 request-timeout: 12 uro: enabled: true timeout: auto httpx: enabled: true timeout: auto ` } // 当引擎改变时,更新 YAML 内容 useEffect(() => { if (engine && open) { // TODO: 从后端 API 获取实际的 YAML 配置 // 如果引擎有配置则使用,否则使用示例配置 const content = engine.configuration || generateSampleYaml(engine) setYamlContent(content) setHasChanges(false) setYamlError(null) } }, [engine, open]) // 验证 YAML 语法 const validateYaml = (content: string) => { if (!content.trim()) { setYamlError(null) return true } try { yaml.load(content) setYamlError(null) return true } catch (error) { const yamlError = error as yaml.YAMLException setYamlError({ message: yamlError.message, line: yamlError.mark?.line ? yamlError.mark.line + 1 : undefined, column: yamlError.mark?.column ? yamlError.mark.column + 1 : undefined, }) return false } } // 处理编辑器内容变化 const handleEditorChange = (value: string | undefined) => { const newValue = value || "" setYamlContent(newValue) setHasChanges(true) validateYaml(newValue) } // 处理编辑器挂载 const handleEditorDidMount = (editor: any) => { editorRef.current = editor setIsEditorReady(true) } // 处理保存 const handleSave = async () => { if (!engine) return // YAML 验证 if (!yamlContent.trim()) { toast.error("配置内容不能为空") return } if (!validateYaml(yamlContent)) { toast.error("YAML 语法错误", { description: yamlError?.message, }) return } setIsSubmitting(true) try { if (onSave) { await onSave(engine.id, yamlContent) } else { // TODO: 调用实际的 API 保存 YAML 配置 await new Promise(resolve => setTimeout(resolve, 1000)) } toast.success("配置保存成功", { description: `引擎 "${engine.name}" 的配置已更新`, }) setHasChanges(false) onOpenChange(false) } catch (error) { console.error("Failed to save YAML config:", error) toast.error("配置保存失败", { description: error instanceof Error ? error.message : "未知错误", }) } finally { setIsSubmitting(false) } } // 处理关闭 const handleClose = () => { if (hasChanges) { const confirmed = window.confirm("您有未保存的更改,确定要关闭吗?") if (!confirmed) return } onOpenChange(false) } return (
编辑引擎配置 - {engine?.name} 使用 Monaco Editor 编辑引擎的 YAML 配置文件,支持语法高亮、自动补全和错误提示。
{/* 语法验证状态 */}
{yamlContent.trim() && ( yamlError ? (
语法错误
) : (
语法正确
) )}
{/* Monaco Editor */}

加载编辑器...

} />
{/* 错误信息显示 */} {yamlError && (

{yamlError.line && yamlError.column ? `第 ${yamlError.line} 行,第 ${yamlError.column} 列` : "YAML 语法错误"}

{yamlError.message}

)}

您有未保存的更改

) }