@numa-tech/numa 1.25.0 → 1.26.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 (80) hide show
  1. package/dist/business-issuer.js +3 -1
  2. package/dist/business-issuer.js.map +1 -1
  3. package/dist/cli.js +3 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config.d.ts +1 -1
  6. package/dist/config.js +2 -2
  7. package/dist/config.js.map +1 -1
  8. package/dist/kb/catalog.js +33 -2
  9. package/dist/kb/catalog.js.map +1 -1
  10. package/dist/kb/chat-stream.d.ts +5 -0
  11. package/dist/kb/chat-stream.js +61 -0
  12. package/dist/kb/chat-stream.js.map +1 -0
  13. package/dist/kb/client.d.ts +75 -6
  14. package/dist/kb/client.js +104 -7
  15. package/dist/kb/client.js.map +1 -1
  16. package/dist/kb/commands.js +92 -7
  17. package/dist/kb/commands.js.map +1 -1
  18. package/dist/kb/config.d.ts +14 -2
  19. package/dist/kb/config.js +21 -7
  20. package/dist/kb/config.js.map +1 -1
  21. package/dist/kb/management-commands.d.ts +7 -0
  22. package/dist/kb/management-commands.js +86 -0
  23. package/dist/kb/management-commands.js.map +1 -0
  24. package/dist/kb/management-schemas.d.ts +106 -0
  25. package/dist/kb/management-schemas.js +33 -0
  26. package/dist/kb/management-schemas.js.map +1 -0
  27. package/dist/kb/transfers.d.ts +4 -0
  28. package/dist/kb/transfers.js +11 -4
  29. package/dist/kb/transfers.js.map +1 -1
  30. package/dist/kb/upload-decisions.d.ts +28 -0
  31. package/dist/kb/upload-decisions.js +23 -0
  32. package/dist/kb/upload-decisions.js.map +1 -0
  33. package/dist/kb/upload-state.d.ts +1 -0
  34. package/dist/kb/upload-state.js +1 -0
  35. package/dist/kb/upload-state.js.map +1 -1
  36. package/dist/kb/web-login.d.ts +10 -0
  37. package/dist/kb/web-login.js +25 -0
  38. package/dist/kb/web-login.js.map +1 -0
  39. package/dist/kb/web-page.d.ts +3 -0
  40. package/dist/kb/web-page.js +114 -0
  41. package/dist/kb/web-page.js.map +1 -0
  42. package/dist/kb/web-queue.d.ts +61 -0
  43. package/dist/kb/web-queue.js +101 -0
  44. package/dist/kb/web-queue.js.map +1 -0
  45. package/dist/kb/web.d.ts +26 -0
  46. package/dist/kb/web.js +234 -0
  47. package/dist/kb/web.js.map +1 -0
  48. package/dist/local-web/context-menu.d.ts +2 -0
  49. package/dist/local-web/context-menu.js +53 -0
  50. package/dist/local-web/context-menu.js.map +1 -0
  51. package/dist/local-web/file-workspace-style.d.ts +2 -0
  52. package/dist/local-web/file-workspace-style.js +58 -0
  53. package/dist/local-web/file-workspace-style.js.map +1 -0
  54. package/dist/local-web/file-workspace.d.ts +2 -0
  55. package/dist/local-web/file-workspace.js +39 -0
  56. package/dist/local-web/file-workspace.js.map +1 -0
  57. package/dist/local-web/security.d.ts +6 -0
  58. package/dist/local-web/security.js +51 -0
  59. package/dist/local-web/security.js.map +1 -0
  60. package/dist/login-recovery.js +7 -2
  61. package/dist/login-recovery.js.map +1 -1
  62. package/dist/oss/transfer-queue.d.ts +7 -51
  63. package/dist/oss/transfer-queue.js +15 -308
  64. package/dist/oss/transfer-queue.js.map +1 -1
  65. package/dist/oss/web-page.js +21 -103
  66. package/dist/oss/web-page.js.map +1 -1
  67. package/dist/oss/web.js +4 -45
  68. package/dist/oss/web.js.map +1 -1
  69. package/dist/platform-profile.d.ts +25 -1
  70. package/dist/platform-profile.js +44 -1
  71. package/dist/platform-profile.js.map +1 -1
  72. package/dist/transfers/persistent-queue.d.ts +65 -0
  73. package/dist/transfers/persistent-queue.js +312 -0
  74. package/dist/transfers/persistent-queue.js.map +1 -0
  75. package/docs/design/kb-capability-upgrade.md +36 -0
  76. package/docs/design/kb-web-workspace.md +97 -0
  77. package/docs/kb-access.md +72 -0
  78. package/package.json +9 -7
  79. package/scripts/export-kb-contract.py +25 -6
  80. package/src/kb/openapi-contract.json +2297 -566
@@ -1,7 +1,6 @@
1
+ import { PersistentTransferQueue } from '../transfers/persistent-queue.js';
1
2
  import { randomUUID } from 'node:crypto';
2
- import { constants } from 'node:fs';
3
- import { lstat, mkdir, open, readFile, rename, rm, chmod } from 'node:fs/promises';
4
- import { isAbsolute, join, relative, sep } from 'node:path';
3
+ import { isAbsolute, relative, sep } from 'node:path';
5
4
  import { z } from 'zod';
6
5
  import { OssError } from './errors.js';
7
6
  import { transferBinding } from './transfer-paths.js';
@@ -35,315 +34,23 @@ export async function createTransferQueue(options) {
35
34
  await queue.initialize();
36
35
  return queue;
37
36
  }
