@morehao/dsh-github-trending 0.5.1 → 0.6.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/CHANGELOG.md +50 -0
- package/README.md +11 -7
- package/client.js +1351 -220
- package/lib/{chunk-R7EUBUTS.js → chunk-WDBZAMWN.js} +632 -145
- package/lib/index.js +5 -1
- package/lib/internal.d.ts +251 -20
- package/lib/internal.js +1 -1
- package/package.json +2 -2
package/client.js
CHANGED
|
@@ -306,6 +306,26 @@ var DICT = {
|
|
|
306
306
|
"runs.filter.monthly": "月榜",
|
|
307
307
|
"runs.filter.failed": "失败",
|
|
308
308
|
"runs.filter.dry": "试跑",
|
|
309
|
+
"runs.type.all": "全部",
|
|
310
|
+
"runs.type.digest": "日报",
|
|
311
|
+
"runs.type.release": "发版",
|
|
312
|
+
"runs.release.empty": "还没有发版运行记录",
|
|
313
|
+
"runs.release.status.ok": "成功",
|
|
314
|
+
"runs.release.status.failed": "失败",
|
|
315
|
+
"runs.release.status.skipped": "跳过",
|
|
316
|
+
"runs.release.status.cancelled": "已取消",
|
|
317
|
+
"runs.release.checked": "检查",
|
|
318
|
+
"runs.release.changed": "有变化",
|
|
319
|
+
"runs.release.newTags": "新版本",
|
|
320
|
+
"runs.release.summarized": "已摘要",
|
|
321
|
+
"runs.release.degraded": "降级",
|
|
322
|
+
"runs.release.failed": "失败仓库",
|
|
323
|
+
"runs.release.rateLimited": "限流",
|
|
324
|
+
"runs.release.duration": "耗时",
|
|
325
|
+
"runs.release.startedAt": "开始",
|
|
326
|
+
"runs.release.finishedAt": "结束",
|
|
327
|
+
"runs.release.error": "错误",
|
|
328
|
+
"runs.release.note": "发版运行只做订阅检查与文档渲染,不产出日报、也不合并待提交的订阅改动。",
|
|
309
329
|
"runs.pendingPr": "待合并",
|
|
310
330
|
"runs.prUnknown": "状态未知",
|
|
311
331
|
"runs.prCreated": "PR 已创建",
|
|
@@ -413,23 +433,104 @@ var DICT = {
|
|
|
413
433
|
"releases.notesChars": "notes 截断",
|
|
414
434
|
"releases.notesChars.help": "单个 Release notes 的截断长度,避免提示词过长(500–20000)。",
|
|
415
435
|
"releases.manage": "管理订阅列表 →",
|
|
416
|
-
"
|
|
417
|
-
"
|
|
418
|
-
"
|
|
419
|
-
"
|
|
436
|
+
"releases.schedule.title": "定时检查",
|
|
437
|
+
"releases.schedule.enabled": "启用每周检查",
|
|
438
|
+
"releases.schedule.help": "每周在一个固定时刻检查全部订阅仓库的新 Release;与榜单调度互相独立。",
|
|
439
|
+
"releases.schedule.weekday": "周几",
|
|
440
|
+
"releases.schedule.time": "时间",
|
|
441
|
+
"releases.schedule.timezone": "时区",
|
|
442
|
+
"releases.schedule.hint": "由插件自己的 60 s tick 触发;错过时刻 6 h 内补跑一次,同一 ISO 周不重复(核心侧还有一道周闸门)。",
|
|
443
|
+
"releases.concurrency": "检查并发",
|
|
444
|
+
"releases.concurrency.help": "同时检查几个仓库;「自动」按订阅数解析(clamp(4, ceil(N/10), 8))。",
|
|
445
|
+
"releases.concurrency.auto": "自动",
|
|
446
|
+
"releases.concurrency.fixed": "指定",
|
|
447
|
+
"releases.budget": "模型预算(秒)",
|
|
448
|
+
"releases.budget.help": "发版阶段调模型的预算总时长;「自动」按订阅数解析(min(300, 30 + 3×N))。",
|
|
449
|
+
"releases.budget.auto": "自动",
|
|
450
|
+
"releases.budget.fixed": "指定",
|
|
451
|
+
"subs.title": "订阅",
|
|
452
|
+
"subs.desc": "输入 owner/repo 立刻知道订没订;每行带最近版本、最近总结与状态,点「变更」看每周记录。",
|
|
453
|
+
"subs.select": "选择",
|
|
454
|
+
"subs.select.done": "完成",
|
|
455
|
+
"subs.cmd.placeholder": "搜索 owner/repo,或输入完整仓库名直接添加",
|
|
456
|
+
"subs.cmd.label": "搜索或添加仓库",
|
|
457
|
+
"subs.cmd.add": "添加",
|
|
458
|
+
"subs.cmd.add.hint": "回车 · 下次运行随产物提交",
|
|
459
|
+
"subs.cmd.subscribed": "已订阅",
|
|
460
|
+
"subs.cmd.subscribed.hint": "已在清单里",
|
|
461
|
+
"subs.meta.count": "{count} 个仓库",
|
|
462
|
+
"subs.meta.cadence": "每周一次",
|
|
463
|
+
"subs.meta.cadence.full": "每周一次({weekday} {time},可在设置里改)",
|
|
464
|
+
"subs.meta.next": "下次 {time}",
|
|
465
|
+
"subs.meta.match": "匹配 {matched} / {total}",
|
|
466
|
+
"subs.meta.lastWeek": "上周 {from} ~ {to} · {changed} 个仓库有变化",
|
|
467
|
+
"subs.meta.thisWeek": "本周 {from} ~ {to} · {changed} 个仓库有变化",
|
|
468
|
+
"subs.meta.lastCheck": "上次发版检查 {time}",
|
|
469
|
+
"subs.add": "添加",
|
|
420
470
|
"subs.add.placeholder": "denoland/deno",
|
|
421
471
|
"subs.add.confirm": "添加",
|
|
422
472
|
"subs.adding": "添加中…",
|
|
423
473
|
"subs.cancel": "取消",
|
|
424
|
-
"subs.add.
|
|
425
|
-
"subs.
|
|
426
|
-
"subs.
|
|
474
|
+
"subs.add.queued": "已添加 {repo},下次运行随产物提交。",
|
|
475
|
+
"subs.remove.queued": "已移除 {repo},下次运行随产物提交。",
|
|
476
|
+
"subs.removed.many": "已移除 {count} 个仓库,下次运行随产物提交。",
|
|
427
477
|
"subs.remove": "移除",
|
|
428
478
|
"subs.removing": "移除中…",
|
|
479
|
+
"subs.row.changes": "变更",
|
|
480
|
+
"subs.row.changesRepo": "查看 {repo} 的变更",
|
|
481
|
+
"subs.row.removeRepo": "移除 {repo}",
|
|
482
|
+
"subs.col.repo": "仓库",
|
|
483
|
+
"subs.col.tag": "最近版本",
|
|
484
|
+
"subs.col.summary": "最近总结",
|
|
485
|
+
"subs.col.status": "状态",
|
|
486
|
+
"subs.col.actions": "行操作",
|
|
487
|
+
"subs.sort.by": "按{column}排序",
|
|
488
|
+
"subs.status.ok": "已更新",
|
|
489
|
+
"subs.status.no_change": "无变化",
|
|
490
|
+
"subs.status.baseline": "待首次检查",
|
|
491
|
+
"subs.status.rate_limited": "限流",
|
|
492
|
+
"subs.status.failed": "失败",
|
|
493
|
+
"subs.keys.move": "↑↓ 移动",
|
|
494
|
+
"subs.keys.enter": "Enter 打开变更 / 添加",
|
|
495
|
+
"subs.keys.esc": "Esc 清空搜索",
|
|
496
|
+
"subs.keys.sort": "点表头排序",
|
|
497
|
+
"subs.sel.count": "已选 {count} 个仓库",
|
|
498
|
+
"subs.sel.all": "全选匹配 {count} 个",
|
|
499
|
+
"subs.sel.clear": "取消",
|
|
500
|
+
"subs.sel.remove": "移除所选",
|
|
501
|
+
"subs.sel.check": "选择 {repo}",
|
|
502
|
+
"subs.sel.column": "选择",
|
|
503
|
+
"subs.confirm.title": "移除 {count} 个仓库",
|
|
504
|
+
"subs.confirm.body": "移除只写入待提交队列,下次运行时随产物一起提交。",
|
|
505
|
+
"subs.confirm.more": "还有 {count} 个",
|
|
506
|
+
"subs.confirm.cancel": "取消",
|
|
507
|
+
"subs.confirm.ok": "确认移除",
|
|
429
508
|
"subs.empty": "还没有订阅任何仓库",
|
|
509
|
+
"subs.empty.hint": "在上面的输入框里输入 owner/repo,回车添加。",
|
|
510
|
+
"subs.empty.match": "没有匹配的仓库",
|
|
511
|
+
"subs.empty.match.hint": "按 Esc 清空搜索,或换一个 owner / 名字。",
|
|
512
|
+
"subs.empty.clear": "清除搜索",
|
|
430
513
|
"subs.loading": "加载订阅列表…",
|
|
431
514
|
"subs.input.invalid": "请输入 owner/repo 形态,例如 vercel/next.js",
|
|
432
|
-
"subs.
|
|
515
|
+
"subs.drawer.title": "发版记录 · {repo}",
|
|
516
|
+
"subs.drawer.close": "关闭",
|
|
517
|
+
"subs.drawer.updated": "最近更新 {date}",
|
|
518
|
+
"subs.drawer.volume": "第 {index} 册 / 共 {total} 册",
|
|
519
|
+
"subs.drawer.prevVolume": "上一册",
|
|
520
|
+
"subs.drawer.nextVolume": "下一册",
|
|
521
|
+
"subs.drawer.loading": "读取发版记录…",
|
|
522
|
+
"subs.drawer.empty": "这个仓库还没有发版记录,第一周检查后会出现在这里",
|
|
523
|
+
"subs.drawer.retry": "重试",
|
|
524
|
+
"subs.drawer.warn.rate_limited": "本周未更新(限流),下次运行会重试",
|
|
525
|
+
"subs.drawer.warn.failed": "本周未更新(失败),下次运行会重试",
|
|
526
|
+
"subs.drawer.note": "数据仓 {path},每周追加一节、新版本在上;面板只读,不改写原文。",
|
|
527
|
+
"weekday.1": "周一",
|
|
528
|
+
"weekday.2": "周二",
|
|
529
|
+
"weekday.3": "周三",
|
|
530
|
+
"weekday.4": "周四",
|
|
531
|
+
"weekday.5": "周五",
|
|
532
|
+
"weekday.6": "周六",
|
|
533
|
+
"weekday.7": "周日",
|
|
433
534
|
"subs.param.hint": "阶段行为参数(每仓上限、回退 Tag、周期等)在设置页「发版订阅」分区调整。",
|
|
434
535
|
"subs.param.link": "前往设置 → 发版订阅",
|
|
435
536
|
"overview.tokens.title": "Token 用量",
|
|
@@ -712,6 +813,26 @@ var DICT = {
|
|
|
712
813
|
"runs.filter.monthly": "Monthly",
|
|
713
814
|
"runs.filter.failed": "Failed",
|
|
714
815
|
"runs.filter.dry": "Dry run",
|
|
816
|
+
"runs.type.all": "All",
|
|
817
|
+
"runs.type.digest": "Digest",
|
|
818
|
+
"runs.type.release": "Release",
|
|
819
|
+
"runs.release.empty": "No release runs yet",
|
|
820
|
+
"runs.release.status.ok": "OK",
|
|
821
|
+
"runs.release.status.failed": "Failed",
|
|
822
|
+
"runs.release.status.skipped": "Skipped",
|
|
823
|
+
"runs.release.status.cancelled": "Cancelled",
|
|
824
|
+
"runs.release.checked": "checked",
|
|
825
|
+
"runs.release.changed": "changed",
|
|
826
|
+
"runs.release.newTags": "new tags",
|
|
827
|
+
"runs.release.summarized": "summarized",
|
|
828
|
+
"runs.release.degraded": "degraded",
|
|
829
|
+
"runs.release.failed": "failed",
|
|
830
|
+
"runs.release.rateLimited": "rate limited",
|
|
831
|
+
"runs.release.duration": "Duration",
|
|
832
|
+
"runs.release.startedAt": "Started",
|
|
833
|
+
"runs.release.finishedAt": "Finished",
|
|
834
|
+
"runs.release.error": "Error",
|
|
835
|
+
"runs.release.note": "A release run only checks subscriptions and renders documents; it produces no digest and does not merge pending subscription changes.",
|
|
715
836
|
"runs.pendingPr": "Pending merge",
|
|
716
837
|
"runs.prUnknown": "State unknown",
|
|
717
838
|
"runs.prCreated": "PR created",
|
|
@@ -819,23 +940,104 @@ var DICT = {
|
|
|
819
940
|
"releases.notesChars": "Notes truncate",
|
|
820
941
|
"releases.notesChars.help": "Truncate each release notes to this length to keep prompts bounded (500–20000).",
|
|
821
942
|
"releases.manage": "Manage subscriptions →",
|
|
822
|
-
"
|
|
823
|
-
"
|
|
824
|
-
"
|
|
825
|
-
"
|
|
943
|
+
"releases.schedule.title": "Weekly check",
|
|
944
|
+
"releases.schedule.enabled": "Enable weekly check",
|
|
945
|
+
"releases.schedule.help": "Check every subscribed repo for new releases at a fixed moment each week; independent of the board schedule.",
|
|
946
|
+
"releases.schedule.weekday": "Weekday",
|
|
947
|
+
"releases.schedule.time": "Time",
|
|
948
|
+
"releases.schedule.timezone": "Time zone",
|
|
949
|
+
"releases.schedule.hint": "Driven by the plugin’s own 60 s tick; a missed moment is caught up within 6 h once, and the same ISO week never runs twice (the core also has a week gate).",
|
|
950
|
+
"releases.concurrency": "Check concurrency",
|
|
951
|
+
"releases.concurrency.help": "How many repos to check at once; “Auto” resolves by subscription count (clamp(4, ceil(N/10), 8)).",
|
|
952
|
+
"releases.concurrency.auto": "Auto",
|
|
953
|
+
"releases.concurrency.fixed": "Fixed",
|
|
954
|
+
"releases.budget": "Model budget (s)",
|
|
955
|
+
"releases.budget.help": "Overall budget for model calls in the releases stage; “Auto” resolves by subscription count (min(300, 30 + 3×N)).",
|
|
956
|
+
"releases.budget.auto": "Auto",
|
|
957
|
+
"releases.budget.fixed": "Fixed",
|
|
958
|
+
"subs.title": "Subscriptions",
|
|
959
|
+
"subs.desc": "Type owner/repo to see instantly whether it is subscribed; each row carries its latest version, latest weekly summary and status, and “Changes” opens the weekly record.",
|
|
960
|
+
"subs.select": "Select",
|
|
961
|
+
"subs.select.done": "Done",
|
|
962
|
+
"subs.cmd.placeholder": "Search owner/repo, or type a full repo name to add it",
|
|
963
|
+
"subs.cmd.label": "Search or add a repo",
|
|
964
|
+
"subs.cmd.add": "Add",
|
|
965
|
+
"subs.cmd.add.hint": "Enter · committed with artifacts on the next run",
|
|
966
|
+
"subs.cmd.subscribed": "Subscribed",
|
|
967
|
+
"subs.cmd.subscribed.hint": "Already in the list",
|
|
968
|
+
"subs.meta.count": "{count} repos",
|
|
969
|
+
"subs.meta.cadence": "Weekly",
|
|
970
|
+
"subs.meta.cadence.full": "Weekly ({weekday} {time}, changeable in Settings)",
|
|
971
|
+
"subs.meta.next": "Next {time}",
|
|
972
|
+
"subs.meta.match": "Match {matched} / {total}",
|
|
973
|
+
"subs.meta.lastWeek": "Last week {from} ~ {to} · {changed} repos changed",
|
|
974
|
+
"subs.meta.thisWeek": "This week {from} ~ {to} · {changed} repos changed",
|
|
975
|
+
"subs.meta.lastCheck": "Last release check {time}",
|
|
976
|
+
"subs.add": "Add",
|
|
826
977
|
"subs.add.placeholder": "denoland/deno",
|
|
827
978
|
"subs.add.confirm": "Add",
|
|
828
979
|
"subs.adding": "Adding…",
|
|
829
980
|
"subs.cancel": "Cancel",
|
|
830
|
-
"subs.add.
|
|
831
|
-
"subs.
|
|
832
|
-
"subs.
|
|
981
|
+
"subs.add.queued": "Added {repo}; committed with artifacts on the next run.",
|
|
982
|
+
"subs.remove.queued": "Removed {repo}; committed with artifacts on the next run.",
|
|
983
|
+
"subs.removed.many": "Removed {count} repos; committed with artifacts on the next run.",
|
|
833
984
|
"subs.remove": "Remove",
|
|
834
985
|
"subs.removing": "Removing…",
|
|
986
|
+
"subs.row.changes": "Changes",
|
|
987
|
+
"subs.row.changesRepo": "Show changes for {repo}",
|
|
988
|
+
"subs.row.removeRepo": "Remove {repo}",
|
|
989
|
+
"subs.col.repo": "Repo",
|
|
990
|
+
"subs.col.tag": "Latest version",
|
|
991
|
+
"subs.col.summary": "Latest summary",
|
|
992
|
+
"subs.col.status": "Status",
|
|
993
|
+
"subs.col.actions": "Row actions",
|
|
994
|
+
"subs.sort.by": "Sort by {column}",
|
|
995
|
+
"subs.status.ok": "Updated",
|
|
996
|
+
"subs.status.no_change": "No change",
|
|
997
|
+
"subs.status.baseline": "Awaiting first check",
|
|
998
|
+
"subs.status.rate_limited": "Rate limited",
|
|
999
|
+
"subs.status.failed": "Failed",
|
|
1000
|
+
"subs.keys.move": "↑↓ move",
|
|
1001
|
+
"subs.keys.enter": "Enter opens changes / adds",
|
|
1002
|
+
"subs.keys.esc": "Esc clears the search",
|
|
1003
|
+
"subs.keys.sort": "Click a header to sort",
|
|
1004
|
+
"subs.sel.count": "Selected {count} repos",
|
|
1005
|
+
"subs.sel.all": "Select all {count} matches",
|
|
1006
|
+
"subs.sel.clear": "Cancel",
|
|
1007
|
+
"subs.sel.remove": "Remove selected",
|
|
1008
|
+
"subs.sel.check": "Select {repo}",
|
|
1009
|
+
"subs.sel.column": "Select",
|
|
1010
|
+
"subs.confirm.title": "Remove {count} repos",
|
|
1011
|
+
"subs.confirm.body": "Removal only writes the pending queue; it is committed with artifacts on the next run.",
|
|
1012
|
+
"subs.confirm.more": "and {count} more",
|
|
1013
|
+
"subs.confirm.cancel": "Cancel",
|
|
1014
|
+
"subs.confirm.ok": "Remove",
|
|
835
1015
|
"subs.empty": "No repos subscribed yet",
|
|
1016
|
+
"subs.empty.hint": "Type owner/repo in the field above and press Enter to add one.",
|
|
1017
|
+
"subs.empty.match": "No matching repos",
|
|
1018
|
+
"subs.empty.match.hint": "Press Esc to clear the search, or try another owner / name.",
|
|
1019
|
+
"subs.empty.clear": "Clear search",
|
|
836
1020
|
"subs.loading": "Loading subscriptions…",
|
|
837
1021
|
"subs.input.invalid": "Enter owner/repo form, e.g. vercel/next.js",
|
|
838
|
-
"subs.
|
|
1022
|
+
"subs.drawer.title": "Release record · {repo}",
|
|
1023
|
+
"subs.drawer.close": "Close",
|
|
1024
|
+
"subs.drawer.updated": "Updated {date}",
|
|
1025
|
+
"subs.drawer.volume": "Volume {index} of {total}",
|
|
1026
|
+
"subs.drawer.prevVolume": "Previous volume",
|
|
1027
|
+
"subs.drawer.nextVolume": "Next volume",
|
|
1028
|
+
"subs.drawer.loading": "Reading the release record…",
|
|
1029
|
+
"subs.drawer.empty": "This repo has no release record yet; it appears here after the first weekly check.",
|
|
1030
|
+
"subs.drawer.retry": "Retry",
|
|
1031
|
+
"subs.drawer.warn.rate_limited": "Not updated this week (rate limited); the next run retries.",
|
|
1032
|
+
"subs.drawer.warn.failed": "Not updated this week (failed); the next run retries.",
|
|
1033
|
+
"subs.drawer.note": "Data repo {path} — one section appended per week, newest first; the panel is read-only and never rewrites the text.",
|
|
1034
|
+
"weekday.1": "Mon",
|
|
1035
|
+
"weekday.2": "Tue",
|
|
1036
|
+
"weekday.3": "Wed",
|
|
1037
|
+
"weekday.4": "Thu",
|
|
1038
|
+
"weekday.5": "Fri",
|
|
1039
|
+
"weekday.6": "Sat",
|
|
1040
|
+
"weekday.7": "Sun",
|
|
839
1041
|
"subs.param.hint": "Stage behaviour parameters (per-repo limit, tag fallback, period, etc.) are adjusted in the settings page Releases section.",
|
|
840
1042
|
"subs.param.link": "Go to Settings → Releases",
|
|
841
1043
|
"overview.tokens.title": "Token usage",
|
|
@@ -1058,6 +1260,7 @@ var CSS = `
|
|
|
1058
1260
|
.dshgt-fact-k{font-size:11.5px;color:var(--gt-muted);margin-bottom:2px;}
|
|
1059
1261
|
.dshgt-fact-v{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
1060
1262
|
.dshgt-block{display:flex;flex-direction:column;gap:8px;}
|
|
1263
|
+
.dshgt-block > .dshgt-btn{align-self:flex-start;}
|
|
1061
1264
|
.dshgt-section-label{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--gt-muted);letter-spacing:.02em;}
|
|
1062
1265
|
.dshgt-section-label:after{content:"";height:1px;flex:1;background:color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
1063
1266
|
.dshgt-section-tail{margin-left:auto;font-size:11.5px;color:var(--gt-muted);}
|
|
@@ -1147,6 +1350,19 @@ var CSS = `
|
|
|
1147
1350
|
.dshgt-overview-seg{margin-bottom:8px;}
|
|
1148
1351
|
.dshgt-overview-empty{padding:14px 2px;}
|
|
1149
1352
|
|
|
1353
|
+
/* 概览用量速览:Token / 发版两张卡,每卡两格;无数据时整卡不渲染。 */
|
|
1354
|
+
.dshgt-usage-glance{gap:8px;}
|
|
1355
|
+
.dshgt-glance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;}
|
|
1356
|
+
.dshgt-glance{border:1px solid var(--gt-border);border-radius:12px;padding:14px 16px 13px;background:var(--gt-card);display:flex;flex-direction:column;gap:10px;min-width:0;}
|
|
1357
|
+
.dshgt-glance-k{font-size:12px;color:var(--gt-muted);letter-spacing:.02em;}
|
|
1358
|
+
.dshgt-glance-vs{display:flex;gap:30px;flex-wrap:wrap;}
|
|
1359
|
+
.dshgt-glance-cell{display:flex;flex-direction:column;gap:2px;min-width:0;}
|
|
1360
|
+
.dshgt-glance-label{font-size:12px;color:var(--gt-muted);}
|
|
1361
|
+
.dshgt-glance-val{display:flex;align-items:baseline;gap:5px;min-width:0;}
|
|
1362
|
+
.dshgt-glance-num{font-size:22px;line-height:1.2;font-weight:650;letter-spacing:-.015em;color:var(--gt-fg);font-variant-numeric:tabular-nums;white-space:nowrap;}
|
|
1363
|
+
.dshgt-glance-unit{font-size:11.5px;color:var(--gt-muted);}
|
|
1364
|
+
.dshgt-glance-note{margin:0;}
|
|
1365
|
+
|
|
1150
1366
|
/* ——— 运行记录 ——— */
|
|
1151
1367
|
.dshgt-runs-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
1152
1368
|
.dshgt-runs-filter{display:flex;gap:4px;margin-left:auto;}
|
|
@@ -1158,6 +1374,8 @@ var CSS = `
|
|
|
1158
1374
|
.dshgt-run-what{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;}
|
|
1159
1375
|
.dshgt-run-muted{color:var(--gt-muted);font-size:12px;margin-left:6px;}
|
|
1160
1376
|
.dshgt-run-files,.dshgt-run-duration{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);text-align:right;}
|
|
1377
|
+
.dshgt-run-tokens{font-size:11.5px;color:var(--gt-muted);text-align:right;white-space:nowrap;}
|
|
1378
|
+
.dshgt-run-item.has-tokens .dshgt-run-row{grid-template-columns:18px 120px 56px minmax(0,1fr) 64px 78px 74px 20px;}
|
|
1161
1379
|
.dshgt-run-chev{color:var(--gt-muted);text-align:center;transition:transform .15s;}
|
|
1162
1380
|
.dshgt-run-item.open .dshgt-run-chev{transform:rotate(90deg);}
|
|
1163
1381
|
.dshgt-run-detail{padding:2px 6px 16px 30px;display:flex;flex-direction:column;gap:10px;}
|
|
@@ -1167,6 +1385,11 @@ var CSS = `
|
|
|
1167
1385
|
.dshgt-detail-v a{color:var(--gt-accent);text-decoration:none;}
|
|
1168
1386
|
.dshgt-detail-v a:hover{text-decoration:underline;}
|
|
1169
1387
|
.dshgt-run-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
1388
|
+
.dshgt-releases-detail{padding-top:10px;border-top:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
1389
|
+
.dshgt-releases-stats{display:flex;flex-wrap:wrap;gap:6px 20px;}
|
|
1390
|
+
.dshgt-releases-stat{display:inline-flex;align-items:baseline;gap:6px;}
|
|
1391
|
+
.dshgt-releases-stat .dshgt-hint{font-size:11.5px;}
|
|
1392
|
+
.dshgt-runs-foot{padding:4px 2px 0;text-align:right;}
|
|
1170
1393
|
|
|
1171
1394
|
/* ——— 日志抽屉 / 关于 ——— */
|
|
1172
1395
|
.dshgt-log-modal{max-width:820px;width:calc(100% - 32px);}
|
|
@@ -1199,6 +1422,99 @@ var CSS = `
|
|
|
1199
1422
|
.dshgt-about-status.err{color:var(--gt-err);}
|
|
1200
1423
|
.dshgt-about-actions{display:flex;align-items:center;gap:8px;flex:none;}
|
|
1201
1424
|
|
|
1425
|
+
/* ——— 订阅:命令栏 + 四列表格 + 选择条 + 发版记录抽屉 ——— */
|
|
1426
|
+
.dshgt-subs{gap:12px;padding-bottom:10px;}
|
|
1427
|
+
.dshgt-subs-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;}
|
|
1428
|
+
.dshgt-subs-head-main{min-width:0;}
|
|
1429
|
+
.dshgt-subs-head h2{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;}
|
|
1430
|
+
.dshgt-subs-dek{margin:4px 0 0;font-size:12.5px;color:var(--gt-muted);line-height:1.55;max-width:640px;}
|
|
1431
|
+
.dshgt-subs-head-actions{margin-left:auto;display:flex;gap:8px;flex:none;}
|
|
1432
|
+
.dshgt-subs-cmdwrap{display:flex;flex-direction:column;gap:8px;}
|
|
1433
|
+
.dshgt-subs-cmd{display:flex;align-items:center;gap:10px;height:46px;padding:0 12px;border:1px solid var(--gt-border);border-radius:10px;background:var(--gt-bg);box-shadow:0 1px 2px color-mix(in srgb,var(--gt-fg) 5%,transparent);}
|
|
1434
|
+
.dshgt-subs-cmd:focus-within{border-color:color-mix(in srgb,var(--gt-accent) 55%,var(--gt-border));box-shadow:0 0 0 3px color-mix(in srgb,var(--gt-accent) 12%,transparent);}
|
|
1435
|
+
.dshgt-subs-cmd input{flex:1;min-width:0;border:0;background:none;outline:0;font:inherit;font-size:15px;color:var(--gt-fg);padding:0;}
|
|
1436
|
+
.dshgt-subs-cmd input::placeholder{color:var(--gt-muted);}
|
|
1437
|
+
.dshgt-subs-kbd{flex:none;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:16px;color:var(--gt-muted);border:1px solid var(--gt-border);border-bottom-width:2px;border-radius:5px;padding:0 5px;background:var(--gt-card);}
|
|
1438
|
+
.dshgt-subs-meta{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 2px;font-size:12px;color:var(--gt-muted);}
|
|
1439
|
+
.dshgt-subs-meta-right{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:11.5px;color:var(--gt-muted);}
|
|
1440
|
+
.dshgt-subs-meta-sep{color:color-mix(in srgb,var(--gt-muted) 55%,transparent);}
|
|
1441
|
+
.dshgt-subs-suggest{display:flex;align-items:center;gap:10px;padding:9px 12px;border:1px dashed color-mix(in srgb,var(--gt-accent) 40%,var(--gt-border));border-radius:9px;background:color-mix(in srgb,var(--gt-accent) 5%,var(--gt-bg));font-size:13px;}
|
|
1442
|
+
.dshgt-subs-suggest .plus{color:var(--gt-accent);font-size:15px;line-height:1;}
|
|
1443
|
+
.dshgt-subs-suggest .repo{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;}
|
|
1444
|
+
.dshgt-subs-suggest .hint{margin-left:auto;font-size:11.5px;color:var(--gt-muted);}
|
|
1445
|
+
.dshgt-subs-table{display:flex;flex-direction:column;min-width:0;}
|
|
1446
|
+
.dshgt-subs-thead,.dshgt-subs-row{display:grid;grid-template-columns:280px 130px 100px 110px minmax(0,1fr);gap:14px;align-items:center;padding:0 8px;}
|
|
1447
|
+
.dshgt-subs-thead{height:32px;border-bottom:1px solid var(--gt-border);font-size:11.5px;color:var(--gt-muted);}
|
|
1448
|
+
.dshgt-subs-th{appearance:none;border:0;background:none;font:inherit;color:inherit;cursor:pointer;padding:0;display:inline-flex;align-items:center;gap:4px;justify-self:start;text-align:left;}
|
|
1449
|
+
.dshgt-subs-th.right{justify-self:end;}
|
|
1450
|
+
.dshgt-subs-th:hover{color:var(--gt-fg);}
|
|
1451
|
+
.dshgt-subs-th[aria-sort="ascending"],.dshgt-subs-th[aria-sort="descending"]{color:var(--gt-fg);}
|
|
1452
|
+
.dshgt-subs-ord{font-size:9px;line-height:1;color:var(--gt-accent);}
|
|
1453
|
+
.dshgt-subs-row{min-height:44px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);cursor:pointer;}
|
|
1454
|
+
.dshgt-subs-row:hover{background:color-mix(in srgb,var(--gt-fg) 3%,var(--gt-bg));}
|
|
1455
|
+
.dshgt-subs-row.is-focus{background:color-mix(in srgb,var(--gt-accent) 7%,var(--gt-bg));box-shadow:inset 2px 0 0 var(--gt-accent);}
|
|
1456
|
+
.dshgt-subs-table.is-selecting .dshgt-subs-thead,.dshgt-subs-table.is-selecting .dshgt-subs-row{grid-template-columns:22px 280px 130px 100px 110px minmax(0,1fr);}
|
|
1457
|
+
.dshgt-subs-cbwrap{display:flex;align-items:center;justify-content:center;min-width:0;}
|
|
1458
|
+
.dshgt-subs-cb{width:14px;height:14px;margin:0;accent-color:var(--gt-accent);justify-self:center;}
|
|
1459
|
+
.dshgt-subs-ident{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
1460
|
+
.dshgt-subs-ident mark{background:color-mix(in srgb,var(--gt-accent) 18%,transparent);color:inherit;border-radius:3px;padding:0 1px;}
|
|
1461
|
+
.dshgt-subs-ver{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-fg);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
|
|
1462
|
+
.dshgt-subs-sum{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;color:var(--gt-muted);text-align:right;white-space:nowrap;}
|
|
1463
|
+
.dshgt-subs-stat{display:flex;align-items:center;gap:6px;padding-left:4px;font-size:12px;color:var(--gt-muted);white-space:nowrap;}
|
|
1464
|
+
.dshgt-subs-thead .dshgt-subs-stat{font-size:11.5px;}
|
|
1465
|
+
.dshgt-subs-stat.warn{color:var(--gt-warn);}
|
|
1466
|
+
.dshgt-subs-stat.err{color:var(--gt-err);}
|
|
1467
|
+
.dshgt-subs-actions{display:flex;align-items:center;justify-content:flex-end;gap:2px;justify-self:end;min-width:116px;}
|
|
1468
|
+
.dshgt-subs-act{appearance:none;border:0;background:none;font:inherit;font-size:12px;color:var(--gt-muted);cursor:pointer;padding:3px 6px;border-radius:5px;white-space:nowrap;}
|
|
1469
|
+
.dshgt-subs-act:hover{color:var(--gt-accent);background:color-mix(in srgb,var(--gt-accent) 10%,transparent);}
|
|
1470
|
+
.dshgt-subs-act.rm{opacity:0;transition:opacity .12s;padding:3px 4px;}
|
|
1471
|
+
.dshgt-subs-row:hover .dshgt-subs-act.rm,.dshgt-subs-row:focus-within .dshgt-subs-act.rm,.dshgt-subs-act.rm:focus-visible{opacity:1;}
|
|
1472
|
+
.dshgt-subs-act.rm:hover{color:var(--gt-err);background:color-mix(in srgb,var(--gt-err) 8%,transparent);}
|
|
1473
|
+
.dshgt-subs-empty{padding:52px 16px 40px;display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;color:var(--gt-muted);font-size:12.5px;}
|
|
1474
|
+
.dshgt-subs-empty b{font-size:14px;font-weight:600;color:var(--gt-fg);}
|
|
1475
|
+
.dshgt-subs-empty .dshgt-btn{margin-top:10px;}
|
|
1476
|
+
.dshgt-subs-keys{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:2px;font-size:11.5px;color:var(--gt-muted);}
|
|
1477
|
+
.dshgt-subs-selbar{position:sticky;bottom:8px;z-index:6;display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 12px;border:1px solid color-mix(in srgb,var(--gt-accent) 30%,var(--gt-border));border-radius:10px;background:color-mix(in srgb,var(--gt-accent) 6%,var(--gt-bg));box-shadow:0 8px 24px color-mix(in srgb,var(--gt-fg) 14%,transparent);font-size:13px;}
|
|
1478
|
+
.dshgt-subs-selbar b{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;}
|
|
1479
|
+
.dshgt-subs-selbar-actions{margin-left:auto;display:flex;align-items:center;gap:8px;}
|
|
1480
|
+
.dshgt-subs-linkbtn{appearance:none;border:0;background:none;font:inherit;font-size:12.5px;color:var(--gt-accent);cursor:pointer;padding:2px 4px;border-radius:5px;}
|
|
1481
|
+
.dshgt-subs-linkbtn:hover{text-decoration:underline;}
|
|
1482
|
+
.dshgt-subs-confirm-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);}
|
|
1483
|
+
.dshgt-subs-drawer-mask{position:fixed;inset:0;z-index:2147483000;display:flex;justify-content:flex-end;background:color-mix(in srgb,var(--gt-fg) 26%,transparent);}
|
|
1484
|
+
.dshgt-subs-drawer{width:460px;max-width:100%;height:100%;display:flex;flex-direction:column;background:var(--gt-bg);border-left:1px solid var(--gt-border);box-shadow:-24px 0 60px color-mix(in srgb,var(--gt-fg) 16%,transparent);}
|
|
1485
|
+
.dshgt-subs-drawer-head{flex:none;display:flex;align-items:flex-start;gap:10px;padding:16px 20px 12px;border-bottom:1px solid var(--gt-border);}
|
|
1486
|
+
.dshgt-subs-drawer-main{flex:1;min-width:0;}
|
|
1487
|
+
.dshgt-subs-drawer-repo{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:600;word-break:break-all;}
|
|
1488
|
+
.dshgt-subs-drawer-sub{margin-top:4px;font-size:11.5px;color:var(--gt-muted);}
|
|
1489
|
+
.dshgt-subs-drawer-close{flex:none;width:28px;height:28px;display:grid;place-items:center;appearance:none;border:0;border-radius:6px;background:none;color:var(--gt-muted);font-size:18px;line-height:1;cursor:pointer;}
|
|
1490
|
+
.dshgt-subs-drawer-close:hover{background:var(--gt-card);color:var(--gt-fg);}
|
|
1491
|
+
.dshgt-subs-drawer-body{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:10px;padding:12px 20px 18px;}
|
|
1492
|
+
.dshgt-subs-vol{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:12px;color:var(--gt-muted);}
|
|
1493
|
+
.dshgt-subs-vol .label{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}
|
|
1494
|
+
.dshgt-subs-drawer-note{margin-top:auto;padding-top:12px;border-top:1px solid var(--gt-border);font-size:11.5px;color:var(--gt-muted);line-height:1.65;word-break:break-word;}
|
|
1495
|
+
.dshgt-subs-drawer-raw{margin:0;padding:12px 14px;border-radius:8px;background:color-mix(in srgb,var(--gt-fg) 5%,var(--gt-card));font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.65;white-space:pre-wrap;overflow-wrap:break-word;}
|
|
1496
|
+
@media (max-width:1040px){
|
|
1497
|
+
.dshgt-subs-thead,.dshgt-subs-row{grid-template-columns:240px 120px 110px minmax(0,1fr);}
|
|
1498
|
+
.dshgt-subs-table.is-selecting .dshgt-subs-thead,.dshgt-subs-table.is-selecting .dshgt-subs-row{grid-template-columns:22px 240px 120px 110px minmax(0,1fr);}
|
|
1499
|
+
.dshgt-subs-sum,.dshgt-subs-th-summary{display:none;}
|
|
1500
|
+
}
|
|
1501
|
+
@media (max-width:720px){
|
|
1502
|
+
.dshgt-subs-thead{display:none;}
|
|
1503
|
+
.dshgt-subs-thead,.dshgt-subs-row{gap:4px 10px;padding:6px 8px;}
|
|
1504
|
+
.dshgt-subs-row{grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:"ident ident stat" "ver sum actions";min-height:0;}
|
|
1505
|
+
.dshgt-subs-table.is-selecting .dshgt-subs-row{grid-template-columns:22px minmax(0,1fr) auto auto;grid-template-areas:"cb ident ident stat" "cb ver sum actions";}
|
|
1506
|
+
.dshgt-subs-ident{grid-area:ident;}
|
|
1507
|
+
.dshgt-subs-ver{grid-area:ver;text-align:left;}
|
|
1508
|
+
.dshgt-subs-sum{display:block;grid-area:sum;text-align:left;}
|
|
1509
|
+
.dshgt-subs-stat{grid-area:stat;justify-self:end;}
|
|
1510
|
+
.dshgt-subs-actions{grid-area:actions;justify-self:end;min-width:0;}
|
|
1511
|
+
/* 触屏没有 hover:窄屏把「移除」常显,否则点不到。 */
|
|
1512
|
+
.dshgt-subs-act.rm{opacity:1;}
|
|
1513
|
+
.dshgt-subs-cbwrap{grid-area:cb;}
|
|
1514
|
+
.dshgt-subs-meta-right{margin-left:0;}
|
|
1515
|
+
.dshgt-subs-drawer{width:100%;border-left:0;}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1202
1518
|
@media (max-width:1100px){
|
|
1203
1519
|
.dshgt-app{grid-template-columns:190px minmax(0,1fr);}
|
|
1204
1520
|
.dshgt-page-head{padding:18px 22px 12px;}
|
|
@@ -1208,6 +1524,7 @@ var CSS = `
|
|
|
1208
1524
|
.dshgt-week{flex-wrap:wrap;}
|
|
1209
1525
|
.dshgt-day{flex:1 1 88px;}
|
|
1210
1526
|
.dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 70px 20px;}
|
|
1527
|
+
.dshgt-run-item.has-tokens .dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 58px 70px 20px;}
|
|
1211
1528
|
.dshgt-run-files{display:none;}
|
|
1212
1529
|
.dshgt-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
|
|
1213
1530
|
.dshgt-dateselect{min-width:180px;}
|
|
@@ -1448,6 +1765,17 @@ async function apiCall(method, path, body, options = {}) {
|
|
|
1448
1765
|
}
|
|
1449
1766
|
return json;
|
|
1450
1767
|
}
|
|
1768
|
+
function releaseRunsOf(state) {
|
|
1769
|
+
if (state === null || state === void 0) return [];
|
|
1770
|
+
const root = Array.isArray(state.releaseRuns) ? state.releaseRuns : void 0;
|
|
1771
|
+
const nested = Array.isArray(state.status?.releaseRuns) ? state.status.releaseRuns : void 0;
|
|
1772
|
+
return root ?? nested ?? [];
|
|
1773
|
+
}
|
|
1774
|
+
function lastReleaseAtOf(state) {
|
|
1775
|
+
if (state === null || state === void 0) return void 0;
|
|
1776
|
+
const value = state.lastReleaseAt ?? state.status?.lastReleaseAt;
|
|
1777
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1778
|
+
}
|
|
1451
1779
|
function getPreview(runId, signal) {
|
|
1452
1780
|
return apiCall("GET", `/preview?id=${encodeURIComponent(runId)}`, void 0, signal === void 0 ? {} : { signal });
|
|
1453
1781
|
}
|
|
@@ -1465,13 +1793,59 @@ async function applyPluginUpdate() {
|
|
|
1465
1793
|
const payload = await apiCall("POST", "/update", {});
|
|
1466
1794
|
return payload.result;
|
|
1467
1795
|
}
|
|
1796
|
+
var SUBSCRIPTION_STATUSES = ["baseline", "ok", "no_change", "rate_limited", "failed"];
|
|
1797
|
+
function normalizeItem(raw) {
|
|
1798
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
1799
|
+
if (typeof raw.fullName !== "string" || raw.fullName.trim() === "") return void 0;
|
|
1800
|
+
const status = SUBSCRIPTION_STATUSES.includes(raw.status) ? raw.status : "baseline";
|
|
1801
|
+
const optional = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
1802
|
+
const item = { fullName: raw.fullName.trim(), status };
|
|
1803
|
+
const url = optional(raw.url);
|
|
1804
|
+
const latestTag = optional(raw.latestTag);
|
|
1805
|
+
const latestSummaryAt = optional(raw.latestSummaryAt);
|
|
1806
|
+
const lastCheckedAt = optional(raw.lastCheckedAt);
|
|
1807
|
+
if (url !== void 0) item.url = url;
|
|
1808
|
+
if (latestTag !== void 0) item.latestTag = latestTag;
|
|
1809
|
+
if (latestSummaryAt !== void 0) item.latestSummaryAt = latestSummaryAt;
|
|
1810
|
+
if (lastCheckedAt !== void 0) item.lastCheckedAt = lastCheckedAt;
|
|
1811
|
+
return item;
|
|
1812
|
+
}
|
|
1813
|
+
function normalizeSubscriptionList(payload) {
|
|
1814
|
+
const repos = Array.isArray(payload?.repos) ? payload.repos.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => item.trim()) : [];
|
|
1815
|
+
const items = Array.isArray(payload?.items) ? payload.items.map(normalizeItem).filter((item) => item !== void 0) : [];
|
|
1816
|
+
return { repos, items };
|
|
1817
|
+
}
|
|
1468
1818
|
async function getSubscriptions(signal) {
|
|
1469
1819
|
const payload = await apiCall("GET", "/subscriptions", void 0, signal === void 0 ? {} : { signal });
|
|
1470
|
-
return
|
|
1820
|
+
return normalizeSubscriptionList(payload);
|
|
1471
1821
|
}
|
|
1472
1822
|
async function postSubscriptions(action, repos) {
|
|
1473
1823
|
const payload = await apiCall("POST", "/subscriptions", { action, repos });
|
|
1474
|
-
return
|
|
1824
|
+
return normalizeSubscriptionList(payload);
|
|
1825
|
+
}
|
|
1826
|
+
async function getSubscriptionDoc(repo, volume, signal) {
|
|
1827
|
+
const query = `?repo=${encodeURIComponent(repo)}${volume === void 0 ? "" : `&volume=${encodeURIComponent(String(volume))}`}`;
|
|
1828
|
+
const payload = await apiCall(
|
|
1829
|
+
"GET",
|
|
1830
|
+
`/subscriptions/releases${query}`,
|
|
1831
|
+
void 0,
|
|
1832
|
+
signal === void 0 ? {} : { signal }
|
|
1833
|
+
);
|
|
1834
|
+
const volumes = Array.isArray(payload.volumes) ? payload.volumes.filter((item) => typeof item === "object" && item !== null).map((item) => ({
|
|
1835
|
+
index: typeof item.index === "number" ? item.index : 1,
|
|
1836
|
+
file: typeof item.file === "string" ? item.file : "",
|
|
1837
|
+
...typeof item.from === "string" ? { from: item.from } : {},
|
|
1838
|
+
...typeof item.to === "string" ? { to: item.to } : {},
|
|
1839
|
+
...typeof item.lines === "number" ? { lines: item.lines } : {}
|
|
1840
|
+
})) : [];
|
|
1841
|
+
const doc = {
|
|
1842
|
+
fullName: typeof payload.fullName === "string" && payload.fullName !== "" ? payload.fullName : repo,
|
|
1843
|
+
volume: typeof payload.volume === "number" ? payload.volume : volume ?? 1,
|
|
1844
|
+
markdown: typeof payload.markdown === "string" ? payload.markdown : ""
|
|
1845
|
+
};
|
|
1846
|
+
if (volumes.length > 0) doc.volumes = volumes;
|
|
1847
|
+
if (typeof payload.updatedAt === "string" && payload.updatedAt !== "") doc.updatedAt = payload.updatedAt;
|
|
1848
|
+
return doc;
|
|
1475
1849
|
}
|
|
1476
1850
|
|
|
1477
1851
|
// client/store.ts
|
|
@@ -2059,6 +2433,9 @@ function SettingsView(props) {
|
|
|
2059
2433
|
),
|
|
2060
2434
|
draft.summarize.enrich === "none" ? null : h(Alert, { kind: "warn" }, h("div", null, t("summarize.enrichNote")))
|
|
2061
2435
|
);
|
|
2436
|
+
const releaseSchedule = draft.releases.schedule ?? { enabled: false, weekday: 1, time: "08:00:00", timezone: "Asia/Shanghai" };
|
|
2437
|
+
const releaseConcurrency = draft.releases.concurrency ?? "auto";
|
|
2438
|
+
const releaseBudget = draft.releases.budgetSeconds ?? "auto";
|
|
2062
2439
|
const releasesCard = h(
|
|
2063
2440
|
Card,
|
|
2064
2441
|
{
|
|
@@ -2086,6 +2463,80 @@ function SettingsView(props) {
|
|
|
2086
2463
|
h(Input, { mono: true, width: 90, value: String(draft.releases.maxNotesChars), onInput: (value) => update((next) => {
|
|
2087
2464
|
next.releases.maxNotesChars = Math.round(Number(value) || 0);
|
|
2088
2465
|
}) })
|
|
2466
|
+
),
|
|
2467
|
+
h(
|
|
2468
|
+
Row,
|
|
2469
|
+
{ label: t("releases.schedule.enabled"), help: t("releases.schedule.help") },
|
|
2470
|
+
h(Toggle, {
|
|
2471
|
+
checked: releaseSchedule.enabled,
|
|
2472
|
+
onChange: (value) => update((next) => {
|
|
2473
|
+
next.releases.schedule = { ...releaseSchedule, enabled: value };
|
|
2474
|
+
})
|
|
2475
|
+
})
|
|
2476
|
+
),
|
|
2477
|
+
h(
|
|
2478
|
+
Row,
|
|
2479
|
+
{ label: t("releases.schedule.weekday") },
|
|
2480
|
+
h(Select, {
|
|
2481
|
+
value: String(releaseSchedule.weekday),
|
|
2482
|
+
options: [1, 2, 3, 4, 5, 6, 7].map((weekday) => ({ value: String(weekday), label: t(`weekday.${weekday}`) })),
|
|
2483
|
+
onChange: (value) => update((next) => {
|
|
2484
|
+
next.releases.schedule = { ...releaseSchedule, weekday: Math.round(Number(value) || 1) };
|
|
2485
|
+
})
|
|
2486
|
+
}),
|
|
2487
|
+
h("span", { className: "dshgt-hint" }, t("releases.schedule.time")),
|
|
2488
|
+
h(Input, { mono: true, width: 90, value: releaseSchedule.time, onInput: (value) => update((next) => {
|
|
2489
|
+
next.releases.schedule = { ...releaseSchedule, time: value };
|
|
2490
|
+
}) }),
|
|
2491
|
+
h("span", { className: "dshgt-hint" }, t("releases.schedule.timezone")),
|
|
2492
|
+
h(Input, { mono: true, width: 170, value: releaseSchedule.timezone, onInput: (value) => update((next) => {
|
|
2493
|
+
next.releases.schedule = { ...releaseSchedule, timezone: value };
|
|
2494
|
+
}) })
|
|
2495
|
+
),
|
|
2496
|
+
h("p", { className: "dshgt-hint" }, t("releases.schedule.hint")),
|
|
2497
|
+
h(
|
|
2498
|
+
Row,
|
|
2499
|
+
{ label: t("releases.concurrency"), help: t("releases.concurrency.help") },
|
|
2500
|
+
h(Select, {
|
|
2501
|
+
value: releaseConcurrency === "auto" ? "auto" : "fixed",
|
|
2502
|
+
options: [
|
|
2503
|
+
{ value: "auto", label: t("releases.concurrency.auto") },
|
|
2504
|
+
{ value: "fixed", label: t("releases.concurrency.fixed") }
|
|
2505
|
+
],
|
|
2506
|
+
onChange: (value) => update((next) => {
|
|
2507
|
+
next.releases.concurrency = value === "auto" ? "auto" : typeof next.releases.concurrency === "number" ? next.releases.concurrency : 4;
|
|
2508
|
+
})
|
|
2509
|
+
}),
|
|
2510
|
+
releaseConcurrency === "auto" ? null : h(Input, {
|
|
2511
|
+
mono: true,
|
|
2512
|
+
width: 70,
|
|
2513
|
+
value: String(releaseConcurrency),
|
|
2514
|
+
onInput: (value) => update((next) => {
|
|
2515
|
+
next.releases.concurrency = Math.round(Number(value) || 1);
|
|
2516
|
+
})
|
|
2517
|
+
})
|
|
2518
|
+
),
|
|
2519
|
+
h(
|
|
2520
|
+
Row,
|
|
2521
|
+
{ label: t("releases.budget"), help: t("releases.budget.help") },
|
|
2522
|
+
h(Select, {
|
|
2523
|
+
value: releaseBudget === "auto" ? "auto" : "fixed",
|
|
2524
|
+
options: [
|
|
2525
|
+
{ value: "auto", label: t("releases.budget.auto") },
|
|
2526
|
+
{ value: "fixed", label: t("releases.budget.fixed") }
|
|
2527
|
+
],
|
|
2528
|
+
onChange: (value) => update((next) => {
|
|
2529
|
+
next.releases.budgetSeconds = value === "auto" ? "auto" : typeof next.releases.budgetSeconds === "number" ? next.releases.budgetSeconds : 150;
|
|
2530
|
+
})
|
|
2531
|
+
}),
|
|
2532
|
+
releaseBudget === "auto" ? null : h(Input, {
|
|
2533
|
+
mono: true,
|
|
2534
|
+
width: 70,
|
|
2535
|
+
value: String(releaseBudget),
|
|
2536
|
+
onInput: (value) => update((next) => {
|
|
2537
|
+
next.releases.budgetSeconds = Math.round(Number(value) || 1);
|
|
2538
|
+
})
|
|
2539
|
+
})
|
|
2089
2540
|
)
|
|
2090
2541
|
);
|
|
2091
2542
|
const currentCard = section === "source" ? sourceCard : section === "model" ? modelCard : section === "repo" ? repoCard : section === "auth" ? authCard : section === "scope" ? scopeCard : section === "summarize" ? summarizeCard : section === "releases" ? releasesCard : scheduleCard;
|
|
@@ -2626,6 +3077,28 @@ function readyRows(t, state) {
|
|
|
2626
3077
|
}
|
|
2627
3078
|
];
|
|
2628
3079
|
}
|
|
3080
|
+
function glanceCell(label, value, unit) {
|
|
3081
|
+
return h(
|
|
3082
|
+
"div",
|
|
3083
|
+
{ className: "dshgt-glance-cell" },
|
|
3084
|
+
h("span", { className: "dshgt-glance-label" }, label),
|
|
3085
|
+
h(
|
|
3086
|
+
"span",
|
|
3087
|
+
{ className: "dshgt-glance-val" },
|
|
3088
|
+
h("span", { className: "dshgt-glance-num dshgt-mono" }, value),
|
|
3089
|
+
unit === void 0 ? null : h("span", { className: "dshgt-glance-unit" }, unit)
|
|
3090
|
+
)
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
function glanceCard(title, cells) {
|
|
3094
|
+
if (cells.length === 0) return null;
|
|
3095
|
+
return h(
|
|
3096
|
+
"div",
|
|
3097
|
+
{ className: "dshgt-glance" },
|
|
3098
|
+
h("div", { className: "dshgt-glance-k" }, title),
|
|
3099
|
+
h("div", { className: "dshgt-glance-vs" }, cells)
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
2629
3102
|
function OverviewView(props) {
|
|
2630
3103
|
const { t, lang, store, controller } = props;
|
|
2631
3104
|
const state = store.state;
|
|
@@ -2649,6 +3122,21 @@ function OverviewView(props) {
|
|
|
2649
3122
|
const todayHasDaily = groupMap.get("daily")?.days.some((day) => day.date === today) ?? false;
|
|
2650
3123
|
const showWaiting = period === "daily" && !todayHasDaily && state.schedule.enabled;
|
|
2651
3124
|
const lastTarget = last === null ? void 0 : digestTarget(last, timeZone);
|
|
3125
|
+
const lastTokens = last?.tokens;
|
|
3126
|
+
const releases = last?.releases;
|
|
3127
|
+
const totalTokens = state.status.totalTokens;
|
|
3128
|
+
const tokenCells = [
|
|
3129
|
+
...lastTokens === void 0 ? [] : [glanceCell(t("overview.tokens.thisRun"), formatTokens(lastTokens), "tokens")],
|
|
3130
|
+
...totalTokens === void 0 ? [] : [glanceCell(t("overview.tokens.total"), formatTokens(totalTokens), "tokens")]
|
|
3131
|
+
];
|
|
3132
|
+
const releaseCells = releases === void 0 ? [] : [
|
|
3133
|
+
glanceCell(t("overview.releases.new"), String(releases.newReleases)),
|
|
3134
|
+
glanceCell(t("overview.releases.repos"), String(releases.repos))
|
|
3135
|
+
];
|
|
3136
|
+
const glanceCards = [
|
|
3137
|
+
glanceCard(t("overview.tokens.title"), tokenCells),
|
|
3138
|
+
glanceCard(t("overview.releases.title"), releaseCells)
|
|
3139
|
+
].filter((card) => card !== null);
|
|
2652
3140
|
return h(
|
|
2653
3141
|
"div",
|
|
2654
3142
|
{ className: "dshgt-view dshgt-overview" },
|
|
@@ -2721,35 +3209,10 @@ function OverviewView(props) {
|
|
|
2721
3209
|
h("div", { className: "dshgt-fact" }, h("div", { className: "dshgt-fact-k" }, t("overview.model")), h("div", { className: "dshgt-fact-v" }, last.model?.model ?? "—"))
|
|
2722
3210
|
)
|
|
2723
3211
|
),
|
|
2724
|
-
h(
|
|
3212
|
+
glanceCards.length === 0 ? null : h(
|
|
2725
3213
|
"section",
|
|
2726
3214
|
{ className: "dshgt-block dshgt-usage-glance" },
|
|
2727
|
-
h(
|
|
2728
|
-
"div",
|
|
2729
|
-
{ className: "dshgt-glance-grid" },
|
|
2730
|
-
h(
|
|
2731
|
-
"div",
|
|
2732
|
-
{ className: "dshgt-glance" },
|
|
2733
|
-
h("div", { className: "dshgt-glance-k" }, t("overview.tokens.title")),
|
|
2734
|
-
h(
|
|
2735
|
-
"div",
|
|
2736
|
-
{ className: "dshgt-glance-vs" },
|
|
2737
|
-
h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.tokens.thisRun")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.tokens === void 0 ? "—" : formatTokens(last.tokens)), h("span", { className: "dshgt-hint" }, "tokens")),
|
|
2738
|
-
h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.tokens.total")), h("span", { className: "dshgt-glance-num dshgt-mono" }, state.status.totalTokens === void 0 ? "—" : formatTokens(state.status.totalTokens)), h("span", { className: "dshgt-hint" }, "tokens"))
|
|
2739
|
-
)
|
|
2740
|
-
),
|
|
2741
|
-
h(
|
|
2742
|
-
"div",
|
|
2743
|
-
{ className: "dshgt-glance" },
|
|
2744
|
-
h("div", { className: "dshgt-glance-k" }, t("overview.releases.title")),
|
|
2745
|
-
h(
|
|
2746
|
-
"div",
|
|
2747
|
-
{ className: "dshgt-glance-vs" },
|
|
2748
|
-
h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.releases.new")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.releases === void 0 ? "—" : String(last.releases.newReleases))),
|
|
2749
|
-
h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.releases.repos")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.releases === void 0 ? "—" : String(last.releases.repos)))
|
|
2750
|
-
)
|
|
2751
|
-
)
|
|
2752
|
-
),
|
|
3215
|
+
h("div", { className: "dshgt-glance-grid" }, glanceCards),
|
|
2753
3216
|
h("p", { className: "dshgt-hint dshgt-glance-note" }, t("overview.tokens.note"))
|
|
2754
3217
|
),
|
|
2755
3218
|
h(
|
|
@@ -2845,6 +3308,11 @@ function shortBucket(period, bucket) {
|
|
|
2845
3308
|
}
|
|
2846
3309
|
|
|
2847
3310
|
// client/runs.ts
|
|
3311
|
+
var KINDS = [
|
|
3312
|
+
{ id: "all", key: "runs.type.all" },
|
|
3313
|
+
{ id: "digest", key: "runs.type.digest" },
|
|
3314
|
+
{ id: "release", key: "runs.type.release" }
|
|
3315
|
+
];
|
|
2848
3316
|
var FILTERS = [
|
|
2849
3317
|
{ id: "all", key: "runs.filter.all" },
|
|
2850
3318
|
{ id: "daily", key: "runs.filter.daily" },
|
|
@@ -2945,6 +3413,7 @@ function LogDrawer(props) {
|
|
|
2945
3413
|
function RunsView(props) {
|
|
2946
3414
|
const { t, store, controller } = props;
|
|
2947
3415
|
const [filter, setFilter] = import_react.default.useState("all");
|
|
3416
|
+
const [kind, setKind] = import_react.default.useState("all");
|
|
2948
3417
|
const [openId, setOpenId] = import_react.default.useState(null);
|
|
2949
3418
|
const [logId, setLogId] = import_react.default.useState(null);
|
|
2950
3419
|
const state = store.state;
|
|
@@ -2952,12 +3421,105 @@ function RunsView(props) {
|
|
|
2952
3421
|
return h("div", { className: "dshgt-empty" }, store.error ?? t("quickfill.loading"));
|
|
2953
3422
|
}
|
|
2954
3423
|
const history = state.status.history;
|
|
2955
|
-
const
|
|
3424
|
+
const releaseRuns = releaseRunsOf(state);
|
|
3425
|
+
const digestMatches = (record) => {
|
|
2956
3426
|
if (filter === "failed") return !record.ok;
|
|
2957
3427
|
if (filter === "dry") return record.kind === "dry-run";
|
|
2958
3428
|
if (filter === "daily" || filter === "weekly" || filter === "monthly") return (record.period ?? "daily") === filter;
|
|
2959
3429
|
return true;
|
|
2960
|
-
}
|
|
3430
|
+
};
|
|
3431
|
+
const releaseMatches = (run) => {
|
|
3432
|
+
if (filter === "failed") return run.status === "failed";
|
|
3433
|
+
return filter === "all";
|
|
3434
|
+
};
|
|
3435
|
+
const entries = [
|
|
3436
|
+
...kind === "release" ? [] : history.filter(digestMatches).map((record) => ({ kind: "digest", key: record.id, at: record.at, record })),
|
|
3437
|
+
...kind === "digest" ? [] : releaseRuns.filter(releaseMatches).map((run) => ({ kind: "release", key: `release:${run.id}`, at: run.finishedAt || run.startedAt, run }))
|
|
3438
|
+
].sort((a, b) => a.at < b.at ? 1 : a.at > b.at ? -1 : 0);
|
|
3439
|
+
const hintCount = kind === "release" ? releaseRuns.length : history.length;
|
|
3440
|
+
const digestNode = (record) => {
|
|
3441
|
+
const open = openId === record.id;
|
|
3442
|
+
const pr = prStatus(t, state, record);
|
|
3443
|
+
return h(
|
|
3444
|
+
"div",
|
|
3445
|
+
{ className: `dshgt-run-item${open ? " open" : ""}${record.tokens === void 0 ? "" : " has-tokens"}`, key: record.id },
|
|
3446
|
+
h(
|
|
3447
|
+
"button",
|
|
3448
|
+
{
|
|
3449
|
+
type: "button",
|
|
3450
|
+
className: "dshgt-run-row",
|
|
3451
|
+
"aria-expanded": open ? "true" : "false",
|
|
3452
|
+
onClick: () => setOpenId(open ? null : record.id)
|
|
3453
|
+
},
|
|
3454
|
+
h("span", { className: `dshgt-lamp ${record.ok ? record.skipped || record.kind === "dry-run" ? "warn" : "ok" : "err"}` }),
|
|
3455
|
+
h("span", { className: "dshgt-run-date" }, shortTime(record.at)),
|
|
3456
|
+
h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`)),
|
|
3457
|
+
h(
|
|
3458
|
+
"span",
|
|
3459
|
+
{ className: "dshgt-run-what" },
|
|
3460
|
+
record.kind === "dry-run" ? t("state.dry") : record.skipped ? t("state.skipped") : record.ok ? t("state.ok") : t("state.failed"),
|
|
3461
|
+
h("span", { className: "dshgt-run-muted" }, recordSummary(t, record)),
|
|
3462
|
+
record.legacy === true ? h("span", { className: "dshgt-tag dshgt-inline-tag" }, t("runs.legacy")) : null
|
|
3463
|
+
),
|
|
3464
|
+
h("span", { className: "dshgt-run-files" }, t("runs.files", { count: record.files })),
|
|
3465
|
+
record.tokens === void 0 ? null : h("span", { className: "dshgt-run-tokens dshgt-mono", title: t("run.usage.tokens") }, `${formatTokens(record.tokens)} tok`),
|
|
3466
|
+
h("span", { className: "dshgt-run-duration" }, duration(record.durationMs)),
|
|
3467
|
+
h("span", { className: "dshgt-run-chev" }, "›")
|
|
3468
|
+
),
|
|
3469
|
+
open ? h(
|
|
3470
|
+
"div",
|
|
3471
|
+
{ className: "dshgt-run-detail" },
|
|
3472
|
+
!record.ok ? h(
|
|
3473
|
+
Alert,
|
|
3474
|
+
{ kind: "err", title: `${t("error.prefix")} ${record.errorCode ?? "INTERNAL"}` },
|
|
3475
|
+
h("div", null, record.errorMessage ?? t("state.failed")),
|
|
3476
|
+
record.errorReason === void 0 ? null : h("div", { className: "dshgt-hint" }, reasonHint(t, record.errorReason) ?? "")
|
|
3477
|
+
) : null,
|
|
3478
|
+
h(
|
|
3479
|
+
"div",
|
|
3480
|
+
{ className: "dshgt-detail-grid" },
|
|
3481
|
+
detailItem(t, "run.usage.commit", record.commit === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.commit)),
|
|
3482
|
+
detailItem(t, "run.usage.hash", h("span", { className: "dshgt-mono" }, shortHash(record.contentHash))),
|
|
3483
|
+
detailItem(t, "run.usage.branch", record.branch === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.branch)),
|
|
3484
|
+
detailItem(t, "runs.detail.coreModel", `${record.coreVersion || "—"} · ${record.model?.model ?? "—"}`),
|
|
3485
|
+
detailItem(t, "runs.detail.date", record.date ?? "—"),
|
|
3486
|
+
detailItem(t, "runs.detail.period", h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`))),
|
|
3487
|
+
detailItem(
|
|
3488
|
+
t,
|
|
3489
|
+
"run.usage.pr",
|
|
3490
|
+
record.prUrl === void 0 ? "—" : h(
|
|
3491
|
+
"span",
|
|
3492
|
+
{ className: "dshgt-inline" },
|
|
3493
|
+
h("a", { href: record.prUrl, target: "_blank", rel: "noreferrer", title: record.prUrl }, t("digest.openPr")),
|
|
3494
|
+
pr === null ? null : h("span", { className: "dshgt-tag" }, pr.label)
|
|
3495
|
+
)
|
|
3496
|
+
),
|
|
3497
|
+
detailItem(t, "runs.detail.warnings", record.warnings.length === 0 ? t("runs.detail.none") : record.warnings.join(";")),
|
|
3498
|
+
detailItem(t, "runs.detail.files", `${record.files} · ${duration(record.durationMs)}`),
|
|
3499
|
+
detailItem(t, "runs.detail.tokens", record.tokens === void 0 ? t("runs.detail.tokensNone") : h("span", { className: "dshgt-mono" }, `${formatTokens(record.tokens)} tokens`))
|
|
3500
|
+
),
|
|
3501
|
+
record.releases === void 0 ? null : ReleasesDetail({ t, record }),
|
|
3502
|
+
record.legacy === true ? h("div", { className: "dshgt-hint" }, t("runs.legacyHint")) : null,
|
|
3503
|
+
h(
|
|
3504
|
+
"div",
|
|
3505
|
+
{ className: "dshgt-run-actions" },
|
|
3506
|
+
record.preview === void 0 ? h("span", { className: "dshgt-hint" }, t("runs.detail.noPreview")) : h(
|
|
3507
|
+
Btn,
|
|
3508
|
+
{
|
|
3509
|
+
small: true,
|
|
3510
|
+
onClick: () => {
|
|
3511
|
+
const target = digestTarget(record, state.schedule.timezone);
|
|
3512
|
+
if (target !== void 0) props.onOpenDigest(target);
|
|
3513
|
+
}
|
|
3514
|
+
},
|
|
3515
|
+
t("runs.detail.readDigest")
|
|
3516
|
+
),
|
|
3517
|
+
h(Btn, { small: true, onClick: () => setLogId(record.id) }, t("runs.detail.log")),
|
|
3518
|
+
record.preview === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, record.preview.file)
|
|
3519
|
+
)
|
|
3520
|
+
) : null
|
|
3521
|
+
);
|
|
3522
|
+
};
|
|
2961
3523
|
return h(
|
|
2962
3524
|
"div",
|
|
2963
3525
|
{ className: "dshgt-view dshgt-runs" },
|
|
@@ -2966,116 +3528,135 @@ function RunsView(props) {
|
|
|
2966
3528
|
h(
|
|
2967
3529
|
"div",
|
|
2968
3530
|
{ className: "dshgt-runs-head" },
|
|
2969
|
-
h("span", { className: "dshgt-hint" }, t("runs.count", { count:
|
|
3531
|
+
h("span", { className: "dshgt-hint" }, t("runs.count", { count: hintCount })),
|
|
2970
3532
|
h(
|
|
2971
3533
|
"div",
|
|
2972
3534
|
{ className: "dshgt-runs-filter" },
|
|
2973
|
-
|
|
3535
|
+
KINDS.map(
|
|
2974
3536
|
(item) => h(
|
|
2975
3537
|
"button",
|
|
2976
3538
|
{
|
|
2977
3539
|
key: item.id,
|
|
2978
3540
|
type: "button",
|
|
2979
3541
|
className: "dshgt-chip",
|
|
2980
|
-
"aria-pressed":
|
|
2981
|
-
onClick: () =>
|
|
3542
|
+
"aria-pressed": kind === item.id ? "true" : "false",
|
|
3543
|
+
onClick: () => {
|
|
3544
|
+
setKind(item.id);
|
|
3545
|
+
if (item.id === "release") setFilter("all");
|
|
3546
|
+
}
|
|
2982
3547
|
},
|
|
2983
3548
|
t(item.key)
|
|
2984
3549
|
)
|
|
3550
|
+
),
|
|
3551
|
+
kind === "release" ? null : h("span", { key: "sep", className: "dshgt-hint" }, "·"),
|
|
3552
|
+
kind === "release" ? null : FILTERS.filter((item) => item.id !== "all").map(
|
|
3553
|
+
(item) => (
|
|
3554
|
+
// 再点一次当前项 = 取消该筛选,这样不必再摆一个和「全部」重名的胶囊。
|
|
3555
|
+
h(
|
|
3556
|
+
"button",
|
|
3557
|
+
{
|
|
3558
|
+
key: item.id,
|
|
3559
|
+
type: "button",
|
|
3560
|
+
className: "dshgt-chip",
|
|
3561
|
+
"aria-pressed": filter === item.id ? "true" : "false",
|
|
3562
|
+
onClick: () => setFilter(filter === item.id ? "all" : item.id)
|
|
3563
|
+
},
|
|
3564
|
+
t(item.key)
|
|
3565
|
+
)
|
|
3566
|
+
)
|
|
2985
3567
|
)
|
|
2986
3568
|
)
|
|
2987
3569
|
),
|
|
2988
|
-
|
|
3570
|
+
entries.length === 0 ? h("div", { className: "dshgt-empty" }, kind === "release" ? t("runs.release.empty") : t("runs.empty")) : h(
|
|
2989
3571
|
"div",
|
|
2990
3572
|
{ className: "dshgt-run-list" },
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
type: "button",
|
|
3001
|
-
className: "dshgt-run-row",
|
|
3002
|
-
"aria-expanded": open ? "true" : "false",
|
|
3003
|
-
onClick: () => setOpenId(open ? null : record.id)
|
|
3004
|
-
},
|
|
3005
|
-
h("span", { className: `dshgt-lamp ${record.ok ? record.skipped || record.kind === "dry-run" ? "warn" : "ok" : "err"}` }),
|
|
3006
|
-
h("span", { className: "dshgt-run-date" }, shortTime(record.at)),
|
|
3007
|
-
h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`)),
|
|
3008
|
-
h(
|
|
3009
|
-
"span",
|
|
3010
|
-
{ className: "dshgt-run-what" },
|
|
3011
|
-
record.kind === "dry-run" ? t("state.dry") : record.skipped ? t("state.skipped") : record.ok ? t("state.ok") : t("state.failed"),
|
|
3012
|
-
h("span", { className: "dshgt-run-muted" }, recordSummary(t, record)),
|
|
3013
|
-
record.legacy === true ? h("span", { className: "dshgt-tag dshgt-inline-tag" }, t("runs.legacy")) : null
|
|
3014
|
-
),
|
|
3015
|
-
h("span", { className: "dshgt-run-files" }, t("runs.files", { count: record.files })),
|
|
3016
|
-
record.tokens === void 0 ? null : h("span", { className: "dshgt-run-tokens dshgt-mono", title: t("run.usage.tokens") }, `${formatTokens(record.tokens)} tok`),
|
|
3017
|
-
h("span", { className: "dshgt-run-duration" }, duration(record.durationMs)),
|
|
3018
|
-
h("span", { className: "dshgt-run-chev" }, "›")
|
|
3019
|
-
),
|
|
3020
|
-
open ? h(
|
|
3021
|
-
"div",
|
|
3022
|
-
{ className: "dshgt-run-detail" },
|
|
3023
|
-
!record.ok ? h(
|
|
3024
|
-
Alert,
|
|
3025
|
-
{ kind: "err", title: `${t("error.prefix")} ${record.errorCode ?? "INTERNAL"}` },
|
|
3026
|
-
h("div", null, record.errorMessage ?? t("state.failed")),
|
|
3027
|
-
record.errorReason === void 0 ? null : h("div", { className: "dshgt-hint" }, reasonHint(t, record.errorReason) ?? "")
|
|
3028
|
-
) : null,
|
|
3029
|
-
h(
|
|
3030
|
-
"div",
|
|
3031
|
-
{ className: "dshgt-detail-grid" },
|
|
3032
|
-
detailItem(t, "run.usage.commit", record.commit === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.commit)),
|
|
3033
|
-
detailItem(t, "run.usage.hash", h("span", { className: "dshgt-mono" }, shortHash(record.contentHash))),
|
|
3034
|
-
detailItem(t, "run.usage.branch", record.branch === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.branch)),
|
|
3035
|
-
detailItem(t, "runs.detail.coreModel", `${record.coreVersion || "—"} · ${record.model?.model ?? "—"}`),
|
|
3036
|
-
detailItem(t, "runs.detail.date", record.date ?? "—"),
|
|
3037
|
-
detailItem(t, "runs.detail.period", h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`))),
|
|
3038
|
-
detailItem(
|
|
3039
|
-
t,
|
|
3040
|
-
"run.usage.pr",
|
|
3041
|
-
record.prUrl === void 0 ? "—" : h(
|
|
3042
|
-
"span",
|
|
3043
|
-
{ className: "dshgt-inline" },
|
|
3044
|
-
h("a", { href: record.prUrl, target: "_blank", rel: "noreferrer", title: record.prUrl }, t("digest.openPr")),
|
|
3045
|
-
pr === null ? null : h("span", { className: "dshgt-tag" }, pr.label)
|
|
3046
|
-
)
|
|
3047
|
-
),
|
|
3048
|
-
detailItem(t, "runs.detail.warnings", record.warnings.length === 0 ? t("runs.detail.none") : record.warnings.join(";")),
|
|
3049
|
-
detailItem(t, "runs.detail.files", `${record.files} · ${duration(record.durationMs)}`),
|
|
3050
|
-
detailItem(t, "runs.detail.tokens", record.tokens === void 0 ? t("runs.detail.tokensNone") : h("span", { className: "dshgt-mono" }, `${formatTokens(record.tokens)} tokens`))
|
|
3051
|
-
),
|
|
3052
|
-
record.releases === void 0 ? null : ReleasesDetail({ t, record }),
|
|
3053
|
-
record.legacy === true ? h("div", { className: "dshgt-hint" }, t("runs.legacyHint")) : null,
|
|
3054
|
-
h(
|
|
3055
|
-
"div",
|
|
3056
|
-
{ className: "dshgt-run-actions" },
|
|
3057
|
-
record.preview === void 0 ? h("span", { className: "dshgt-hint" }, t("runs.detail.noPreview")) : h(
|
|
3058
|
-
Btn,
|
|
3059
|
-
{
|
|
3060
|
-
small: true,
|
|
3061
|
-
onClick: () => {
|
|
3062
|
-
const target = digestTarget(record, state.schedule.timezone);
|
|
3063
|
-
if (target !== void 0) props.onOpenDigest(target);
|
|
3064
|
-
}
|
|
3065
|
-
},
|
|
3066
|
-
t("runs.detail.readDigest")
|
|
3067
|
-
),
|
|
3068
|
-
h(Btn, { small: true, onClick: () => setLogId(record.id) }, t("runs.detail.log")),
|
|
3069
|
-
record.preview === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, record.preview.file)
|
|
3070
|
-
)
|
|
3071
|
-
) : null
|
|
3072
|
-
);
|
|
3073
|
-
})
|
|
3573
|
+
entries.map(
|
|
3574
|
+
(entry) => entry.kind === "digest" ? digestNode(entry.record) : h(ReleaseRunItem, {
|
|
3575
|
+
key: entry.key,
|
|
3576
|
+
t,
|
|
3577
|
+
run: entry.run,
|
|
3578
|
+
open: openId === entry.key,
|
|
3579
|
+
onToggle: () => setOpenId(openId === entry.key ? null : entry.key)
|
|
3580
|
+
})
|
|
3581
|
+
)
|
|
3074
3582
|
),
|
|
3075
3583
|
state.status.totalTokens === void 0 ? null : h("div", { className: "dshgt-runs-foot dshgt-hint" }, t("runs.footer.total", { total: formatTokens(state.status.totalTokens) })),
|
|
3076
3584
|
logId === null ? null : h(LogDrawer, { t, runId: logId, onClose: () => setLogId(null) })
|
|
3077
3585
|
);
|
|
3078
3586
|
}
|
|
3587
|
+
var RELEASE_LAMP = {
|
|
3588
|
+
ok: "ok",
|
|
3589
|
+
failed: "err",
|
|
3590
|
+
skipped: "warn",
|
|
3591
|
+
cancelled: "warn"
|
|
3592
|
+
};
|
|
3593
|
+
function ReleaseRunItem(props) {
|
|
3594
|
+
const { t, run } = props;
|
|
3595
|
+
const lamp = RELEASE_LAMP[run.status] ?? "warn";
|
|
3596
|
+
const headStats = [
|
|
3597
|
+
[t("runs.release.checked"), run.checked],
|
|
3598
|
+
[t("runs.release.changed"), run.changed],
|
|
3599
|
+
[t("runs.release.newTags"), run.newTags]
|
|
3600
|
+
];
|
|
3601
|
+
return h(
|
|
3602
|
+
"div",
|
|
3603
|
+
{ className: `dshgt-run-item${props.open ? " open" : ""}${run.tokens === void 0 ? "" : " has-tokens"}` },
|
|
3604
|
+
h(
|
|
3605
|
+
"button",
|
|
3606
|
+
{
|
|
3607
|
+
type: "button",
|
|
3608
|
+
className: "dshgt-run-row",
|
|
3609
|
+
"aria-expanded": props.open ? "true" : "false",
|
|
3610
|
+
onClick: props.onToggle
|
|
3611
|
+
},
|
|
3612
|
+
h("span", { className: `dshgt-lamp ${lamp}` }),
|
|
3613
|
+
h("span", { className: "dshgt-run-date" }, shortTime(run.startedAt)),
|
|
3614
|
+
h("span", { className: "dshgt-pchip" }, t("runs.type.release")),
|
|
3615
|
+
h(
|
|
3616
|
+
"span",
|
|
3617
|
+
{ className: "dshgt-run-what" },
|
|
3618
|
+
t(`runs.release.status.${run.status}`),
|
|
3619
|
+
h("span", { className: "dshgt-run-muted" }, headStats.map(([label, value]) => `${label} ${value}`).join(" · "))
|
|
3620
|
+
),
|
|
3621
|
+
h("span", { className: "dshgt-run-files" }, run.failed > 0 ? `${t("runs.release.failed")} ${run.failed}` : ""),
|
|
3622
|
+
run.tokens === void 0 ? null : h("span", { className: "dshgt-run-tokens dshgt-mono", title: t("run.usage.tokens") }, `${formatTokens(run.tokens)} tok`),
|
|
3623
|
+
h("span", { className: "dshgt-run-duration" }, duration(run.durationMs)),
|
|
3624
|
+
h("span", { className: "dshgt-run-chev" }, "›")
|
|
3625
|
+
),
|
|
3626
|
+
props.open ? h(
|
|
3627
|
+
"div",
|
|
3628
|
+
{ className: "dshgt-run-detail" },
|
|
3629
|
+
run.status === "failed" ? h(
|
|
3630
|
+
Alert,
|
|
3631
|
+
{ kind: "err", title: `${t("error.prefix")} ${run.errorCode ?? "INTERNAL"}` },
|
|
3632
|
+
h("div", null, run.errorMessage ?? t("state.failed"))
|
|
3633
|
+
) : null,
|
|
3634
|
+
h(
|
|
3635
|
+
"div",
|
|
3636
|
+
{ className: "dshgt-detail-grid" },
|
|
3637
|
+
detailItem(t, "runs.release.startedAt", shortTime(run.startedAt)),
|
|
3638
|
+
detailItem(t, "runs.release.finishedAt", shortTime(run.finishedAt)),
|
|
3639
|
+
detailItem(t, "runs.release.duration", duration(run.durationMs)),
|
|
3640
|
+
detailItem(t, "runs.release.checked", String(run.checked)),
|
|
3641
|
+
detailItem(t, "runs.release.changed", String(run.changed)),
|
|
3642
|
+
detailItem(t, "runs.release.newTags", String(run.newTags)),
|
|
3643
|
+
detailItem(t, "runs.release.summarized", String(run.summarized)),
|
|
3644
|
+
detailItem(t, "runs.release.degraded", String(run.degraded)),
|
|
3645
|
+
detailItem(t, "runs.release.failed", String(run.failed)),
|
|
3646
|
+
detailItem(t, "runs.release.rateLimited", String(run.rateLimited)),
|
|
3647
|
+
detailItem(t, "run.usage.tokens", run.tokens === void 0 ? "—" : formatTokens(run.tokens)),
|
|
3648
|
+
detailItem(t, "run.usage.commit", run.commit === void 0 ? "—" : h("span", { className: "dshgt-mono" }, run.commit)),
|
|
3649
|
+
detailItem(t, "run.usage.branch", run.branch === void 0 ? "—" : h("span", { className: "dshgt-mono" }, run.branch)),
|
|
3650
|
+
detailItem(
|
|
3651
|
+
t,
|
|
3652
|
+
"run.usage.pr",
|
|
3653
|
+
run.prUrl === void 0 ? "—" : h("a", { href: run.prUrl, target: "_blank", rel: "noreferrer", title: run.prUrl }, t("digest.openPr"))
|
|
3654
|
+
)
|
|
3655
|
+
),
|
|
3656
|
+
h("p", { className: "dshgt-hint", style: { margin: 0 } }, t("runs.release.note"))
|
|
3657
|
+
) : null
|
|
3658
|
+
);
|
|
3659
|
+
}
|
|
3079
3660
|
function ReleasesDetail(props) {
|
|
3080
3661
|
const { t, record } = props;
|
|
3081
3662
|
const r = record.releases;
|
|
@@ -3782,126 +4363,676 @@ function metaLine(rendered) {
|
|
|
3782
4363
|
|
|
3783
4364
|
// client/subscriptions.ts
|
|
3784
4365
|
var REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
4366
|
+
var KNOWN_STATUSES = ["baseline", "ok", "no_change", "rate_limited", "failed"];
|
|
4367
|
+
var DATE_RE2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
4368
|
+
function errorText(failure) {
|
|
4369
|
+
return failure instanceof Error ? failure.message : String(failure);
|
|
4370
|
+
}
|
|
4371
|
+
function monthDay(value) {
|
|
4372
|
+
if (value === void 0 || value === "") return "—";
|
|
4373
|
+
return DATE_RE2.test(value) ? value.slice(5) : value;
|
|
4374
|
+
}
|
|
4375
|
+
function clock(value) {
|
|
4376
|
+
return /^\d{2}:\d{2}/.test(value) ? value.slice(0, 5) : value;
|
|
4377
|
+
}
|
|
4378
|
+
function weekdayLabel(t, weekday) {
|
|
4379
|
+
return weekday >= 1 && weekday <= 7 ? t(`weekday.${weekday}`) : String(weekday);
|
|
4380
|
+
}
|
|
4381
|
+
function toneOf(status) {
|
|
4382
|
+
if (status === "ok") return "ok";
|
|
4383
|
+
if (status === "rate_limited") return "warn";
|
|
4384
|
+
if (status === "failed") return "err";
|
|
4385
|
+
return "idle";
|
|
4386
|
+
}
|
|
4387
|
+
function statusLabel(t, status) {
|
|
4388
|
+
if (status === void 0) return "—";
|
|
4389
|
+
return KNOWN_STATUSES.includes(status) ? t(`subs.status.${status}`) : "—";
|
|
4390
|
+
}
|
|
4391
|
+
function mergeRows(list) {
|
|
4392
|
+
if (list === null) return [];
|
|
4393
|
+
const byName = /* @__PURE__ */ new Map();
|
|
4394
|
+
for (const item of list.items) byName.set(item.fullName, item);
|
|
4395
|
+
const names = [...list.repos];
|
|
4396
|
+
for (const item of list.items) {
|
|
4397
|
+
if (!names.includes(item.fullName)) names.push(item.fullName);
|
|
4398
|
+
}
|
|
4399
|
+
return names.map((name) => {
|
|
4400
|
+
const item = byName.get(name);
|
|
4401
|
+
return item === void 0 ? { name } : { name, item };
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
function sortValue(row, key) {
|
|
4405
|
+
if (key === "name") return row.name.toLowerCase();
|
|
4406
|
+
if (key === "tag") return row.item?.latestTag ?? "";
|
|
4407
|
+
return row.item?.latestSummaryAt ?? "";
|
|
4408
|
+
}
|
|
4409
|
+
function sortRows(rows, sort) {
|
|
4410
|
+
return [...rows].sort((a, b) => {
|
|
4411
|
+
const av = sortValue(a, sort.key);
|
|
4412
|
+
const bv = sortValue(b, sort.key);
|
|
4413
|
+
if (av === bv) return a.name.localeCompare(b.name);
|
|
4414
|
+
if (av === "") return 1;
|
|
4415
|
+
if (bv === "") return -1;
|
|
4416
|
+
return (av < bv ? -1 : 1) * sort.dir;
|
|
4417
|
+
});
|
|
4418
|
+
}
|
|
4419
|
+
function highlight(text, needle) {
|
|
4420
|
+
if (needle === "") return text;
|
|
4421
|
+
const lower = text.toLowerCase();
|
|
4422
|
+
const parts = [];
|
|
4423
|
+
let index = 0;
|
|
4424
|
+
let found = lower.indexOf(needle);
|
|
4425
|
+
let key = 0;
|
|
4426
|
+
while (found >= 0) {
|
|
4427
|
+
if (found > index) parts.push(text.slice(index, found));
|
|
4428
|
+
parts.push(h("mark", { key: `m${key}` }, text.slice(found, found + needle.length)));
|
|
4429
|
+
key += 1;
|
|
4430
|
+
index = found + needle.length;
|
|
4431
|
+
found = lower.indexOf(needle, index);
|
|
4432
|
+
}
|
|
4433
|
+
if (index === 0) return text;
|
|
4434
|
+
if (index < text.length) parts.push(text.slice(index));
|
|
4435
|
+
return parts;
|
|
4436
|
+
}
|
|
4437
|
+
function weekStart(date) {
|
|
4438
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
|
|
4439
|
+
if (match === null) return date;
|
|
4440
|
+
const value = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
|
|
4441
|
+
const dayIndex = (value.getUTCDay() + 6) % 7;
|
|
4442
|
+
value.setUTCDate(value.getUTCDate() - dayIndex);
|
|
4443
|
+
return value.toISOString().slice(0, 10);
|
|
4444
|
+
}
|
|
4445
|
+
function metaOf(t, store) {
|
|
4446
|
+
const state = store?.state ?? null;
|
|
4447
|
+
const schedule = state?.schedule;
|
|
4448
|
+
const releaseSchedule = state?.settings?.releases?.schedule;
|
|
4449
|
+
const weekday = typeof schedule?.releaseWeekday === "number" ? schedule.releaseWeekday : releaseSchedule?.weekday;
|
|
4450
|
+
const time = typeof schedule?.releaseTime === "string" && schedule.releaseTime !== "" ? schedule.releaseTime : releaseSchedule?.time;
|
|
4451
|
+
const timezone = (typeof schedule?.releaseTimezone === "string" && schedule.releaseTimezone !== "" ? schedule.releaseTimezone : releaseSchedule?.timezone) ?? schedule?.timezone ?? "Asia/Shanghai";
|
|
4452
|
+
const cadence = weekday === void 0 || time === void 0 || time === "" ? t("subs.meta.cadence") : t("subs.meta.cadence.full", { weekday: weekdayLabel(t, weekday), time: clock(time) });
|
|
4453
|
+
const nextAt = typeof schedule?.nextReleaseAt === "string" && schedule.nextReleaseAt !== "" ? schedule.nextReleaseAt : void 0;
|
|
4454
|
+
const next = nextAt === void 0 ? void 0 : shortTime(nextAt);
|
|
4455
|
+
const runs = releaseRunsOf(state);
|
|
4456
|
+
const newest = runs.length === 0 ? void 0 : runs.reduce((a, b) => Date.parse(b.finishedAt || b.startedAt) > Date.parse(a.finishedAt || a.startedAt) ? b : a);
|
|
4457
|
+
const lastCheckAt = newest?.finishedAt ?? lastReleaseAtOf(state);
|
|
4458
|
+
const lastCheck = typeof lastCheckAt === "string" && lastCheckAt !== "" ? shortTime(lastCheckAt) : void 0;
|
|
4459
|
+
let lastWeek;
|
|
4460
|
+
if (newest !== void 0) {
|
|
4461
|
+
const today = zonedDateString(/* @__PURE__ */ new Date(), timezone);
|
|
4462
|
+
const currentFrom = weekStart(today);
|
|
4463
|
+
const lastFrom = addDays(currentFrom, -7);
|
|
4464
|
+
const at = newest.finishedAt !== "" ? newest.finishedAt : newest.startedAt;
|
|
4465
|
+
const runDate = zonedDateString(new Date(at), timezone);
|
|
4466
|
+
if (runDate >= lastFrom && runDate <= addDays(lastFrom, 6)) {
|
|
4467
|
+
lastWeek = t("subs.meta.lastWeek", { from: monthDay(lastFrom), to: monthDay(addDays(lastFrom, 6)), changed: newest.changed });
|
|
4468
|
+
} else if (runDate >= currentFrom && runDate <= addDays(currentFrom, 6)) {
|
|
4469
|
+
lastWeek = t("subs.meta.thisWeek", { from: monthDay(currentFrom), to: monthDay(addDays(currentFrom, 6)), changed: newest.changed });
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
const info = { cadence };
|
|
4473
|
+
if (next !== void 0) info.next = next;
|
|
4474
|
+
if (lastWeek !== void 0) info.lastWeek = lastWeek;
|
|
4475
|
+
if (lastCheck !== void 0) info.lastCheck = lastCheck;
|
|
4476
|
+
return info;
|
|
4477
|
+
}
|
|
4478
|
+
function isMissingDoc(code, message) {
|
|
4479
|
+
if (code !== void 0 && /NOT_?FOUND|MISSING|NO_?DOC/i.test(code)) return true;
|
|
4480
|
+
return /not\s*found|no such file|enoent|404|不存在|no release document|has no release|无发版记录/i.test(message);
|
|
4481
|
+
}
|
|
4482
|
+
function docPath(repo, volume, volumes) {
|
|
4483
|
+
const entry = volumes?.find((item) => item.index === volume);
|
|
4484
|
+
if (entry !== void 0 && entry.file !== "") return `releases/${entry.file}`;
|
|
4485
|
+
return `releases/${repo}-${String(volume).padStart(2, "0")}.md`;
|
|
4486
|
+
}
|
|
4487
|
+
function DocDrawer(props) {
|
|
4488
|
+
const { t, repo } = props;
|
|
4489
|
+
const [volume, setVolume] = import_react.default.useState(void 0);
|
|
4490
|
+
const [doc, setDoc] = import_react.default.useState(null);
|
|
4491
|
+
const [loading, setLoading] = import_react.default.useState(true);
|
|
4492
|
+
const [missing, setMissing] = import_react.default.useState(false);
|
|
4493
|
+
const [error, setError] = import_react.default.useState(null);
|
|
4494
|
+
const [attempt, setAttempt] = import_react.default.useState(0);
|
|
4495
|
+
const closeRef = import_react.default.useRef(null);
|
|
4496
|
+
import_react.default.useEffect(() => {
|
|
4497
|
+
const controller = new AbortController();
|
|
4498
|
+
setLoading(true);
|
|
4499
|
+
setError(null);
|
|
4500
|
+
setMissing(false);
|
|
4501
|
+
getSubscriptionDoc(repo, volume, controller.signal).then((payload) => {
|
|
4502
|
+
if (controller.signal.aborted) return;
|
|
4503
|
+
setDoc(payload);
|
|
4504
|
+
setMissing(payload.markdown.trim() === "");
|
|
4505
|
+
setLoading(false);
|
|
4506
|
+
}).catch((failure) => {
|
|
4507
|
+
if (controller.signal.aborted) return;
|
|
4508
|
+
const message = errorText(failure);
|
|
4509
|
+
const code = failure.code;
|
|
4510
|
+
if (isMissingDoc(code, message)) setMissing(true);
|
|
4511
|
+
else setError(message);
|
|
4512
|
+
setLoading(false);
|
|
4513
|
+
});
|
|
4514
|
+
return () => controller.abort();
|
|
4515
|
+
}, [repo, volume, attempt]);
|
|
4516
|
+
import_react.default.useEffect(() => {
|
|
4517
|
+
const onKey = (event) => {
|
|
4518
|
+
if (event.key === "Escape") props.onClose();
|
|
4519
|
+
};
|
|
4520
|
+
document.addEventListener("keydown", onKey);
|
|
4521
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
4522
|
+
}, [props]);
|
|
4523
|
+
import_react.default.useEffect(() => {
|
|
4524
|
+
closeRef.current?.focus?.();
|
|
4525
|
+
}, []);
|
|
4526
|
+
const total = doc?.volumes !== void 0 && doc.volumes.length > 0 ? doc.volumes.length : 1;
|
|
4527
|
+
const current = doc?.volume ?? volume ?? 1;
|
|
4528
|
+
const stale = props.status === "rate_limited" || props.status === "failed";
|
|
4529
|
+
let nodes = null;
|
|
4530
|
+
let parseFailed = false;
|
|
4531
|
+
if (doc !== null && !missing && error === null) {
|
|
4532
|
+
try {
|
|
4533
|
+
nodes = renderMarkdown(doc.markdown).nodes;
|
|
4534
|
+
} catch {
|
|
4535
|
+
parseFailed = true;
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
const content = loading ? h("p", { className: "dshgt-hint" }, t("subs.drawer.loading")) : missing ? h("div", { className: "dshgt-subs-empty" }, h("span", null, t("subs.drawer.empty"))) : error !== null ? h(
|
|
4539
|
+
Alert,
|
|
4540
|
+
{ kind: "err", title: t("subs.drawer.title", { repo }) },
|
|
4541
|
+
h("div", null, error),
|
|
4542
|
+
h("div", { style: { marginTop: 8 } }, h(Btn, { small: true, onClick: () => setAttempt((current2) => current2 + 1) }, t("subs.drawer.retry")))
|
|
4543
|
+
) : parseFailed || nodes === null ? h("pre", { className: "dshgt-subs-drawer-raw" }, doc?.markdown ?? "") : h("div", { className: "dshgt-md" }, nodes);
|
|
4544
|
+
return h(
|
|
4545
|
+
"div",
|
|
4546
|
+
{
|
|
4547
|
+
className: "dshgt-subs-drawer-mask",
|
|
4548
|
+
onClick: (event) => {
|
|
4549
|
+
if (event.target === event.currentTarget) props.onClose();
|
|
4550
|
+
}
|
|
4551
|
+
},
|
|
4552
|
+
h(
|
|
4553
|
+
"aside",
|
|
4554
|
+
{ className: "dshgt-subs-drawer", role: "dialog", "aria-modal": "true", "aria-label": t("subs.drawer.title", { repo }) },
|
|
4555
|
+
h(
|
|
4556
|
+
"header",
|
|
4557
|
+
{ className: "dshgt-subs-drawer-head" },
|
|
4558
|
+
h(
|
|
4559
|
+
"div",
|
|
4560
|
+
{ className: "dshgt-subs-drawer-main" },
|
|
4561
|
+
h("div", { className: "dshgt-subs-drawer-repo" }, repo),
|
|
4562
|
+
doc === null ? null : h(
|
|
4563
|
+
"div",
|
|
4564
|
+
{ className: "dshgt-subs-drawer-sub" },
|
|
4565
|
+
doc.updatedAt === void 0 ? t("subs.drawer.volume", { index: current, total }) : t("subs.drawer.updated", { date: doc.updatedAt })
|
|
4566
|
+
)
|
|
4567
|
+
),
|
|
4568
|
+
h(
|
|
4569
|
+
"button",
|
|
4570
|
+
{
|
|
4571
|
+
type: "button",
|
|
4572
|
+
className: "dshgt-subs-drawer-close",
|
|
4573
|
+
"aria-label": t("subs.drawer.close"),
|
|
4574
|
+
title: t("subs.drawer.close"),
|
|
4575
|
+
ref: closeRef,
|
|
4576
|
+
onClick: () => props.onClose()
|
|
4577
|
+
},
|
|
4578
|
+
"×"
|
|
4579
|
+
)
|
|
4580
|
+
),
|
|
4581
|
+
h(
|
|
4582
|
+
"div",
|
|
4583
|
+
{ className: "dshgt-subs-drawer-body" },
|
|
4584
|
+
stale ? h(Alert, { kind: "warn" }, t(`subs.drawer.warn.${props.status ?? "failed"}`)) : null,
|
|
4585
|
+
total > 1 ? h(
|
|
4586
|
+
"div",
|
|
4587
|
+
{ className: "dshgt-subs-vol" },
|
|
4588
|
+
h("span", { className: "label" }, t("subs.drawer.volume", { index: current, total })),
|
|
4589
|
+
h(
|
|
4590
|
+
Btn,
|
|
4591
|
+
{
|
|
4592
|
+
small: true,
|
|
4593
|
+
disabled: loading || current <= 1,
|
|
4594
|
+
title: t("subs.drawer.prevVolume"),
|
|
4595
|
+
onClick: () => setVolume(current - 1)
|
|
4596
|
+
},
|
|
4597
|
+
t("subs.drawer.prevVolume")
|
|
4598
|
+
),
|
|
4599
|
+
h(
|
|
4600
|
+
Btn,
|
|
4601
|
+
{
|
|
4602
|
+
small: true,
|
|
4603
|
+
disabled: loading || current >= total,
|
|
4604
|
+
title: t("subs.drawer.nextVolume"),
|
|
4605
|
+
onClick: () => setVolume(current + 1)
|
|
4606
|
+
},
|
|
4607
|
+
t("subs.drawer.nextVolume")
|
|
4608
|
+
)
|
|
4609
|
+
) : null,
|
|
4610
|
+
content,
|
|
4611
|
+
loading ? null : h(
|
|
4612
|
+
"div",
|
|
4613
|
+
{ className: "dshgt-subs-drawer-note" },
|
|
4614
|
+
t("subs.drawer.note", { path: docPath(repo, current, doc?.volumes) })
|
|
4615
|
+
)
|
|
4616
|
+
)
|
|
4617
|
+
)
|
|
4618
|
+
);
|
|
4619
|
+
}
|
|
3785
4620
|
function SubscriptionsView(props) {
|
|
3786
4621
|
const { t } = props;
|
|
3787
|
-
const [
|
|
4622
|
+
const [list, setList] = import_react.default.useState(null);
|
|
3788
4623
|
const [error, setError] = import_react.default.useState(null);
|
|
3789
|
-
const [busy, setBusy] = import_react.default.useState(null);
|
|
3790
|
-
const [adding, setAdding] = import_react.default.useState(false);
|
|
3791
|
-
const [input, setInput] = import_react.default.useState("");
|
|
3792
4624
|
const [note, setNote] = import_react.default.useState(null);
|
|
3793
|
-
const
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
4625
|
+
const [busy, setBusy] = import_react.default.useState(null);
|
|
4626
|
+
const [query, setQuery] = import_react.default.useState("");
|
|
4627
|
+
const [sort, setSort] = import_react.default.useState({ key: "name", dir: 1 });
|
|
4628
|
+
const [selecting, setSelecting] = import_react.default.useState(false);
|
|
4629
|
+
const [selected, setSelected] = import_react.default.useState([]);
|
|
4630
|
+
const [confirming, setConfirming] = import_react.default.useState(null);
|
|
4631
|
+
const [openRepo, setOpenRepo] = import_react.default.useState(null);
|
|
4632
|
+
const [focus, setFocus] = import_react.default.useState(-1);
|
|
4633
|
+
const load = import_react.default.useCallback((signal) => {
|
|
4634
|
+
getSubscriptions(signal).then((next) => {
|
|
4635
|
+
if (signal?.aborted === true) return;
|
|
4636
|
+
setList(next);
|
|
4637
|
+
setError(null);
|
|
4638
|
+
}).catch((failure) => {
|
|
4639
|
+
if (signal?.aborted === true) return;
|
|
4640
|
+
setError(errorText(failure));
|
|
4641
|
+
setList({ repos: [], items: [] });
|
|
3798
4642
|
});
|
|
3799
4643
|
}, []);
|
|
3800
4644
|
import_react.default.useEffect(() => {
|
|
3801
|
-
|
|
4645
|
+
const controller = new AbortController();
|
|
4646
|
+
load(controller.signal);
|
|
4647
|
+
return () => controller.abort();
|
|
3802
4648
|
}, [load]);
|
|
3803
|
-
const
|
|
3804
|
-
|
|
3805
|
-
const
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
}
|
|
4649
|
+
const inputRef = import_react.default.useRef(null);
|
|
4650
|
+
import_react.default.useEffect(() => {
|
|
4651
|
+
const onKey = (event) => {
|
|
4652
|
+
if (event.key.toLowerCase() !== "k" || !(event.metaKey || event.ctrlKey)) return;
|
|
4653
|
+
event.preventDefault();
|
|
4654
|
+
inputRef.current?.focus?.();
|
|
4655
|
+
};
|
|
4656
|
+
document.addEventListener("keydown", onKey);
|
|
4657
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
4658
|
+
}, []);
|
|
4659
|
+
const rows = mergeRows(list);
|
|
4660
|
+
const needle = query.trim().toLowerCase();
|
|
4661
|
+
const matched = needle === "" ? rows : rows.filter((row) => row.name.toLowerCase().includes(needle));
|
|
4662
|
+
const sorted = sortRows(matched, sort);
|
|
4663
|
+
const candidate = needle !== "" && REPO_PATTERN.test(query.trim()) ? query.trim() : void 0;
|
|
4664
|
+
const subscribed = candidate !== void 0 && rows.some((row) => row.name.toLowerCase() === candidate.toLowerCase());
|
|
4665
|
+
const activeFocus = focus >= 0 && focus < sorted.length ? focus : -1;
|
|
4666
|
+
const toggleSelect = (repo) => {
|
|
4667
|
+
setSelected((current) => current.includes(repo) ? current.filter((item) => item !== repo) : [...current, repo]);
|
|
4668
|
+
};
|
|
4669
|
+
const addRepo = (repo) => {
|
|
3810
4670
|
setBusy("add");
|
|
3811
4671
|
setError(null);
|
|
3812
4672
|
setNote(null);
|
|
3813
|
-
postSubscriptions("add",
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
setNote(t("subs.add.queued"));
|
|
3818
|
-
}).catch((failure) => setError(
|
|
4673
|
+
postSubscriptions("add", [repo]).then((next) => {
|
|
4674
|
+
setList(next);
|
|
4675
|
+
setQuery("");
|
|
4676
|
+
setFocus(-1);
|
|
4677
|
+
setNote(t("subs.add.queued", { repo }));
|
|
4678
|
+
}).catch((failure) => setError(errorText(failure))).finally(() => setBusy(null));
|
|
3819
4679
|
};
|
|
3820
|
-
const
|
|
4680
|
+
const removeOne = (repo) => {
|
|
3821
4681
|
setBusy(`remove:${repo}`);
|
|
3822
4682
|
setError(null);
|
|
3823
4683
|
setNote(null);
|
|
3824
|
-
postSubscriptions("remove", [repo]).then((
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
4684
|
+
postSubscriptions("remove", [repo]).then((next) => {
|
|
4685
|
+
setList(next);
|
|
4686
|
+
setSelected((current) => current.filter((item) => item !== repo));
|
|
4687
|
+
setNote(t("subs.remove.queued", { repo }));
|
|
4688
|
+
}).catch((failure) => setError(errorText(failure))).finally(() => setBusy(null));
|
|
3828
4689
|
};
|
|
3829
|
-
const
|
|
4690
|
+
const removeMany = (repos) => {
|
|
4691
|
+
setBusy("remove:many");
|
|
4692
|
+
setError(null);
|
|
4693
|
+
setNote(null);
|
|
4694
|
+
postSubscriptions("remove", repos).then((next) => {
|
|
4695
|
+
setList(next);
|
|
4696
|
+
setSelected([]);
|
|
4697
|
+
setSelecting(false);
|
|
4698
|
+
setConfirming(null);
|
|
4699
|
+
setNote(t("subs.removed.many", { count: repos.length }));
|
|
4700
|
+
}).catch((failure) => {
|
|
4701
|
+
setError(errorText(failure));
|
|
4702
|
+
setConfirming(null);
|
|
4703
|
+
}).finally(() => setBusy(null));
|
|
4704
|
+
};
|
|
4705
|
+
const onSort = (key) => {
|
|
4706
|
+
setSort((current) => current.key === key ? { key, dir: current.dir === 1 ? -1 : 1 } : { key, dir: 1 });
|
|
4707
|
+
};
|
|
4708
|
+
const header = (key, labelKey, right) => {
|
|
4709
|
+
const active = sort.key === key;
|
|
4710
|
+
return h(
|
|
4711
|
+
"button",
|
|
4712
|
+
{
|
|
4713
|
+
key,
|
|
4714
|
+
type: "button",
|
|
4715
|
+
role: "columnheader",
|
|
4716
|
+
className: `dshgt-subs-th dshgt-subs-th-${key}${right ? " right" : ""}`,
|
|
4717
|
+
"aria-sort": active ? sort.dir === 1 ? "ascending" : "descending" : "none",
|
|
4718
|
+
"aria-label": t("subs.sort.by", { column: t(labelKey) }),
|
|
4719
|
+
onClick: () => onSort(key)
|
|
4720
|
+
},
|
|
4721
|
+
t(labelKey),
|
|
4722
|
+
active ? h("span", { className: "dshgt-subs-ord" }, sort.dir === 1 ? "▲" : "▼") : null
|
|
4723
|
+
);
|
|
4724
|
+
};
|
|
4725
|
+
const onCommandKey = (event) => {
|
|
4726
|
+
if (event.isComposing === true) return;
|
|
4727
|
+
if (event.key === "Escape") {
|
|
4728
|
+
setQuery("");
|
|
4729
|
+
setFocus(-1);
|
|
4730
|
+
if (selecting) {
|
|
4731
|
+
setSelecting(false);
|
|
4732
|
+
setSelected([]);
|
|
4733
|
+
}
|
|
4734
|
+
return;
|
|
4735
|
+
}
|
|
4736
|
+
if (event.key === "Enter") {
|
|
4737
|
+
if (candidate !== void 0 && !subscribed) {
|
|
4738
|
+
event.preventDefault();
|
|
4739
|
+
addRepo(candidate);
|
|
4740
|
+
return;
|
|
4741
|
+
}
|
|
4742
|
+
if (activeFocus >= 0) {
|
|
4743
|
+
event.preventDefault();
|
|
4744
|
+
setOpenRepo(sorted[activeFocus]?.name ?? null);
|
|
4745
|
+
}
|
|
4746
|
+
return;
|
|
4747
|
+
}
|
|
4748
|
+
if (event.key === "ArrowDown") {
|
|
4749
|
+
event.preventDefault();
|
|
4750
|
+
setFocus(Math.min(sorted.length - 1, focus + 1));
|
|
4751
|
+
return;
|
|
4752
|
+
}
|
|
4753
|
+
if (event.key === "ArrowUp") {
|
|
4754
|
+
event.preventDefault();
|
|
4755
|
+
setFocus(Math.max(-1, focus - 1));
|
|
4756
|
+
}
|
|
4757
|
+
};
|
|
4758
|
+
const meta = metaOf(t, props.store);
|
|
4759
|
+
const metaRight = needle !== "" ? [t("subs.meta.match", { matched: sorted.length, total: rows.length })] : [
|
|
4760
|
+
meta.lastCheck === void 0 ? void 0 : t("subs.meta.lastCheck", { time: meta.lastCheck }),
|
|
4761
|
+
meta.lastWeek
|
|
4762
|
+
].filter((item) => item !== void 0);
|
|
4763
|
+
const drawerRow = openRepo === null ? void 0 : rows.find((row) => row.name === openRepo);
|
|
4764
|
+
const rowNodes = sorted.map((row, index) => {
|
|
4765
|
+
const item = row.item;
|
|
4766
|
+
const tone = toneOf(item?.status);
|
|
4767
|
+
const checkbox = selecting ? h(
|
|
4768
|
+
"span",
|
|
4769
|
+
{ key: "cb", role: "cell", className: "dshgt-subs-cbwrap" },
|
|
4770
|
+
h("input", {
|
|
4771
|
+
type: "checkbox",
|
|
4772
|
+
className: "dshgt-subs-cb",
|
|
4773
|
+
checked: selected.includes(row.name),
|
|
4774
|
+
"aria-label": t("subs.sel.check", { repo: row.name }),
|
|
4775
|
+
onClick: (event) => event.stopPropagation(),
|
|
4776
|
+
onChange: () => toggleSelect(row.name)
|
|
4777
|
+
})
|
|
4778
|
+
) : null;
|
|
4779
|
+
return h(
|
|
4780
|
+
"div",
|
|
4781
|
+
{
|
|
4782
|
+
key: row.name,
|
|
4783
|
+
role: "row",
|
|
4784
|
+
className: `dshgt-subs-row${index === activeFocus ? " is-focus" : ""}`,
|
|
4785
|
+
onClick: () => {
|
|
4786
|
+
if (selecting) toggleSelect(row.name);
|
|
4787
|
+
else setOpenRepo(row.name);
|
|
4788
|
+
}
|
|
4789
|
+
},
|
|
4790
|
+
checkbox,
|
|
4791
|
+
h("span", { key: "name", role: "cell", className: "dshgt-subs-ident", title: row.name }, highlight(row.name, needle)),
|
|
4792
|
+
h("span", { key: "tag", role: "cell", className: "dshgt-subs-ver", title: item?.latestTag ?? "" }, item?.latestTag ?? "—"),
|
|
4793
|
+
h(
|
|
4794
|
+
"span",
|
|
4795
|
+
{ key: "sum", role: "cell", className: "dshgt-subs-sum", title: item?.latestSummaryAt ?? "" },
|
|
4796
|
+
monthDay(item?.latestSummaryAt)
|
|
4797
|
+
),
|
|
4798
|
+
h(
|
|
4799
|
+
"span",
|
|
4800
|
+
{ key: "status", role: "cell", className: `dshgt-subs-stat ${tone}` },
|
|
4801
|
+
h("span", { className: `dshgt-dot ${tone}` }),
|
|
4802
|
+
statusLabel(t, item?.status)
|
|
4803
|
+
),
|
|
4804
|
+
h(
|
|
4805
|
+
"span",
|
|
4806
|
+
{ key: "act", role: "cell", className: "dshgt-subs-actions" },
|
|
4807
|
+
h(
|
|
4808
|
+
"button",
|
|
4809
|
+
{
|
|
4810
|
+
type: "button",
|
|
4811
|
+
className: "dshgt-subs-act",
|
|
4812
|
+
"aria-label": t("subs.row.changesRepo", { repo: row.name }),
|
|
4813
|
+
onClick: (event) => {
|
|
4814
|
+
event.stopPropagation();
|
|
4815
|
+
setOpenRepo(row.name);
|
|
4816
|
+
}
|
|
4817
|
+
},
|
|
4818
|
+
t("subs.row.changes")
|
|
4819
|
+
),
|
|
4820
|
+
h(
|
|
4821
|
+
"button",
|
|
4822
|
+
{
|
|
4823
|
+
type: "button",
|
|
4824
|
+
className: "dshgt-subs-act rm",
|
|
4825
|
+
"aria-label": t("subs.row.removeRepo", { repo: row.name }),
|
|
4826
|
+
disabled: busy !== null,
|
|
4827
|
+
onClick: (event) => {
|
|
4828
|
+
event.stopPropagation();
|
|
4829
|
+
removeOne(row.name);
|
|
4830
|
+
}
|
|
4831
|
+
},
|
|
4832
|
+
busy === `remove:${row.name}` ? t("subs.removing") : t("subs.remove")
|
|
4833
|
+
)
|
|
4834
|
+
)
|
|
4835
|
+
);
|
|
4836
|
+
});
|
|
4837
|
+
const tableBody = list === null ? h("p", { className: "dshgt-hint" }, t("subs.loading")) : rows.length === 0 ? h(
|
|
4838
|
+
"div",
|
|
4839
|
+
{ className: "dshgt-subs-empty" },
|
|
4840
|
+
h("b", null, t("subs.empty")),
|
|
4841
|
+
h("span", null, t("subs.empty.hint"))
|
|
4842
|
+
) : sorted.length === 0 ? candidate !== void 0 && !subscribed ? (
|
|
4843
|
+
// 输入完整 owner/repo 时上方已给出「+ 添加」建议,这里不再叠一句「没有匹配」。
|
|
4844
|
+
null
|
|
4845
|
+
) : h(
|
|
4846
|
+
"div",
|
|
4847
|
+
{ className: "dshgt-subs-empty" },
|
|
4848
|
+
h("b", null, t("subs.empty.match")),
|
|
4849
|
+
h("span", null, t("subs.empty.match.hint")),
|
|
4850
|
+
h(Btn, { small: true, onClick: () => setQuery("") }, t("subs.empty.clear"))
|
|
4851
|
+
) : h(
|
|
4852
|
+
"div",
|
|
4853
|
+
{ className: `dshgt-subs-table${selecting ? " is-selecting" : ""}`, role: "table", "aria-label": t("subs.title") },
|
|
4854
|
+
h(
|
|
4855
|
+
"div",
|
|
4856
|
+
{ className: "dshgt-subs-thead", role: "row" },
|
|
4857
|
+
selecting ? h("span", { key: "cb", role: "columnheader", className: "dshgt-subs-cbwrap" }, h("span", { className: "dshgt-hint" }, t("subs.sel.column"))) : null,
|
|
4858
|
+
header("name", "subs.col.repo", false),
|
|
4859
|
+
header("tag", "subs.col.tag", true),
|
|
4860
|
+
header("summary", "subs.col.summary", true),
|
|
4861
|
+
h("span", { key: "status", role: "columnheader", className: "dshgt-subs-stat" }, t("subs.col.status")),
|
|
4862
|
+
h("span", { key: "act", role: "columnheader", className: "dshgt-subs-actions", "aria-label": t("subs.col.actions") })
|
|
4863
|
+
),
|
|
4864
|
+
h("div", { role: "rowgroup" }, rowNodes)
|
|
4865
|
+
);
|
|
3830
4866
|
return h(
|
|
3831
4867
|
"div",
|
|
3832
4868
|
{ className: "dshgt-view dshgt-subs" },
|
|
3833
4869
|
h(
|
|
3834
4870
|
"section",
|
|
3835
|
-
{ className: "dshgt-
|
|
4871
|
+
{ className: "dshgt-subs-head" },
|
|
3836
4872
|
h(
|
|
3837
4873
|
"div",
|
|
3838
|
-
{ className: "dshgt-subs-head" },
|
|
4874
|
+
{ className: "dshgt-subs-head-main" },
|
|
3839
4875
|
h("h2", null, t("subs.title")),
|
|
4876
|
+
h("p", { className: "dshgt-subs-dek" }, t("subs.desc"))
|
|
4877
|
+
),
|
|
4878
|
+
h(
|
|
4879
|
+
"div",
|
|
4880
|
+
{ className: "dshgt-subs-head-actions" },
|
|
3840
4881
|
h(
|
|
3841
|
-
|
|
3842
|
-
{
|
|
3843
|
-
|
|
4882
|
+
Btn,
|
|
4883
|
+
{
|
|
4884
|
+
small: true,
|
|
4885
|
+
onClick: () => {
|
|
4886
|
+
if (selecting) setSelected([]);
|
|
4887
|
+
setSelecting(!selecting);
|
|
4888
|
+
}
|
|
4889
|
+
},
|
|
4890
|
+
selecting ? t("subs.select.done") : t("subs.select")
|
|
3844
4891
|
)
|
|
4892
|
+
)
|
|
4893
|
+
),
|
|
4894
|
+
h(
|
|
4895
|
+
"div",
|
|
4896
|
+
{ className: "dshgt-subs-cmdwrap" },
|
|
4897
|
+
h(
|
|
4898
|
+
"div",
|
|
4899
|
+
{ className: "dshgt-subs-cmd" },
|
|
4900
|
+
h("input", {
|
|
4901
|
+
type: "text",
|
|
4902
|
+
ref: inputRef,
|
|
4903
|
+
value: query,
|
|
4904
|
+
placeholder: t("subs.cmd.placeholder"),
|
|
4905
|
+
"aria-label": t("subs.cmd.label"),
|
|
4906
|
+
"aria-keyshortcuts": "Meta+K Control+K",
|
|
4907
|
+
autoComplete: "off",
|
|
4908
|
+
spellCheck: false,
|
|
4909
|
+
onInput: (event) => {
|
|
4910
|
+
setQuery(event.target.value);
|
|
4911
|
+
setFocus(-1);
|
|
4912
|
+
},
|
|
4913
|
+
onKeyDown: onCommandKey
|
|
4914
|
+
}),
|
|
4915
|
+
h("kbd", { className: "dshgt-subs-kbd" }, "⌘K")
|
|
3845
4916
|
),
|
|
3846
|
-
h(
|
|
3847
|
-
error === null ? null : h(Alert, { kind: "err" }, error),
|
|
3848
|
-
note === null ? null : h(Alert, { kind: "ok" }, note),
|
|
3849
|
-
repos === null ? h("p", { className: "dshgt-hint" }, t("subs.loading")) : list.length === 0 ? h("div", { className: "dshgt-empty" }, t("subs.empty")) : h(
|
|
4917
|
+
h(
|
|
3850
4918
|
"div",
|
|
3851
|
-
{ className: "dshgt-subs-
|
|
4919
|
+
{ className: "dshgt-subs-meta" },
|
|
3852
4920
|
h(
|
|
3853
|
-
"
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
4921
|
+
"span",
|
|
4922
|
+
null,
|
|
4923
|
+
t("subs.meta.count", { count: rows.length }),
|
|
4924
|
+
" · ",
|
|
4925
|
+
h(
|
|
4926
|
+
"button",
|
|
4927
|
+
{ type: "button", className: "dshgt-subs-linkbtn", title: t("subs.param.link"), onClick: () => props.onOpenSettings() },
|
|
4928
|
+
meta.cadence
|
|
4929
|
+
),
|
|
4930
|
+
meta.next === void 0 ? null : ` · ${t("subs.meta.next", { time: meta.next })}`
|
|
3857
4931
|
),
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
h("span", { className: "dshgt-mono dshgt-subs-repo" }, repo),
|
|
3863
|
-
h(
|
|
3864
|
-
"span",
|
|
3865
|
-
{ className: "dshgt-subs-actions" },
|
|
3866
|
-
h(
|
|
3867
|
-
Btn,
|
|
3868
|
-
{ small: true, variant: "danger", onClick: () => doRemove(repo), disabled: busy !== null },
|
|
3869
|
-
busy === `remove:${repo}` ? t("subs.removing") : t("subs.remove")
|
|
3870
|
-
)
|
|
3871
|
-
)
|
|
3872
|
-
)
|
|
4932
|
+
metaRight.length === 0 ? null : h(
|
|
4933
|
+
"span",
|
|
4934
|
+
{ className: "dshgt-subs-meta-right" },
|
|
4935
|
+
metaRight.flatMap((part, index) => index === 0 ? [part] : [h("span", { key: `sep${index}`, className: "dshgt-subs-meta-sep" }, "·"), part])
|
|
3873
4936
|
)
|
|
4937
|
+
)
|
|
4938
|
+
),
|
|
4939
|
+
candidate === void 0 ? null : h(
|
|
4940
|
+
"div",
|
|
4941
|
+
{ className: "dshgt-subs-suggest" },
|
|
4942
|
+
subscribed ? [
|
|
4943
|
+
h("span", { key: "pill", className: "dshgt-tag" }, t("subs.cmd.subscribed")),
|
|
4944
|
+
h("span", { key: "repo", className: "repo" }, candidate),
|
|
4945
|
+
h("span", { key: "hint", className: "hint" }, t("subs.cmd.subscribed.hint"))
|
|
4946
|
+
] : [
|
|
4947
|
+
h("span", { key: "plus", className: "plus" }, "+"),
|
|
4948
|
+
h("span", { key: "add" }, t("subs.cmd.add")),
|
|
4949
|
+
h("span", { key: "repo", className: "repo" }, candidate),
|
|
4950
|
+
h("span", { key: "hint", className: "hint" }, t("subs.cmd.add.hint"))
|
|
4951
|
+
]
|
|
4952
|
+
),
|
|
4953
|
+
error === null ? null : h(Alert, { kind: "err" }, error),
|
|
4954
|
+
note === null ? null : h(Alert, { kind: "ok" }, note),
|
|
4955
|
+
tableBody,
|
|
4956
|
+
h(
|
|
4957
|
+
"div",
|
|
4958
|
+
{ className: "dshgt-subs-keys" },
|
|
4959
|
+
h("span", null, t("subs.keys.move")),
|
|
4960
|
+
h("span", null, t("subs.keys.enter")),
|
|
4961
|
+
h("span", null, t("subs.keys.esc")),
|
|
4962
|
+
h("span", null, t("subs.keys.sort"))
|
|
4963
|
+
),
|
|
4964
|
+
selecting && rows.length > 0 ? h(
|
|
4965
|
+
"div",
|
|
4966
|
+
{ className: "dshgt-subs-selbar" },
|
|
4967
|
+
h("span", null, t("subs.sel.count", { count: selected.length })),
|
|
4968
|
+
h(
|
|
4969
|
+
"button",
|
|
4970
|
+
{
|
|
4971
|
+
type: "button",
|
|
4972
|
+
className: "dshgt-subs-linkbtn",
|
|
4973
|
+
onClick: () => setSelected(sorted.map((row) => row.name))
|
|
4974
|
+
},
|
|
4975
|
+
t("subs.sel.all", { count: sorted.length })
|
|
3874
4976
|
),
|
|
3875
|
-
|
|
4977
|
+
h(
|
|
4978
|
+
"span",
|
|
4979
|
+
{ className: "dshgt-subs-selbar-actions" },
|
|
4980
|
+
h(
|
|
4981
|
+
Btn,
|
|
4982
|
+
{
|
|
4983
|
+
small: true,
|
|
4984
|
+
onClick: () => {
|
|
4985
|
+
setSelected([]);
|
|
4986
|
+
setSelecting(false);
|
|
4987
|
+
}
|
|
4988
|
+
},
|
|
4989
|
+
t("subs.sel.clear")
|
|
4990
|
+
),
|
|
4991
|
+
h(
|
|
4992
|
+
Btn,
|
|
4993
|
+
{ small: true, variant: "danger", disabled: busy !== null || selected.length === 0, onClick: () => setConfirming(selected) },
|
|
4994
|
+
t("subs.sel.remove")
|
|
4995
|
+
)
|
|
4996
|
+
)
|
|
4997
|
+
) : null,
|
|
4998
|
+
confirming === null ? null : h(
|
|
4999
|
+
"div",
|
|
5000
|
+
{
|
|
5001
|
+
className: "dshgt-modal-mask",
|
|
5002
|
+
onClick: (event) => {
|
|
5003
|
+
if (event.target === event.currentTarget) setConfirming(null);
|
|
5004
|
+
}
|
|
5005
|
+
},
|
|
5006
|
+
h(
|
|
3876
5007
|
"div",
|
|
3877
|
-
{ className: "dshgt-
|
|
3878
|
-
h("
|
|
5008
|
+
{ className: "dshgt-modal", role: "dialog", "aria-modal": "true", "aria-label": t("subs.confirm.title", { count: confirming.length }) },
|
|
5009
|
+
h("h3", { style: { margin: 0, fontSize: 14 } }, t("subs.confirm.title", { count: confirming.length })),
|
|
3879
5010
|
h(
|
|
3880
|
-
"
|
|
3881
|
-
{ className: "dshgt-subs-
|
|
3882
|
-
h(
|
|
3883
|
-
mono: true,
|
|
3884
|
-
width: 320,
|
|
3885
|
-
value: input,
|
|
3886
|
-
placeholder: t("subs.add.placeholder"),
|
|
3887
|
-
onInput: (value) => setInput(value)
|
|
3888
|
-
}),
|
|
3889
|
-
h(Btn, { small: true, variant: "primary", onClick: doAdd, disabled: busy !== null }, busy === "add" ? t("subs.adding") : t("subs.add.confirm")),
|
|
3890
|
-
h(Btn, { small: true, onClick: () => {
|
|
3891
|
-
setAdding(false);
|
|
3892
|
-
setInput("");
|
|
3893
|
-
setError(null);
|
|
3894
|
-
} }, t("subs.cancel"))
|
|
5011
|
+
"ul",
|
|
5012
|
+
{ className: "dshgt-subs-confirm-list" },
|
|
5013
|
+
confirming.slice(0, 6).map((repo) => h("li", { key: repo }, repo))
|
|
3895
5014
|
),
|
|
3896
|
-
h("p", { className: "dshgt-hint" }, t("subs.
|
|
3897
|
-
|
|
5015
|
+
confirming.length > 6 ? h("p", { className: "dshgt-hint", style: { margin: 0 } }, t("subs.confirm.more", { count: confirming.length - 6 })) : null,
|
|
5016
|
+
h("p", { className: "dshgt-hint", style: { margin: 0 } }, t("subs.confirm.body")),
|
|
5017
|
+
h(
|
|
5018
|
+
"div",
|
|
5019
|
+
{ className: "dshgt-footer", style: { justifyContent: "flex-end" } },
|
|
5020
|
+
h(Btn, { small: true, onClick: () => setConfirming(null) }, t("subs.confirm.cancel")),
|
|
5021
|
+
h(
|
|
5022
|
+
Btn,
|
|
5023
|
+
{ small: true, variant: "danger", disabled: busy !== null, onClick: () => removeMany(confirming) },
|
|
5024
|
+
t("subs.confirm.ok")
|
|
5025
|
+
)
|
|
5026
|
+
)
|
|
5027
|
+
)
|
|
3898
5028
|
),
|
|
3899
|
-
h(
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
5029
|
+
openRepo === null ? null : h(DocDrawer, {
|
|
5030
|
+
key: openRepo,
|
|
5031
|
+
t,
|
|
5032
|
+
repo: openRepo,
|
|
5033
|
+
...drawerRow?.item?.status === void 0 ? {} : { status: drawerRow.item.status },
|
|
5034
|
+
onClose: () => setOpenRepo(null)
|
|
5035
|
+
})
|
|
3905
5036
|
);
|
|
3906
5037
|
}
|
|
3907
5038
|
|
|
@@ -4436,7 +5567,7 @@ function apply(ctx) {
|
|
|
4436
5567
|
...digestTarget2 === void 0 ? {} : { selected: digestTarget2 },
|
|
4437
5568
|
onSelect: setDigestTarget,
|
|
4438
5569
|
onOpenRuns: openRuns
|
|
4439
|
-
}) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : view === "subscriptions" ? h(SubscriptionsView, { t, onOpenSettings: openSettings }) : h(SettingsView, { t, store: value, pickDirectory, onOpenSubscriptions: openSubscriptions });
|
|
5570
|
+
}) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : view === "subscriptions" ? h(SubscriptionsView, { t, store: value, onOpenSettings: openSettings }) : h(SettingsView, { t, store: value, pickDirectory, onOpenSubscriptions: openSubscriptions });
|
|
4440
5571
|
return h(
|
|
4441
5572
|
"div",
|
|
4442
5573
|
{ className: "dshgt-root dshgt-shell" },
|