- ansible-helpers.tsx (114): types, mapPlaybook, categories, samplePlaybook, getStatusBadge, formatDate - AnsibleFormDialog.tsx (111): 新建/编辑 Playbook 弹窗 - AnsibleDetailDialog.tsx (47): 查看 Playbook 内容弹窗 - AnsibleLogsDialog.tsx (38): 执行日志弹窗 - AnsibleManager.tsx (740->535): 主组件保留统计卡片+Tab布局+列表+表格+状态管理
112 lines
3.9 KiB
TypeScript
112 lines
3.9 KiB
TypeScript
// Ansible 新建/编辑 Playbook 弹窗 // Logan.Li
|
|
import { CheckCircle } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import {
|
|
Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
|
|
} from '@/components/ui/dialog';
|
|
import {
|
|
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { categories } from './ansible-helpers';
|
|
|
|
export interface PlaybookFormData {
|
|
name: string;
|
|
description: string;
|
|
content: string;
|
|
category: string;
|
|
tags: string;
|
|
timeout: number;
|
|
}
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
editingId: number | null;
|
|
formData: PlaybookFormData;
|
|
setFormData: React.Dispatch<React.SetStateAction<PlaybookFormData>>;
|
|
onSave: () => void;
|
|
}
|
|
|
|
const AnsibleFormDialog: React.FC<Props> = ({ open, onOpenChange, editingId, formData, setFormData, onSave }) => {
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="max-w-4xl max-h-[90vh]">
|
|
<DialogHeader>
|
|
<DialogTitle>{editingId !== null ? '编辑 Playbook' : '新建 Playbook'}</DialogTitle>
|
|
<DialogDescription>编写 Ansible Playbook 实现自动化运维</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="space-y-4 overflow-y-auto max-h-[60vh] pr-1">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<Label>名称</Label>
|
|
<Input
|
|
value={formData.name}
|
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
placeholder="Playbook 名称"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label>分类</Label>
|
|
<Select value={formData.category} onValueChange={(v) => setFormData({ ...formData, category: v })}>
|
|
<SelectTrigger><SelectValue /></SelectTrigger>
|
|
<SelectContent>
|
|
{categories.map(c => (
|
|
<SelectItem key={c.value} value={c.value}>{c.label}</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<Label>描述</Label>
|
|
<Input
|
|
value={formData.description}
|
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
|
placeholder="Playbook 描述"
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<Label>标签(逗号分隔)</Label>
|
|
<Input
|
|
value={formData.tags}
|
|
onChange={(e) => setFormData({ ...formData, tags: e.target.value })}
|
|
placeholder="如: nginx, web, 部署"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label>超时(秒)</Label>
|
|
<Input
|
|
type="number"
|
|
value={formData.timeout}
|
|
onChange={(e) => setFormData({ ...formData, timeout: Number(e.target.value) })}
|
|
placeholder="600"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<Label>Playbook 内容 (YAML)</Label>
|
|
<Textarea
|
|
value={formData.content}
|
|
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
|
|
className="min-h-[380px] font-mono text-sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>取消</Button>
|
|
<Button onClick={onSave}>
|
|
<CheckCircle className="w-4 h-4 mr-2" />
|
|
{editingId !== null ? '保存' : '创建'}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
export default AnsibleFormDialog;
|