Skip to content

Frontend

Wenkang Zhu edited this page Aug 10, 2026 · 3 revisions

React 前端(src)

结构总览

src/
├── App.tsx                 # 全局主题(AntD ConfigProvider,明暗主题)
├── main.tsx                # 入口
├── pages/
│   └── HomePage.tsx        # 唯一主页面:侧栏 + 标签页 + 各面板
├── components/
│   ├── home/HomeQuickActions.tsx    # 首页快捷操作
│   ├── host/HostEditorDialog.tsx    # 主机编辑对话框
│   ├── terminal/TerminalTabs.tsx    # 会话标签栏
│   ├── terminal/TerminalPane.tsx    # 会话面板容器
│   ├── terminal/XtermView.tsx       # xterm.js 渲染封装
│   ├── status/ServerStatusPanel.tsx # 监控指标面板
│   ├── sftp/SftpPanel.tsx           # SFTP 面板容器(目录 + 传输队列)
│   ├── sftp/FileExplorer.tsx        # 远程文件浏览
│   └── sftp/TransferQueue.tsx       # 传输任务队列
├── stores/                 # Zustand stores(无业务逻辑在组件内)
│   ├── host.ts             #   主机配置 CRUD(invoke)
│   ├── session.ts          #   会话状态机(后端权威状态,无回写/无超时改写)
│   ├── monitor.ts          #   监控快照 + 长任务状态 + 事件缓存补投
│   ├── sftp.ts             #   SFTP 目录 + 传输任务 + 事件缓存补投
│   ├── layout.ts           #   侧栏宽度(可拖拽)
│   └── theme.ts            #   明暗主题
├── types/                  # TS 类型定义(与 Rust 模型 camelCase 对齐)
│   ├── host.ts · session.ts · monitor.ts · sftp.ts
└── test/                   # 单测 + 集成测试 + mocks

Store 职责(Zustand,不可变更新)

Store 状态 职责
host hosts: HostConfig[] 主机列表 CRUD,调用 list_hosts / save_host / delete_host
session sessions: Map<id, SessionInfo>、activeView、statusMessage 会话生命周期,applySessionStatus/Progress 消费后端权威事件;Connected 后初始化该会话 SFTP 根目录;closeSession 只请求后端 teardown 后清理本地投影(含 monitor/sftp 的 clearSession);事件监听入口 initListeners
monitor snapshots、tasks、sessionTaskMap、pendingTaskEvents 监控快照缓存、长任务状态机、事件缓存补投(invoke 返回前到达的 task:status 在任务元数据到达后应用)
sftp sessionStates: Map<sessionId, SftpState>、pendingTaskEvents 目录浏览、任务队列、进度更新,监听 sftp:progress / sftp:task_status,同样带事件缓存补投
layout sidebarWidth 侧栏拖拽宽度(MAX_SIDEBAR_WIDTH 钳制)
theme theme: 'light' 'dark'

关键流程

会话打开

HomePage 点击主机 → sessionStore.openSession(hostId)
  → invoke('open_session') → 写入 sessions + activeView
  → monitorStore.startMonitoring(失败不阻断主流程)
  → initListeners 注册:session:status / session:progress / monitor:snapshot / task:status
  → Connected 事件到达 → 自动初始化 SFTP 根目录(listDir '/')

会话关闭

closeSession(sessionId) → invoke('close_session')(后端统一 teardown Terminal/Monitoring/SFTP)
  → 移除本地 sessions 投影 + 重置 activeView
  → monitorStore.clearSession / sftpStore.clearSession(只清投影,不再发停止命令)

终端渲染(xterm.js)

  • XtermView 持有 xterm Terminal + FitAddon,只负责渲染
  • 键盘输入 → writeTerminal(sessionId, data) → invoke write_terminal
  • 后端 terminal:data → xterm 写入缓冲区
  • 尺寸变化 → FitAddon → resizeTerminal → invoke resize_terminal

监控面板

  • monitor:snapshot 事件 → applySnapshot → ServerStatusPanel 直接消费
  • task:status → applyTaskStatus(未知任务缓存,latest-wins,元数据到达后补投)
  • 前端不做任何聚合,一次更新一个完整 payload(无分图请求)

SFTP

  • SftpPanel 展示 FileExplorer + TransferQueue
  • 上传/下载经 Tauri dialog 选文件 → sftp_upload / sftp_download 返回 TransferTask
  • sftp:progress(~500ms)更新进度条(终态任务忽略进度回退),sftp:task_status 驱动任务状态机;Done 时进度强制为总大小
  • 快速完成/快速失败事件先于 invoke 返回时缓存,任务元数据写入后补投,避免任务卡 Pending

测试策略(前端)

  • 单测:stores 状态流转(stores.test.ts,含事件缓存补投、latest-wins、clearSession 清理)、类型/工具(fixtures)
  • 组件测试:React Testing Library(components.test.tsx、xterm-view.test.tsx),无业务逻辑断言
  • 集成测试:homepage.integration.test.tsx —— invoke/event 契约验证
  • Mock:src/test/mocks/(tauri.ts、event.ts、dialog.ts),jsdom 环境(setup.ts)
  • E2E:Playwright + __TAURI_TEST__ 桥接(e2e/app.spec.ts),mock 后端事件驱动全闭环

注意

  • 组件内不允许业务逻辑;只消费 store 状态与事件
  • 事件监听由各 store 的 initListeners 注册(session / monitor / sftp),统一在 HomePage useEffect 的 cleanup 中销毁
  • 前端类型必须与 Rust serde camelCase 输出严格一致

Clone this wiki locally