@lokvis/ui-react 0.5.0 → 0.5.1

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.
@@ -3,14 +3,13 @@
3
3
  *
4
4
  * 展示上次工作流执行的输出资产,提供:
5
5
  * - 单项下载(从 runtime.exportAsset 取 blob,触发浏览器下载)
6
- * - 全部下载(逐项触发,BATCH_DOWNLOAD_DELAY_MS 间隔,避免浏览器拦截;长期方案见该常量注释)
6
+ * - 全部下载(JSZip 打包为单个 ZIP,一次用户手势完成)
7
7
  * - 清空输出列表
8
8
  *
9
9
  * 与 apps/playground 的 DownloadManager(独立工具页)不同:本组件是 Workspace
10
10
  * 内嵌的轻量面板,数据来自 store.lastOutputIds(由 workflow-slice.run 写入)。
11
11
  *
12
12
  * 下载命名:`lokvis-output-{assetId前8位}.{ext}`,简洁且避免覆盖。
13
- * 不引入 JSZip(需新增依赖),用浏览器原生 downloadBlob 实现。
14
13
  */
15
14
  import * as React from 'react';
16
15
  export interface DownloadPanelProps {
@@ -1 +1 @@
1
- {"version":3,"file":"DownloadPanel.d.ts","sourceRoot":"","sources":["../../src/components/DownloadPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAqCD,wBAAgB,aAAa,CAAC,EAAE,SAAc,EAAE,EAAE,kBAAkB,4BA0LnE"}
1
+ {"version":3,"file":"DownloadPanel.d.ts","sourceRoot":"","sources":["../../src/components/DownloadPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAqBD,wBAAgB,aAAa,CAAC,EAAE,SAAc,EAAE,EAAE,kBAAkB,4BA8LnE"}
@@ -4,33 +4,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  *
5
5
  * 展示上次工作流执行的输出资产,提供:
6
6
  * - 单项下载(从 runtime.exportAsset 取 blob,触发浏览器下载)
7
- * - 全部下载(逐项触发,BATCH_DOWNLOAD_DELAY_MS 间隔,避免浏览器拦截;长期方案见该常量注释)
7
+ * - 全部下载(JSZip 打包为单个 ZIP,一次用户手势完成)
8
8
  * - 清空输出列表
9
9
  *
10
10
  * 与 apps/playground 的 DownloadManager(独立工具页)不同:本组件是 Workspace
11
11
  * 内嵌的轻量面板,数据来自 store.lastOutputIds(由 workflow-slice.run 写入)。
12
12
  *
13
13
  * 下载命名:`lokvis-output-{assetId前8位}.{ext}`,简洁且避免覆盖。
14
- * 不引入 JSZip(需新增依赖),用浏览器原生 downloadBlob 实现。
15
14
  */
16
15
  import * as React from 'react';
16
+ import JSZip from 'jszip';
17
17
  import { Icon } from '@lokvis/ui-core';
18
18
  import { useWorkspaceStore } from '../store/index.js';
19
19
  import { formatBytes } from '../utils.js';
20
- /**
21
- * 批量下载时每项之间的延迟毫秒数。
22
- *
23
- * 短期方案:浏览器(尤其 Chrome)会拦截同一 tick 内触发的多个 programmatic
24
- * `<a download>` 点击,把第一个之后的视为"非用户手势"弹窗拦截。两次下载之间
25
- * 插入小延迟可绕过该启发式判定。该值是经验值,不是规范要求 —— 不同浏览器
26
- * 版本行为可能变化。
27
- *
28
- * 长期方案:用 JSZip 将多个输出打包成单个 ZIP 下载(只需一次用户手势)。
29
- * 本组件暂未引入 JSZip 依赖(见文件头注释),待 M2 引入 archive capability 后
30
- * 一并迁移,届时可移除此常量与 sleep 调用。
31
- */
32
- const BATCH_DOWNLOAD_DELAY_MS = 200;
33
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
34
20
  /** 从扩展名或 mime 推断下载扩展名 */
35
21
  function extFromMime(mime) {
36
22
  const sub = mime.split('/')[1] ?? 'bin';
@@ -103,42 +89,47 @@ export function DownloadPanel({ className = '' }) {
103
89
  async function handleDownloadAll() {
104
90
  if (!runtime || batchDownloading)
105
91
  return;
92
+ // 单文件时直接下载,无需 ZIP 开销
93
+ if (outputAssets.length === 1) {
94
+ void handleDownloadOne(outputAssets[0].id);
95
+ return;
96
+ }
106
97
  setBatchDownloading(true);
107
98
  setError(null);
108
- setStatus('Downloading outputs...');
109
- // 用本地 Set 跟踪本次循环已下载 id,避免 downloaded 闭包快照与 state 不同步
110
- // (review 反馈:循环中 setDownloaded 更新 state 但闭包 downloaded 不变,
111
- // 虽有 batchDownloading guard 阻止并发,逻辑上仍应读取最新已下载集合)
112
- const localDownloaded = new Set(downloaded);
99
+ setStatus('Packaging outputs...');
113
100
  try {
101
+ const zip = new JSZip();
114
102
  for (const asset of outputAssets) {
115
- // 卸载后立即停止循环(避免对已卸载组件 setState)
116
103
  if (!mountedRef.current)
117
104
  return;
118
- if (localDownloaded.has(asset.id))
119
- continue;
120
105
  try {
121
106
  const blob = await runtime.exportAsset(asset.id);
122
107
  const ext = extFromMime(asset.metadata.mimeType);
123
108
  const filename = `lokvis-output-${asset.id.slice(0, 8)}.${ext}`;
124
- downloadBlob(blob, filename);
125
- localDownloaded.add(asset.id);
126
- if (mountedRef.current) {
127
- setDownloaded((prev) => new Set(prev).add(asset.id));
128
- }
129
- await sleep(BATCH_DOWNLOAD_DELAY_MS);
109
+ zip.file(filename, blob);
130
110
  }
131
111
  catch (err) {
112
+ // 单项失败不阻断打包,记录错误继续
132
113
  if (mountedRef.current) {
133
114
  setError(err instanceof Error ? err.message : String(err));
134
115
  }
135
- // 单项失败不阻断后续
136
116
  }
137
117
  }
118
+ if (!mountedRef.current)
119
+ return;
120
+ const zipBlob = await zip.generateAsync({ type: 'blob' });
121
+ downloadBlob(zipBlob, 'lokvis-outputs.zip');
122
+ // 标记全部已下载
138
123
  if (mountedRef.current) {
124
+ setDownloaded(new Set(outputAssets.map((a) => a.id)));
139
125
  setStatus('Downloads complete');
140
126
  }
141
127
  }
128
+ catch (err) {
129
+ if (mountedRef.current) {
130
+ setError(err instanceof Error ? err.message : String(err));
131
+ }
132
+ }
142
133
  finally {
143
134
  if (mountedRef.current) {
144
135
  setBatchDownloading(false);
@@ -1 +1 @@
1
- {"version":3,"file":"DownloadPanel.js","sourceRoot":"","sources":["../../src/components/DownloadPanel.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM1C;;;;;;;;;;;GAWG;AACH,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAEpC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAEnF,yBAAyB;AACzB,SAAS,WAAW,CAAC,IAAY;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IACxC,yCAAyC;IACzC,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AACjC,CAAC;AAED,cAAc;AACd,SAAS,YAAY,CAAC,IAAU,EAAE,QAAgB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC;IACb,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC,CAAC,KAAK,EAAE,CAAC;IACV,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC7B,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAE,SAAS,GAAG,EAAE,EAAsB;IACnE,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAExD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IAC3E,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAE9D,iCAAiC;IACjC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACrB,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,OAAO,GAAG,EAAE;YACZ,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC3B,CAAC,CAAC;IACF,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,8CAA8C;IAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACxC,OAAO,aAAa;aACnB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;aAC5C,MAAM,CAAC,CAAC,CAAC,EAA8B,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAC5D,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IAE5B,8BAA8B;IAC9B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACrB,aAAa,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAEpB,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5E,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAChF,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,KAAK,YAAY,CAAC,MAAM,CAAC;IAEzF,KAAK,UAAU,iBAAiB,CAAC,EAAU;QAC3C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC;YACL,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAG,iBAAiB,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;YAChE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC7B,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACzB,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC;QACD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACf,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACzB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3D,CAAC;QACD,CAAC;IACD,CAAC;IAED,KAAK,UAAU,iBAAiB;QAChC,IAAI,CAAC,OAAO,IAAI,gBAAgB;YAAE,OAAO;QACzC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC1B,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,SAAS,CAAC,wBAAwB,CAAC,CAAC;QACpC,qDAAqD;QACrD,2DAA2D;QAC3D,iDAAiD;QACjD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC;YACL,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBACnC,+BAA+B;gBAC/B,IAAI,CAAC,UAAU,CAAC,OAAO;oBAAE,OAAO;gBAChC,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAAE,SAAS;gBAC5C,IAAI,CAAC;oBACL,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBACjD,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACjD,MAAM,QAAQ,GAAG,iBAAiB,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;oBAChE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;oBAC7B,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBAC9B,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;wBACzB,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;oBACrD,CAAC;oBACD,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;gBACrC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACf,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;wBACzB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC3D,CAAC;oBACD,YAAY;gBACZ,CAAC;YACD,CAAC;YACD,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACzB,SAAS,CAAC,oBAAoB,CAAC,CAAC;YAChC,CAAC;QACD,CAAC;gBAAS,CAAC;YACX,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACzB,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;QACD,CAAC;IACD,CAAC;IAED,SAAS,WAAW;QACpB,YAAY,EAAE,CAAC;QACf,aAAa,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,OAAO,CACP,eACA,SAAS,EAAE,mFAAmF,SAAS,EAAE,gBAC9F,eAAe,aAE1B,eAAK,SAAS,EAAC,4FAA4F,aAC3G,eAAM,SAAS,EAAC,mFAAmF,wBAE5F,EACP,gBAAM,SAAS,EAAC,yDAAyD,aACxE,eAAe,OAAG,YAAY,CAAC,MAAM,cAAK,WAAW,CAAC,SAAS,CAAC,IAC1D,IACD,EAEN,eAAK,SAAS,EAAC,mDAAmD,aACjE,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;wBAC5B,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;wBAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;wBACvC,OAAO,CACP,eAEA,SAAS,EAAC,kFAAkF,aAE5F,eAAK,SAAS,EAAC,yBAAyB,aACxC,eAAM,SAAS,EAAC,2GAA2G,YAC1H,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,GAC7B,EACN,IAAI,IAAI,CACT,gBAAM,SAAS,EAAC,wDAAwD,aACvE,IAAI,CAAC,KAAK,YAAG,IAAI,CAAC,MAAM,IAClB,CACN,EACD,eAAM,SAAS,EAAC,yDAAyD,YACxE,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAC1B,IACD,EACN,cAAK,SAAS,EAAC,yBAAyB,YACxC,kBACA,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,EAC/C,SAAS,EAAE,yFACX,YAAY;4CACZ,CAAC,CAAC,4DAA4D;4CAC9D,CAAC,CAAC,gGACF,EAAE,aAEF,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,YAC9B,eAAM,CAAC,EAAC,gEAAgE,GAAG,GACpE,EACN,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,IAChC,GACH,KA/BD,KAAK,CAAC,EAAE,CAgCP,CACL,CAAC;oBACF,CAAC,CAAC,EAEF,eAAK,SAAS,EAAC,kCAAkC,aACjD,iBACA,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,iBAAiB,EAAE,EACvC,QAAQ,EAAE,gBAAgB,IAAI,aAAa,EAC3C,SAAS,EAAC,kMAAkM,YAE3M,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,GAC5C,EACT,iBACA,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,2IAA2I,sBAG5I,IACH,IACA,EAEL,KAAK,IAAI,CACV,YAAG,SAAS,EAAC,mDAAmD,EAAC,IAAI,EAAC,OAAO,YAC5E,KAAK,GACF,CACH,IACK,CACL,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"DownloadPanel.js","sourceRoot":"","sources":["../../src/components/DownloadPanel.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokvis/ui-react",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Lokvis Workspace UI - React components for Image/Video/PDF Workspace",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,13 +30,14 @@
30
30
  "react-dom": "^19.0.0"
31
31
  },
32
32
  "dependencies": {
33
+ "jszip": "^3.10.0",
33
34
  "zustand": "^5.0.0",
34
- "@lokvis/schema": "0.5.0",
35
- "@lokvis/runtime": "0.5.0",
36
- "@lokvis/sdk": "0.5.0",
37
- "@lokvis/ui-core": "0.5.0",
38
- "@lokvis/capability": "0.5.0",
39
- "@lokvis/workflow": "0.5.0"
35
+ "@lokvis/schema": "0.5.1",
36
+ "@lokvis/runtime": "0.5.1",
37
+ "@lokvis/sdk": "0.5.1",
38
+ "@lokvis/ui-core": "0.5.1",
39
+ "@lokvis/capability": "0.5.1",
40
+ "@lokvis/workflow": "0.5.1"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/react": "^19.0.0",
@@ -3,17 +3,17 @@
3
3
  *
4
4
  * 展示上次工作流执行的输出资产,提供:
5
5
  * - 单项下载(从 runtime.exportAsset 取 blob,触发浏览器下载)
6
- * - 全部下载(逐项触发,BATCH_DOWNLOAD_DELAY_MS 间隔,避免浏览器拦截;长期方案见该常量注释)
6
+ * - 全部下载(JSZip 打包为单个 ZIP,一次用户手势完成)
7
7
  * - 清空输出列表
8
8
  *
9
9
  * 与 apps/playground 的 DownloadManager(独立工具页)不同:本组件是 Workspace
10
10
  * 内嵌的轻量面板,数据来自 store.lastOutputIds(由 workflow-slice.run 写入)。
11
11
  *
12
12
  * 下载命名:`lokvis-output-{assetId前8位}.{ext}`,简洁且避免覆盖。
13
- * 不引入 JSZip(需新增依赖),用浏览器原生 downloadBlob 实现。
14
13
  */
15
14
 
16
15
  import * as React from 'react';
16
+ import JSZip from 'jszip';
17
17
  import { Icon } from '@lokvis/ui-core';
18
18
  import { useWorkspaceStore } from '../store/index.js';
19
19
  import { formatBytes } from '../utils.js';
@@ -22,22 +22,6 @@ export interface DownloadPanelProps {
22
22
  className?: string;
23
23
  }
24
24
 
25
- /**
26
- * 批量下载时每项之间的延迟毫秒数。
27
- *
28
- * 短期方案:浏览器(尤其 Chrome)会拦截同一 tick 内触发的多个 programmatic
29
- * `<a download>` 点击,把第一个之后的视为"非用户手势"弹窗拦截。两次下载之间
30
- * 插入小延迟可绕过该启发式判定。该值是经验值,不是规范要求 —— 不同浏览器
31
- * 版本行为可能变化。
32
- *
33
- * 长期方案:用 JSZip 将多个输出打包成单个 ZIP 下载(只需一次用户手势)。
34
- * 本组件暂未引入 JSZip 依赖(见文件头注释),待 M2 引入 archive capability 后
35
- * 一并迁移,届时可移除此常量与 sleep 调用。
36
- */
37
- const BATCH_DOWNLOAD_DELAY_MS = 200;
38
-
39
- const sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
40
-
41
25
  /** 从扩展名或 mime 推断下载扩展名 */
42
26
  function extFromMime(mime: string): string {
43
27
  const sub = mime.split('/')[1] ?? 'bin';
@@ -115,38 +99,42 @@ export function DownloadPanel({ className = '' }: DownloadPanelProps) {
115
99
 
116
100
  async function handleDownloadAll() {
117
101
  if (!runtime || batchDownloading) return;
102
+ // 单文件时直接下载,无需 ZIP 开销
103
+ if (outputAssets.length === 1) {
104
+ void handleDownloadOne(outputAssets[0]!.id);
105
+ return;
106
+ }
118
107
  setBatchDownloading(true);
119
108
  setError(null);
120
- setStatus('Downloading outputs...');
121
- // 用本地 Set 跟踪本次循环已下载 id,避免 downloaded 闭包快照与 state 不同步
122
- // (review 反馈:循环中 setDownloaded 更新 state 但闭包 downloaded 不变,
123
- // 虽有 batchDownloading guard 阻止并发,逻辑上仍应读取最新已下载集合)
124
- const localDownloaded = new Set(downloaded);
109
+ setStatus('Packaging outputs...');
125
110
  try {
111
+ const zip = new JSZip();
126
112
  for (const asset of outputAssets) {
127
- // 卸载后立即停止循环(避免对已卸载组件 setState)
128
113
  if (!mountedRef.current) return;
129
- if (localDownloaded.has(asset.id)) continue;
130
114
  try {
131
115
  const blob = await runtime.exportAsset(asset.id);
132
116
  const ext = extFromMime(asset.metadata.mimeType);
133
117
  const filename = `lokvis-output-${asset.id.slice(0, 8)}.${ext}`;
134
- downloadBlob(blob, filename);
135
- localDownloaded.add(asset.id);
136
- if (mountedRef.current) {
137
- setDownloaded((prev) => new Set(prev).add(asset.id));
138
- }
139
- await sleep(BATCH_DOWNLOAD_DELAY_MS);
118
+ zip.file(filename, blob);
140
119
  } catch (err) {
120
+ // 单项失败不阻断打包,记录错误继续
141
121
  if (mountedRef.current) {
142
122
  setError(err instanceof Error ? err.message : String(err));
143
123
  }
144
- // 单项失败不阻断后续
145
124
  }
146
125
  }
126
+ if (!mountedRef.current) return;
127
+ const zipBlob = await zip.generateAsync({ type: 'blob' });
128
+ downloadBlob(zipBlob, 'lokvis-outputs.zip');
129
+ // 标记全部已下载
147
130
  if (mountedRef.current) {
131
+ setDownloaded(new Set(outputAssets.map((a) => a.id)));
148
132
  setStatus('Downloads complete');
149
133
  }
134
+ } catch (err) {
135
+ if (mountedRef.current) {
136
+ setError(err instanceof Error ? err.message : String(err));
137
+ }
150
138
  } finally {
151
139
  if (mountedRef.current) {
152
140
  setBatchDownloading(false);