` —— 编辑抽屉里的「轮盘位置」编号输入框 |
+
+用户原话:「**这个不需要被调整就不要给出去**」—— 意思是这是内部机制,不该裸露给用户,**UI 不显示即可**。
+
+### 要求
+
+- **从 UI 移除这两个字段**(抽屉不再显示)
+- `src/js/views/prompts.js` 里对应的**读取/写入/监听**(`setV('#fApps', ...)`、`setV('#fOrder', ...)`、`payload` 里的 `app_scopes_json` / `inject_order`、`['fName','fContent','fTags','fApps','fOrder']` 的 dirty 监听数组)**全部清理干净**
+- 同时清理 i18n 里不再使用的 key(`f.apps`、`f.appsPh`、`f.order` 等,中英双语都要删)
+- **不要动后端/数据库/schema**:`app_scopes_json` 和 `inject_order` 字段**保留**(后端与其他流程可能仍依赖,尤其 `set_pin_order` 写的就是 pin order)。只是**前端不再让用户直接编辑它们**
+- 注意:`src/js/store.js:92` 有 `inject_order` 的解析(`parseInt(p.inject_order, 10)`),那是内部排序逻辑,**保留**
+
+---
+
+# 硬约束
+
+- 无 cargo,本机不编译。**CI 必须全绿**(cargo check/clippy/test + frontend static checks + playwright)
+- Playwright:**新增拖拽排序的真实验证用例**(pointer 事件驱动,不是 `fill()` 那种假交互)。断言:按住→移动→松手后 DOM 顺序变化**且** `set_pin_order` 被调用
+- 既有测试不得回归
+- i18n 中英双语同步,删掉的 key 两侧一致
+- 一个 commit `fix(ui): real pointer-based manual sort + hide internal fields from drawer`,push,PR `--base master`,**不合并**
+- 遵守 LOOM 流程
+
+---
+
+## 最终交付
+
+```
+## 拖拽为什么拖不动
+(先给逐条证据链:mousedown/draggable 时序问题、dataset attribute 名核实结果、以及任何你发现的其他断点。**先证明你找到了真根因再动手**)
+
+## 实现方案
+(为什么选 pointer 事件而非修 HTML5 原生拖拽;插入位置指示怎么做的;滚动冲突怎么解;非 manual 模式的处理策略及理由)
+
+## 删除字段
+(删了哪些 UI 元素 + 清理了哪些 JS/i18n;确认后端字段保留未被破坏)
+
+## 测试
+(CI 结果 + 新拖拽用例的断言细节 + 回归结果)
+
+## 真机验证清单
+(用户在 Windows 上按什么顺序试,每步预期)
+
+## 未编译验证清单
+```
+
+```json
+COMPLETION_NOTIFY
+source: assistant
+task: promptkey-manual-sort-fix
+deliverables:
+- root cause of "drag does not move" proven with evidence
+- pointer-event based manual sort implemented and visually verified
+- insertion indicator + scroll coexistence + click-suppression handled
+- app scope & inject order fields removed from drawer UI, JS, and i18n
+- backend fields preserved
+- CI green incl. a real pointer-driven drag test
+- branch fix/wheel-manual-drag-and-hide-fields + PR against master (not merged)
+status: success
+errors: none
+```
diff --git a/.loom/state.json b/.loom/state.json
index fe794e8..599279e 100644
--- a/.loom/state.json
+++ b/.loom/state.json
@@ -4,7 +4,7 @@
"name": "promptkey",
"status": "complete",
"created_at": "2026-10-06T08:16:56.246Z",
- "updated_at": "2026-10-07T04:30:31.807Z"
+ "updated_at": "2026-10-07T06:08:09.960Z"
},
"understanding": {
"confirmed": [
diff --git a/.loom/tasks.json b/.loom/tasks.json
index 9bf97c9..aa4929b 100644
--- a/.loom/tasks.json
+++ b/.loom/tasks.json
@@ -940,6 +940,100 @@
"created_at": "2026-10-07T04:17:40.992Z",
"updated_at": "2026-10-07T04:30:31.807Z",
"completed_at": "2026-10-07T04:30:31.807Z"
+ },
+ {
+ "id": "TASK-010",
+ "title": "Fix wheel mirror manual drag (pointer-based) + hide app-scope/order fields from drawer",
+ "outcome": "Wheel mirror list in the prompts view supports real pointer-driven reorder (mouse+touch) with insertion indicator, auto-switching to manual sort; the edit drawer no longer exposes app_scopes_json / inject_order inputs while backend fields stay intact.",
+ "acceptance": [
+ {
+ "criterion": "Dragging a wheel-mirror row by pointer reorders the DOM and calls set_pin_order with the new id sequence; verified by a Playwright test using real mouse.down/move/up events",
+ "verify_by": "python tests/e2e/wheel_sort_drag_e2e.py asserts DOM order change + set_pin_order payload",
+ "evidence": "tests/e2e/wheel_sort_drag_e2e.py: mouse.down on Delta row, move to above Beta, mouse.up -> __CALLS__ records set_pin_order ids=[1,4,2,3], DOM shows Alpha,Delta,Beta,Gamma. Mid-drag assertions verify .dragging lift + .wm-insert slot marker."
+ },
+ {
+ "criterion": "Drag works when wheelSort starts in 'auto' (default): first successful drag switches mode to manual, persists pk-wheel-sort, and the dropped order survives reload",
+ "verify_by": "e2e asserts wheelSortBtn label flips to manual + set_pin_order called once with final order",
+ "evidence": "e2e asserts localStorage pk-wheel-sort === 'manual' and sortBtn label 手动 after the drop; DOM order Alpha,Delta,Beta,Gamma is read back after loadPrompts re-render (mock writes inject_order per set_pin_order)."
+ },
+ {
+ "criterion": "Edit drawer shows no '应用范围'/'轮盘位置' inputs; saving an existing prompt preserves its app_scopes_json and inject_order instead of wiping them",
+ "verify_by": "e2e opens drawer: #fApps/#fOrder absent; update_prompt payload echoes stored values",
+ "evidence": "e2e: #fApps/#fOrder count 0, drawer text lacks both labels; update_prompt payload echoes app_scopes_json='[\"Code.exe\"]' and inject_order='1'."
+ },
+ {
+ "criterion": "i18n keys f.apps / f.order removed from both zh-CN.js and en-US.js; no dangling references; node --check clean on all JS",
+ "verify_by": "grep -rn 'f\\.apps\\|f\\.order' src/ returns nothing; find src -name '*.js' | node --check loop",
+ "evidence": "grep -rn 'f\\.apps\\|f\\.order\\|fApps\\|fOrder' src/ -> only a code comment remains; node --check loop clean."
+ }
+ ],
+ "done_when": [],
+ "boundaries": [
+ "Does not change backend/schema: prompts.app_scopes_json and prompts.inject_order columns, set_pin_order IPC, and store.js pinOrder parsing stay untouched",
+ "Does not change wheel.html/wheel.js runtime wheel ordering behavior"
+ ],
+ "depends_on": [],
+ "reads": [
+ ".loom/design/task-brief-manual-sort-and-hide-fields.md",
+ "src/js/views/prompts.js",
+ "src/js/store.js",
+ "src/index.html",
+ "src/styles.css",
+ "src/js/i18n/zh-CN.js",
+ "src/js/i18n/en-US.js",
+ "tests/e2e/hotkey_status_e2e.py"
+ ],
+ "touches": [
+ "src/js/views/prompts.js",
+ "src/index.html",
+ "src/styles.css",
+ "src/js/i18n/zh-CN.js",
+ "src/js/i18n/en-US.js",
+ "tests/e2e/wheel_sort_drag_e2e.py",
+ ".github/workflows/ci.yml"
+ ],
+ "implements": ".loom/design/task-brief-manual-sort-and-hide-fields.md",
+ "design_exemption": "",
+ "capability_hooks": [],
+ "capability_exemption": "Interaction fix within existing design-system tokens; no new professional field is engaged",
+ "integrity_version": 1,
+ "covers": [],
+ "status": "done",
+ "progress": {
+ "completed": [],
+ "current": "complete",
+ "next": ""
+ },
+ "evidence": [
+ "Pointer-based manual sort replaces HTML5 DnD in bindMirrorDrag (prompts.js): mouse drags from anywhere on a row after 5px vertical threshold; touch drags only from the grip (touch-action:none) so row presses still scroll .leftcol. Dragged row lifts via position:fixed + translate3d; dashed .wm-insert slot marks the landing position through plain flex reflow. Drop commits via set_pin_order; commits from auto mode flip wheelSort to manual only after the write succeeds.",
+ "Drawer no longer renders 应用范围/轮盘位置 inputs; update_prompt now passes app_scopes_json/inject_order through unchanged so a save cannot wipe set_pin_order output or stored scopes. i18n keys f.apps/f.order removed in zh-CN + en-US; wheel.sortAutoSwitch added on both sides.",
+ "Local e2e: wheel_sort_drag_e2e.py 17/17, hotkey_status 10/10, hotkey_recorder 22/22, no_tauri 13/13; node --check clean on all src js; check_capabilities OK. Visual verification screenshots mid-drag/after-drop/drawer taken via Playwright.",
+ {
+ "type": "acceptance_results",
+ "results": [
+ {
+ "criterion": "Dragging a wheel-mirror row by pointer reorders the DOM and calls set_pin_order with the new id sequence; verified by a Playwright test using real mouse.down/move/up events",
+ "evidence": "tests/e2e/wheel_sort_drag_e2e.py: mouse.down on Delta row, move to above Beta, mouse.up -> __CALLS__ records set_pin_order ids=[1,4,2,3], DOM shows Alpha,Delta,Beta,Gamma. Mid-drag assertions verify .dragging lift + .wm-insert slot marker."
+ },
+ {
+ "criterion": "Drag works when wheelSort starts in 'auto' (default): first successful drag switches mode to manual, persists pk-wheel-sort, and the dropped order survives reload",
+ "evidence": "e2e asserts localStorage pk-wheel-sort === 'manual' and sortBtn label 手动 after the drop; DOM order Alpha,Delta,Beta,Gamma is read back after loadPrompts re-render (mock writes inject_order per set_pin_order)."
+ },
+ {
+ "criterion": "Edit drawer shows no '应用范围'/'轮盘位置' inputs; saving an existing prompt preserves its app_scopes_json and inject_order instead of wiping them",
+ "evidence": "e2e: #fApps/#fOrder count 0, drawer text lacks both labels; update_prompt payload echoes app_scopes_json='[\"Code.exe\"]' and inject_order='1'."
+ },
+ {
+ "criterion": "i18n keys f.apps / f.order removed from both zh-CN.js and en-US.js; no dangling references; node --check clean on all JS",
+ "evidence": "grep -rn 'f\\.apps\\|f\\.order\\|fApps\\|fOrder' src/ -> only a code comment remains; node --check loop clean."
+ }
+ ],
+ "at": "2026-10-07T06:08:09.959Z"
+ }
+ ],
+ "created_at": "2026-10-07T05:55:04.721Z",
+ "updated_at": "2026-10-07T06:08:09.959Z",
+ "completed_at": "2026-10-07T06:08:09.959Z"
}
]
}
diff --git a/src/index.html b/src/index.html
index 2c90c1c..4974b1b 100644
--- a/src/index.html
+++ b/src/index.html
@@ -199,8 +199,6 @@