snapshot: AnsibleManager拆分前快照
This commit is contained in:
1 parent
16205fdb2b
commit
e6d9f364e5
13 files changed
+660
-103
No files matched your search
@@ -3,6 +3,7 @@ import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -59,6 +60,8 @@ export function CronJobManager() {
|
||||
const [executionsLoading, setExecutionsLoading] = useState(false);
|
||||
const [expandedExec, setExpandedExec] = useState<number | null>(null);
|
||||
const [executingId, setExecutingId] = useState<number | null>(null);
|
||||
// 批量选择(批量删除) // Logan.Li
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||
// editingId === null 表示新建模式;非 null 表示编辑已有任务 // Logan.Li
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
const [formJob, setFormJob] = useState({
|
||||
@@ -250,6 +253,42 @@ export function CronJobManager() {
|
||||
}
|
||||
};
|
||||
|
||||
// 批量选择相关 // Logan.Li
|
||||
const toggleSelect = (id: number) => {
|
||||
setSelectedIds((prev) =>
|
||||
prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
const toggleSelectAll = () => {
|
||||
if (selectedIds.length === filteredJobs.length && filteredJobs.length > 0) {
|
||||
setSelectedIds([]);
|
||||
} else {
|
||||
setSelectedIds(filteredJobs.map((j) => j.id));
|
||||
}
|
||||
};
|
||||
|
||||
// 批量删除任务(带确认框) // Logan.Li
|
||||
const handleBatchDelete = async () => {
|
||||
if (selectedIds.length === 0) return;
|
||||
const ok = await _confirm({
|
||||
title: '批量删除定时任务',
|
||||
description: `确定删除选中的 ${selectedIds.length} 个任务吗?此操作不可恢复。`,
|
||||
confirmText: '批量删除',
|
||||
variant: 'destructive',
|
||||
});
|
||||
if (!ok) return;
|
||||
try {
|
||||
await cronJobApi.batchDelete(selectedIds);
|
||||
toast.success(`已删除 ${selectedIds.length} 个任务`);
|
||||
setSelectedIds([]);
|
||||
refreshData();
|
||||
} catch (error) {
|
||||
console.error('Failed to batch delete jobs:', error);
|
||||
toast.error('批量删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
@@ -318,16 +357,44 @@ export function CronJobManager() {
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-secondary)]" />
|
||||
<Input
|
||||
placeholder="搜索任务..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-10 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
|
||||
/>
|
||||
<div className="flex items-center justify-between flex-wrap gap-4">
|
||||
<div className="flex items-center gap-3 flex-wrap">
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-secondary)]" />
|
||||
<Input
|
||||
placeholder="搜索任务..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-10 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
{filteredJobs.length > 0 && (
|
||||
<label className="flex items-center gap-2 text-sm text-[var(--dg-text-secondary)] cursor-pointer select-none">
|
||||
<Checkbox
|
||||
checked={
|
||||
selectedIds.length === filteredJobs.length && filteredJobs.length > 0
|
||||
}
|
||||
onCheckedChange={toggleSelectAll}
|
||||
className="border-[var(--dg-border)]"
|
||||
/>
|
||||
全选
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
{selectedIds.length > 0 && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-[var(--dg-text-secondary)]">已选择 {selectedIds.length} 项</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-red-500/30 text-red-400 hover:bg-red-500/10"
|
||||
onClick={handleBatchDelete}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
批量删除
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{initialLoading ? (
|
||||
@@ -346,7 +413,14 @@ export function CronJobManager() {
|
||||
{filteredJobs.map((job) => (
|
||||
<Card key={job.id} className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex items-center pt-1">
|
||||
<Checkbox
|
||||
checked={selectedIds.includes(job.id)}
|
||||
onCheckedChange={() => toggleSelect(job.id)}
|
||||
className="border-[var(--dg-border)]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-3 flex-wrap">
|
||||
<h3 className="font-medium text-[var(--dg-text-primary)]">{job.name}</h3>
|
||||
|
||||
Reference in new issue
Block a user