@lokvis/ui-react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/AssetPanel.d.ts +2 -2
  3. package/dist/components/AssetPanel.d.ts.map +1 -1
  4. package/dist/components/AssetPanel.js +80 -7
  5. package/dist/components/AssetPanel.js.map +1 -1
  6. package/dist/components/Canvas.d.ts +9 -1
  7. package/dist/components/Canvas.d.ts.map +1 -1
  8. package/dist/components/Canvas.js +41 -3
  9. package/dist/components/Canvas.js.map +1 -1
  10. package/dist/components/CommandPalette.d.ts +48 -0
  11. package/dist/components/CommandPalette.d.ts.map +1 -0
  12. package/dist/components/CommandPalette.js +154 -0
  13. package/dist/components/CommandPalette.js.map +1 -0
  14. package/dist/components/CompareSlider.d.ts +25 -0
  15. package/dist/components/CompareSlider.d.ts.map +1 -0
  16. package/dist/components/CompareSlider.js +106 -0
  17. package/dist/components/CompareSlider.js.map +1 -0
  18. package/dist/components/DownloadPanel.d.ts +20 -0
  19. package/dist/components/DownloadPanel.d.ts.map +1 -0
  20. package/dist/components/DownloadPanel.js +169 -0
  21. package/dist/components/DownloadPanel.js.map +1 -0
  22. package/dist/components/ErrorBanner.d.ts +22 -0
  23. package/dist/components/ErrorBanner.d.ts.map +1 -0
  24. package/dist/components/ErrorBanner.js +47 -0
  25. package/dist/components/ErrorBanner.js.map +1 -0
  26. package/dist/components/ExifPanel.d.ts +26 -0
  27. package/dist/components/ExifPanel.d.ts.map +1 -0
  28. package/dist/components/ExifPanel.js +104 -0
  29. package/dist/components/ExifPanel.js.map +1 -0
  30. package/dist/components/GlobalDropzone.d.ts +37 -0
  31. package/dist/components/GlobalDropzone.d.ts.map +1 -0
  32. package/dist/components/GlobalDropzone.js +154 -0
  33. package/dist/components/GlobalDropzone.js.map +1 -0
  34. package/dist/components/HistoryPanel.d.ts +17 -7
  35. package/dist/components/HistoryPanel.d.ts.map +1 -1
  36. package/dist/components/HistoryPanel.js +74 -62
  37. package/dist/components/HistoryPanel.js.map +1 -1
  38. package/dist/components/Inspector.d.ts.map +1 -1
  39. package/dist/components/Inspector.js +3 -1
  40. package/dist/components/Inspector.js.map +1 -1
  41. package/dist/components/PipelineBar.d.ts.map +1 -1
  42. package/dist/components/PipelineBar.js +4 -3
  43. package/dist/components/PipelineBar.js.map +1 -1
  44. package/dist/components/ProgressBar.d.ts +18 -0
  45. package/dist/components/ProgressBar.d.ts.map +1 -0
  46. package/dist/components/ProgressBar.js +35 -0
  47. package/dist/components/ProgressBar.js.map +1 -0
  48. package/dist/components/StatusBar.d.ts +8 -2
  49. package/dist/components/StatusBar.d.ts.map +1 -1
  50. package/dist/components/StatusBar.js +59 -4
  51. package/dist/components/StatusBar.js.map +1 -1
  52. package/dist/components/ThemeToggle.d.ts +20 -0
  53. package/dist/components/ThemeToggle.d.ts.map +1 -0
  54. package/dist/components/ThemeToggle.js +60 -0
  55. package/dist/components/ThemeToggle.js.map +1 -0
  56. package/dist/components/WorkflowEditor.d.ts +24 -0
  57. package/dist/components/WorkflowEditor.d.ts.map +1 -0
  58. package/dist/components/WorkflowEditor.js +160 -0
  59. package/dist/components/WorkflowEditor.js.map +1 -0
  60. package/dist/components/WorkflowTemplates.d.ts +23 -0
  61. package/dist/components/WorkflowTemplates.d.ts.map +1 -0
  62. package/dist/components/WorkflowTemplates.js +32 -0
  63. package/dist/components/WorkflowTemplates.js.map +1 -0
  64. package/dist/components/Workspace.d.ts +48 -2
  65. package/dist/components/Workspace.d.ts.map +1 -1
  66. package/dist/components/Workspace.js +80 -5
  67. package/dist/components/Workspace.js.map +1 -1
  68. package/dist/data/workflow-templates.d.ts +42 -0
  69. package/dist/data/workflow-templates.d.ts.map +1 -0
  70. package/dist/data/workflow-templates.js +112 -0
  71. package/dist/data/workflow-templates.js.map +1 -0
  72. package/dist/hooks/useDebouncedRun.d.ts +49 -0
  73. package/dist/hooks/useDebouncedRun.d.ts.map +1 -0
  74. package/dist/hooks/useDebouncedRun.js +117 -0
  75. package/dist/hooks/useDebouncedRun.js.map +1 -0
  76. package/dist/hooks/useLokvis.js +1 -1
  77. package/dist/hooks/useMediaQuery.d.ts +27 -0
  78. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  79. package/dist/hooks/useMediaQuery.js +41 -0
  80. package/dist/hooks/useMediaQuery.js.map +1 -0
  81. package/dist/hooks/useShareLink.d.ts +58 -0
  82. package/dist/hooks/useShareLink.d.ts.map +1 -0
  83. package/dist/hooks/useShareLink.js +120 -0
  84. package/dist/hooks/useShareLink.js.map +1 -0
  85. package/dist/hooks/useTheme.d.ts +30 -0
  86. package/dist/hooks/useTheme.d.ts.map +1 -0
  87. package/dist/hooks/useTheme.js +105 -0
  88. package/dist/hooks/useTheme.js.map +1 -0
  89. package/dist/hooks/useWorkflowProgress.d.ts +28 -0
  90. package/dist/hooks/useWorkflowProgress.d.ts.map +1 -0
  91. package/dist/hooks/useWorkflowProgress.js +25 -0
  92. package/dist/hooks/useWorkflowProgress.js.map +1 -0
  93. package/dist/hooks/useWorkflows.d.ts +86 -0
  94. package/dist/hooks/useWorkflows.d.ts.map +1 -0
  95. package/dist/hooks/useWorkflows.js +247 -0
  96. package/dist/hooks/useWorkflows.js.map +1 -0
  97. package/dist/index.d.ts +26 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +26 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/store/assets-slice.d.ts.map +1 -1
  102. package/dist/store/assets-slice.js +19 -0
  103. package/dist/store/assets-slice.js.map +1 -1
  104. package/dist/store/history-slice.d.ts +18 -0
  105. package/dist/store/history-slice.d.ts.map +1 -0
  106. package/dist/store/history-slice.js +42 -0
  107. package/dist/store/history-slice.js.map +1 -0
  108. package/dist/store/index.d.ts +1 -0
  109. package/dist/store/index.d.ts.map +1 -1
  110. package/dist/store/index.js +3 -0
  111. package/dist/store/index.js.map +1 -1
  112. package/dist/store/runtime-slice.d.ts +10 -2
  113. package/dist/store/runtime-slice.d.ts.map +1 -1
  114. package/dist/store/runtime-slice.js +77 -28
  115. package/dist/store/runtime-slice.js.map +1 -1
  116. package/dist/store/types.d.ts +70 -1
  117. package/dist/store/types.d.ts.map +1 -1
  118. package/dist/store/types.js +10 -0
  119. package/dist/store/types.js.map +1 -1
  120. package/dist/store/workflow-slice.d.ts +1 -1
  121. package/dist/store/workflow-slice.d.ts.map +1 -1
  122. package/dist/store/workflow-slice.js +167 -20
  123. package/dist/store/workflow-slice.js.map +1 -1
  124. package/dist/store.d.ts +76 -0
  125. package/dist/store.d.ts.map +1 -0
  126. package/dist/store.js +217 -0
  127. package/dist/store.js.map +1 -0
  128. package/package.json +9 -6
  129. package/src/components/AssetPanel.tsx +154 -12
  130. package/src/components/Canvas.tsx +85 -7
  131. package/src/components/CommandPalette.tsx +300 -0
  132. package/src/components/CompareSlider.tsx +186 -0
  133. package/src/components/DownloadPanel.tsx +252 -0
  134. package/src/components/ErrorBanner.tsx +95 -0
  135. package/src/components/ExifPanel.tsx +187 -0
  136. package/src/components/GlobalDropzone.tsx +220 -0
  137. package/src/components/HistoryPanel.tsx +231 -104
  138. package/src/components/Inspector.tsx +7 -2
  139. package/src/components/PipelineBar.tsx +13 -12
  140. package/src/components/ProgressBar.tsx +104 -0
  141. package/src/components/StatusBar.tsx +124 -5
  142. package/src/components/ThemeToggle.tsx +122 -0
  143. package/src/components/WorkflowEditor.tsx +382 -0
  144. package/src/components/WorkflowTemplates.tsx +101 -0
  145. package/src/components/Workspace.tsx +207 -9
  146. package/src/data/workflow-templates.ts +137 -0
  147. package/src/hooks/useDebouncedRun.ts +151 -0
  148. package/src/hooks/useLokvis.ts +1 -1
  149. package/src/hooks/useMediaQuery.ts +53 -0
  150. package/src/hooks/useShareLink.ts +158 -0
  151. package/src/hooks/useTheme.ts +116 -0
  152. package/src/hooks/useWorkflowProgress.ts +41 -0
  153. package/src/hooks/useWorkflows.ts +326 -0
  154. package/src/index.ts +32 -0
  155. package/src/store/assets-slice.ts +19 -0
  156. package/src/store/history-slice.ts +65 -0
  157. package/src/store/index.ts +3 -0
  158. package/src/store/runtime-slice.ts +89 -32
  159. package/src/store/types.ts +71 -1
  160. package/src/store/workflow-slice.ts +178 -20
