dsh-session-curator 0.2.0 → 0.3.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.
- package/README.md +6 -5
- package/README.zh-CN.md +6 -5
- package/lib/client.js +124 -458
- package/lib/host/delete.js +77 -0
- package/lib/host/fs-utils.js +1 -15
- package/lib/host/open.js +9 -15
- package/lib/host/paths.js +5 -13
- package/lib/host/routes.js +3 -20
- package/lib/host/session-manager.js +22 -159
- package/lib/index.js +6 -10
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +5 -5
- package/lib/host/retention.js +0 -24
- package/lib/host/trash.js +0 -279
package/lib/client.js
CHANGED
|
@@ -41,16 +41,12 @@ __export(index_exports, {
|
|
|
41
41
|
GroupHeader: () => GroupHeader,
|
|
42
42
|
NS: () => NS,
|
|
43
43
|
SessionRow: () => SessionRow,
|
|
44
|
-
TRASH_DAYS_MAX: () => TRASH_DAYS_MAX,
|
|
45
|
-
TRASH_DAYS_MIN: () => TRASH_DAYS_MIN,
|
|
46
|
-
TRASH_RETENTION_DAYS: () => TRASH_RETENTION_DAYS,
|
|
47
44
|
UsagePanel: () => UsagePanel,
|
|
48
45
|
apply: () => apply,
|
|
49
46
|
cachedSnapshot: () => cachedSnapshot,
|
|
50
47
|
collapseKey: () => collapseKey,
|
|
51
48
|
describeSession: () => describeSession,
|
|
52
49
|
dialogStore: () => dialogStore,
|
|
53
|
-
effectiveTrashDays: () => effectiveTrashDays,
|
|
54
50
|
filterRows: () => filterRows,
|
|
55
51
|
forgetDetails: () => forgetDetails,
|
|
56
52
|
forgetSnapshot: () => forgetSnapshot,
|
|
@@ -61,14 +57,12 @@ __export(index_exports, {
|
|
|
61
57
|
isGroupCollapsed: () => isGroupCollapsed,
|
|
62
58
|
matchesFilter: () => matchesFilter,
|
|
63
59
|
matchesSearch: () => matchesSearch,
|
|
64
|
-
|
|
60
|
+
mutationStore: () => mutationStore,
|
|
65
61
|
sectionIdFor: () => sectionIdFor,
|
|
66
62
|
showNotice: () => showNotice,
|
|
67
|
-
showTrashUndo: () => showTrashUndo,
|
|
68
63
|
sortRows: () => sortRows,
|
|
69
64
|
toastStore: () => toastStore,
|
|
70
65
|
toggledCollapse: () => toggledCollapse,
|
|
71
|
-
undoTrash: () => undoTrash,
|
|
72
66
|
workspaceSummaries: () => workspaceSummaries
|
|
73
67
|
});
|
|
74
68
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -190,79 +184,38 @@ function useStore(store) {
|
|
|
190
184
|
// src/client/dialog.ts
|
|
191
185
|
var dialogStore = createStore(null);
|
|
192
186
|
var mutationStore = createStore(0);
|
|
193
|
-
function
|
|
194
|
-
dialogStore.set({ kind: "
|
|
195
|
-
}
|
|
196
|
-
function requestPurge(ids, title) {
|
|
197
|
-
dialogStore.set({ kind: "purge", ids, title });
|
|
198
|
-
}
|
|
199
|
-
function requestPurgeOld(days, count, bytes) {
|
|
200
|
-
dialogStore.set({ kind: "purge-old", ids: [], title: "", days, count, bytes });
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// src/client/format.ts
|
|
204
|
-
function formatBytes(bytes) {
|
|
205
|
-
if (typeof bytes !== "number" || !Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
206
|
-
const units = ["B", "KB", "MB", "GB"];
|
|
207
|
-
let value = bytes;
|
|
208
|
-
let unit = 0;
|
|
209
|
-
while (value >= 1024 && unit < units.length - 1) {
|
|
210
|
-
value /= 1024;
|
|
211
|
-
unit += 1;
|
|
212
|
-
}
|
|
213
|
-
return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
214
|
-
}
|
|
215
|
-
function formatTime(ms) {
|
|
216
|
-
if (typeof ms !== "number" || ms <= 0) return "";
|
|
217
|
-
try {
|
|
218
|
-
return new Date(ms).toLocaleString();
|
|
219
|
-
} catch {
|
|
220
|
-
return "";
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
function baseName(path) {
|
|
224
|
-
if (typeof path !== "string" || path === "") return "";
|
|
225
|
-
const parts = path.split(/[\\/]/).filter((part) => part !== "");
|
|
226
|
-
return parts.length > 0 ? parts[parts.length - 1] : path;
|
|
187
|
+
function requestDelete(ids, title) {
|
|
188
|
+
dialogStore.set({ kind: "delete", ids, title });
|
|
227
189
|
}
|
|
228
190
|
|
|
229
191
|
// src/client/i18n.ts
|
|
230
192
|
var NS = "session-curator";
|
|
231
193
|
var zh = {
|
|
232
194
|
sectionLabel: "会话管理",
|
|
233
|
-
|
|
195
|
+
deleteSession: "删除会话",
|
|
234
196
|
titleArchived: "已归档",
|
|
235
197
|
titlePinned: "已置顶",
|
|
236
|
-
titleTrash: "回收站",
|
|
237
198
|
refresh: "刷新",
|
|
238
199
|
loading: "读取中…",
|
|
239
200
|
retry: "重试",
|
|
240
201
|
emptyArchived: "还没有归档的会话。在会话行的「⋯」菜单里归档后会出现在这里。",
|
|
241
202
|
emptyPinned: "没有置顶的会话。",
|
|
242
|
-
emptyTrash: "回收站是空的。",
|
|
243
203
|
unarchive: "取消归档",
|
|
244
204
|
pin: "置顶",
|
|
245
205
|
unpin: "取消置顶",
|
|
246
|
-
restore: "恢复",
|
|
247
|
-
restoreUnavailable: "无法恢复(缺元数据)",
|
|
248
|
-
purge: "永久删除",
|
|
249
|
-
moveToTrash: "移入回收站",
|
|
250
206
|
rowActions: "更多操作",
|
|
251
207
|
selectAll: "全选",
|
|
252
208
|
selectNone: "取消选择",
|
|
253
209
|
selected: "已选 {n} 项",
|
|
254
|
-
emptyTrashAll: "清空回收站",
|
|
255
210
|
total: "合计 {n} 个会话 · {size}",
|
|
256
211
|
working: "处理中…",
|
|
257
212
|
sessionRunning: "会话正在运行,先停止它再删除。",
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
confirmPurgeAction: "永久删除",
|
|
265
|
-
ackPurge: "我明白这无法撤销",
|
|
213
|
+
// 物理删除的确认弹窗(唯一一种弹窗):正文必须写清"不可恢复"并指路归档。
|
|
214
|
+
confirmDeleteTitle: "永久删除",
|
|
215
|
+
confirmDeleteBody: "「{title}」将被永久删除:日志文件会从磁盘上彻底移除,无法恢复。如果想以后还能找回,请改用「归档」。",
|
|
216
|
+
confirmDeleteManyBody: "选中的 {n} 个会话将被永久删除:日志文件会从磁盘上彻底移除,无法恢复。如果想以后还能找回,请改用「归档」。",
|
|
217
|
+
confirmDeleteAction: "永久删除",
|
|
218
|
+
ackDelete: "我明白这无法撤销",
|
|
266
219
|
cancel: "取消",
|
|
267
220
|
close: "关闭",
|
|
268
221
|
noProject: "(未知目录)",
|
|
@@ -282,7 +235,7 @@ var zh = {
|
|
|
282
235
|
workspaceActions: "整个工作区",
|
|
283
236
|
workspaceMenu: "工作区操作",
|
|
284
237
|
archiveWorkspace: "整个工作区归档",
|
|
285
|
-
|
|
238
|
+
deleteWorkspace: "整个工作区删除",
|
|
286
239
|
workspaceRunningHint: "这个工作区里有会话正在运行,危险动作已禁用",
|
|
287
240
|
// 运行中徽标(宿主用官方的 workspace/session-activity 判定)。
|
|
288
241
|
running: "运行中",
|
|
@@ -296,14 +249,13 @@ var zh = {
|
|
|
296
249
|
// 磁盘占用视图。
|
|
297
250
|
titleUsage: "磁盘占用",
|
|
298
251
|
usageTitle: "磁盘占用",
|
|
299
|
-
usageTotal: "共 {n} 个会话 · {size}
|
|
252
|
+
usageTotal: "共 {n} 个会话 · {size}",
|
|
300
253
|
usageByWorkspace: "按工作区",
|
|
301
254
|
usageLargest: "最占地方的会话",
|
|
302
255
|
usageOldest: "最久没打开的会话",
|
|
303
256
|
usageLoading: "正在统计…",
|
|
304
257
|
usageArchived: "已归档",
|
|
305
258
|
usagePinned: "已置顶",
|
|
306
|
-
usageTrashed: "在回收站",
|
|
307
259
|
usageSuggestArchive: "建议归档",
|
|
308
260
|
usageArchive: "归档",
|
|
309
261
|
usageUnarchive: "取消归档",
|
|
@@ -325,12 +277,11 @@ var zh = {
|
|
|
325
277
|
configMeta: "行内显示体积与文件数",
|
|
326
278
|
configMetaHint: "关掉后每行只留标题(平铺时仍会显示文件夹)",
|
|
327
279
|
configOrder: "排序",
|
|
328
|
-
configOrderHint: "
|
|
280
|
+
configOrderHint: "原顺序就是宿主给的顺序",
|
|
329
281
|
orderHost: "原顺序",
|
|
330
282
|
orderTitle: "标题",
|
|
331
283
|
orderBytes: "体积",
|
|
332
284
|
orderCreatedAt: "创建时间",
|
|
333
|
-
orderDeletedAt: "删除时间",
|
|
334
285
|
// 搜索与过滤(只影响显示;批量操作与计数仍按整个页签算)。
|
|
335
286
|
searchLabel: "搜索会话",
|
|
336
287
|
searchPlaceholder: "搜索标题或目录…",
|
|
@@ -340,22 +291,6 @@ var zh = {
|
|
|
340
291
|
timeRecent: "最近 7 天",
|
|
341
292
|
filtered: "已过滤出 {n} 个会话(共 {total} 个)",
|
|
342
293
|
emptyFiltered: "没有符合搜索条件的会话。",
|
|
343
|
-
// 回收站保留策略(永久删除:永远先预览、再确认,绝不自动后台清理)。
|
|
344
|
-
configTrashDays: "回收站保留天数",
|
|
345
|
-
configTrashDaysHint: "「清理 N 天前」按这个天数算;不会自动执行,每次都要先看预览再确认",
|
|
346
|
-
retentionDays: "{n} 天",
|
|
347
|
-
retentionCustom: "自定义",
|
|
348
|
-
customDaysPlaceholder: "天数",
|
|
349
|
-
customDaysLabel: "自定义保留天数",
|
|
350
|
-
customDaysHint: "填 {min}–{max} 之间的整数;留空就用上面的档位",
|
|
351
|
-
customDaysInvalid: "天数要在 {min}–{max} 之间",
|
|
352
|
-
trashCleanup: "删除 {n} 天前的会话",
|
|
353
|
-
trashPreview: "将删除 {n} 个会话 · {size}",
|
|
354
|
-
trashPreviewNone: "没有超过 {days} 天的会话",
|
|
355
|
-
trashPreviewLoading: "正在统计…",
|
|
356
|
-
confirmPurgeOldTitle: "清理旧会话",
|
|
357
|
-
confirmPurgeOldBody: "将永久删除 {n} 个在 {days} 天前移入回收站的会话({size}),无法恢复。",
|
|
358
|
-
ackPurgeOld: "我明白这无法撤销",
|
|
359
294
|
configAutoUpdate: "自动检查更新",
|
|
360
295
|
configAutoUpdateHint: "打开这个页面时问一次 npm registry(10 分钟内有缓存)",
|
|
361
296
|
configReset: "恢复默认",
|
|
@@ -377,50 +312,34 @@ var zh = {
|
|
|
377
312
|
hoverStats: "{size} · {n} 个文件",
|
|
378
313
|
hoverCwd: "原目录",
|
|
379
314
|
hoverArchived: "已归档",
|
|
380
|
-
hoverPinned: "已置顶"
|
|
381
|
-
hoverTrashed: "在回收站",
|
|
382
|
-
hoverDeleted: "删除于",
|
|
383
|
-
// 删除成功后的撤销提示(`Toast`)。
|
|
384
|
-
toastTrashed: "「{title}」已移入回收站",
|
|
385
|
-
toastTrashedMany: "{n} 个会话已移入回收站",
|
|
386
|
-
toastUndo: "撤销",
|
|
387
|
-
toastUndoFailed: "撤销失败:{reason}"
|
|
315
|
+
hoverPinned: "已置顶"
|
|
388
316
|
};
|
|
389
317
|
var en = {
|
|
390
318
|
sectionLabel: "Session manager",
|
|
391
|
-
|
|
319
|
+
deleteSession: "Delete session",
|
|
392
320
|
titleArchived: "Archived",
|
|
393
321
|
titlePinned: "Pinned",
|
|
394
|
-
titleTrash: "Trash",
|
|
395
322
|
refresh: "Refresh",
|
|
396
323
|
loading: "Loading…",
|
|
397
324
|
retry: "Retry",
|
|
398
325
|
emptyArchived: "No archived sessions yet. Archive one from its “⋯” menu and it shows up here.",
|
|
399
326
|
emptyPinned: "No pinned sessions.",
|
|
400
|
-
emptyTrash: "The trash is empty.",
|
|
401
327
|
unarchive: "Unarchive",
|
|
402
328
|
pin: "Pin",
|
|
403
329
|
unpin: "Unpin",
|
|
404
|
-
restore: "Restore",
|
|
405
|
-
restoreUnavailable: "Cannot restore (no metadata)",
|
|
406
|
-
purge: "Delete permanently",
|
|
407
|
-
moveToTrash: "Move to trash",
|
|
408
330
|
rowActions: "More actions",
|
|
409
331
|
selectAll: "Select all",
|
|
410
332
|
selectNone: "Clear selection",
|
|
411
333
|
selected: "{n} selected",
|
|
412
|
-
emptyTrashAll: "Empty trash",
|
|
413
334
|
total: "{n} sessions · {size}",
|
|
414
335
|
working: "Working…",
|
|
415
336
|
sessionRunning: "This session is running; stop it before deleting.",
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
confirmPurgeAction: "Delete permanently",
|
|
423
|
-
ackPurge: "I understand this cannot be undone",
|
|
337
|
+
// The one confirmation dialog: it must spell out "permanent" and point at archiving instead.
|
|
338
|
+
confirmDeleteTitle: "Delete permanently",
|
|
339
|
+
confirmDeleteBody: "“{title}” is deleted permanently: its log files are removed from disk for good and cannot be recovered. If you want to be able to bring it back later, use Archive instead.",
|
|
340
|
+
confirmDeleteManyBody: "{n} selected sessions are deleted permanently: their log files are removed from disk for good and cannot be recovered. If you want to be able to bring them back later, use Archive instead.",
|
|
341
|
+
confirmDeleteAction: "Delete permanently",
|
|
342
|
+
ackDelete: "I understand this cannot be undone",
|
|
424
343
|
cancel: "Cancel",
|
|
425
344
|
close: "Close",
|
|
426
345
|
noProject: "(unknown directory)",
|
|
@@ -440,7 +359,7 @@ var en = {
|
|
|
440
359
|
workspaceActions: "Whole workspace",
|
|
441
360
|
workspaceMenu: "Workspace actions",
|
|
442
361
|
archiveWorkspace: "Archive this whole workspace",
|
|
443
|
-
|
|
362
|
+
deleteWorkspace: "Delete this whole workspace",
|
|
444
363
|
workspaceRunningHint: "A session in this workspace is running, so the destructive actions are off",
|
|
445
364
|
// Running badge (the host asks the official workspace/session-activity hook).
|
|
446
365
|
running: "Running",
|
|
@@ -454,14 +373,13 @@ var en = {
|
|
|
454
373
|
// Disk usage view.
|
|
455
374
|
titleUsage: "Disk usage",
|
|
456
375
|
usageTitle: "Disk usage",
|
|
457
|
-
usageTotal: "{n} sessions · {size}
|
|
376
|
+
usageTotal: "{n} sessions · {size}",
|
|
458
377
|
usageByWorkspace: "By workspace",
|
|
459
378
|
usageLargest: "Largest sessions",
|
|
460
379
|
usageOldest: "Least recently opened",
|
|
461
380
|
usageLoading: "Measuring…",
|
|
462
381
|
usageArchived: "Archived",
|
|
463
382
|
usagePinned: "Pinned",
|
|
464
|
-
usageTrashed: "In trash",
|
|
465
383
|
usageSuggestArchive: "Archive suggested",
|
|
466
384
|
usageArchive: "Archive",
|
|
467
385
|
usageUnarchive: "Unarchive",
|
|
@@ -483,12 +401,11 @@ var en = {
|
|
|
483
401
|
configMeta: "Show size and file count per row",
|
|
484
402
|
configMetaHint: "Off leaves only the title (the folder still shows in the flat list)",
|
|
485
403
|
configOrder: "Order",
|
|
486
|
-
configOrderHint: "Host order is what the host sent
|
|
404
|
+
configOrderHint: "Host order is what the host sent",
|
|
487
405
|
orderHost: "Host",
|
|
488
406
|
orderTitle: "Title",
|
|
489
407
|
orderBytes: "Size",
|
|
490
408
|
orderCreatedAt: "Created",
|
|
491
|
-
orderDeletedAt: "Deleted",
|
|
492
409
|
// Search and filtering (display only; batch actions and counts still cover the whole tab).
|
|
493
410
|
searchLabel: "Search sessions",
|
|
494
411
|
searchPlaceholder: "Search title or folder…",
|
|
@@ -498,22 +415,6 @@ var en = {
|
|
|
498
415
|
timeRecent: "Last 7 days",
|
|
499
416
|
filtered: "{n} of {total} sessions match",
|
|
500
417
|
emptyFiltered: "No session matches the search.",
|
|
501
|
-
// Trash retention (permanent deletion: always preview, then confirm; never automatic).
|
|
502
|
-
configTrashDays: "Trash retention",
|
|
503
|
-
configTrashDaysHint: "How “clean up N days ago” counts the days; it never runs on its own — every cleanup needs a preview and a confirmation",
|
|
504
|
-
retentionDays: "{n} days",
|
|
505
|
-
retentionCustom: "Custom",
|
|
506
|
-
customDaysPlaceholder: "Days",
|
|
507
|
-
customDaysLabel: "Custom retention days",
|
|
508
|
-
customDaysHint: "An integer between {min} and {max}; leave it empty to use the preset above",
|
|
509
|
-
customDaysInvalid: "Days must be between {min} and {max}",
|
|
510
|
-
trashCleanup: "Delete sessions older than {n} days",
|
|
511
|
-
trashPreview: "{n} sessions · {size} will be deleted",
|
|
512
|
-
trashPreviewNone: "Nothing is older than {days} days",
|
|
513
|
-
trashPreviewLoading: "Counting…",
|
|
514
|
-
confirmPurgeOldTitle: "Clean up old sessions",
|
|
515
|
-
confirmPurgeOldBody: "{n} sessions moved to the trash more than {days} days ago ({size}) are deleted for good and cannot be recovered.",
|
|
516
|
-
ackPurgeOld: "I understand this cannot be undone",
|
|
517
418
|
configAutoUpdate: "Check for updates automatically",
|
|
518
419
|
configAutoUpdateHint: "Asks the npm registry when this page opens (cached for 10 minutes)",
|
|
519
420
|
configReset: "Reset to defaults",
|
|
@@ -535,14 +436,7 @@ var en = {
|
|
|
535
436
|
hoverStats: "{size} · {n} files",
|
|
536
437
|
hoverCwd: "Folder",
|
|
537
438
|
hoverArchived: "Archived",
|
|
538
|
-
hoverPinned: "Pinned"
|
|
539
|
-
hoverTrashed: "In trash",
|
|
540
|
-
hoverDeleted: "Deleted",
|
|
541
|
-
// Undo notice after a successful delete (`Toast`).
|
|
542
|
-
toastTrashed: "“{title}” moved to the trash",
|
|
543
|
-
toastTrashedMany: "{n} sessions moved to the trash",
|
|
544
|
-
toastUndo: "Undo",
|
|
545
|
-
toastUndoFailed: "Undo failed: {reason}"
|
|
439
|
+
hoverPinned: "Pinned"
|
|
546
440
|
};
|
|
547
441
|
var dictionaries = { zh, en };
|
|
548
442
|
function text(t, key, params) {
|
|
@@ -554,8 +448,7 @@ function text(t, key, params) {
|
|
|
554
448
|
}
|
|
555
449
|
var TAB_LABEL = {
|
|
556
450
|
archived: "titleArchived",
|
|
557
|
-
pinned: "titlePinned"
|
|
558
|
-
trash: "titleTrash"
|
|
451
|
+
pinned: "titlePinned"
|
|
559
452
|
};
|
|
560
453
|
|
|
561
454
|
// src/client/snapshot.ts
|
|
@@ -635,15 +528,6 @@ var S = {
|
|
|
635
528
|
background: "var(--dsw-alias-interactive-bg-active)",
|
|
636
529
|
flex: "0 0 auto"
|
|
637
530
|
},
|
|
638
|
-
badgeDanger: {
|
|
639
|
-
color: "var(--dsw-alias-state-error-primary)",
|
|
640
|
-
fontSize: "10px",
|
|
641
|
-
lineHeight: "16px",
|
|
642
|
-
padding: "0 6px",
|
|
643
|
-
borderRadius: "8px",
|
|
644
|
-
background: "var(--dsw-alias-interactive-bg-active)",
|
|
645
|
-
flex: "0 0 auto"
|
|
646
|
-
},
|
|
647
531
|
/** 「运行中」:同款胶囊,但用业务蓝表示"它是活的",不是危险。 */
|
|
648
532
|
badgeRunning: {
|
|
649
533
|
color: "var(--dsw-alias-state-business-primary)",
|
|
@@ -789,11 +673,6 @@ var S = {
|
|
|
789
673
|
/** 下拉锚点:文字 + 双向箭头图标,别被挤窄(长标签在按钮里折行是这个仓库踩过的坑)。 */
|
|
790
674
|
dropdownAnchor: { flex: "0 0 auto" },
|
|
791
675
|
dropdownButton: { flex: "0 0 auto", whiteSpace: "nowrap" },
|
|
792
|
-
/** 保留策略那一格:档位下拉 + 自定义天数输入框。 */
|
|
793
|
-
retentionDays: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap", justifyContent: "flex-end" },
|
|
794
|
-
customDaysInput: { width: "88px", flex: "0 0 auto" },
|
|
795
|
-
/** 天数非法时只把边框标红,不动尺寸(否则整行会跳一下)。 */
|
|
796
|
-
customDaysInvalid: { borderColor: "var(--dsw-alias-state-error-primary)" },
|
|
797
676
|
configFoot: {
|
|
798
677
|
display: "flex",
|
|
799
678
|
alignItems: "center",
|
|
@@ -860,18 +739,9 @@ var S = {
|
|
|
860
739
|
background: "var(--dsw-alias-interactive-bg-active)",
|
|
861
740
|
flex: "0 0 auto"
|
|
862
741
|
},
|
|
863
|
-
hoverBadgeDanger: {
|
|
864
|
-
color: "var(--dsw-alias-state-error-primary)",
|
|
865
|
-
fontSize: "10px",
|
|
866
|
-
lineHeight: "16px",
|
|
867
|
-
padding: "0 6px",
|
|
868
|
-
borderRadius: "8px",
|
|
869
|
-
background: "var(--dsw-alias-interactive-bg-active)",
|
|
870
|
-
flex: "0 0 auto"
|
|
871
|
-
},
|
|
872
742
|
/**
|
|
873
|
-
* 侧边栏会话行 hover
|
|
874
|
-
* `components/
|
|
743
|
+
* 侧边栏会话行 hover 时那个「删除会话」图标按钮(见
|
|
744
|
+
* `components/delete-row-button.ts`):16×16 的朴素按钮,**两种状态都没有底色**,
|
|
875
745
|
* 只有前景色变深一档。
|
|
876
746
|
*
|
|
877
747
|
* `color-mix` 是 DSH 自己的产物里就在用的写法(例如 ui-deliverables 的
|
|
@@ -883,45 +753,6 @@ var S = {
|
|
|
883
753
|
rowIconButtonHover: { ...ROW_ICON_BUTTON, color: "color-mix(in srgb, var(--dsw-alias-state-error-primary) 78%, #000)" }
|
|
884
754
|
};
|
|
885
755
|
|
|
886
|
-
// src/client/toast.ts
|
|
887
|
-
var toastStore = createStore(null);
|
|
888
|
-
var sequence = 0;
|
|
889
|
-
function showTrashUndo(ids, title) {
|
|
890
|
-
if (ids.length === 0) return;
|
|
891
|
-
sequence += 1;
|
|
892
|
-
toastStore.set({ seq: sequence, ids: [...ids], title, error: null });
|
|
893
|
-
}
|
|
894
|
-
function showNotice(message) {
|
|
895
|
-
if (message === "") return;
|
|
896
|
-
sequence += 1;
|
|
897
|
-
toastStore.set({ seq: sequence, ids: [], title: message, error: null });
|
|
898
|
-
}
|
|
899
|
-
function dismissToast() {
|
|
900
|
-
toastStore.set(null);
|
|
901
|
-
}
|
|
902
|
-
function failToast(reason) {
|
|
903
|
-
const current2 = toastStore.get();
|
|
904
|
-
if (current2 === null) return;
|
|
905
|
-
toastStore.set({ ...current2, error: reason });
|
|
906
|
-
}
|
|
907
|
-
async function undoTrash() {
|
|
908
|
-
const current2 = toastStore.get();
|
|
909
|
-
if (current2 === null || current2.error !== null) return;
|
|
910
|
-
try {
|
|
911
|
-
const value = await call("restore", { ids: current2.ids });
|
|
912
|
-
const failure = firstFailure(value.results);
|
|
913
|
-
if (failure !== null) {
|
|
914
|
-
failToast(failure);
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
mutationStore.set(mutationStore.get() + 1);
|
|
918
|
-
rememberSnapshot(value);
|
|
919
|
-
dismissToast();
|
|
920
|
-
} catch (thrown) {
|
|
921
|
-
failToast(reportError(thrown));
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
|
|
925
756
|
// src/client/components/dialog-host.ts
|
|
926
757
|
function DialogHost(props) {
|
|
927
758
|
const t = props.t;
|
|
@@ -929,18 +760,15 @@ function DialogHost(props) {
|
|
|
929
760
|
const [busy, setBusy] = React2.useState(false);
|
|
930
761
|
const [ack, setAck] = React2.useState(false);
|
|
931
762
|
const [error, setError] = React2.useState(null);
|
|
932
|
-
const requestKey = request === null ? "" : `${request.kind}:${request.ids.join(",")}:${request.title}
|
|
763
|
+
const requestKey = request === null ? "" : `${request.kind}:${request.ids.join(",")}:${request.title}`;
|
|
933
764
|
React2.useEffect(() => {
|
|
934
765
|
setAck(false);
|
|
935
766
|
setError(null);
|
|
936
767
|
}, [requestKey]);
|
|
937
768
|
if (request === null) return null;
|
|
938
|
-
const purgeOld = request.kind === "purge-old";
|
|
939
|
-
const purge = request.kind === "purge" || purgeOld;
|
|
940
769
|
const many = request.ids.length > 1;
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
const body = purgeOld ? text(t, "confirmPurgeOldBody", { n: request.count ?? 0, days, size: formatBytes(request.bytes ?? 0) }) : purge ? many ? text(t, "confirmPurgeManyBody", { n: request.ids.length }) : text(t, "confirmPurgeBody", { title: request.title }) : text(t, "confirmTrashBody", { title: request.title });
|
|
770
|
+
const title = t("confirmDeleteTitle");
|
|
771
|
+
const body = many ? text(t, "confirmDeleteManyBody", { n: request.ids.length }) : text(t, "confirmDeleteBody", { title: request.title });
|
|
944
772
|
const close = () => {
|
|
945
773
|
if (busy) return;
|
|
946
774
|
dialogStore.set(null);
|
|
@@ -948,14 +776,12 @@ function DialogHost(props) {
|
|
|
948
776
|
const confirm = async () => {
|
|
949
777
|
setBusy(true);
|
|
950
778
|
try {
|
|
951
|
-
const
|
|
952
|
-
const value = await call(endpoint, purgeOld ? { days } : { ids: request.ids });
|
|
779
|
+
const value = await call("delete", { ids: request.ids });
|
|
953
780
|
const failure = firstFailure(value.results);
|
|
954
781
|
if (failure === null) {
|
|
955
782
|
dialogStore.set(null);
|
|
956
783
|
rememberSnapshot(value);
|
|
957
784
|
mutationStore.set(mutationStore.get() + 1);
|
|
958
|
-
if (!purge) showTrashUndo(request.ids, request.title);
|
|
959
785
|
} else {
|
|
960
786
|
setError(failure);
|
|
961
787
|
}
|
|
@@ -982,14 +808,14 @@ function DialogHost(props) {
|
|
|
982
808
|
{
|
|
983
809
|
size: "md",
|
|
984
810
|
variant: "primary",
|
|
985
|
-
disabled: busy ||
|
|
811
|
+
disabled: busy || !ack,
|
|
986
812
|
onClick: () => void confirm()
|
|
987
813
|
},
|
|
988
|
-
|
|
814
|
+
t("confirmDeleteAction")
|
|
989
815
|
)
|
|
990
816
|
)
|
|
991
817
|
},
|
|
992
|
-
|
|
818
|
+
React2.createElement(
|
|
993
819
|
"div",
|
|
994
820
|
{ style: S.column },
|
|
995
821
|
React2.createElement(
|
|
@@ -1001,10 +827,10 @@ function DialogHost(props) {
|
|
|
1001
827
|
disabled: busy,
|
|
1002
828
|
onChange: (event) => setAck(Boolean(event.target.checked))
|
|
1003
829
|
}),
|
|
1004
|
-
|
|
830
|
+
t("ackDelete")
|
|
1005
831
|
),
|
|
1006
832
|
error ? React2.createElement("div", { style: S.error }, error) : null
|
|
1007
|
-
)
|
|
833
|
+
)
|
|
1008
834
|
);
|
|
1009
835
|
}
|
|
1010
836
|
|
|
@@ -1040,6 +866,32 @@ async function describeSession(sessionId) {
|
|
|
1040
866
|
return request;
|
|
1041
867
|
}
|
|
1042
868
|
|
|
869
|
+
// src/client/format.ts
|
|
870
|
+
function formatBytes(bytes) {
|
|
871
|
+
if (typeof bytes !== "number" || !Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
872
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
873
|
+
let value = bytes;
|
|
874
|
+
let unit = 0;
|
|
875
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
876
|
+
value /= 1024;
|
|
877
|
+
unit += 1;
|
|
878
|
+
}
|
|
879
|
+
return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
880
|
+
}
|
|
881
|
+
function formatTime(ms) {
|
|
882
|
+
if (typeof ms !== "number" || ms <= 0) return "";
|
|
883
|
+
try {
|
|
884
|
+
return new Date(ms).toLocaleString();
|
|
885
|
+
} catch {
|
|
886
|
+
return "";
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
function baseName(path) {
|
|
890
|
+
if (typeof path !== "string" || path === "") return "";
|
|
891
|
+
const parts = path.split(/[\\/]/).filter((part) => part !== "");
|
|
892
|
+
return parts.length > 0 ? parts[parts.length - 1] : path;
|
|
893
|
+
}
|
|
894
|
+
|
|
1043
895
|
// src/client/components/session-hover.ts
|
|
1044
896
|
function SessionHover(props) {
|
|
1045
897
|
const t = props.t;
|
|
@@ -1059,9 +911,8 @@ function SessionHover(props) {
|
|
|
1059
911
|
}, [props.sessionId]);
|
|
1060
912
|
if (detail === null) return null;
|
|
1061
913
|
const badges = [];
|
|
1062
|
-
if (detail.
|
|
1063
|
-
if (detail.
|
|
1064
|
-
if (detail.pinned) badges.push({ key: "pinned", label: t("hoverPinned"), danger: false });
|
|
914
|
+
if (detail.archived) badges.push({ key: "archived", label: t("hoverArchived") });
|
|
915
|
+
if (detail.pinned) badges.push({ key: "pinned", label: t("hoverPinned") });
|
|
1065
916
|
const lines = [
|
|
1066
917
|
React3.createElement(
|
|
1067
918
|
"div",
|
|
@@ -1079,16 +930,6 @@ function SessionHover(props) {
|
|
|
1079
930
|
)
|
|
1080
931
|
);
|
|
1081
932
|
}
|
|
1082
|
-
if (detail.trashed && detail.deletedAt) {
|
|
1083
|
-
lines.push(
|
|
1084
|
-
React3.createElement(
|
|
1085
|
-
"div",
|
|
1086
|
-
{ key: "deletedAt", style: S.hoverLine },
|
|
1087
|
-
React3.createElement("span", { style: S.hoverLabel }, t("hoverDeleted")),
|
|
1088
|
-
React3.createElement("span", { style: S.hoverMeta }, formatTime(detail.deletedAt))
|
|
1089
|
-
)
|
|
1090
|
-
);
|
|
1091
|
-
}
|
|
1092
933
|
if (badges.length > 0) {
|
|
1093
934
|
lines.push(
|
|
1094
935
|
React3.createElement(
|
|
@@ -1099,7 +940,7 @@ function SessionHover(props) {
|
|
|
1099
940
|
"span",
|
|
1100
941
|
{
|
|
1101
942
|
key: badge.key,
|
|
1102
|
-
style:
|
|
943
|
+
style: S.hoverBadge
|
|
1103
944
|
},
|
|
1104
945
|
badge.label
|
|
1105
946
|
)
|
|
@@ -1146,12 +987,12 @@ async function copyText(value) {
|
|
|
1146
987
|
}
|
|
1147
988
|
|
|
1148
989
|
// src/client/groups.ts
|
|
1149
|
-
function workspaceSummaries(archived, pinned
|
|
990
|
+
function workspaceSummaries(archived, pinned) {
|
|
1150
991
|
const summaries = /* @__PURE__ */ new Map();
|
|
1151
992
|
const bucketOf = (key) => {
|
|
1152
993
|
let summary = summaries.get(key);
|
|
1153
994
|
if (summary === void 0) {
|
|
1154
|
-
summary = { key, archivableIds: [],
|
|
995
|
+
summary = { key, archivableIds: [], deletableIds: [], activeIds: [] };
|
|
1155
996
|
summaries.set(key, summary);
|
|
1156
997
|
}
|
|
1157
998
|
return summary;
|
|
@@ -1160,11 +1001,10 @@ function workspaceSummaries(archived, pinned, trashed) {
|
|
|
1160
1001
|
for (const row of rows) {
|
|
1161
1002
|
const summary = bucketOf(groupKeyOf(row));
|
|
1162
1003
|
summary.archivableIds.push(row.sessionId);
|
|
1163
|
-
summary.
|
|
1004
|
+
summary.deletableIds.push(row.sessionId);
|
|
1164
1005
|
if (row.active === true) summary.activeIds.push(row.sessionId);
|
|
1165
1006
|
}
|
|
1166
1007
|
}
|
|
1167
|
-
for (const row of trashed) bucketOf(groupKeyOf(row));
|
|
1168
1008
|
return summaries;
|
|
1169
1009
|
}
|
|
1170
1010
|
function groupKeyOf(row) {
|
|
@@ -1215,13 +1055,9 @@ function sortRows(rows, order) {
|
|
|
1215
1055
|
return [...rows].sort((left, right) => (right.bytes ?? 0) - (left.bytes ?? 0));
|
|
1216
1056
|
}
|
|
1217
1057
|
if (order === "createdAt") return [...rows].sort(descending((row) => row.createdAt));
|
|
1218
|
-
if (order === "deletedAt") return [...rows].sort(descending((row) => row.deletedAt));
|
|
1219
1058
|
return rows;
|
|
1220
1059
|
}
|
|
1221
1060
|
var RECENT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1222
|
-
function isTrashRow(row) {
|
|
1223
|
-
return typeof row.deletedAt === "number";
|
|
1224
|
-
}
|
|
1225
1061
|
function matchesSearch(row, search) {
|
|
1226
1062
|
const needle = search.trim().toLowerCase();
|
|
1227
1063
|
if (needle === "") return true;
|
|
@@ -1229,7 +1065,6 @@ function matchesSearch(row, search) {
|
|
|
1229
1065
|
return haystacks.some((value) => typeof value === "string" && value.toLowerCase().includes(needle));
|
|
1230
1066
|
}
|
|
1231
1067
|
function timeStampOf(row) {
|
|
1232
|
-
if (isTrashRow(row)) return typeof row.deletedAt === "number" && row.deletedAt > 0 ? row.deletedAt : null;
|
|
1233
1068
|
if (typeof row.createdAt === "number" && row.createdAt > 0) return row.createdAt;
|
|
1234
1069
|
return null;
|
|
1235
1070
|
}
|
|
@@ -1263,21 +1098,6 @@ function toggledCollapse(key, overrides, fallback) {
|
|
|
1263
1098
|
}
|
|
1264
1099
|
|
|
1265
1100
|
// src/client/settings.ts
|
|
1266
|
-
var TRASH_RETENTION_DAYS = [7, 30, 90];
|
|
1267
|
-
var DEFAULT_TRASH_DAYS = 30;
|
|
1268
|
-
var TRASH_DAYS_MIN = 1;
|
|
1269
|
-
var TRASH_DAYS_MAX = 3650;
|
|
1270
|
-
function parseCustomDays(raw) {
|
|
1271
|
-
const trimmed = raw.trim();
|
|
1272
|
-
if (trimmed === "") return null;
|
|
1273
|
-
if (!/^\d+$/.test(trimmed)) return null;
|
|
1274
|
-
const value = Number(trimmed);
|
|
1275
|
-
if (!Number.isSafeInteger(value) || value < TRASH_DAYS_MIN || value > TRASH_DAYS_MAX) return null;
|
|
1276
|
-
return value;
|
|
1277
|
-
}
|
|
1278
|
-
function effectiveTrashDays(settings) {
|
|
1279
|
-
return parseCustomDays(settings.trashDaysCustom) ?? settings.trashDays;
|
|
1280
|
-
}
|
|
1281
1101
|
var DEFAULT_SETTINGS = {
|
|
1282
1102
|
tab: "archived",
|
|
1283
1103
|
grouping: true,
|
|
@@ -1287,9 +1107,7 @@ var DEFAULT_SETTINGS = {
|
|
|
1287
1107
|
order: "host",
|
|
1288
1108
|
autoUpdate: true,
|
|
1289
1109
|
search: "",
|
|
1290
|
-
timeFilter: "all"
|
|
1291
|
-
trashDays: DEFAULT_TRASH_DAYS,
|
|
1292
|
-
trashDaysCustom: ""
|
|
1110
|
+
timeFilter: "all"
|
|
1293
1111
|
};
|
|
1294
1112
|
var SEARCH_MAX_LENGTH = 200;
|
|
1295
1113
|
var SETTINGS_KEY = "dsh-session-curator.settings";
|
|
@@ -1304,19 +1122,14 @@ function readSettings() {
|
|
|
1304
1122
|
const value = validate(parsed[key]);
|
|
1305
1123
|
if (value !== void 0) next[key] = value;
|
|
1306
1124
|
};
|
|
1307
|
-
pick("tab", (value) => value === "archived" || value === "pinned"
|
|
1125
|
+
pick("tab", (value) => value === "archived" || value === "pinned" ? value : void 0);
|
|
1308
1126
|
pick("grouping", (value) => typeof value === "boolean" ? value : void 0);
|
|
1309
1127
|
pick("groupDefault", (value) => value === "expanded" || value === "collapsed" ? value : void 0);
|
|
1310
1128
|
pick("showMeta", (value) => typeof value === "boolean" ? value : void 0);
|
|
1311
|
-
pick(
|
|
1312
|
-
"order",
|
|
1313
|
-
(value) => value === "host" || value === "title" || value === "bytes" || value === "createdAt" || value === "deletedAt" ? value : void 0
|
|
1314
|
-
);
|
|
1129
|
+
pick("order", (value) => value === "host" || value === "title" || value === "bytes" || value === "createdAt" ? value : void 0);
|
|
1315
1130
|
pick("autoUpdate", (value) => typeof value === "boolean" ? value : void 0);
|
|
1316
1131
|
pick("search", (value) => typeof value === "string" ? value.slice(0, SEARCH_MAX_LENGTH) : void 0);
|
|
1317
1132
|
pick("timeFilter", (value) => value === "all" || value === "recent" ? value : void 0);
|
|
1318
|
-
pick("trashDays", (value) => typeof value === "number" && TRASH_RETENTION_DAYS.includes(value) ? value : void 0);
|
|
1319
|
-
pick("trashDaysCustom", (value) => typeof value === "string" ? value.slice(0, 8) : void 0);
|
|
1320
1133
|
return next;
|
|
1321
1134
|
} catch {
|
|
1322
1135
|
return { ...DEFAULT_SETTINGS };
|
|
@@ -1360,6 +1173,18 @@ function writeSidebarArchived(show) {
|
|
|
1360
1173
|
}
|
|
1361
1174
|
}
|
|
1362
1175
|
|
|
1176
|
+
// src/client/toast.ts
|
|
1177
|
+
var toastStore = createStore(null);
|
|
1178
|
+
var sequence = 0;
|
|
1179
|
+
function showNotice(message) {
|
|
1180
|
+
if (message === "") return;
|
|
1181
|
+
sequence += 1;
|
|
1182
|
+
toastStore.set({ seq: sequence, message });
|
|
1183
|
+
}
|
|
1184
|
+
function dismissToast() {
|
|
1185
|
+
toastStore.set(null);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1363
1188
|
// src/client/update.ts
|
|
1364
1189
|
var updateStore = createStore({ state: "idle", value: null, error: null });
|
|
1365
1190
|
async function checkUpdate(force) {
|
|
@@ -1497,11 +1322,11 @@ function workspaceActionsOf(t, summary) {
|
|
|
1497
1322
|
disabled: summary.archivableIds.length === 0 || summary.activeIds.length > 0
|
|
1498
1323
|
},
|
|
1499
1324
|
{
|
|
1500
|
-
id: "
|
|
1501
|
-
label: t("
|
|
1325
|
+
id: "delete",
|
|
1326
|
+
label: t("deleteWorkspace"),
|
|
1502
1327
|
icon: React5.createElement(import_dsh_client_ui_primitives3.IconTrashOutlineRegular, { size: 14 }),
|
|
1503
1328
|
danger: true,
|
|
1504
|
-
disabled: summary.
|
|
1329
|
+
disabled: summary.deletableIds.length === 0 || summary.activeIds.length > 0
|
|
1505
1330
|
}
|
|
1506
1331
|
];
|
|
1507
1332
|
}
|
|
@@ -1518,7 +1343,7 @@ function SessionRow(props) {
|
|
|
1518
1343
|
if (row.bytes) meta.push(formatBytes(row.bytes));
|
|
1519
1344
|
if (row.files) meta.push(text(t, "files", { n: row.files }));
|
|
1520
1345
|
}
|
|
1521
|
-
const time =
|
|
1346
|
+
const time = formatTime(row.createdAt);
|
|
1522
1347
|
if (time !== "") meta.push(time);
|
|
1523
1348
|
const menu = props.menu;
|
|
1524
1349
|
const running = row.active === true;
|
|
@@ -1578,12 +1403,11 @@ var React7 = __toESM(require("react"), 1);
|
|
|
1578
1403
|
var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1579
1404
|
function usageRow(t, row, busy, onArchive, onUnarchive) {
|
|
1580
1405
|
const badges = [];
|
|
1581
|
-
if (row.
|
|
1582
|
-
else if (row.archived) badges.push({ key: "archived", label: t("usageArchived"), style: S.badge });
|
|
1406
|
+
if (row.archived) badges.push({ key: "archived", label: t("usageArchived"), style: S.badge });
|
|
1583
1407
|
else if (row.pinned) badges.push({ key: "pinned", label: t("usagePinned"), style: S.badge });
|
|
1584
1408
|
if (row.active) badges.push({ key: "running", label: t("running"), style: S.badgeRunning });
|
|
1585
|
-
const action = row.
|
|
1586
|
-
const when =
|
|
1409
|
+
const action = row.archived ? { label: t("usageUnarchive"), run: () => onUnarchive(row.sessionId) } : row.active ? null : { label: t("usageArchive"), run: () => onArchive(row.sessionId) };
|
|
1410
|
+
const when = formatTime(row.createdAt);
|
|
1587
1411
|
return React7.createElement(
|
|
1588
1412
|
"div",
|
|
1589
1413
|
{ key: row.sessionId, style: S.usageRow },
|
|
@@ -1637,8 +1461,7 @@ function UsagePanel(props) {
|
|
|
1637
1461
|
{ style: S.configHint },
|
|
1638
1462
|
props.loading ? t("usageLoading") : usage === null ? props.error ?? "" : text(t, "usageTotal", {
|
|
1639
1463
|
n: usage.totalSessions,
|
|
1640
|
-
size: formatBytes(usage.totalBytes)
|
|
1641
|
-
disk: usage.onDiskSessions
|
|
1464
|
+
size: formatBytes(usage.totalBytes)
|
|
1642
1465
|
})
|
|
1643
1466
|
)
|
|
1644
1467
|
)
|
|
@@ -1696,9 +1519,6 @@ function SessionManagerPanel(props) {
|
|
|
1696
1519
|
const [collapsedOverrides, setCollapsedOverrides] = React8.useState({});
|
|
1697
1520
|
const [menuFor, setMenuFor] = React8.useState(null);
|
|
1698
1521
|
const [workspaceMenuFor, setWorkspaceMenuFor] = React8.useState(null);
|
|
1699
|
-
const [trashStats, setTrashStats] = React8.useState(null);
|
|
1700
|
-
const [trashStatsError, setTrashStatsError] = React8.useState(null);
|
|
1701
|
-
const [trashStatsBusy, setTrashStatsBusy] = React8.useState(false);
|
|
1702
1522
|
const [usage, setUsage] = React8.useState(null);
|
|
1703
1523
|
const [usageError, setUsageError] = React8.useState(null);
|
|
1704
1524
|
const [usageBusy, setUsageBusy] = React8.useState(false);
|
|
@@ -1738,26 +1558,6 @@ function SessionManagerPanel(props) {
|
|
|
1738
1558
|
setMenuFor(null);
|
|
1739
1559
|
setWorkspaceMenuFor(null);
|
|
1740
1560
|
}, [tab]);
|
|
1741
|
-
const retentionDays = effectiveTrashDays(settings);
|
|
1742
|
-
React8.useEffect(() => {
|
|
1743
|
-
if (tab !== "config") return;
|
|
1744
|
-
let cancelled = false;
|
|
1745
|
-
setTrashStatsBusy(true);
|
|
1746
|
-
setTrashStatsError(null);
|
|
1747
|
-
void call("trash-stats", { days: retentionDays }).then((value) => {
|
|
1748
|
-
if (!cancelled) setTrashStats(value);
|
|
1749
|
-
}).catch((failure) => {
|
|
1750
|
-
if (!cancelled) {
|
|
1751
|
-
setTrashStats(null);
|
|
1752
|
-
setTrashStatsError(reportError(failure));
|
|
1753
|
-
}
|
|
1754
|
-
}).finally(() => {
|
|
1755
|
-
if (!cancelled) setTrashStatsBusy(false);
|
|
1756
|
-
});
|
|
1757
|
-
return () => {
|
|
1758
|
-
cancelled = true;
|
|
1759
|
-
};
|
|
1760
|
-
}, [tab, retentionDays]);
|
|
1761
1561
|
React8.useEffect(() => {
|
|
1762
1562
|
if (tab !== "usage") return;
|
|
1763
1563
|
let cancelled = false;
|
|
@@ -1808,8 +1608,7 @@ function SessionManagerPanel(props) {
|
|
|
1808
1608
|
};
|
|
1809
1609
|
const archived = snapshot ? snapshot.archived : [];
|
|
1810
1610
|
const pinned = snapshot ? snapshot.pinned : [];
|
|
1811
|
-
const
|
|
1812
|
-
const rows = sortRows(tab === "archived" ? archived : tab === "pinned" ? pinned : tab === "trash" ? trashed : [], settings.order);
|
|
1611
|
+
const rows = sortRows(tab === "archived" ? archived : pinned, settings.order);
|
|
1813
1612
|
const filter = React8.useMemo(
|
|
1814
1613
|
() => ({ search: settings.search, timeFilter: settings.timeFilter }),
|
|
1815
1614
|
[settings.search, settings.timeFilter]
|
|
@@ -1826,7 +1625,6 @@ function SessionManagerPanel(props) {
|
|
|
1826
1625
|
const tabs = [
|
|
1827
1626
|
{ id: "archived", label: t(TAB_LABEL.archived), count: archived.length },
|
|
1828
1627
|
{ id: "pinned", label: t(TAB_LABEL.pinned), count: pinned.length },
|
|
1829
|
-
{ id: "trash", label: t(TAB_LABEL.trash), count: trashed.length },
|
|
1830
1628
|
{ id: "usage", label: t("titleUsage"), count: 0 },
|
|
1831
1629
|
{ id: "config", label: t("titleConfig"), count: 0 }
|
|
1832
1630
|
];
|
|
@@ -1834,13 +1632,9 @@ function SessionManagerPanel(props) {
|
|
|
1834
1632
|
{ value: "host", label: t("orderHost") },
|
|
1835
1633
|
{ value: "title", label: t("orderTitle") },
|
|
1836
1634
|
{ value: "bytes", label: t("orderBytes") },
|
|
1837
|
-
{ value: "createdAt", label: t("orderCreatedAt") }
|
|
1838
|
-
{ value: "deletedAt", label: t("orderDeletedAt") }
|
|
1635
|
+
{ value: "createdAt", label: t("orderCreatedAt") }
|
|
1839
1636
|
];
|
|
1840
|
-
const
|
|
1841
|
-
const customDaysValid = customDays.trim() === "" || parseCustomDays(customDays) !== null;
|
|
1842
|
-
const retentionOptions = TRASH_RETENTION_DAYS.map((days) => ({ value: days, label: text(t, "retentionDays", { n: days }) }));
|
|
1843
|
-
const summaries = React8.useMemo(() => workspaceSummaries(archived, pinned, trashed), [archived, pinned, trashed]);
|
|
1637
|
+
const summaries = React8.useMemo(() => workspaceSummaries(archived, pinned), [archived, pinned]);
|
|
1844
1638
|
const copyRowPath = async (sessionId) => {
|
|
1845
1639
|
try {
|
|
1846
1640
|
const value = await openSessionPath(sessionId);
|
|
@@ -1863,9 +1657,9 @@ function SessionManagerPanel(props) {
|
|
|
1863
1657
|
};
|
|
1864
1658
|
const rowMenu = (row) => {
|
|
1865
1659
|
const running = row.active === true;
|
|
1866
|
-
const
|
|
1867
|
-
id: "
|
|
1868
|
-
label: t("
|
|
1660
|
+
const deleteSession = {
|
|
1661
|
+
id: "delete",
|
|
1662
|
+
label: t("deleteSession"),
|
|
1869
1663
|
icon: React8.createElement(import_dsh_client_ui_primitives6.IconTrashOutlineRegular, { size: 14 }),
|
|
1870
1664
|
danger: true,
|
|
1871
1665
|
disabled: running
|
|
@@ -1890,49 +1684,27 @@ function SessionManagerPanel(props) {
|
|
|
1890
1684
|
items: [
|
|
1891
1685
|
{ id: "unarchive", label: t("unarchive"), icon: React8.createElement(import_dsh_client_ui_primitives6.IconUnarchiveOutlineRegular, { size: 14 }) },
|
|
1892
1686
|
{ id: "pin", label: t("pin"), icon: React8.createElement(import_dsh_client_ui_primitives6.IconPinOutlineRegular, { size: 14 }) },
|
|
1893
|
-
|
|
1894
|
-
...locate
|
|
1895
|
-
],
|
|
1896
|
-
run: (id) => {
|
|
1897
|
-
setMenuFor(null);
|
|
1898
|
-
if (handleLocate(id)) return;
|
|
1899
|
-
if (id === "trash") requestTrash([row.sessionId], row.title);
|
|
1900
|
-
else void run(id, [row.sessionId]);
|
|
1901
|
-
}
|
|
1902
|
-
};
|
|
1903
|
-
}
|
|
1904
|
-
if (tab === "pinned") {
|
|
1905
|
-
return {
|
|
1906
|
-
items: [
|
|
1907
|
-
{ id: "unpin", label: t("unpin"), icon: React8.createElement(import_dsh_client_ui_primitives6.IconPinOutlineRegular, { size: 14 }) },
|
|
1908
|
-
moveToTrash,
|
|
1687
|
+
deleteSession,
|
|
1909
1688
|
...locate
|
|
1910
1689
|
],
|
|
1911
1690
|
run: (id) => {
|
|
1912
1691
|
setMenuFor(null);
|
|
1913
1692
|
if (handleLocate(id)) return;
|
|
1914
|
-
if (id === "
|
|
1693
|
+
if (id === "delete") requestDelete([row.sessionId], row.title);
|
|
1915
1694
|
else void run(id, [row.sessionId]);
|
|
1916
1695
|
}
|
|
1917
1696
|
};
|
|
1918
1697
|
}
|
|
1919
|
-
const restorable = row.restorable !== false;
|
|
1920
1698
|
return {
|
|
1921
1699
|
items: [
|
|
1922
|
-
{
|
|
1923
|
-
|
|
1924
|
-
label: t(restorable ? "restore" : "restoreUnavailable"),
|
|
1925
|
-
icon: React8.createElement(import_dsh_client_ui_primitives6.IconRefreshOutlineRegular, { size: 14 }),
|
|
1926
|
-
disabled: !restorable
|
|
1927
|
-
},
|
|
1928
|
-
{ id: "purge", label: t("purge"), icon: React8.createElement(import_dsh_client_ui_primitives6.IconTrashOutlineRegular, { size: 14 }), danger: true },
|
|
1700
|
+
{ id: "unpin", label: t("unpin"), icon: React8.createElement(import_dsh_client_ui_primitives6.IconPinOutlineRegular, { size: 14 }) },
|
|
1701
|
+
deleteSession,
|
|
1929
1702
|
...locate
|
|
1930
1703
|
],
|
|
1931
1704
|
run: (id) => {
|
|
1932
1705
|
setMenuFor(null);
|
|
1933
1706
|
if (handleLocate(id)) return;
|
|
1934
|
-
if (id === "
|
|
1935
|
-
if (id === "purge") requestPurge([row.sessionId], row.title);
|
|
1707
|
+
if (id === "delete") requestDelete([row.sessionId], row.title);
|
|
1936
1708
|
else void run(id, [row.sessionId]);
|
|
1937
1709
|
}
|
|
1938
1710
|
};
|
|
@@ -1942,36 +1714,27 @@ function SessionManagerPanel(props) {
|
|
|
1942
1714
|
const summary = summaries.get(group.key);
|
|
1943
1715
|
if (summary === void 0) return;
|
|
1944
1716
|
if (id === "archive") void run("archive", summary.archivableIds);
|
|
1945
|
-
if (id === "
|
|
1717
|
+
if (id === "delete") requestDelete(summary.deletableIds, group.title);
|
|
1946
1718
|
};
|
|
1947
1719
|
const batch = [];
|
|
1948
1720
|
if (tab === "archived" && selected.length > 0) {
|
|
1949
1721
|
batch.push({ label: t("unarchive"), run: () => void run("unarchive", selected) });
|
|
1950
1722
|
batch.push({
|
|
1951
|
-
label: t("
|
|
1723
|
+
label: t("deleteSession"),
|
|
1952
1724
|
variant: "outline",
|
|
1953
|
-
run: () =>
|
|
1725
|
+
run: () => requestDelete(selected, selectedRows[0] ? selectedRows[0].title : "")
|
|
1954
1726
|
});
|
|
1955
1727
|
}
|
|
1956
1728
|
if (tab === "pinned" && selected.length > 0) {
|
|
1957
1729
|
batch.push({ label: t("unpin"), run: () => void run("unpin", selected) });
|
|
1958
1730
|
batch.push({
|
|
1959
|
-
label: t("
|
|
1731
|
+
label: t("deleteSession"),
|
|
1960
1732
|
variant: "outline",
|
|
1961
|
-
run: () =>
|
|
1962
|
-
});
|
|
1963
|
-
}
|
|
1964
|
-
if (tab === "trash" && selected.length > 0) {
|
|
1965
|
-
const canRestore = selectedRows.some((row) => row.restorable !== false);
|
|
1966
|
-
batch.push({ label: t("restore"), disabled: !canRestore, run: () => void run("restore", selected) });
|
|
1967
|
-
batch.push({
|
|
1968
|
-
label: t("purge"),
|
|
1969
|
-
variant: "outline",
|
|
1970
|
-
run: () => requestPurge(selected, selectedRows[0] ? selectedRows[0].title : "")
|
|
1733
|
+
run: () => requestDelete(selected, selectedRows[0] ? selectedRows[0].title : "")
|
|
1971
1734
|
});
|
|
1972
1735
|
}
|
|
1973
1736
|
const totals = snapshot ? snapshot.totals : null;
|
|
1974
|
-
const totalBytes = tab === "archived"
|
|
1737
|
+
const totalBytes = tab === "archived" && totals ? totals.archivedBytes : 0;
|
|
1975
1738
|
const nodes = [];
|
|
1976
1739
|
let first = true;
|
|
1977
1740
|
for (const block of blocks) {
|
|
@@ -1991,8 +1754,8 @@ function SessionManagerPanel(props) {
|
|
|
1991
1754
|
onToggleGroup: () => toggleGroup(group),
|
|
1992
1755
|
onToggleCollapse: () => toggleCollapse(key),
|
|
1993
1756
|
// 「整个工作区」:跨页签的目标集合由 `workspaceSummaries()` 算好。
|
|
1994
|
-
//
|
|
1995
|
-
//
|
|
1757
|
+
// 每个渲染出来的分组都至少有一行,所以 `summary` 一定有值;`workspaceActionsOf`
|
|
1758
|
+
// 再按"有没有在跑的会话"把危险项置 `disabled`。
|
|
1996
1759
|
workspaceActions: summary === void 0 ? [] : workspaceActionsOf(t, summary),
|
|
1997
1760
|
workspaceMenuOpen: workspaceMenuFor === group.key,
|
|
1998
1761
|
onToggleWorkspaceMenu: () => setWorkspaceMenuFor(workspaceMenuFor === group.key ? null : group.key),
|
|
@@ -2012,7 +1775,6 @@ function SessionManagerPanel(props) {
|
|
|
2012
1775
|
busy,
|
|
2013
1776
|
showCwd: block.group === null,
|
|
2014
1777
|
showMeta: settings.showMeta,
|
|
2015
|
-
showDeletedAt: tab === "trash",
|
|
2016
1778
|
checked: selected.includes(row.sessionId),
|
|
2017
1779
|
onToggle: () => toggle(row.sessionId),
|
|
2018
1780
|
menu: rowMenu(row),
|
|
@@ -2038,29 +1800,6 @@ function SessionManagerPanel(props) {
|
|
|
2038
1800
|
),
|
|
2039
1801
|
React8.createElement("div", { style: S.configControl }, control)
|
|
2040
1802
|
);
|
|
2041
|
-
const retentionCount = trashStats === null ? 0 : trashStats.count;
|
|
2042
|
-
const retentionBytes = trashStats === null ? 0 : trashStats.bytes;
|
|
2043
|
-
const retentionFoot = React8.createElement(
|
|
2044
|
-
"div",
|
|
2045
|
-
{ key: "config:trash-preview", style: S.configFoot },
|
|
2046
|
-
trashStatsBusy ? React8.createElement("span", { style: S.configHint }, t("trashPreviewLoading")) : trashStatsError !== null ? React8.createElement("span", { style: S.error }, trashStatsError) : React8.createElement(
|
|
2047
|
-
"span",
|
|
2048
|
-
{ style: S.configHint },
|
|
2049
|
-
retentionCount > 0 ? text(t, "trashPreview", { n: retentionCount, size: formatBytes(retentionBytes) }) : text(t, "trashPreviewNone", { days: retentionDays })
|
|
2050
|
-
),
|
|
2051
|
-
React8.createElement(
|
|
2052
|
-
import_dsh_client_ui_primitives6.Button,
|
|
2053
|
-
{
|
|
2054
|
-
size: "sm",
|
|
2055
|
-
variant: "outline",
|
|
2056
|
-
// 自定义天数非法时不给点:这时候 `retentionDays` 回落到档位,点下去删的和看到的
|
|
2057
|
-
// 那行数字对不上(虽然那行也是按档位算的,但用户以为自己填的数生效了)。
|
|
2058
|
-
disabled: busy || trashStatsBusy || retentionCount === 0 || !customDaysValid,
|
|
2059
|
-
onClick: () => requestPurgeOld(retentionDays, retentionCount, retentionBytes)
|
|
2060
|
-
},
|
|
2061
|
-
text(t, "trashCleanup", { n: retentionDays })
|
|
2062
|
-
)
|
|
2063
|
-
);
|
|
2064
1803
|
const filterBar = React8.createElement(
|
|
2065
1804
|
"div",
|
|
2066
1805
|
{ style: S.filterBar },
|
|
@@ -2115,8 +1854,7 @@ function SessionManagerPanel(props) {
|
|
|
2115
1854
|
value: settings.tab,
|
|
2116
1855
|
options: [
|
|
2117
1856
|
{ value: "archived", label: t(TAB_LABEL.archived) },
|
|
2118
|
-
{ value: "pinned", label: t(TAB_LABEL.pinned) }
|
|
2119
|
-
{ value: "trash", label: t(TAB_LABEL.trash) }
|
|
1857
|
+
{ value: "pinned", label: t(TAB_LABEL.pinned) }
|
|
2120
1858
|
],
|
|
2121
1859
|
label: t("configTab"),
|
|
2122
1860
|
onChange: (next) => void updateSettings({ tab: next })
|
|
@@ -2209,39 +1947,6 @@ function SessionManagerPanel(props) {
|
|
|
2209
1947
|
onChange: (next) => void updateSettings({ order: next })
|
|
2210
1948
|
})
|
|
2211
1949
|
),
|
|
2212
|
-
// ── 回收站保留策略 ──────────────────────────────────────────────
|
|
2213
|
-
// 这条**故意不做成自动清理**:它是本插件唯一不可撤销的动作。这里只让用户选一个
|
|
2214
|
-
// 天数(档位或自定义)并看到预览,真正的删除必须再点一次、再过一道确认弹窗(`purge-old`)。
|
|
2215
|
-
configRow(
|
|
2216
|
-
"config:trash-days",
|
|
2217
|
-
t("configTrashDays"),
|
|
2218
|
-
t("configTrashDaysHint"),
|
|
2219
|
-
React8.createElement(
|
|
2220
|
-
"div",
|
|
2221
|
-
{ style: S.retentionDays },
|
|
2222
|
-
React8.createElement(Dropdown, {
|
|
2223
|
-
id: "session-curator-trash-days",
|
|
2224
|
-
value: settings.trashDays,
|
|
2225
|
-
options: retentionOptions,
|
|
2226
|
-
label: t("configTrashDays"),
|
|
2227
|
-
// 填了自定义天数时锚点显示"自定义",否则显示档位 —— 让"现在到底按哪个算"一眼可见。
|
|
2228
|
-
display: customDaysValid && customDays.trim() !== "" ? t("retentionCustom") : void 0,
|
|
2229
|
-
open: openDropdown === "trash-days",
|
|
2230
|
-
onToggle: (next) => setOpenDropdown(next ? "trash-days" : null),
|
|
2231
|
-
onChange: (next) => void updateSettings({ trashDays: next, trashDaysCustom: "" })
|
|
2232
|
-
}),
|
|
2233
|
-
React8.createElement(import_dsh_client_ui_primitives6.Input, {
|
|
2234
|
-
value: customDays,
|
|
2235
|
-
placeholder: t("customDaysPlaceholder"),
|
|
2236
|
-
"aria-label": t("customDaysLabel"),
|
|
2237
|
-
"aria-invalid": !customDaysValid,
|
|
2238
|
-
title: text(t, "customDaysHint", { min: TRASH_DAYS_MIN, max: TRASH_DAYS_MAX }),
|
|
2239
|
-
style: customDaysValid ? S.customDaysInput : { ...S.customDaysInput, ...S.customDaysInvalid },
|
|
2240
|
-
onChange: (event) => void updateSettings({ trashDaysCustom: event.target.value })
|
|
2241
|
-
})
|
|
2242
|
-
)
|
|
2243
|
-
),
|
|
2244
|
-
retentionFoot,
|
|
2245
1950
|
configRow(
|
|
2246
1951
|
"config:auto",
|
|
2247
1952
|
t("configAutoUpdate"),
|
|
@@ -2416,7 +2121,7 @@ function SessionManagerPanel(props) {
|
|
|
2416
2121
|
loading && !snapshot ? React8.createElement("div", { style: S.empty }, t("loading")) : filtered.length === 0 ? React8.createElement(
|
|
2417
2122
|
"div",
|
|
2418
2123
|
{ style: S.empty },
|
|
2419
|
-
filtering ? t("emptyFiltered") : tab === "archived" ? t("emptyArchived") :
|
|
2124
|
+
filtering ? t("emptyFiltered") : tab === "archived" ? t("emptyArchived") : t("emptyPinned")
|
|
2420
2125
|
) : React8.createElement("div", { style: S.list }, nodes)
|
|
2421
2126
|
) : null,
|
|
2422
2127
|
isDataTab ? React8.createElement(
|
|
@@ -2445,19 +2150,6 @@ function SessionManagerPanel(props) {
|
|
|
2445
2150
|
action.label
|
|
2446
2151
|
)
|
|
2447
2152
|
),
|
|
2448
|
-
tab === "trash" && trashed.length > 0 ? React8.createElement(
|
|
2449
|
-
import_dsh_client_ui_primitives6.Button,
|
|
2450
|
-
{
|
|
2451
|
-
size: "sm",
|
|
2452
|
-
variant: "outline",
|
|
2453
|
-
disabled: busy,
|
|
2454
|
-
onClick: () => requestPurge(
|
|
2455
|
-
trashed.map((row) => row.sessionId),
|
|
2456
|
-
""
|
|
2457
|
-
)
|
|
2458
|
-
},
|
|
2459
|
-
t("emptyTrashAll")
|
|
2460
|
-
) : null,
|
|
2461
2153
|
busy ? React8.createElement("span", { style: S.footer }, t("working")) : null
|
|
2462
2154
|
) : null,
|
|
2463
2155
|
isUsage ? usagePage : null,
|
|
@@ -2470,7 +2162,7 @@ function SessionManagerPanel(props) {
|
|
|
2470
2162
|
filtering ? React8.createElement("span", null, text(t, "filtered", { n: filtered.length, total: rows.length })) : null,
|
|
2471
2163
|
grouping && groups.length > 0 ? React8.createElement("span", null, text(t, "workspaces", { n: groups.length })) : null,
|
|
2472
2164
|
selected.length > 0 ? React8.createElement("span", null, text(t, "selected", { n: selected.length })) : null,
|
|
2473
|
-
snapshot ? React8.createElement("span", { style: S.mono, title: snapshot.
|
|
2165
|
+
snapshot ? React8.createElement("span", { style: S.mono, title: snapshot.sessionsDir }, snapshot.sessionsDir) : null
|
|
2474
2166
|
) : null
|
|
2475
2167
|
);
|
|
2476
2168
|
}
|
|
@@ -2480,52 +2172,26 @@ var React9 = __toESM(require("react"), 1);
|
|
|
2480
2172
|
var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2481
2173
|
var HOLD_MS = 5e3;
|
|
2482
2174
|
function ToastHost(props) {
|
|
2483
|
-
const t = props.t;
|
|
2484
2175
|
const notice = useStore(toastStore);
|
|
2485
2176
|
if (notice === null) return null;
|
|
2486
|
-
if (notice.error !== null) {
|
|
2487
|
-
return React9.createElement(
|
|
2488
|
-
import_dsh_client_ui_primitives7.Toast,
|
|
2489
|
-
{
|
|
2490
|
-
text: text(t, "toastUndoFailed", { reason: notice.error }),
|
|
2491
|
-
icon: React9.createElement(import_dsh_client_ui_primitives7.IconWarningOutlineRegular, {}),
|
|
2492
|
-
onDone: dismissToast
|
|
2493
|
-
},
|
|
2494
|
-
`session-curator-toast-${notice.seq}`
|
|
2495
|
-
);
|
|
2496
|
-
}
|
|
2497
|
-
if (notice.ids.length === 0) {
|
|
2498
|
-
return React9.createElement(
|
|
2499
|
-
import_dsh_client_ui_primitives7.Toast,
|
|
2500
|
-
{
|
|
2501
|
-
text: notice.title,
|
|
2502
|
-
holdMs: HOLD_MS,
|
|
2503
|
-
onDone: dismissToast
|
|
2504
|
-
},
|
|
2505
|
-
`session-curator-toast-${notice.seq}`
|
|
2506
|
-
);
|
|
2507
|
-
}
|
|
2508
|
-
const many = notice.ids.length > 1;
|
|
2509
2177
|
return React9.createElement(
|
|
2510
2178
|
import_dsh_client_ui_primitives7.Toast,
|
|
2511
2179
|
{
|
|
2512
|
-
text:
|
|
2513
|
-
tone: "success",
|
|
2180
|
+
text: notice.message,
|
|
2514
2181
|
holdMs: HOLD_MS,
|
|
2515
|
-
actions: [{ label: t("toastUndo"), onClick: () => void undoTrash() }],
|
|
2516
2182
|
onDone: dismissToast
|
|
2517
2183
|
},
|
|
2518
2184
|
`session-curator-toast-${notice.seq}`
|
|
2519
2185
|
);
|
|
2520
2186
|
}
|
|
2521
2187
|
|
|
2522
|
-
// src/client/components/
|
|
2188
|
+
// src/client/components/delete-row-button.ts
|
|
2523
2189
|
var React10 = __toESM(require("react"), 1);
|
|
2524
2190
|
var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2525
|
-
function
|
|
2191
|
+
function DeleteRowButton(props) {
|
|
2526
2192
|
const [hovered, setHovered] = React10.useState(false);
|
|
2527
2193
|
const title = props.displayTitle || props.sessionId;
|
|
2528
|
-
const label = props.t("
|
|
2194
|
+
const label = props.t("deleteSession");
|
|
2529
2195
|
return React10.createElement(import_dsh_client_ui_primitives8.Tooltip, {
|
|
2530
2196
|
label,
|
|
2531
2197
|
side: "bottom",
|
|
@@ -2539,7 +2205,7 @@ function TrashRowButton(props) {
|
|
|
2539
2205
|
"aria-label": `${title} — ${label}`,
|
|
2540
2206
|
onPointerEnter: () => setHovered(true),
|
|
2541
2207
|
onPointerLeave: () => setHovered(false),
|
|
2542
|
-
onClick: () =>
|
|
2208
|
+
onClick: () => requestDelete([props.sessionId], title)
|
|
2543
2209
|
},
|
|
2544
2210
|
React10.createElement(import_dsh_client_ui_primitives8.IconTrashOutlineRegular, { size: 14 })
|
|
2545
2211
|
)
|
|
@@ -2551,7 +2217,7 @@ var MENU_ID = "session-curator.delete";
|
|
|
2551
2217
|
var OVERLAY_ID = "session-curator.dialog";
|
|
2552
2218
|
var TOAST_ID = "session-curator.toast";
|
|
2553
2219
|
var HOVER_ID = "session-curator.hover";
|
|
2554
|
-
var ROW_ACTION_ID = "session-curator.
|
|
2220
|
+
var ROW_ACTION_ID = "session-curator.delete-row";
|
|
2555
2221
|
var SECTION_ID = "session-curator";
|
|
2556
2222
|
var NAV_SECTION_ID = "archived-sessions";
|
|
2557
2223
|
function sectionIdFor(ctx) {
|
|
@@ -2581,7 +2247,7 @@ function apply(ctx) {
|
|
|
2581
2247
|
name: "sidebar.workspaces.session.menu.item",
|
|
2582
2248
|
id: MENU_ID,
|
|
2583
2249
|
order: 500,
|
|
2584
|
-
label: () => t("
|
|
2250
|
+
label: () => t("deleteSession"),
|
|
2585
2251
|
locale: NS
|
|
2586
2252
|
},
|
|
2587
2253
|
(props) => {
|
|
@@ -2593,10 +2259,10 @@ function apply(ctx) {
|
|
|
2593
2259
|
separatorBefore: true,
|
|
2594
2260
|
onSelect: () => {
|
|
2595
2261
|
setMenuOpen(false);
|
|
2596
|
-
|
|
2262
|
+
requestDelete([props.sessionId], props.displayTitle || props.sessionId);
|
|
2597
2263
|
}
|
|
2598
2264
|
},
|
|
2599
|
-
t("
|
|
2265
|
+
t("deleteSession")
|
|
2600
2266
|
);
|
|
2601
2267
|
},
|
|
2602
2268
|
"menu item"
|
|
@@ -2644,7 +2310,7 @@ function apply(ctx) {
|
|
|
2644
2310
|
order: 500,
|
|
2645
2311
|
locale: NS
|
|
2646
2312
|
},
|
|
2647
|
-
|
|
2313
|
+
DeleteRowButton,
|
|
2648
2314
|
"row action"
|
|
2649
2315
|
);
|
|
2650
2316
|
contribute(
|