From c58323a13ac86a8f3ad48d6dd5b669f3c851489a Mon Sep 17 00:00:00 2001 From: xiami762 <> Date: Wed, 27 May 2026 14:36:43 +0800 Subject: [PATCH 1/4] feat(webui): add custom device access wizard (API/WebCLI/Syslog) Extend Device Integration with custom device onboarding for API, WebCLI, and syslog modes, including types, panel UI, and tests. Document a third web2cli capture path when CLI requirements are already specified. Co-authored-by: Cursor --- .flocks/plugins/skills/web2cli/SKILL.md | 5 +- .../CustomDeviceAccessPanel.tsx | 449 ++++++++++++++++++ .../DeviceIntegration/customDevice.test.ts | 85 ++++ .../pages/DeviceIntegration/customDevice.ts | 143 ++++++ .../pages/DeviceIntegration/index.test.tsx | 238 ++++++++++ webui/src/pages/DeviceIntegration/index.tsx | 105 +++- webui/src/types/index.ts | 23 + 7 files changed, 1032 insertions(+), 16 deletions(-) create mode 100644 webui/src/pages/DeviceIntegration/CustomDeviceAccessPanel.tsx create mode 100644 webui/src/pages/DeviceIntegration/customDevice.test.ts create mode 100644 webui/src/pages/DeviceIntegration/customDevice.ts create mode 100644 webui/src/pages/DeviceIntegration/index.test.tsx diff --git a/.flocks/plugins/skills/web2cli/SKILL.md b/.flocks/plugins/skills/web2cli/SKILL.md index 27fe5685f..cccdbb34c 100644 --- a/.flocks/plugins/skills/web2cli/SKILL.md +++ b/.flocks/plugins/skills/web2cli/SKILL.md @@ -133,8 +133,9 @@ print(js("window.__apiCapture.config.captureMode")) ### 4. 明确需要捕获的功能/操作 -- 要求用户手动操作要捕获的页面动作,例如查询、翻页、筛选、提交表单、点击按钮、导出数据。 -- 或者请求用户描述需要 hook 的操作或功能,便于你直接去页面代替用户执行 +- 方式 1:要求用户手动操作要捕获的页面动作,例如查询、翻页、筛选、提交表单、点击按钮、导出数据。 +- 方式 2:请求用户描述需要 hook 的操作或功能,你直接去页面代替用户执行 +- 方式 3:用户之前已经描述了需要的 CLI功能,你直接去页面代替用户执行 需要确认捕获是否开始时: diff --git a/webui/src/pages/DeviceIntegration/CustomDeviceAccessPanel.tsx b/webui/src/pages/DeviceIntegration/CustomDeviceAccessPanel.tsx new file mode 100644 index 000000000..c20b8e616 --- /dev/null +++ b/webui/src/pages/DeviceIntegration/CustomDeviceAccessPanel.tsx @@ -0,0 +1,449 @@ +import { useEffect, useMemo, useState, type InputHTMLAttributes, type TextareaHTMLAttributes } from 'react'; +import { ChevronLeft, Loader2, MessageSquare, RefreshCw, Route, Workflow, X } from 'lucide-react'; +import { useNavigate } from 'react-router-dom'; +import { useToast } from '@/components/common/Toast'; +import SessionChat from '@/components/common/SessionChat'; +import { useSessionChat } from '@/hooks/useSessionChat'; +import { toolAPI } from '@/api/tool'; +import type { + APIServiceSummary, + CustomDeviceAccessMode, + CustomDeviceApiDraft, + CustomDeviceWebCliDraft, +} from '@/types'; +import { + buildCustomDevicePrompt, + buildCustomDeviceSessionContext, + buildCustomDeviceWelcomeMessage, + findTemplateForCustomDevice, +} from './customDevice'; + +type PanelView = 'details' | 'rex' | 'guide'; + +const EMPTY_API_DRAFT: CustomDeviceApiDraft = { + accessMode: 'api', + deviceName: '', + vendorName: '', + version: '', + baseUrl: '', + docsUrl: '', + capabilities: '全部 API', +}; + +const EMPTY_WEBCLI_DRAFT: CustomDeviceWebCliDraft = { + accessMode: 'webcli', + deviceName: '', + vendorName: '', + version: '', + productUrl: '', + targetInterfaces: '', + authHint: '', +}; + +function FieldLabel({ label, required = false }: { label: string; required?: boolean }) { + return ( + + ); +} + +function TextInput(props: InputHTMLAttributes) { + return ( + + ); +} + +function TextArea(props: TextareaHTMLAttributes) { + return ( +