@@ -1,29 +1,78 @@
1
- export const createRuntimeSlice = (set, get) => ({
2
- runtime: null,
3
- initializing: false,
4
- initError: null,
5
- running: false,
6
- statusMessage: 'Idle',
7
- error: null,
8
- async init(runtime) {
9
- set({ runtime, initializing: true, initError: null });
10
- try {
11
- await get().refreshAssets();
12
- await get().refreshCapabilities();
13
- set({ initializing: false, statusMessage: 'Ready' });
14
- }
15
- catch (err) {
16
- set({
17
- initializing: false,
18
- initError: err instanceof Error ? err.message : String(err),
19
- });
20
- }
21
- },
22
- setStatus(message) {
23
- set({ statusMessage: message });
24
- },
25
- setError(error) {
26
- set({ error });
27
- },
28
- });
1
+ /**
2
+ * 历史事件订阅解除函数。
3
+ *
4
+ * 修复 review 报告:原为模块级 let,多个 store 实例(测试 / 多 Workspace)
5
+ * 共用同一变量,后创建的 store 会覆盖前者,先前的订阅无法被正确清理 → 泄漏。
6
+ * 现迁到 createRuntime slice 工厂闭包内,每个 store 实例持有独立 offFn。
7
+ */
8
+ export const createRuntimeSlice = (set, get) => {
9
+ /** 当前 store 实例的历史订阅解除函数(闭包私有,实例间隔离) */
10
+ let offHistoryChanged = null;
11
+ return {
12
+ runtime: null,
13
+ initializing: false,
14
+ initError: null,
15
+ running: false,
16
+ statusMessage: 'Idle',
17
+ error: null,
18
+ errorSeq: 0,
19
+ storageUsage: null,
20
+ async init(runtime) {
21
+ // 重入 init 时先清理上一次的历史订阅(避免重复订阅泄漏)
22
+ if (offHistoryChanged) {
23
+ offHistoryChanged();
24
+ offHistoryChanged = null;
25
+ }
26
+ set({ runtime, initializing: true, initError: null });
27
+ try {
28
+ // W7.1: 订阅 history:changed,把 runtime 历史事件桥接到 store,
29
+ // 使 HistoryPanel 无需各自订阅,store 成为历史状态单一来源。
30
+ // workspace 单工作流场景下直接采用事件携带的 workflowId/entries/cursor
31
+ // 覆盖 store,无需额外过滤。
32
+ offHistoryChanged = runtime.eventBus.on('history:changed', (e) => {
33
+ if (e.type !== 'history:changed')
34
+ return;
35
+ set({
36
+ historyEntries: e.entries,
37
+ historyCursor: e.currentIndex,
38
+ historyWorkflowId: e.workflowId,
39
+ });
40
+ });
41
+ await get().refreshAssets();
42
+ await get().refreshCapabilities();
43
+ await get().refreshStorageUsage();
44
+ set({ initializing: false, statusMessage: 'Ready' });
45
+ }
46
+ catch (err) {
47
+ set({
48
+ initializing: false,
49
+ initError: err instanceof Error ? err.message : String(err),
50
+ });
51
+ }
52
+ },
53
+ setStatus(message) {
54
+ set({ statusMessage: message });
55
+ },
56
+ setError(error) {
57
+ // errorSeq 在设置非 null error 时递增,使 ErrorBanner 能感知新错误事件
58
+ // 重新弹出(避免相同错误消息重复出现时 banner 因引用相等不触发 useEffect)
59
+ set((state) => ({
60
+ error,
61
+ errorSeq: error !== null ? state.errorSeq + 1 : state.errorSeq,
62
+ }));
63
+ },
64
+ async refreshStorageUsage() {
65
+ const { runtime } = get();
66
+ if (!runtime)
67
+ return;
68
+ try {
69
+ const usage = await runtime.getStorageUsage();
70
+ set({ storageUsage: usage });
71
+ }
72
+ catch {
73
+ // 查询失败不阻断,保持上次值或 null
74
+ }
75
+ },
76
+ };
77
+ };
29
78
  //# sourceMappingURL=runtime-slice.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-slice.js","sourceRoot":"","sources":["../../src/store/runtime-slice.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,kBAAkB,GAK3B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,IAAI;IACb,YAAY,EAAE,KAAK;IACnB,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,KAAK;IACd,aAAa,EAAE,MAAM;IACrB,KAAK,EAAE,IAAI;IAEX,KAAK,CAAC,IAAI,CAAC,OAAO;QAChB,GAAG,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;YAC5B,MAAM,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;YAClC,GAAG,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC;gBACF,YAAY,EAAE,KAAK;gBACnB,SAAS,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC5D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,SAAS,CAAC,OAAO;QACf,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,QAAQ,CAAC,KAAK;QACZ,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACjB,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"runtime-slice.js","sourceRoot":"","sources":["../../src/store/runtime-slice.ts"],"names":[],"mappings":"AA2BA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAK3B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACf,uCAAuC;IACvC,IAAI,iBAAiB,GAAwB,IAAI,CAAC;IAElD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,MAAM;QACrB,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,CAAC;QACX,YAAY,EAAE,IAAI;QAElB,KAAK,CAAC,IAAI,CAAC,OAAO;YAChB,iCAAiC;YACjC,IAAI,iBAAiB,EAAE,CAAC;gBACtB,iBAAiB,EAAE,CAAC;gBACpB,iBAAiB,GAAG,IAAI,CAAC;YAC3B,CAAC;YACD,GAAG,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,IAAI,CAAC;gBACH,oDAAoD;gBACpD,0CAA0C;gBAC1C,uDAAuD;gBACvD,mBAAmB;gBACnB,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAc,EAAE,EAAE;oBAC5E,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB;wBAAE,OAAO;oBACzC,GAAG,CAAC;wBACF,cAAc,EAAE,CAAC,CAAC,OAAO;wBACzB,aAAa,EAAE,CAAC,CAAC,YAAY;wBAC7B,iBAAiB,EAAE,CAAC,CAAC,UAAU;qBAChC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;gBACH,MAAM,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;gBAC5B,MAAM,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;gBAClC,MAAM,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;gBAClC,GAAG,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;YACvD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC;oBACF,YAAY,EAAE,KAAK;oBACnB,SAAS,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBAC5D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,SAAS,CAAC,OAAO;YACf,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QAClC,CAAC;QAED,QAAQ,CAAC,KAAK;YACZ,sDAAsD;YACtD,gDAAgD;YAChD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACd,KAAK;gBACL,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;aAC/D,CAAC,CAAC,CAAC;QACN,CAAC;QAED,KAAK,CAAC,mBAAmB;YACvB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC;gBAC9C,GAAG,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;YACxB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -4,7 +4,7 @@
