feat: register plan management in vault nav + remote HTTP routes
Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled

- VaultViewLayout: lazy import + Wrench icon + sidebar menu + planManagement section render

- remoteHttpServer: loadModules 加载 4 新 store + resetAllCaches 重置 + 6 条预案 GET 路由 (templates/plans/plan/:id/command-catalog/aggregation-rules)
This commit is contained in:
2026-10-30 17:00:38 +08:00
committed by trae-solo-agent
parent a5744e720b
commit 4417f62d7e
2 changed files with 86 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useCallback, lazy, Suspense, useState, useEffect } from "react";
import { AlertTriangle, Bell, Activity, Network, FileText, BarChart3 } from "lucide-react";
import { AlertTriangle, Bell, Activity, Network, FileText, BarChart3, Wrench } from "lucide-react";
import { WorkbenchView } from "./WorkbenchView";
import { deleteVaultKey } from "../../application/defaultKeyPassphrases";
import { usePluginImporterCommit } from "../../application/state/usePluginImporterCommit";
@@ -33,6 +33,8 @@ import { InspectionErrorBoundary } from "../inspection/InspectionErrorBoundary";
const AlertCenterPage = lazy(() => import("../inspection/AlertCenterPage"));
const AlertRulesPage = lazy(() => import("../inspection/AlertRulesPage"));
const InspectionCenterPage = lazy(() => import("../inspection/InspectionCenterPage"));
// 预案管理(v1.3:双轨预案 + AI 生成)
const PlanManagementPage = lazy(() => import("../inspection/PlanManagementPage").then((m) => ({ default: m.PlanManagementPage })));
// 运行监控 - 3D 拓扑大屏
const MonitoringTopologyView = lazy(() => import("../monitoring/MonitoringTopologyView"));
// 巡检报告
@@ -960,6 +962,30 @@ export function VaultViewLayout({ ctx }: { ctx: VaultViewLayoutContext }) {
)}
</Tooltip>
{/* 预案管理 - planManagement(v1.3 双轨预案 + AI 生成) */}
<Tooltip>
<TooltipTrigger asChild>
<RippleButton
variant={currentSection === "planManagement" ? "secondary" : "ghost"}
className={cn(
"w-full h-10",
sidebarCollapsed
? "justify-center p-0"
: "justify-start gap-3",
currentSection === "planManagement" &&
"bg-foreground/10 text-foreground hover:bg-foreground/15 border-border/40",
)}
onClick={() => setCurrentSection("planManagement")}
>
<Wrench size={16} className="flex-shrink-0" />
{!sidebarCollapsed && "预案管理"}
</RippleButton>
</TooltipTrigger>
{sidebarCollapsed && (
<TooltipContent side="right">预案管理</TooltipContent>
)}
</Tooltip>
{/* 巡检报告 - reports */}
<Tooltip>
<TooltipTrigger asChild>
@@ -1705,6 +1731,19 @@ export function VaultViewLayout({ ctx }: { ctx: VaultViewLayoutContext }) {
</LazyLoadBoundary>
)}
{/* 预案管理(v1.3) */}
{currentSection === "planManagement" && (
<LazyLoadBoundary name="Plan management" resetKey="plan-management">
<Suspense fallback={<VaultSectionLoading />}>
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
<InspectionErrorBoundary>
<PlanManagementPage />
</InspectionErrorBoundary>
</div>
</Suspense>
</LazyLoadBoundary>
)}
{/* 巡检报告 */}
{currentSection === "reports" && (
<LazyLoadBoundary name="Inspection report" resetKey="inspection-report">

View File

@@ -199,7 +199,12 @@ function loadModules() {
const reportStore = require("./bridges/inspection/reportStore.cjs");
const dailyReportStore = require("./bridges/inspection/dailyReportStore.cjs");
const reportScheduleStore = require("./bridges/inspection/reportScheduleStore.cjs");
return { inspectionStorage, deviceStore, alertRecordStore, inspectionResultStore, alertRuleStore, reportStore, dailyReportStore, reportScheduleStore };
// v1.3 预案管理新增
const planTemplateStore = require("./bridges/inspection/planTemplateStore.cjs");
const devicePlanStore = require("./bridges/inspection/devicePlanStore.cjs");
const commandCatalogStore = require("./bridges/inspection/commandCatalogStore.cjs");
const aggregationEngine = require("./bridges/inspection/aggregationEngine.cjs");
return { inspectionStorage, deviceStore, alertRecordStore, inspectionResultStore, alertRuleStore, reportStore, dailyReportStore, reportScheduleStore, planTemplateStore, devicePlanStore, commandCatalogStore, aggregationEngine };
}
// 每次 API 请求前重置所有 store 的模块级缓存,强制从磁盘重新加载
@@ -212,6 +217,10 @@ function resetAllCaches(modules) {
try { m.alertRuleStore._resetForTest?.(); } catch {}
try { m.reportStore._resetForTest?.(); } catch {}
try { m.dailyReportStore._resetForTest?.(); } catch {}
// v1.3 预案
try { m.planTemplateStore._resetForTest?.(); } catch {}
try { m.devicePlanStore._resetForTest?.(); } catch {}
try { m.commandCatalogStore._resetForTest?.(); } catch {}
}
/**
@@ -507,6 +516,42 @@ async function handleApi(pathname, method, body, query) {
return { ok: true, results };
}
// ════════════════════════════════════════════════════════
// v1.3 预案管理路由(远程浏览器访问)
// ════════════════════════════════════════════════════════
// GET /api/plan-templates —— 预案模板列表
if (method === "GET" && pathname === "/api/plan-templates") {
return { ok: true, templates: planTemplateStore.listTemplates(readStorage) };
}
// GET /api/device-plans —— 设备预案列表(带可选 filter 查询参数)
if (method === "GET" && pathname === "/api/device-plans") {
const filters = {};
if (query.status) filters.status = query.status;
if (query.level) filters.level = query.level;
if (query.device_type) filters.device_type = query.device_type;
return { ok: true, plans: devicePlanStore.listPlans(readStorage, filters) };
}
// GET /api/device-plans/:id —— 单条预案详情
const planMatch = pathname.match(/^\/api\/device-plans\/([^/]+)$/);
if (method === "GET" && planMatch) {
const plan = devicePlanStore.getPlan(readStorage, decodeURIComponent(planMatch[1]));
if (!plan) return { ok: false, error: "Plan not found" };
return { ok: true, plan };
}
// GET /api/command-catalog —— 预置命令目录
if (method === "GET" && pathname === "/api/command-catalog") {
return { ok: true, commands: commandCatalogStore.listCommands(readStorage) };
}
// GET /api/aggregation-rules —— 聚合规则
if (method === "GET" && pathname === "/api/aggregation-rules") {
return { ok: true, rules: aggregationEngine.listRules(readStorage) };
}
// GET /api/devices/enabled —— 已启用巡检的设备列表
if (method === "GET" && pathname === "/api/devices/enabled") {
const enabled = deviceStore.getEnabledDevices(readStorage);