38
- export class TransferQueue {
39
- options;
40
- jobs = [];
41
- active = new Map();
42
- actions = new Map();
43
- saving = Promise.resolve();
44
- closing = false;
45
- closed;
46
- lock;
47
- worker;
48
- maximum;
49
- storageError = false;
50
- constructor(options) {
51
- this.options = options;
52
- this.worker = options.worker ?? createTransferWorker();
53
- this.maximum = options.maxConcurrent ?? 3;
54
- if (!Number.isInteger(this.maximum) || this.maximum < 1 || this.maximum > 10)
55
- throw new OssError('Invalid concurrency', 'oss_input_invalid', 400);
56
- }
57
- async initialize() {
58
- const directory = this.options.directory;
59
- await mkdir(directory, { recursive: true, mode: 0o700 });
60
- const info = await lstat(directory);
61
- if (!info.isDirectory() || info.isSymbolicLink())
62
- throw new OssError('任务目录无效。', 'oss_transfer_storage_invalid');
63
- await chmod(directory, 0o700);
64
- const path = join(directory, 'queue.lock');
65
- try {
66
- this.lock = await open(path, 'wx', 0o600);
67
- }
68
- catch (error) {
69
- if (error.code !== 'EEXIST')
70
- throw error;
71
- // Serialize stale-PID recovery: comparing an inode before unlink is not
72
- // sufficient when two new servers start at the same time.
73
- const recoveryPath = join(directory, 'queue.recovery.lock');
74
- const recovery = await open(recoveryPath, 'wx', 0o600).catch(() => { throw new OssError('任务队列正在恢复,或上次恢复被中断;请检查本机任务目录。', 'oss_transfer_queue_busy', 409); });
75
- try {
76
- const existing = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
77
- let identity;
78
- try {
79
- identity = await existing.stat();
80
- if (!identity.isFile() || identity.size > 100)
81
- throw new Error('invalid lock');
82
- const pid = Number((await existing.readFile('utf8')).trim());
83
- if (!Number.isSafeInteger(pid) || pid <= 0)
84
- throw new OssError('任务目录锁无效,请检查本机任务目录。', 'oss_transfer_storage_invalid');
85
- let alive = true;
86
- try {
87
- process.kill(pid, 0);
88
- }
89
- catch (e) {
90
- if (e.code === 'ESRCH')
91
- alive = false;
92
- }
93
- if (alive)
94
- throw new OssError(`另一个 OSS 网页服务(PID ${pid})正在使用此账号的任务队列。`, 'oss_transfer_queue_busy', 409);
95
- }
96
- finally {
97
- await existing.close();
98
- }
99
- const current = await lstat(path);
100
- if (current.dev !== identity.dev || current.ino !== identity.ino)
101
- throw new OssError('任务队列已被占用。', 'oss_transfer_queue_busy', 409);
102
- await rm(path);
103
- this.lock = await open(path, 'wx', 0o600);
104
- }
105
- finally {
106
- await recovery.close();
107
- await rm(recoveryPath, { force: true });
108
- }
109
- }
110
- try {
111
- await this.lock.writeFile(String(process.pid));
112
- await this.lock.sync();
113
- const statePath = join(directory, 'tasks.json');
114
- const info = await lstat(statePath).catch(e => { if (e.code === 'ENOENT')
115
- return undefined; throw e; });
116
- if (info) {
117
- if (!info.isFile() || info.isSymbolicLink() || info.size > 16 * 1024 * 1024)
118
- throw new Error('invalid state file');
119
- const state = stateSchema.parse(JSON.parse(await readFile(statePath, 'utf8')));
120
- const seen = new Set();
121
- for (const job of state.jobs) {
122
- const rel = relative(job.localRoot, job.localPath);
123
- if (!isAbsolute(job.localPath) || !isAbsolute(job.localRoot) || !rel || rel === '..' || rel.startsWith('..' + sep) || isAbsolute(rel) || seen.has(job.id))
124
- throw new Error('invalid job path');
125
- seen.add(job.id);
126
- if (['queued', 'running', 'pausing', 'cancelling'].includes(job.status))
127
- job.status = 'paused';
128
- }
129
- this.jobs = state.jobs;
130
- }
131
- await this.save();
132
- }
133
- catch (error) {
134
- await this.unlock();
135
- if (error instanceof OssError)
136
- throw error;
137
- throw new OssError('本机任务记录无法读取或写入;请检查任务目录。', 'oss_transfer_storage_invalid');
138
- }
139
- }
140
- list() {
141
- return this.jobs.map(job => {
142
- const { checkpoint: _checkpoint, binding: _binding, source: _source, localRoot: _root, ...view } = job;
143
- const active = this.active.get(job.id);
144
- const bytesPerSecond = active && job.status === 'running' ? Math.max(0, (job.transferred - active.initial) / Math.max(1, (Date.now() - active.started) / 1000)) : 0;
145
- return { ...view, bytesPerSecond };
37
+ export class TransferQueue extends PersistentTransferQueue {
38
+ adapter;
39
+ constructor(adapter) {
40
+ super({ directory: adapter.directory, maxConcurrent: adapter.maxConcurrent, worker: adapter.worker ?? createTransferWorker(), stateSchema,
41
+ validate: job => { jobSchema.parse(job); const rel = relative(job.localRoot, job.localPath); if (!isAbsolute(job.localPath) || !isAbsolute(job.localRoot) || !rel || rel === '..' || rel.startsWith('..' + sep) || isAbsolute(rel))
42
+ throw new Error('invalid job path'); },
43
+ conflicts: (a, b) => a.direction === b.direction && (b.direction === 'download' ? a.localPath === b.localPath : a.binding === b.binding && a.key === b.key),
44
+ context: (job, base) => ({ ...base, session: async () => { const session = await adapter.session(job.grantId); if (transferBinding(session) !== job.binding)
45
+ throw new OssError('Binding changed', 'oss_transfer_binding_changed'); return session; } }),
46
+ view: job => { const { checkpoint: _checkpoint, binding: _binding, source: _source, localRoot: _root, ...view } = job; return view; },
47
+ safeError, committed: job => { delete job.checkpoint; }
146
48
  });
49
+ this.adapter = adapter;
147
50
  }
148
51
  async add(direction, session, files) {
149
- if (this.closing || this.storageError)
150
- throw new OssError('任务队列不可用。', 'oss_transfer_storage_invalid');
151
- const pending = this.jobs.filter(j => !['completed', 'cancelled'].includes(j.status));
152
- if (!files.length || pending.length + files.length > 10000)
153
- throw new OssError('未完成任务数量已达上限。', 'oss_transfer_limit', 400);
154
52
  const binding = transferBinding(session), date = new Date().toISOString();
155
- const additions = files.map(file => jobSchema.parse({ ...file, id: randomUUID(), direction, grantId: session.grantId, binding, transferred: 0, status: 'queued', createdAt: date, updatedAt: date }));
156
- for (const job of additions) {
157
- if (pending.some(other => other.direction === direction && (direction === 'download' ? other.localPath === job.localPath : other.binding === job.binding && other.key === job.key)))
158
- throw new OssError('同一路径已有未完成任务。', 'oss_transfer_duplicate', 409);
159
- pending.push(job);
160
- }
161
- let excess = this.jobs.length + additions.length - 10000;
162
- this.jobs = this.jobs.filter(job => { if (excess > 0 && ['completed', 'cancelled'].includes(job.status)) {
163
- excess--;
164
- return false;
165
- } return true; });
166
- this.jobs.push(...additions);
167
- await this.save();
168
- this.schedule();
169
- const ids = new Set(additions.map(j => j.id));
170
- return this.list().filter(j => ids.has(j.id));
171
- }
172
- context(job, controller) {
173
- return { signal: controller.signal, session: async () => {
174
- const session = await this.options.session(job.grantId);
175
- if (transferBinding(session) !== job.binding)
176
- throw new OssError('Binding changed', 'oss_transfer_binding_changed');
177
- return session;
178
- }, save: () => this.save(), progress: bytes => { if (Number.isFinite(bytes)) {
179
- job.transferred = Math.max(0, Math.min(job.size, bytes));
180
- job.updatedAt = new Date().toISOString();
181
- } } };
182
- }
183
- schedule() {
184
- if (this.closing || this.storageError)
185
- return;
186
- for (const job of this.jobs) {
187
- if (this.active.size >= this.maximum)
188
- break;
189
- if (job.status !== 'queued')
190
- continue;
191
- const controller = new AbortController();
192
- job.status = 'running';
193
- delete job.error;
194
- const active = { controller, done: Promise.resolve(), started: Date.now(), initial: job.transferred };
195
- this.active.set(job.id, active);
196
- active.done = (async () => {
197
- try {
198
- await this.save();
199
- await this.worker.run(job, this.context(job, controller));
200
- // A committed object/file cannot be undone by a late pause or cancellation.
201
- job.status = 'completed';
202
- job.transferred = job.size;
203
- delete job.checkpoint;
204
- }
205
- catch (error) {
206
- if (controller.signal.aborted)
207
- job.status = 'paused';
208
- else {
209
- job.status = 'failed';
210
- job.error = safeError(error);
211
- }
212
- }
213
- finally {
214
- job.updatedAt = new Date().toISOString();
215
- try {
216
- await this.save();
217
- }
218
- catch {
219
- this.storageError = true;
220
- }
221
- this.active.delete(job.id);
222
- this.schedule();
223
- }
224
- })();
225
- }
226
- }
227
- action(id, action) {
228
- const previous = this.actions.get(id) ?? Promise.resolve();
229
- const next = previous.catch(() => { }).then(() => this.performAction(id, action));
230
- this.actions.set(id, next);
231
- void next.finally(() => { if (this.actions.get(id) === next)
232
- this.actions.delete(id); }).catch(() => { });
233
- return next;
234
- }
235
- async performAction(id, action) {
236
- if (this.closing)
237
- throw new OssError('任务服务正在关闭。', 'oss_transfer_storage_invalid');
238
- const job = this.jobs.find(j => j.id === id);
239
- if (!job)
240
- throw new OssError('任务不存在。', 'oss_input_invalid', 404);
241
- if (['completed', 'cancelled'].includes(job.status))
242
- return;
243
- if (action === 'resume') {
244
- if (!['paused', 'failed'].includes(job.status))
245
- return;
246
- if (this.storageError)
247
- throw new OssError('任务记录写入失败。', 'oss_transfer_storage_invalid');
248
- job.status = 'queued';
249
- delete job.error;
250
- await this.save();
251
- this.schedule();
252
- return;
253
- }
254
- const active = this.active.get(id);
255
- job.status = action === 'pause' ? 'pausing' : 'cancelling';
256
- active?.controller.abort();
257
- if (active)
258
- await active.done;
259
- if (job.status === 'completed')
260
- return;
261
- if (action === 'cancel') {
262
- try {
263
- await this.worker.cancel(job, this.context(job, new AbortController()));
264
- if (job.status !== 'completed')
265
- job.status = 'cancelled';
266
- delete job.checkpoint;
267
- delete job.error;
268
- }
269
- catch (error) {
270
- job.status = 'failed';
271
- job.error = safeError(error);
272
- }
273
- }
274
- else
275
- job.status = 'paused';
276
- job.updatedAt = new Date().toISOString();
277
- await this.save();
278
- }
279
- save() {
280
- const write = this.saving.catch(() => { }).then(async () => {
281
- const data = JSON.stringify({ version: 1, jobs: this.jobs });
282
- if (Buffer.byteLength(data) > 16 * 1024 * 1024)
283
- throw new Error('state too large');
284
- const temporary = join(this.options.directory, `.tasks-${randomUUID()}.tmp`);
285
- const file = await open(temporary, 'wx', 0o600);
286
- try {
287
- await file.writeFile(data);
288
- await file.sync();
289
- await file.close();
290
- await rename(temporary, join(this.options.directory, 'tasks.json'));
291
- // Persist the rename as well as the JSON bytes before acknowledging a checkpoint.
292
- let parent;
293
- try {
294
- parent = await open(this.options.directory, constants.O_RDONLY);
295
- await parent.sync();
296
- }
297
- catch (error) {
298
- if (process.platform !== 'win32' || !['EPERM', 'EISDIR', 'EINVAL', 'ENOTSUP'].includes(error.code ?? ''))
299
- throw error;
300
- }
301
- finally {
302
- await parent?.close();
303
- }
304
- }
305
- finally {
306
- await file.close().catch(() => { });
307
- await rm(temporary, { force: true }).catch(() => { });
308
- }
309
- });
310
- this.saving = write;
311
- return write;
312
- }
313
- close() {
314
- if (this.closed)
315
- return this.closed;
316
- this.closing = true;
317
- this.closed = (async () => {
318
- try {
319
- for (const job of this.jobs)
320
- if (job.status === 'queued')
321
- job.status = 'paused';
322
- for (const active of this.active.values())
323
- active.controller.abort();
324
- await Promise.allSettled([...this.active.values()].map(a => a.done));
325
- await Promise.allSettled([...this.actions.values()]);
326
- await this.save();
327
- }
328
- finally {
329
- await this.unlock();
330
- }
331
- })();
332
- return this.closed;
333
- }
334
- async unlock() {
335
- if (!this.lock)
336
- return;
337
- const lock = this.lock;
338
- this.lock = undefined;
339
- try {
340
- const owned = await lock.stat(), current = await lstat(join(this.options.directory, 'queue.lock'));
341
- if (owned.ino === current.ino && owned.dev === current.dev)
342
- await rm(join(this.options.directory, 'queue.lock'));
343
- }
344
- finally {
345
- await lock.close();
346
- }
53
+ return this.enqueue(files.map(file => jobSchema.parse({ ...file, id: randomUUID(), direction, grantId: session.grantId, binding, transferred: 0, status: 'queued', createdAt: date, updatedAt: date })));
347
54
  }
348
55
  }
349
56
  //# sourceMappingURL=transfer-queue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-queue.js","sourceRoot":"","sources":["../../src/oss/transfer-queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transfer-queue.js","sourceRoot":"","sources":["../../src/oss/transfer-queue.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,6 @@
1
+ import { FILE_WORKSPACE_CSS } from '../local-web/file-workspace-style.js';
2
+ import { FILE_WORKSPACE_JS } from '../local-web/file-workspace.js';
3
+ import { LOCAL_CONTEXT_MENU_JS } from '../local-web/context-menu.js';
1
4
  import { OSS_REFRESH_ICON, OSS_COPY_ICON } from "./web-icons.js";
2
5
  /** Self-contained local assets: no CDN, remote fonts, analytics or credential-bearing markup. */
3
6
  export const OSS_WEB_HTML = String.raw `<!doctype html>
@@ -30,63 +33,10 @@ export const OSS_WEB_HTML = String.raw `<!doctype html>
30
33
  <section id="operations-panel" class="operations-panel" hidden aria-label="文件操作进度"><div id="operations-list"></div><p>关闭浏览器后继续执行。停止服务会中断文件操作;已完成部分保留,重启后不会自动续做。</p></section>
31
34
  <template id="copy-icon">${OSS_COPY_ICON}</template>
32
35
  </body></html>`;
33
- export const OSS_WEB_CSS = String.raw `
34
- .file-menu{position:fixed;z-index:20;min-width:175px;padding:5px;background:white;border:1px solid #d4ded6;border-radius:8px;box-shadow:0 8px 28px #20372e26}.file-menu button{display:block;width:100%;border:0;text-align:left;padding:9px 12px}.file-menu button:focus{background:#eff5f1}.file-menu button[aria-disabled=true]{color:#99a49e}.permission-tip{position:fixed;z-index:30;max-width:min(330px,calc(100vw - 16px));padding:10px 12px;background:#263c31;color:#fff;border-radius:6px;box-shadow:0 6px 24px #20372e26;font-size:12px;line-height:1.7;overflow-wrap:anywhere}
35
- #statistics-result{display:grid;grid-template-columns:100px 1fr;gap:12px;margin:20px 0;font-variant-numeric:tabular-nums}#statistics-result dd{margin:0;font-weight:600}#statistics-status{margin-top:10px}
36
- #statistics-dialog{width:min(640px,90vw);max-width:90vw;max-height:90vh;overflow:auto}#statistics-result dd{overflow-wrap:anywhere}.statistics-table{margin:22px 0 10px}.statistics-table caption{text-align:left;font-weight:600;margin-bottom:6px}.statistics-table th:first-child,.statistics-table td:first-child{width:44%;overflow-wrap:anywhere}.statistics-table th:not(:first-child),.statistics-table td:not(:first-child){text-align:right;font-variant-numeric:tabular-nums}.statistics-table td{color:#4a6554}#statistics-dialog .dialog-actions{position:sticky;bottom:-26px;background:#fff;padding:14px 0;margin-top:10px}
37
- #links-dialog{width:min(680px,90vw);max-width:90vw;max-height:90vh;overflow:auto}#links-expires{margin-left:12px;max-width:100%}.links-renew{margin-top:12px;white-space:normal}#links-session-hint{margin:8px 0 12px}#links-result article{border-top:1px solid #dbe3de;padding:14px 0}#links-result h3{font-size:13px;overflow-wrap:anywhere;margin:0 0 8px}#links-result textarea{width:100%;font:11px/1.6 ui-monospace,monospace;resize:vertical;overflow-wrap:anywhere;min-height:72px}#links-result .link-copy{display:flex;align-items:center;gap:8px}#links-status{overflow-wrap:anywhere}#links-dialog .dialog-actions{position:sticky;bottom:-26px;background:white;padding:14px 0}
38
- #operation-dialog{max-height:90vh;overflow:auto;width:min(520px,90vw)}
39
- #destination-picker{margin-top:16px}#destination-hint{font-size:12px;margin-bottom:8px}.destination-tree{max-height:260px;overflow:auto;border:1px solid #dbe3de;border-radius:6px;padding:6px;background:#fafcfb}.destination-children{padding-left:18px}.destination-line{display:flex;align-items:center;gap:4px;min-height:34px;border-radius:4px}.destination-line button{border:0;background:transparent;padding:6px;color:#344b41}.destination-toggle{width:28px;flex-shrink:0}.destination-name{display:flex;align-items:center;gap:8px;flex:1;min-width:0;text-align:left;white-space:normal;overflow-wrap:anywhere}.destination-name .folder-icon{flex-shrink:0}.destination-item[aria-selected=true]>.destination-line{background:#dfede3}.destination-item:focus{outline:none}.destination-item:focus-visible>.destination-line{outline:2px solid #16805a;outline-offset:-2px}.destination-status{font-size:11px;color:#7b8d81;margin-left:32px}.destination-more{font-size:12px;margin:4px 0 4px 32px}.destination-editor{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 6px 32px}.destination-editor input{width:100%;min-width:0;padding:7px;border:1px solid #cbd9cf;border-radius:4px;background:white;color:#23322e}.destination-editor button{font-size:12px;padding:6px 9px}
40
- #operation-dialog label{display:block;font-size:12px;margin:16px 0 8px}#operation-value{width:100%;border:1px solid #cbd9cf;padding:10px;border-radius:5px;color:#23322e}#operation-source{overflow-wrap:anywhere}#operation-help{margin-top:10px}#operation-error{color:#a7473d}
41
- .operations-panel{flex-shrink:0;background:#f0f6f2;border-top:1px solid #cbd9cf;max-height:24vh;overflow:auto;padding:10px 26px;font-size:12px}.operations-panel>p{font-size:11px;color:#74867b;margin-top:5px}.operation-row{display:flex;align-items:center;gap:12px;padding:5px 0}.operation-row span{flex:1;overflow-wrap:anywhere}.operation-row button{font-size:12px;padding:5px 10px}.upload-actions{flex-wrap:wrap;justify-content:flex-end}
42
-
43
- .icon-button{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;min-width:34px;min-height:34px}
44
- :root{font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif;color:#23322e;background:#f5f7f5;font-size:14px;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,select{cursor:pointer}button{border:1px solid #d8e0db;background:white;color:#344b41;border-radius:6px;padding:8px 12px;white-space:nowrap}button:hover:not(:disabled){background:#eff5f1;border-color:#a5bcae}button:disabled{opacity:.4;cursor:not-allowed}input:focus-visible,button:focus-visible,select:focus-visible{outline:2px solid #16805a;outline-offset:2px}input[type=checkbox]{accent-color:#197854;width:15px;height:15px;cursor:pointer}input[type=search]{border:1px solid #dbe3de;border-radius:6px;padding:9px 12px;min-width:160px;background:#fafcfb;color:#23322e}select{border:0;background:transparent;color:#263d31;max-width:100%;padding:6px 24px 6px 0;font-weight:550}h1,h2,p{margin:0}h1{font-size:27px;letter-spacing:-.7px;font-weight:600}h2{font-size:15px;font-weight:600}.topbar{height:62px;padding:0 26px;background:#20372e;color:#ecf4ed;display:flex;align-items:center;gap:20px}.brand{font-size:24px;letter-spacing:-1px;font-weight:650;color:inherit;text-decoration:none}.brand span{font-size:16px;font-weight:400;letter-spacing:.5px;color:#a9c0b0;margin-left:12px}.local{font-size:11px;color:#cee0d5;display:flex;align-items:center;gap:6px}.local i{height:6px;width:6px;background:#8edaac;border-radius:50%}.topnote{margin-left:auto;color:#aac0b2;font-size:12px;letter-spacing:2px}.authorization{display:flex;align-items:center;justify-content:space-between;gap:24px;background:#fff;border-bottom:1px solid #dbe3de;padding:16px 26px}.grant-field{min-width:0;display:flex;align-items:center;gap:12px;flex:1}.grant-field label{font-size:12px;color:#7a8c80;white-space:nowrap}.session-controls{display:flex;align-items:center;gap:18px;flex-shrink:0}.expiry{display:flex;align-items:center;gap:10px;font-size:11px;color:#718076}.expiry strong{font-family:ui-monospace,SFMono-Regular,monospace;color:#2b674c;font-size:20px;font-weight:500;min-width:62px}.expiry strong.warning{color:#b45309}.expiry strong.expired{color:#bf403d}.check{display:flex;align-items:center;gap:5px;font-size:12px;white-space:nowrap}.quiet{background:transparent;border-color:transparent;color:#718577;padding:6px 8px}.primary{color:white;background:#227b54;border-color:#227b54}.primary:hover:not(:disabled){background:#196140;color:white}.danger{color:#9f4b40}.destructive{color:white;background:#a7473d;border-color:#a7473d}.notice{margin:0;padding:10px 26px;background:#fff4df;border-bottom:1px solid #ead9b8;color:#845422;font-size:13px;line-height:1.6}.notice.success{background:#e9f6ec;color:#266342;border-color:#c9e3d0}.workspace{display:grid;grid-template-columns:205px minmax(420px,1fr) 310px;min-height:calc(100vh - 137px)}.sidebar{border-right:1px solid #dbe3de;padding:30px 16px;display:flex;flex-direction:column;background:#f0f4f0;min-width:0}.eyebrow{font-size:10px;letter-spacing:1.7px;color:#89988d;font-weight:600}.sidebar .eyebrow{padding-left:10px}.root-button{display:flex;align-items:center;gap:10px;margin-top:18px;white-space:normal;text-align:left;overflow-wrap:anywhere;background:#e1ebe2;border:0;color:#24573d;font-size:13px}.folder-icon{display:inline-block;width:16px;height:11px;background:#9fbba1;border-radius:2px;position:relative;flex-shrink:0;margin-top:3px}.folder-icon:before{content:"";position:absolute;left:0;top:-3px;width:7px;height:4px;border-radius:2px 2px 0 0;background:inherit}.scope-label{font-size:11px;color:#86978a;margin:23px 10px 9px}.scope{font-family:ui-monospace,SFMono-Regular,monospace;font-size:12px;color:#637c6a;overflow-wrap:anywhere;line-height:1.7}.sidebar>.scope{padding:0 10px}.sidebar-bottom{margin-top:auto;padding:40px 10px 0;color:#607e68;font-size:12px}.sidebar-bottom p{margin-top:12px;line-height:1.8;color:#8b9b8e;font-size:11px}.files{background:white;min-width:0;padding:30px 28px 0;display:flex;flex-direction:column}.page-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.page-heading .eyebrow{margin-bottom:8px}.location{display:flex;align-items:center;gap:6px;border-top:1px solid #e8ede9;border-bottom:1px solid #e8ede9;padding:9px 0;min-width:0}.location nav{display:flex;align-items:center;flex-wrap:wrap;flex:1;gap:2px;min-width:0}.location nav button{padding:4px 7px;border:0;font-size:12px;max-width:220px;overflow:hidden;text-overflow:ellipsis}.location nav span{color:#c1ccc4}.toolbar{display:flex;gap:8px;align-items:center;margin:18px 0}.toolbar input[type=search]{flex:1;min-width:0}.toolbar button{font-size:12px;padding:7px 9px}#selection-count{font-size:11px;color:#819286;white-space:nowrap}.table-wrap{overflow-x:auto;min-height:290px}table{width:100%;border-collapse:collapse;table-layout:fixed}th{text-align:left;font-size:11px;color:#8a978e;font-weight:500;border-bottom:1px solid #e3e9e4;padding:11px 9px}td{padding:12px 9px;border-bottom:1px solid #f0f3f0;font-size:12px;color:#79897e}.check-cell{width:30px;padding-left:0}.size-cell{width:82px;text-align:right;font-variant-numeric:tabular-nums}.date-cell{width:145px;text-align:right}tr:hover td{background:#f7faf7}tr.active td{background:#edf5ee}td .entry{border:0;background:transparent;padding:0;display:flex;align-items:center;gap:10px;max-width:100%;color:#354e3e;font-size:13px;text-align:left}td .entry span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-icon{display:inline-block;width:13px;height:16px;border:1px solid #a8b8ad;background:#f5f8f5;border-radius:2px;flex-shrink:0}.empty{text-align:center;padding:65px 20px;color:#8b9b8f;line-height:1.9}.list-footer{border-top:1px solid #e9eee9;display:flex;align-items:center;justify-content:space-between;color:#92a095;font-size:11px;padding:13px 0;margin-top:auto;min-height:48px}.preview-panel{border-left:1px solid #dbe3de;display:flex;flex-direction:column;padding:29px 20px 20px;background:#f8faf7;min-width:0}.preview-heading{display:flex;justify-content:space-between;align-items:center}.preview-heading h2{font-size:13px;color:#61776a}.preview-body{padding-top:25px;flex:1;min-width:0}.preview-empty{text-align:center;color:#859889;padding:80px 0;line-height:2}.preview-empty small{color:#a0aca2;font-size:11px}.preview-body h3{font-size:15px;line-height:1.7;overflow-wrap:anywhere;font-weight:500;margin:0 0 18px}.preview-body dl{font-size:11px;display:grid;grid-template-columns:60px minmax(0,1fr);gap:10px;margin:20px 0;color:#91a094}.preview-body dd{margin:0;color:#607968;overflow-wrap:anywhere}.preview-body pre{font:11px/1.8 ui-monospace,SFMono-Regular,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:50vh;overflow:auto;background:#edf2ec;padding:12px;border-radius:5px;color:#48654e}.preview-body img{max-width:100%;max-height:40vh;object-fit:contain;border-radius:4px}.preview-body p{font-size:12px;line-height:1.8;color:#8c9a8f}.preview-actions{display:flex;gap:8px;padding-top:20px}.preview-actions button{flex:1;font-size:12px}.transfer{border-top:1px solid #dce8df;padding:14px 0;font-size:12px}.transfer>div{display:flex;align-items:center;justify-content:space-between}.transfer progress{width:100%;height:5px;accent-color:#227b54;margin:10px 0}.transfer span{font-size:11px;color:#7b9082}dialog{border:1px solid #d4ded6;border-radius:10px;padding:26px;max-width:min(480px,90vw);color:#344c3c;box-shadow:0 20px 80px #182c2530}dialog::backdrop{background:#1c322747}dialog h2{font-size:19px;margin-bottom:15px}dialog p{font-size:13px;line-height:1.8;color:#879489}dialog ul{max-height:180px;overflow:auto;padding-left:20px;font-size:12px;line-height:1.9;overflow-wrap:anywhere}.dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:24px}[hidden]{display:none!important}@media(min-width:1500px){.workspace{grid-template-columns:235px minmax(500px,1fr) 370px}.files{padding-left:38px;padding-right:38px}}@media(max-width:1100px){.workspace{grid-template-columns:160px minmax(360px,1fr) 260px}.files{padding:24px 18px 0}.authorization{flex-wrap:wrap;gap:10px}.grant-field{flex-basis:100%}.session-controls{margin-left:auto}.date-cell{width:110px}.toolbar{flex-wrap:wrap}.toolbar input[type=search]{flex-basis:100%}}@media(max-width:820px){.workspace{grid-template-columns:1fr}.sidebar{display:none}.preview-panel{border-left:0;border-top:1px solid #dbe3de}.preview-empty{padding:20px}.files{min-height:60vh}.authorization{padding:14px 18px}.grant-field{gap:7px;flex-wrap:wrap}.grant-field select{flex:1;min-width:180px}.session-controls{width:100%;justify-content:space-between;gap:8px}.expiry{gap:6px}.topbar{padding:0 18px}.topnote{display:none}.date-cell{width:110px}.preview-body pre{max-height:280px}.preview-actions{max-width:360px}}
45
- /* Independent scrolling keeps file actions within the current viewport. */
46
- body{height:100vh;height:100dvh;display:flex;flex-direction:column;overflow:hidden}
47
- .topbar,.authorization,.notice{flex-shrink:0}.notice{max-height:20vh;overflow:auto}
48
- .workspace{flex:1;min-height:0;overflow:hidden}.sidebar{min-height:0;overflow:auto}
49
- .files{min-height:0;overflow:hidden}.files>:not(.table-wrap){flex-shrink:0}
50
- .table-wrap{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain}
51
- .table-wrap thead{position:sticky;top:0;background:#fff;z-index:1}
52
- .list-footer{margin-top:0;flex-shrink:0}.preview-panel{min-height:0;overflow:hidden}
53
- .preview-heading,.preview-actions{flex-shrink:0}.preview-body{min-height:0;overflow:auto;overscroll-behavior:contain;padding-right:6px}
54
- .preview-actions{border-top:1px solid #dbe3de;margin-top:16px;padding-top:16px;background:#f8faf7}
55
- .preview-body h4{font-size:12px;font-weight:600;margin:24px 0 12px;color:#496553}
56
- .preview-body dl{grid-template-columns:78px minmax(0,1fr)}.preview-body dt{overflow-wrap:anywhere}
57
- .preview-body .metadata-list{grid-template-columns:minmax(0,1fr);gap:5px}.metadata-list dd{padding-bottom:9px}
58
- .copy-field{display:flex;align-items:flex-start;gap:6px;min-width:0}.copy-field>span{min-width:0;overflow-wrap:anywhere}
59
- .copy-button{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:2px;width:24px;height:24px;margin-top:-3px}
60
- .copy-button svg{width:15px;height:15px}.copy-button.copied{color:#18764e;background:#e1f2e7}
61
- .copy-field a{color:#197854;text-underline-offset:3px;line-height:1.7}.copy-manual{width:100%;font:inherit}
62
- .clipboard-fallback{position:fixed;left:0;top:0;opacity:0;pointer-events:none}
63
- .icon-button{color:#526f5e}.icon-button svg{display:block}.is-loading svg{animation:oss-refresh-spin .8s linear infinite}
64
- @keyframes oss-refresh-spin{to{transform:rotate(360deg)}}
65
- @media(prefers-reduced-motion:reduce){.is-loading svg{animation:none}.is-loading{opacity:.55}}
66
- @media(max-width:820px){.workspace{display:flex;flex-direction:column;overflow:auto}.files{flex:none;height:58dvh;min-height:330px}.preview-panel{flex:none;height:45dvh;min-height:270px}.preview-body pre{max-height:none}}
67
-
68
- .topbar{height:auto;min-height:62px;flex-wrap:wrap;gap:12px;padding-top:10px;padding-bottom:10px}#service-stop{font-size:12px;background:transparent;border-color:#82958a;color:#edf5ef}.upload-actions{display:flex;gap:8px}.tasks-panel{position:fixed;right:20px;bottom:20px;top:155px;width:min(480px,calc(100vw - 32px));z-index:5;background:#fff;border:1px solid #cbd9cf;border-radius:10px;box-shadow:0 12px 50px #20372e30;display:flex;flex-direction:column;overflow:hidden}.tasks-heading{display:flex;align-items:center;justify-content:space-between;padding:15px 18px;border-bottom:1px solid #e4ebe5}.tasks-note{font-size:12px;line-height:1.8;color:#718577;padding:12px 18px}.tasks-list{overflow:auto;overscroll-behavior:contain;flex:1;min-height:0}.task-card{padding:15px 18px;border-top:1px solid #e8eee9}.task-card h3{font-size:13px;margin:0 0 7px;overflow-wrap:anywhere;font-weight:550}.task-meta,.task-path,.task-stats{font-size:11px;color:#738a7b;line-height:1.7;overflow-wrap:anywhere}.task-path{font-family:ui-monospace,SFMono-Regular,monospace}.task-card progress{width:100%;height:6px;accent-color:#227b54;margin:10px 0 6px}.task-actions{display:flex;gap:7px;margin-top:10px}.task-actions button{font-size:12px;padding:5px 10px}.task-error,#tasks-connection{font-size:12px;color:#9f4b40;line-height:1.7;overflow-wrap:anywhere}.task-error{margin-top:8px}#tasks-connection{padding:0 18px 10px}#tasks-toggle{font-size:12px;background:#2f4b3e;border-color:#607969;color:#edf5ef}#tasks-count{font-variant-numeric:tabular-nums;margin-left:5px}@media(max-width:820px){.tasks-panel{top:140px;right:16px;bottom:16px}.upload-actions{gap:5px}.upload-actions button{font-size:12px;padding:7px 9px}}
69
-
70
- /* Collapsed rails keep both expand buttons visible and give space back to the file list. */
71
- .workspace{--sidebar-width:205px;--preview-width:310px;grid-template-columns:var(--sidebar-width) minmax(0,1fr) var(--preview-width)}
72
- .sidebar-heading{display:flex;align-items:center;justify-content:space-between;gap:6px;flex-shrink:0}.sidebar-heading .eyebrow{letter-spacing:1px;font-size:11px}
73
- .panel-toggle{width:28px;height:28px;padding:0;flex-shrink:0;font-size:24px;line-height:1}
74
- .sidebar-content{display:flex;flex-direction:column;flex:1;min-height:0;overflow:auto}.sidebar-content>.scope{padding:0 10px}.sidebar-content .root-button{flex-shrink:0}
75
- .preview-content{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
76
- @media(min-width:1500px){.workspace{--sidebar-width:235px;--preview-width:370px}}
77
- @media(min-width:821px) and (max-width:1100px){.workspace{--sidebar-width:160px;--preview-width:260px}}
78
- .workspace[data-sidebar-collapsed=true]{--sidebar-width:44px}.workspace[data-preview-collapsed=true]{--preview-width:44px}
79
- .workspace[data-sidebar-collapsed=true] .sidebar,.workspace[data-preview-collapsed=true] .preview-panel{padding:20px 7px;overflow:hidden}
80
- .workspace[data-sidebar-collapsed=true] .sidebar-heading,.workspace[data-preview-collapsed=true] .preview-heading{flex-direction:column-reverse;gap:16px}
81
- .workspace[data-sidebar-collapsed=true] .sidebar-heading h2,.workspace[data-preview-collapsed=true] .preview-heading h2{writing-mode:vertical-rl;letter-spacing:2px;font-size:11px;padding:0;font-weight:500}
82
- @media(max-width:820px){
83
- .sidebar{display:flex;flex:none;padding:12px 18px;max-height:38dvh;border-right:0;border-bottom:1px solid #dbe3de}.sidebar-content{flex:auto}.sidebar-bottom{padding-top:16px}.sidebar-heading .eyebrow{padding-left:0}
84
- .workspace[data-sidebar-collapsed=true] .sidebar,.workspace[data-preview-collapsed=true] .preview-panel{height:auto;min-height:0;max-height:none;padding:8px 18px}
85
- .workspace[data-sidebar-collapsed=true] .sidebar-heading,.workspace[data-preview-collapsed=true] .preview-heading{flex-direction:row;gap:8px}
86
- .workspace[data-sidebar-collapsed=true] .sidebar-heading h2,.workspace[data-preview-collapsed=true] .preview-heading h2{writing-mode:horizontal-tb;letter-spacing:1px}
87
- }
88
- `;
36
+ export const OSS_WEB_CSS = FILE_WORKSPACE_CSS;
89
37
  export const OSS_WEB_JS = String.raw `(() => {
38
+ ${LOCAL_CONTEXT_MENU_JS}
39
+ ${FILE_WORKSPACE_JS}
90
40
  'use strict';
91
41
  const $ = id => document.getElementById(id);
92
42
  const fragment = new URLSearchParams(location.hash.slice(1));
@@ -185,14 +135,11 @@ function visible() { const query = $('search').value.toLocaleLowerCase(); return
185
135
  function renderRows() {
186
136
  const body = $('rows'); body.replaceChildren(); const rows = visible();
187
137
  for (const row of rows) {
188
- const tr = node('tr'); tr.oncontextmenu = event => openFileMenu(event, row); tr.tabIndex = 0; tr.onkeydown = event => { if (event.key === 'ContextMenu' || event.shiftKey && event.key === 'F10') openFileMenu(event, row, tr); }; if (state.file?.key === row.key) tr.className = 'active';
189
138
  const checkCell = node('td', undefined, 'check-cell');
190
139
  { const check = document.createElement('input'); check.type = 'checkbox'; check.checked = state.selected.has(row.key); check.setAttribute('aria-label', '选择 ' + displayName(row.key)); check.onchange = () => { if (check.checked) state.selected.add(row.key); else state.selected.delete(row.key); updateSelection(); controls(); }; checkCell.append(check); }
191
- tr.append(checkCell);
192
- const name = node('td'); const button = node('button', undefined, 'entry'); button.title = row.key;
193
- button.append(node('span', undefined, row.directory ? 'folder-icon' : 'file-icon'), node('span', displayName(row.key.slice(state.dir.length) || row.key)));
194
- button.onclick = () => row.directory ? navigate(row.key) : preview(row); name.append(button); tr.append(name);
195
- tr.append(node('td', row.directory ? '—' : bytes(row.sizeBytes), 'size-cell'), node('td', date(row.lastModified), 'date-cell'));
140
+ const tr=workspaceFileRow({leading:checkCell,title:row.key,name:displayName(row.key.slice(state.dir.length)||row.key),icon:row.directory?'folder-icon':'file-icon',selected:state.file?.key===row.key,
141
+ onOpen:()=>row.directory?navigate(row.key):preview(row),onMenu:(event,anchor)=>openFileMenu(event,row,anchor),
142
+ cells:[[row.directory?'—':bytes(row.sizeBytes),'size-cell'],[date(row.lastModified),'date-cell']]});
196
143
  body.append(tr);
197
144
  }
198
145
  $('empty').hidden = rows.length > 0; $('empty').textContent = state.loading ? '正在读取文件…' : $('search').value ? '已加载列表中没有匹配项' : '此目录暂无文件';
@@ -419,24 +366,13 @@ function renderTasks(jobs) {
419
366
  for (const job of jobs) {
420
367
  let card = taskCards.get(job.id);
421
368
  if (!card) {
422
- const root = node('article', undefined, 'task-card'), title = node('h3'), meta = node('p', undefined, 'task-meta'), path = node('p', undefined, 'task-path'), progress = node('progress'), stats = node('p', undefined, 'task-stats'), error = node('p', undefined, 'task-error'), buttons = node('div', undefined, 'task-actions');
423
- progress.max = 100; progress.setAttribute('aria-label', '文件传输进度');
424
- const actions = new Map();
425
- for (const [action, label] of [['pause','暂停'],['resume','恢复'],['cancel','取消']]) { const button = node('button', label); button.onclick = () => taskAction(job.id, action); actions.set(action, button); buttons.append(button); }
426
- root.append(title, meta, path, progress, stats, error, buttons); $('tasks-list').append(root);
427
- card = { root, title, meta, path, progress, stats, error, actions }; taskCards.set(job.id, card);
369
+ card=createWorkspaceTransferCard(job.id,taskAction);$('tasks-list').append(card.root);taskCards.set(job.id,card);
428
370
  }
429
371
  const prior = taskStatuses.get(job.id);
430
372
  if ((prior || transfersLoaded) && prior !== 'completed' && job.status === 'completed' && job.direction === 'upload') markListingChanged(job.grantId);
431
373
  taskStatuses.set(job.id, job.status);
432
- setText(card.title, job.key); setText(card.meta, (job.direction === 'upload' ? '上传' : '下载') + ' · Grant #' + job.grantId + ' · ' + (taskLabels[job.status] || '状态未知'));
433
- setText(card.path, job.localPath); card.path.title = job.localPath;
434
- card.progress.value = job.size > 0 ? Math.min(100, job.transferred / job.size * 100) : job.status === 'completed' ? 100 : 0;
435
- card.progress.setAttribute('aria-valuetext', bytes(job.transferred) + ' / ' + bytes(job.size));
436
- setText(card.stats, bytes(job.transferred) + ' / ' + bytes(job.size) + (job.status === 'running' ? ' · ' + bytes(Math.max(0, Number(job.bytesPerSecond) || 0)) + '/s' : ''));
437
- setText(card.error, job.error || ''); card.error.hidden = !job.error;
438
- const available = { pause: ['queued','running'].includes(job.status), resume: ['paused','failed'].includes(job.status), cancel: ['queued','running','paused','failed'].includes(job.status) };
439
- for (const [action, button] of card.actions) { button.hidden = !available[action]; button.disabled = taskBusy.has(job.id); }
374
+ updateWorkspaceTransferCard(card,job,{title:job.key,meta:(job.direction==='upload'?'上传':'下载')+' · Grant #'+job.grantId+' · '+(taskLabels[job.status]||'状态未知'),
375
+ progress:bytes(job.transferred)+' / '+bytes(job.size),stats:bytes(job.transferred)+' / '+bytes(job.size)+(job.status==='running'?' · '+bytes(Math.max(0,Number(job.bytesPerSecond)||0))+'/s':'')},taskBusy.has(job.id));
440
376
  }
441
377
  $('tasks-empty').hidden = jobs.length > 0;
442
378
  setText($('tasks-count'), String(jobs.length));
@@ -475,7 +411,7 @@ async function deleteFiles() {
475
411
  catch (error) { fail(error); }
476
412
  finally { state.mutating = false; controls(); }
477
413
  }
478
- let menuOwner = null, permissionTipOwner = null, permissionTipTimer = null;
414
+ let permissionTipOwner = null, permissionTipTimer = null;
479
415
  function hidePermissionTip() { clearTimeout(permissionTipTimer); permissionTipTimer = null; $('permission-tip').hidden = true; permissionTipOwner?.removeAttribute('aria-describedby'); permissionTipOwner = null; }
480
416
  function showPermissionTip(button, missing) {
481
417
  hidePermissionTip(); button.focus(); permissionTipOwner = button;
@@ -486,18 +422,19 @@ function showPermissionTip(button, missing) {
486
422
  tip.style.left = Math.max(8,Math.min(bounds.left,window.innerWidth - tip.offsetWidth - 8)) + 'px';
487
423
  tip.style.top = Math.max(8,Math.min(bounds.bottom + 6,window.innerHeight - tip.offsetHeight - 8)) + 'px';
488
424
  }
489
- function closeFileMenu(restore = false) { hidePermissionTip(); $('file-menu').hidden = true; if (restore) menuOwner?.focus(); }
425
+ const fileMenu = createLocalContextMenu($('file-menu'), hidePermissionTip);
426
+ function closeFileMenu(restore = false) { fileMenu.close(restore); }
490
427
  function openFileMenu(event, row, anchor) {
491
428
  event.preventDefault(); closeFileMenu();
492
429
  if (!state.ready || state.stopping || state.mutating || remaining() <= 0) return;
493
- const menu = $('file-menu'); document.body.append(menu,$('permission-tip')); menu.replaceChildren(); menuOwner = anchor || event.currentTarget;
430
+ const menu = $('file-menu'); document.body.append(menu,$('permission-tip')); fileMenu.begin(event,anchor);
494
431
  const permissions = {read:'读取权限(oss:GetObject)',write:'写入权限(oss:PutObject)',delete:'删除权限(oss:DeleteObject)',list:'列举权限(oss:ListObjects)'};
495
432
  const actions = [['delete',row.directory ? '删除文件夹…' : '删除文件…',['delete']],['copy','拷贝到…',['read','write']],['move','移动到…',['read','write','delete']],['rename','重命名…',['read','write','delete']]];
496
433
  for (const [kind,label,required] of actions) {
497
434
  const missing = [...required,...(row.directory ? ['list'] : [])].filter(permission => !state.session[permission]).map(permission => permissions[permission]);
498
- const button = node('button',label,kind === 'delete' ? 'danger' : ''); button.setAttribute('role','menuitem'); button.setAttribute('aria-disabled',String(missing.length > 0));
435
+ const button = fileMenu.item(label, () => { if (kind === 'delete') askDelete([row.key]); else askOperation(kind,row); },
436
+ {danger:kind === 'delete',disabled:missing.length > 0,onDisabled:button => showPermissionTip(button,missing)});
499
437
  button.onblur = hidePermissionTip;
500
- button.onclick = () => { if (missing.length) { showPermissionTip(button,missing); return; } closeFileMenu(); if (kind === 'delete') askDelete([row.key]); else askOperation(kind,row); }; menu.append(button);
501
438
  }
502
439
  const selected = state.selected.has(row.key) ? state.rows.filter(item => state.selected.has(item.key)) : [row];
503
440
  const links = node('button', '临时下载链接…'); links.setAttribute('role','menuitem');
@@ -508,11 +445,7 @@ function openFileMenu(event, row, anchor) {
508
445
  const missing = [...new Set(selected.map(item => item.directory ? 'list' : 'read'))].filter(permission => !state.session[permission]).map(permission => permissions[permission]);
509
446
  statistics.setAttribute('aria-disabled',String(missing.length > 0)); statistics.onblur = hidePermissionTip;
510
447
  statistics.onclick = () => { if (missing.length) { showPermissionTip(statistics,missing); return; } closeFileMenu(); startStatistics(selected); }; menu.append(statistics);
511
- menu.hidden = false;
512
- const bounds = anchor?.getBoundingClientRect();
513
- menu.style.left = Math.max(8, Math.min(bounds ? bounds.left : event.clientX, window.innerWidth - menu.offsetWidth - 8)) + 'px';
514
- menu.style.top = Math.max(8, Math.min(bounds ? bounds.bottom : event.clientY, window.innerHeight - menu.offsetHeight - 8)) + 'px';
515
- [...menu.children].find(button => !button.disabled)?.focus();
448
+ fileMenu.show(event,anchor);
516
449
  }
517
450
  let destinationTree = null;
518
451
  function clearDestinationTree() {
@@ -598,7 +531,7 @@ async function loadDestinationBranch(tree, branch) {
598
531
  function openDestinationMenu(event, tree, branch, anchor) {
599
532
  event.preventDefault(); event.stopPropagation(); closeFileMenu();
600
533
  if (tree !== destinationTree || state.mutating || state.stopping || branch.choose.disabled) return;
601
- const menu = $('file-menu'); menu.replaceChildren(); menuOwner = branch.item;
534
+ const menu = $('file-menu'); fileMenu.begin(event,anchor || branch.item,$('operation-dialog'));
602
535
  // A modal dialog makes body-level menus inert; keep the menu and tooltip in its top layer.
603
536
  $('operation-dialog').append(menu,$('permission-tip'));
604
537
  const create = node('button','创建子目录…'); create.setAttribute('role','menuitem'); create.setAttribute('aria-disabled',String(!tree.writable));
@@ -612,11 +545,7 @@ function openDestinationMenu(event, tree, branch, anchor) {
612
545
  branch.status.hidden = false; branch.status.textContent = ''; branch.more.hidden = !branch.marker;
613
546
  branch.editor.hidden = false; branch.nameInput.value = ''; branch.nameInput.focus();
614
547
  };
615
- menu.append(create); menu.hidden = false;
616
- const bounds = anchor?.getBoundingClientRect();
617
- menu.style.left = Math.max(8,Math.min(bounds ? bounds.left : event.clientX,window.innerWidth - menu.offsetWidth - 8)) + 'px';
618
- menu.style.top = Math.max(8,Math.min(bounds ? bounds.bottom : event.clientY,window.innerHeight - menu.offsetHeight - 8)) + 'px';
619
- create.focus();
548
+ menu.append(create); fileMenu.show(event,anchor);
620
549
  }
621
550
  async function createDestinationDirectory(tree, branch) {
622
551
  if (tree !== destinationTree || !tree.writable || state.mutating || state.stopping || branch.choose.disabled) return;
@@ -783,17 +712,6 @@ $('operation-dialog').oncancel = event => { if (state.mutating) { event.preventD
783
712
  $('operation-value').oninput = syncDestinationSelection;
784
713
  $('operation-confirm').onclick = confirmOperation;
785
714
  $('operation-value').onkeydown = event => { if (event.key === 'Enter') { event.preventDefault(); confirmOperation(); } };
786
- document.addEventListener('click', event => { if (!$('file-menu').contains(event.target)) closeFileMenu(); });
787
- document.addEventListener('keydown', event => {
788
- const menu = $('file-menu'); if (menu.hidden) return;
789
- if (event.key === 'Escape' || event.key === 'Tab') { if (event.key === 'Escape') event.preventDefault(); closeFileMenu(true); return; }
790
- if (['ArrowDown','ArrowUp','Home','End'].includes(event.key)) {
791
- event.preventDefault(); const buttons = [...menu.children].filter(button => !button.disabled), index = buttons.indexOf(document.activeElement);
792
- const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1 : (index + (event.key === 'ArrowDown' ? 1 : buttons.length - 1)) % buttons.length;
793
- buttons[next]?.focus();
794
- }
795
- });
796
- document.addEventListener('scroll', () => closeFileMenu(), true);
797
715
  setInterval(pollOperations, 1000);
798
716
  let pollingService = false;
799
717
  async function pollService() {