4
4
  * 把原 store.ts 顶部的 WorkspaceState / WorkspaceActions 抽出,
5
5
  * 供各 slice 引用,避免循环依赖。
6
6
  */
7
- import type { Asset, Capability } from '@lokvis/schema';
7
+ import type { Asset, Capability, HistoryEntry } from '@lokvis/schema';
8
8
  import type { LokvisRuntime } from '@lokvis/runtime';
9
9
  import type { CapabilityMap, NodeStatus, WorkspaceNode } from '../types.js';
10
10
  /** 工作台完整状态 */
@@ -35,6 +35,29 @@ export interface WorkspaceState {
35
35
  statusMessage: string;
36
36
  /** 错误信息 */
37
37
  error: string | null;
38
+ /**
39
+ * 错误事件序号(单调递增)。每次 setError(非 null) 都递增,使
40
+ * ErrorBanner 能在相同错误消息重复出现时仍感知到"新错误事件"重新弹出。
41
+ * null error 不递增。0 表示初始无错误状态。
42
+ */
43
+ errorSeq: number;
44
+ /** 存储配额使用情况(W6.7):{ usage, quota } 字节,null 表示未查询 */
45
+ storageUsage: {
46
+ usage: number;
47
+ quota: number;
48
+ } | null;
49
+ /** 历史栈条目(W7.1):当前活跃工作流的执行历史 */
50
+ historyEntries: HistoryEntry[];
51
+ /** 历史栈游标(W7.1):-1 表示无已应用条目(初始);i 表示第 i 条已应用 */
52
+ historyCursor: number;
53
+ /** 当前历史所属的工作流 ID(W7.1) */
54
+ historyWorkflowId: string | null;
55
+ /** 上次工作流执行的输出 Asset ID 列表(W9.4/W9.5):用于 before/after 对比与下载管理 */
56
+ lastOutputIds: string[];
57
+ /** 当前选中的输出 Asset ID(W9.4):用于多输出场景选择 */
58
+ selectedOutputId: string | null;
59
+ /** 当前正在运行的工作流 ID(W11.6:用于 cancel) */
60
+ currentRunId: string | null;
38
61
  }
