+
+ 任务分类管理
+ 分类用于任务筛选与归档;修改不会影响任务执行,删除后任务会移入未分类。
-
-
-
- 新分类
-
-
setNewName(event.target.value)}
- placeholder="例如:外网评估"
- maxLength={80}
- onKeyDown={(event) => {
- if (event.key === "Enter") void createCategory();
- }}
- />
-
-
-
-
-
- {categories.length === 0 &&
暂无分类
}
- {categories.map((category) => (
-
-
- {editingID === category.id ? (
-
setEditingName(event.target.value)}
- onKeyDown={(event) => {
- if (event.key === "Enter") void renameCategory();
- if (event.key === "Escape") setEditingID(null);
- }}
- aria-label={`重命名分类 ${category.name}`}
+
setActiveTaskID(null)}
+ onDragEnd={handleDragEnd}
+ >
+
+
+
+
+
+
- ) : (
-
+ {categories.map((category) => (
+ selectCategory(category)}
+ />
+ ))}
+
+
+
+
+
+ {selectedView !== "uncategorized" && (
+
+ 分类名称
+ setDraftName(event.target.value)}
+ placeholder="例如:外网评估"
+ maxLength={80}
+ onKeyDown={(event) => {
+ if (event.key === "Enter") void saveCategory();
+ }}
+ />
+
+ {selectedCategory
+ ? `当前有 ${selectedCategory.task_count} 个任务使用该分类。重命名后会同步更新任务列表。`
+ : "创建后可在新建任务和任务列表筛选中使用。"}
+
+
)}
-
- {category.task_count} 个任务
-
- {editingID === category.id && (
-
+ {selectedView !== "new" && (
+
+
+
+ {selectedCategory ? "分类任务" : "未分类任务"}
+
+ {selectedCategory
+ ? `该分类包含 ${visibleTasks.length} 个任务。`
+ : `当前有 ${visibleTasks.length} 个任务尚未分类。`}
+
+
+
+ {visibleTasks.length === 0 ? (
+
+
+ {selectedCategory ? "该分类暂无任务" : "暂无未分类任务"}
+ 此处将在任务归入后显示内容。
+
+
+ ) : (
+
+ {visibleTasks.map((task) => (
+
+ ))}
+
+ )}
+
)}
-
-
- ))}
+
+
-
+
{activeTask ? : null}
+
+
+ {selectedCategory && (
+
+ )}
+
+ {selectedView !== "uncategorized" && (
+
+ )}
+
-
!next && setDeleting(null)}>
+
- 删除分类“{deleting?.name}”?
+ 删除分类「{selectedCategory?.name || "未命名分类"}」?
- 分类删除后,其中 {deleting?.task_count ?? 0} 个任务会自动移入“未分类”,任务数据不会被删除。
+ 分类删除后,其中 {selectedCategory?.task_count ?? 0} 个任务会自动移入“未分类”,任务数据不会被删除。
- 取消
- void deleteCategory()} disabled={saving}>
- 删除
+ 取消
+ {
+ event.preventDefault();
+ void deleteCategory();
+ }}
+ >
+ {deleting && }
+ {deleting ? "删除中" : "删除"}
diff --git a/web/src/app/(main)/system/llm/page.tsx b/web/src/app/(main)/system/llm/page.tsx
index 2a5db5b..b08c6ef 100644
--- a/web/src/app/(main)/system/llm/page.tsx
+++ b/web/src/app/(main)/system/llm/page.tsx
@@ -415,8 +415,6 @@ function ProfileSheet({
e.preventDefault()}
>
diff --git a/web/src/app/(main)/system/tools/page.tsx b/web/src/app/(main)/system/tools/page.tsx
index d8a320c..a3ca873 100644
--- a/web/src/app/(main)/system/tools/page.tsx
+++ b/web/src/app/(main)/system/tools/page.tsx
@@ -313,6 +313,7 @@ function ToolEditor({
function ToolGridCard({ tool, onClick }: { tool: Tool; onClick: () => void }) {
return (
{tool.description || "(无描述)"}
diff --git a/web/src/components/ui/sheet.tsx b/web/src/components/ui/sheet.tsx
index ce2b56a..8d0e1d3 100644
--- a/web/src/components/ui/sheet.tsx
+++ b/web/src/components/ui/sheet.tsx
@@ -3,7 +3,7 @@
import * as React from "react"
import { Dialog as SheetPrimitive } from "radix-ui"
-import { cn, radixOverlayWasOpenAtPointerDown } from "@/lib/utils"
+import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { XIcon } from "lucide-react"
@@ -50,7 +50,6 @@ function SheetContent({
children,
side = "right",
showCloseButton = true,
- onInteractOutside,
...props
}: React.ComponentProps & {
side?: "top" | "right" | "bottom" | "left"
@@ -62,18 +61,6 @@ function SheetContent({
{
- const target = e.detail.originalEvent.target as Element | null
- const onOverlay = !!target?.closest?.("[data-slot='sheet-overlay']")
- if (!onOverlay || radixOverlayWasOpenAtPointerDown()) e.preventDefault()
- onInteractOutside?.(e)
- }}
className={cn(
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10",
className
diff --git a/web/src/lib/mock/data.ts b/web/src/lib/mock/data.ts
index 4035f93..51a0007 100644
--- a/web/src/lib/mock/data.ts
+++ b/web/src/lib/mock/data.ts
@@ -2935,6 +2935,7 @@ export const tools: Tool[] = [
agents: ["worker", "mainagent"],
enabled: true,
kind: "builtin",
+ calls: 1842,
},
{
key: "report_finding",
@@ -2953,6 +2954,7 @@ export const tools: Tool[] = [
agents: ["worker"],
enabled: true,
kind: "builtin",
+ calls: 96,
},
{
key: "upsert_asset",
@@ -2962,6 +2964,7 @@ export const tools: Tool[] = [
agents: ["worker"],
enabled: true,
kind: "builtin",
+ calls: 417,
},
{
key: "list_goals",
@@ -2971,6 +2974,7 @@ export const tools: Tool[] = [
agents: ["planner"],
enabled: true,
kind: "builtin",
+ calls: 238,
},
{
key: "nuclei_scan",
@@ -2985,6 +2989,7 @@ export const tools: Tool[] = [
enabled: true,
kind: "command",
exec: { command: "nuclei", args: ["-u", "{{target}}"] },
+ calls: 31,
},
];
diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts
index 238939d..6377d97 100644
--- a/web/src/lib/types.ts
+++ b/web/src/lib/types.ts
@@ -935,6 +935,7 @@ export interface Tool {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
exec?: Record; // 自定义工具执行规格(kind!=builtin)
deferred?: boolean; // schema 延迟(SearchExtraTools/ExecuteExtraTool)
+ calls?: number; // persistent runtime invocation count (older APIs may omit it)
}
// ---- Stats ----