feat: migrate workbench to React
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
{"file":".trellis/spec/frontend/index.md","reason":"Review frontend quality, component, hook, and state conventions."}
|
||||
{"file":".trellis/spec/guides/cross-layer-thinking-guide.md","reason":"Verify API-to-React-to-OpenLayers data flow and cleanup boundaries."}
|
||||
{"file":".trellis/spec/guides/code-reuse-thinking-guide.md","reason":"Check that migration does not leave duplicate DOM and React implementations or duplicate map logic."}
|
||||
32
.trellis/tasks/08-26-react-workbench-migration/design.md
Normal file
32
.trellis/tasks/08-26-react-workbench-migration/design.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Technical Design
|
||||
|
||||
## Frontend Boundary
|
||||
|
||||
Create a Vite app under `workbench/client/` (or a clearly scoped `workbench/frontend/` directory) with React 19 and TypeScript. Keep Node/server code CommonJS and keep `/api/*` payloads unchanged. The production build should emit a deterministic directory consumed by `workbench/server.js`; development mode may use a Vite proxy to the workbench API.
|
||||
|
||||
## OpenLayers Migration Strategy
|
||||
|
||||
- Import OpenLayers modules directly from the installed `ol` package in TypeScript; remove the runtime `/vendor/ol/*.js` import map from the React build.
|
||||
- Keep one `Map` instance per mounted map component. A `useOpenLayersMap` hook creates it once after the container ref is available, registers interactions/listeners, and calls `map.setTarget(undefined)` plus listener cleanup on unmount.
|
||||
- Keep the layer registry in an adapter module/hook (`map/layers.ts`), created once with stable `VectorSource` and `VectorLayer` instances. React state changes update sources, styles, visibility, and selection overlays through explicit adapter methods rather than recreating the map.
|
||||
- Use typed GeoJSON/read helpers at the API boundary; preserve EPSG:4326 to EPSG:3857 conversion and current fit/selection behavior.
|
||||
- OpenLayers event callbacks publish typed selection/pointer events to React state. React panels render from that state and issue API mutations; they do not query or mutate DOM nodes owned by OpenLayers.
|
||||
- Import `ol/ol.css` from the Vite entry and keep map container dimensions in application CSS.
|
||||
|
||||
## UI and State
|
||||
|
||||
- Use shadcn/ui primitives for buttons, inputs, checkboxes, select, tabs/segmented filters, dialogs, sheets, alerts, and toast feedback. Keep the existing dense three-column workbench layout.
|
||||
- Define API/state types in `src/types/` based on the actual `/api/state` and mutation payloads. Use a small typed client in `src/lib/api.ts`.
|
||||
- Use React hooks/context for session and editor state. Keep transient map selection and staged overrides separate from server state; avoid introducing a large state library unless the migration proves one necessary.
|
||||
- Split components by existing workflow boundaries: `ImportScreen`, `WorkbenchShell`, `LayerPanel`, `DiagnosticsPanel`, `MapCanvas`, `RoadInspector`, `SignalEditor`, and shared `ui/` primitives.
|
||||
|
||||
## Static Hosting
|
||||
|
||||
- Update `workbench/server.js` to serve Vite `index.html` and hashed assets in production, with a safe fallback for the SPA route while retaining `/vendor/*` only for compatibility during transition.
|
||||
- Keep `npm run road:workbench` self-contained for production assets. Add Vite dev/proxy scripts without requiring the Node workbench server to become an ESM application.
|
||||
|
||||
## Risks and Compatibility
|
||||
|
||||
- OpenLayers owns imperative objects and must not be recreated on every React render; the hook/adapter boundary is mandatory.
|
||||
- Existing style functions close over selected road state. Convert them to adapter-managed mutable selection refs or call `layer.changed()` after selection updates.
|
||||
- The first migration should preserve behavior and layout; visual redesign is explicitly deferred.
|
||||
@@ -0,0 +1,4 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
{"file":".trellis/spec/frontend/index.md","reason":"Load the project frontend conventions before introducing Vite, React, TypeScript, and shadcn/ui."}
|
||||
{"file":".trellis/spec/guides/cross-layer-thinking-guide.md","reason":"The migration changes the browser build, static hosting, API client, and imperative map lifecycle together."}
|
||||
{"file":".trellis/spec/guides/code-reuse-thinking-guide.md","reason":"Reuse current OpenLayers styles, API payloads, and editor behavior instead of duplicating domain logic."}
|
||||
20
.trellis/tasks/08-26-react-workbench-migration/implement.md
Normal file
20
.trellis/tasks/08-26-react-workbench-migration/implement.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Implementation Plan
|
||||
|
||||
1. Add Vite, React 19, TypeScript, Tailwind/shadcn/ui dependencies and scripts; establish `tsconfig`, Vite config, aliases, CSS variables, and production output location.
|
||||
2. Define typed API/state contracts and a fetch client from the existing `/api/*` payloads; add focused serialization tests.
|
||||
3. Build the OpenLayers adapter and `useOpenLayersMap` hook. Port the current layer registry, styles, source updates, selection interaction, fit behavior, and cleanup tests before moving inspector UI.
|
||||
4. Port the import-first flow and shell/layout to React, then migrate layer controls, summaries, diagnostics, road inspector, connection editor, centerline editor, signal editor, and save/compile actions.
|
||||
5. Replace the server's legacy `/app.js`/`/app.css` production serving with Vite build output while retaining a compatibility path only where needed for rollback.
|
||||
6. Remove the old DOM-driven entry after parity is demonstrated; keep OpenLayers vendor serving only if legacy mode still needs it.
|
||||
7. Add browser/component smoke coverage for no-session import, active-session map render, a road selection/edit, and compile/export request wiring.
|
||||
8. Run `npm run build`, frontend tests, existing `npm test`, and a manual workbench smoke check at desktop/mobile widths; fix parity regressions.
|
||||
|
||||
Validation commands:
|
||||
|
||||
- `npm run build`
|
||||
- `npm run format:check`
|
||||
- frontend test command added by this task
|
||||
- `npm test`
|
||||
- `node --check workbench/server.js`
|
||||
|
||||
Rollback point: retain the legacy client in a separate compatibility path until the React build serves the same API workflow and OpenLayers interaction checks pass.
|
||||
43
.trellis/tasks/08-26-react-workbench-migration/prd.md
Normal file
43
.trellis/tasks/08-26-react-workbench-migration/prd.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# 迁移工作台到 React 前端
|
||||
|
||||
## Goal
|
||||
|
||||
将现有原生 HTML/CSS/JS 工作台迁移到 Vite、React 19、TypeScript 和 shadcn/ui,获得可维护、可扩展且具备类型安全的成熟前端工程结构,同时保留当前 OSM 导入、地图查看、道路参数编辑、诊断、信号灯编辑、重新编译和道路包导出能力。
|
||||
|
||||
## Confirmed Facts
|
||||
|
||||
- 当前前端位于 `workbench/client/index.html`、`workbench/client/app.js` 和 `workbench/client/app.css`。
|
||||
- `workbench/client/app.js` 使用 OpenLayers 浏览器模块,并动态创建部分控制面板和图层开关。
|
||||
- `workbench/server.js` 提供静态资源和 `/api/state`、`/api/import`、`/api/overrides`、`/api/traffic-signals`、`/api/compile`、`/api/export.zip` 等接口。
|
||||
- 当前项目是 CommonJS Node 包,尚无前端构建脚本、TypeScript 配置、Vite 配置或 shadcn/ui 依赖。
|
||||
- 地图核心继续使用已有的 OpenLayers 10;本任务是前端工程迁移,不替换地图引擎。
|
||||
|
||||
## Requirements
|
||||
|
||||
1. 建立独立、可构建的 Vite React 19 TypeScript 前端入口并迁移工作台代码。
|
||||
2. 配置 shadcn/ui 所需的 CSS 变量、组件基础设施和图标/交互约定,优先使用其组件承载按钮、表单、面板、弹层和提示。
|
||||
3. 将页面状态、API 调用、地图图层/选择逻辑和编辑表单拆分为 React 组件、hooks、类型和服务模块,避免主要业务 UI 继续依赖全局 `querySelector` 和动态 `innerHTML`。
|
||||
4. 保留现有服务端 API 契约和 OSM 导入工作流;必要时只调整静态资源托管和开发/生产构建入口。
|
||||
5. 保留 OpenLayers 地图的现有图层、样式、选择和交互行为,并确保状态变化正确驱动地图与检查器更新。
|
||||
6. 提供开发模式和生产构建命令;Node 工作台服务能提供构建后的前端资源。
|
||||
7. 为核心 API 客户端、状态转换和至少一个关键交互增加 TypeScript/自动化验证。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- `npm run build` 能在干净依赖安装后生成前端生产构建产物。
|
||||
- `npm run dev`(或等价命令)能启动 Vite 开发服务器并加载工作台页面。
|
||||
- `npm run road:workbench` 使用构建产物时仍能打开工作台;无活动工作区时显示 OSM 导入界面,有活动工作区时显示地图和编辑器。
|
||||
- OSM 导入、图层开关、道路选择/参数暂存、诊断筛选、交通信号编辑、保存、重新编译和 ZIP 导出均保持可用。
|
||||
- 页面不再通过原生 `querySelector`/`innerHTML` 组织主要业务 UI;业务状态和 API 数据具有明确 TypeScript 类型。
|
||||
- 现有 Node 编译器测试继续通过;新增前端构建和关键工作流验证通过。
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- 不修改道路编译算法、OSM 解析规则、GeoJSON 数据结构或现有 HTTP API 语义。
|
||||
- 不更换 OpenLayers 为其他地图引擎。
|
||||
- 不引入认证、多用户协作、服务端渲染或远程部署平台。
|
||||
- 不在本任务内重新定义道路参数模型或增加新的业务功能。
|
||||
|
||||
## Open Product Decision
|
||||
|
||||
迁移是否同时允许明显的视觉和信息架构重设计?推荐第一阶段以“功能和工作流等价 + shadcn/ui 统一视觉”为目标,保留现有三栏地图工作台布局;这样可以把风险集中在工程迁移,后续再单独做 UX 重构。若本任务同时重做布局,交付周期和回归范围会显著增加。
|
||||
26
.trellis/tasks/08-26-react-workbench-migration/task.json
Normal file
26
.trellis/tasks/08-26-react-workbench-migration/task.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "react-workbench-migration",
|
||||
"name": "react-workbench-migration",
|
||||
"title": "迁移工作台到 React 前端",
|
||||
"description": "将现有原生 HTML/CSS/JS 工作台迁移到 Vite、React 19、TypeScript 和 shadcn/ui,保持现有工作流能力",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-26",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user