39
62
  /** 工作台操作 */
40
63
  export interface WorkspaceActions {
@@ -62,16 +85,62 @@ export interface WorkspaceActions {
62
85
  selectNode(id: string | null): void;
63
86
  /** 设置节点状态 */
64
87
  setNodeStatus(id: string, status: NodeStatus, error?: string, duration?: number): void;
88
+ /**
89
+ * 移动节点到新位置(线性链重排,W10.4)。
90
+ * @param from 源索引(0-based)
91
+ * @param to 目标索引(0-based,移动后该节点的新位置)
92
+ */
93
+ moveNode(from: number, to: number): void;
94
+ /**
95
+ * 在指定位置插入节点(W11.1)。
96
+ * @param index 目标位置(0-based;越界时自动 clamp 到 [0, length])
97
+ * @param capability 能力名
98
+ */
99
+ insertNodeAt(index: number, capability: string): void;
65
100
  /** 执行工作流 */
66
101
  run(): Promise<Asset[]>;
102
+ /** 取消当前运行(W11.6) */
103
+ cancelRun(): Promise<void>;
104
+ /**
105
+ * 应用工作流模板(W11.4):替换当前 nodes 为模板节点序列。
106
+ * @param templateNodes 模板节点(capability + 默认 params)
107
+ */
108
+ loadWorkflowTemplate(templateNodes: Array<{
109
+ capability: string;
110
+ params: Record<string, unknown>;
111
+ }>): void;
67
112
  /** 设置状态消息 */
68
113
  setStatus(message: string): void;
69
114
  /** 设置错误 */
70
115
  setError(error: string | null): void;
116
+ /** 刷新存储配额使用情况(W6.7) */
117
+ refreshStorageUsage(): Promise<void>;
118
+ /** 刷新历史栈(W7.1) */
119
+ refreshHistory(workflowId: string): Promise<void>;
120
+ /** 撤销一步(W7.1) */
121
+ undo(): Promise<void>;
122
+ /** 重做一步(W7.1) */
123
+ redo(): Promise<void>;
124
+ /** 跳转到指定历史条目(W7.1) */
125
+ jumpToHistory(index: number): Promise<void>;
71
126
  /** 清空工作流 */
72
127
  clearWorkflow(): void;
128
+ /** 选择输出资产(W9.4) */
129
+ selectOutput(id: string | null): void;
130
+ /** 清空上次输出列表(W9.4/W9.5) */
131
+ clearOutputs(): void;
73
132
  }
74
133
  export type WorkspaceStore = WorkspaceState & WorkspaceActions;
134
+ /**
135
+ * 工作流最大节点数(M1 MVP 约束)。
136
+ *
137
+ * UI 层独立定义此常量而非 import runtime 包的 MAX_WORKFLOW_STEPS,
138
+ * 因为 ui-react → runtime 的方向依赖违反五层架构约束(UI → Workflow → Runtime)。
139
+ * 两层各自维护同值常量,通过测试 + 文档约定保持同步
140
+ * (runtime 测试断言 MAX_WORKFLOW_STEPS === 5,UI 层此常量也为 5)。
141
+ * 调整上限时需同步修改两处 + 相关注释。
142
+ */
143
+ export declare const MAX_WORKFLOW_STEPS = 5;
75
144
  /** 生成节点 ID */
76
145
  export declare function genNodeId(): string;
77
146
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5E,cAAc;AACd,MAAM,WAAW,cAAc;IAC7B,iBAAiB;IACjB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,sBAAsB;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,cAAc;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,iBAAiB;IACjB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC,cAAc;IACd,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,+BAA+B;IAC/B,aAAa,EAAE,aAAa,CAAC;IAE7B,mBAAmB;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,iBAAiB;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,gBAAgB;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB,oDAAoD;IACpD,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEtD,+BAA+B;IAC/B,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC,gEAAgE;IAChE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC,qCAAqC;IACrC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,YAAY;AACZ,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,aAAa;IACb,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,aAAa;IACb,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,WAAW;IACX,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW;IACX,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,YAAY;IACZ,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,WAAW;IACX,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,cAAc;IACd,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa;IACb,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACpE,WAAW;IACX,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW;IACX,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACpC,aAAa;IACb,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvF;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtD,YAAY;IACZ,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACxB,oBAAoB;IACpB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B;;;OAGG;IACH,oBAAoB,CAClB,aAAa,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GAC5E,IAAI,CAAC;IACR,aAAa;IACb,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW;IACX,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,uBAAuB;IACvB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,kBAAkB;IAClB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,iBAAiB;IACjB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,iBAAiB;IACjB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,sBAAsB;IACtB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,YAAY;IACZ,aAAa,IAAI,IAAI,CAAC;IACtB,mBAAmB;IACnB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,0BAA0B;IAC1B,YAAY,IAAI,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAE/D;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,cAAc;AACd,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
@@ -1,3 +1,13 @@
1
+ /**
2
+ * 工作流最大节点数(M1 MVP 约束)。
3
+ *
4
+ * UI 层独立定义此常量而非 import runtime 包的 MAX_WORKFLOW_STEPS,
5
+ * 因为 ui-react → runtime 的方向依赖违反五层架构约束(UI → Workflow → Runtime)。
6
+ * 两层各自维护同值常量,通过测试 + 文档约定保持同步
7
+ * (runtime 测试断言 MAX_WORKFLOW_STEPS === 5,UI 层此常量也为 5)。
8
+ * 调整上限时需同步修改两处 + 相关注释。
9
+ */
10
+ export const MAX_WORKFLOW_STEPS = 5;
1
11
  /** 生成节点 ID */
2
12
  export function genNodeId() {
3
13
  return `node_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAoFA,cAAc;AACd,MAAM,UAAU,SAAS;IACvB,OAAO,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AA+IA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,cAAc;AACd,MAAM,UAAU,SAAS;IACvB,OAAO,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC"}
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import type { StateCreator } from 'zustand';
12
12
  import type { WorkspaceStore, WorkspaceState, WorkspaceActions } from './types.js';
13
- export interface WorkflowSlice extends Pick<WorkspaceState, 'nodes' | 'selectedNodeId'>, Pick<WorkspaceActions, 'addNode' | 'updateNodeParams' | 'removeNode' | 'selectNode' | 'setNodeStatus' | 'run' | 'clearWorkflow'> {
13
+ export interface WorkflowSlice extends Pick<WorkspaceState, 'nodes' | 'selectedNodeId' | 'lastOutputIds' | 'selectedOutputId' | 'currentRunId'>, Pick<WorkspaceActions, 'addNode' | 'updateNodeParams' | 'removeNode' | 'selectNode' | 'setNodeStatus' | 'moveNode' | 'insertNodeAt' | 'run' | 'cancelRun' | 'loadWorkflowTemplate' | 'clearWorkflow' | 'selectOutput' | 'clearOutputs'> {
14
14
  }
15
15
  export declare const createWorkflowSlice: StateCreator<WorkspaceStore, [
16
16
  ], [
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-slice.d.ts","sourceRoot":"","sources":["../../src/store/workflow-slice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnF,MAAM,WAAW,aACf,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,gBAAgB,CAAC,EACtD,IAAI,CACF,gBAAgB,EACd,SAAS,GACT,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,KAAK,GACL,eAAe,CAClB;CAAG;AAER,eAAO,MAAM,mBAAmB,EAAE,YAAY,CAC5C,cAAc,EACd;CAAE,EACF;CAAE,EACF,aAAa,CAgHb,CAAC"}
1
+ {"version":3,"file":"workflow-slice.d.ts","sourceRoot":"","sources":["../../src/store/workflow-slice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnF,MAAM,WAAW,aACf,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,gBAAgB,GAAG,eAAe,GAAG,kBAAkB,GAAG,cAAc,CAAC,EAC9G,IAAI,CACF,gBAAgB,EACd,SAAS,GACT,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,UAAU,GACV,cAAc,GACd,KAAK,GACL,WAAW,GACX,sBAAsB,GACtB,eAAe,GACf,cAAc,GACd,cAAc,CACjB;CAAG;AAER,eAAO,MAAM,mBAAmB,EAAE,YAAY,CAC5C,cAAc,EACd;CAAE,EACF;CAAE,EACF,aAAa,CAqQb,CAAC"}
@@ -1,8 +1,16 @@
1
- import { genNodeId } from './types.js';
1
+ import { genNodeId, MAX_WORKFLOW_STEPS } from './types.js';
2
2
  export const createWorkflowSlice = (set, get) => ({
3
3
  nodes: [],
4
4
  selectedNodeId: null,
5
+ lastOutputIds: [],
6
+ selectedOutputId: null,
7
+ currentRunId: null,
5
8
  addNode(capability) {
9
+ // W10.1/W10.3: 节点数上限(与 runtime MAX_WORKFLOW_STEPS 对齐,UI 层独立常量)
10
+ if (get().nodes.length >= MAX_WORKFLOW_STEPS) {
11
+ get().setError(`工作流最多 ${MAX_WORKFLOW_STEPS} 个节点(M1 MVP 限制),请先删除不需要的节点`);
12
+ return;
13
+ }
6
14
  const node = {
7
15
  id: genNodeId(),
8
16
  capability,
@@ -33,71 +41,206 @@ export const createWorkflowSlice = (set, get) => ({
33
41
  nodes: state.nodes.map((n) => n.id === id ? { ...n, status, error, duration } : n),
34
42
  }));
35
43
  },
44
+ moveNode(from, to) {
45
+ set((state) => {
46
+ if (from < 0 || from >= state.nodes.length ||
47
+ to < 0 || to >= state.nodes.length ||
48
+ from === to) {
49
+ return {};
50
+ }
51
+ const next = [...state.nodes];
52
+ const [moved] = next.splice(from, 1);
53
+ if (!moved)
54
+ return {};
55
+ next.splice(to, 0, moved);
56
+ return { nodes: next };
57
+ });
58
+ },
59
+ insertNodeAt(index, capability) {
60
+ // W11.1: 在指定位置插入节点(与节点数上限对齐)
61
+ if (get().nodes.length >= MAX_WORKFLOW_STEPS) {
62
+ get().setError(`工作流最多 ${MAX_WORKFLOW_STEPS} 个节点(M1 MVP 限制),请先删除不需要的节点`);
63
+ return;
64
+ }
65
+ if (!capability)
66
+ return;
67
+ const node = {
68
+ id: genNodeId(),
69
+ capability,
70
+ params: {},
71
+ status: 'idle',
72
+ };
73
+ set((state) => {
74
+ const next = [...state.nodes];
75
+ const at = Math.max(0, Math.min(index, next.length));
76
+ next.splice(at, 0, node);
77
+ return { nodes: next, selectedNodeId: node.id };
78
+ });
79
+ },
80
+ loadWorkflowTemplate(templateNodes) {
81
+ // W11.4: 用模板节点序列替换当前工作流,清空上次输出
82
+ const nodes = templateNodes.map(({ capability, params }) => ({
83
+ id: genNodeId(),
84
+ capability,
85
+ params,
86
+ status: 'idle',
87
+ }));
88
+ set({
89
+ nodes,
90
+ selectedNodeId: nodes[0]?.id ?? null,
91
+ lastOutputIds: [],
92
+ selectedOutputId: null,
93
+ error: null,
94
+ });
95
+ },
96
+ async cancelRun() {
97
+ // W11.6: 取消当前运行。本函数仅负责向 runtime 发起 cancel 信号;
98
+ // running / currentRunId / 节点状态的归位由 run() 的 finally 统一处理,
99
+ // 避免 cancel 与 run() 的 finally 同时写状态造成竞态
100
+ // (review 反馈:若 cancel() 抛错,旧实现仍会 set running: false 伪造
101
+ // "已停止",但底层工作流仍在运行,UI 状态与实际不符)。
102
+ //
103
+ // 时序:cancel() 成功 → runtime.run() 返回 status='cancelled'
104
+ // → run() 兜底把 pending/running 节点标 cancelled + finally 归位。
105
+ // cancel() 抛错:不伪造停止状态,仅记录错误让用户感知"取消失败,仍在运行"。
106
+ const { runtime, currentRunId } = get();
107
+ if (!runtime || !currentRunId)
108
+ return;
109
+ set({ statusMessage: 'Cancelling...' });
110
+ try {
111
+ await runtime.cancel(currentRunId);
112
+ }
113
+ catch (err) {
114
+ const message = err instanceof Error ? err.message : String(err);
115
+ console.warn('[lokvis] cancelRun failed:', message);
116
+ get().setError(`取消失败,工作流仍在运行:${message}`);
117
+ }
118
+ // 不在此设置 running / currentRunId / 节点状态;
119
+ // 等 run() 的 await runtime.run() 返回后,由 run() 统一归位。
120
+ },
36
121
  async run() {
37
- const { runtime, nodes, selectedAssetId } = get();
122
+ const { runtime, nodes, selectedAssetId, running } = get();
38
123
  if (!runtime)
39
124
  throw new Error('Runtime not initialized');
40
125
  if (nodes.length === 0)
41
126
  throw new Error('Workflow is empty');
42
127
  if (!selectedAssetId)
43
128
  throw new Error('No asset selected');
44
- set({ running: true, error: null, statusMessage: 'Running...' });
129
+ // 并发保护:正在运行时再次调用直接拒绝(避免事件订阅泄漏 + currentRunId 覆盖)
130
+ if (running) {
131
+ throw new Error('Workflow is already running');
132
+ }
133
+ set({ running: true, error: null, statusMessage: 'Running...', currentRunId: null });
45
134
  // 重置所有节点状态
46
135
  set((state) => ({
47
- nodes: state.nodes.map((n) => ({ ...n, status: 'pending', error: undefined })),
136
+ nodes: state.nodes.map((n) => ({ ...n, status: 'pending', error: undefined, duration: undefined })),
48
137
  }));
138
+ // 修复 review 报告:原实现节点状态粒度不足
139
+ // - completed: 全部节点设 success(OK,但无耗时)
140
+ // - failed: 仅把仍为 pending 的节点设 failed,但 executor 在抛错前已 emit
141
+ // node:finished 给前面成功的节点(这些 status 仍是 pending)→ 这些节点
142
+ // 也被标 failed,UI 误显示前面成功的步骤都失败了
143
+ // - cancelled: 完全未处理
144
+ //
145
+ // 修复:订阅 node:started / node:finished / node:failed 事件实时更新节点状态,
146
+ // 这样 completed/failed/cancelled 三种情况下节点状态都精确
147
+ const offStarted = runtime.eventBus.on('node:started', (e) => {
148
+ get().setNodeStatus(e.nodeId, 'running');
149
+ });
150
+ const offFinished = runtime.eventBus.on('node:finished', (e) => {
151
+ get().setNodeStatus(e.nodeId, 'success', undefined, e.duration);
152
+ });
153
+ const offNodeFailed = runtime.eventBus.on('node:failed', (e) => {
154
+ const errMsg = e.error instanceof Error ? e.error.message : String(e.error);
155
+ get().setNodeStatus(e.nodeId, 'failed', errMsg);
156
+ });
49
157
  try {
50
158
  // 构建 Workflow
51
159
  const workflow = buildLinearWorkflow(nodes);
160
+ // W11.6: 记录当前 workflowId 供 cancelRun() 使用
161
+ set({ currentRunId: workflow.id });
52
162
  const input = await runtime.getAsset(selectedAssetId);
53
163
  set({ statusMessage: 'Running workflow...' });
54
164
  const result = await runtime.run(workflow, [input]);
55
- // 更新节点状态
56
- if (result.status === 'completed') {
57
- for (const node of nodes) {
58
- get().setNodeStatus(node.id, 'success', undefined, undefined);
59
- }
60
- }
61
- else if (result.status === 'failed') {
62
- for (const node of nodes) {
63
- if (get().nodes.find((n) => n.id === node.id)?.status === 'pending') {
64
- get().setNodeStatus(node.id, 'failed', result.error);
165
+ // 兜底:取消订阅后,根据 result.status 把剩余 pending 节点归位
166
+ // - completed: finishedNodeIds 已涵盖所有节点(无需额外处理)
167
+ // - failed: 失败节点之后未执行的节点标 cancelled
168
+ // - cancelled: 失败节点之外所有 running/pending 节点标 cancelled
169
+ if (result.status !== 'completed') {
170
+ for (const node of get().nodes) {
171
+ if (node.status === 'pending' || node.status === 'running') {
172
+ get().setNodeStatus(node.id, 'cancelled');
65
173
  }
66
174
  }
67
175
  }
68
- // 加载输出资产
176
+ // 加载输出资产。失败时收集失败 id 并设置 error 让用户感知(不静默丢弃)
69
177
  const outputs = [];
178
+ const failedOutputIds = [];
70
179
  for (const id of result.outputs) {
71
180
  try {
72
181
  outputs.push(await runtime.getAsset(id));
73
182
  }
74
- catch {
75
- // skip
183
+ catch (err) {
184
+ console.warn(`[lokvis] getAsset(${id}) failed:`, err);
185
+ failedOutputIds.push(id);
76
186
  }
77
187
  }
188
+ if (failedOutputIds.length > 0) {
189
+ get().setError(`${failedOutputIds.length} 个输出资产加载失败,可能存储损坏`);
190
+ }
191
+ // W9.4/W9.5: 记录输出 Asset ID,供 before/after 对比与下载管理使用。
192
+ // 仅在 status === 'completed' 时记录,失败/取消的输出无意义。
193
+ if (result.status === 'completed' && outputs.length > 0) {
194
+ const firstOutput = outputs[0];
195
+ set({
196
+ lastOutputIds: outputs.map((o) => o.id),
197
+ selectedOutputId: firstOutput ? firstOutput.id : null,
198
+ });
199
+ }
78
200
  set({
79
201
  running: false,
80
202
  statusMessage: `Workflow ${result.status} in ${result.duration}ms`,
81
203
  });
82
204
  if (result.status === 'failed') {
83
- set({ error: result.error ?? 'Workflow failed' });
205
+ get().setError(result.error ?? 'Workflow failed');
84
206
  }
85
207
  await get().refreshAssets();
208
+ await get().refreshStorageUsage();
86
209
  return outputs;
87
210
  }
88
211
  catch (err) {
89
212
  const message = err instanceof Error ? err.message : String(err);
90
213
  set({
91
214
  running: false,
92
- error: message,
215
+ currentRunId: null,
93
216
  statusMessage: 'Failed',
94
217
  });
218
+ get().setError(message);
219
+ // 异常退出时把仍在 pending/running 的节点标 failed
220
+ for (const node of get().nodes) {
221
+ if (node.status === 'pending' || node.status === 'running') {
222
+ get().setNodeStatus(node.id, 'failed', message);
223
+ }
224
+ }
95
225
  throw err;
96
226
  }
227
+ finally {
228
+ // W11.6: 清除 currentRunId(成功/失败/取消都应清除)
229
+ set({ currentRunId: null });
230
+ offStarted();
231
+ offFinished();
232
+ offNodeFailed();
233
+ }
97
234
  },
98
235
  clearWorkflow() {
99
236
  set({ nodes: [], selectedNodeId: null });
100
237
  },
238
+ selectOutput(id) {
239
+ set({ selectedOutputId: id });
240
+ },
241
+ clearOutputs() {
242
+ set({ lastOutputIds: [], selectedOutputId: null });
243
+ },
101
244
  });
102
245
  /** 把工作台节点序列构建为线性 Workflow */
103
246
  function buildLinearWorkflow(nodes) {
@@ -112,7 +255,11 @@ function buildLinearWorkflow(nodes) {
112
255
  }));
113
256
  const edges = [];
114
257
  for (let i = 0; i < workflowNodes.length - 1; i++) {
115
- edges.push({ from: workflowNodes[i].id, to: workflowNodes[i + 1].id });
258
+ const fromNode = workflowNodes[i];
259
+ const toNode = workflowNodes[i + 1];
260
+ if (!fromNode || !toNode)
261
+ continue;
262
+ edges.push({ from: fromNode.id, to: toNode.id });
116
263
  }
117
264
  return {
118
265
  id: `wf_${Date.now().toString(36)}`,
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-slice.js","sourceRoot":"","sources":["../../src/store/workflow-slice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-slice.js","sourceRoot":"","sources":["../../src/store/workflow-slice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Workspace UI 状态管理
3
+ *
4
+ * 使用 Zustand 管理工作台状态。Runtime 永远不知道 React,
5
+ * 但 UI 层负责把 Runtime 事件桥接到 store。
6
+ */
7
+ import type { Asset, Capability } from '@lokvis/schema';
8
+ import type { LokvisRuntime } from '@lokvis/runtime';
9
+ import type { CapabilityMap, NodeStatus, WorkspaceNode } from './types.js';
10
+ /** 工作台完整状态 */
11
+ export interface WorkspaceState {
12
+ /** Runtime 实例 */
13
+ runtime: LokvisRuntime | null;
14
+ /** 是否正在初始化 Runtime */
15
+ initializing: boolean;
16
+ /** 初始化错误 */
17
+ initError: string | null;
18
+ /** 所有已导入资产 */
19
+ assets: Asset[];
20
+ /** 当前选中的资产 ID */
21
+ selectedAssetId: string | null;
22
+ /** 资产缩略图(AssetId → ObjectURL) */
23
+ thumbnails: Record<string, string>;
24
+ /** 所有已注册能力 */
25
+ capabilities: Capability[];
26
+ /** 能力映射表(name → Capability) */
27
+ capabilityMap: CapabilityMap;
28
+ /** 工作流节点序列(线性链) */
29
+ nodes: WorkspaceNode[];
30
+ /** 当前选中的节点 ID */
31
+ selectedNodeId: string | null;
32
+ /** 是否正在执行工作流 */
33
+ running: boolean;
34
+ /** 全局状态消息 */
35
+ statusMessage: string;
36
+ /** 错误信息 */
37
+ error: string | null;
38
+ }
39
+ /** 工作台操作 */
40
+ export interface WorkspaceActions {
41
+ /** 初始化 Runtime */
42
+ init(runtime: LokvisRuntime): Promise<void>;
43
+ /** 刷新资产列表 */
44
+ refreshAssets(): Promise<void>;
45
+ /** 刷新能力列表 */
46
+ refreshCapabilities(): Promise<void>;
47
+ /** 导入文件 */
48
+ importFiles(files: File[]): Promise<void>;
49
+ /** 选择资产 */
50
+ selectAsset(id: string | null): void;
51
+ /** 设置缩略图 */
52
+ setThumbnail(id: string, url: string): void;
53
+ /** 删除资产 */
54
+ removeAsset(id: string): Promise<void>;
55
+ /** 添加工作流节点 */
56
+ addNode(capability: string): void;
57
+ /** 更新节点参数 */
58
+ updateNodeParams(id: string, params: Record<string, unknown>): void;
59
+ /** 删除节点 */
60
+ removeNode(id: string): void;
61
+ /** 选择节点 */
62
+ selectNode(id: string | null): void;
63
+ /** 设置节点状态 */
64
+ setNodeStatus(id: string, status: NodeStatus, error?: string, duration?: number): void;
65
+ /** 执行工作流 */
66
+ run(): Promise<Asset[]>;
67
+ /** 设置状态消息 */
68
+ setStatus(message: string): void;
69
+ /** 设置错误 */
70
+ setError(error: string | null): void;
71
+ /** 清空工作流 */
72
+ clearWorkflow(): void;
73
+ }
74
+ export type WorkspaceStore = WorkspaceState & WorkspaceActions;
75
+ export declare const useWorkspaceStore: import("zustand").UseBoundStore<import("zustand").StoreApi<WorkspaceStore>>;
76
+ //# sourceMappingURL=store.d.ts.map