@morehao/dsh-github-trending 0.4.1 → 0.4.2
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 +21 -0
- package/README.md +6 -6
- package/client.js +501 -324
- package/lib/{chunk-QXAKMNHQ.js → chunk-WTVBXQYN.js} +18 -3
- package/lib/index.js +1 -1
- package/lib/internal.d.ts +10 -5
- package/lib/internal.js +1 -1
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -228,12 +228,15 @@ var DICT = {
|
|
|
228
228
|
"skip.unchanged": "内容与分支上已有产物一致,未新增提交。",
|
|
229
229
|
"label.optional": "可选",
|
|
230
230
|
"nav.overview": "概览",
|
|
231
|
-
"nav.digest": "
|
|
231
|
+
"nav.digest": "榜单",
|
|
232
232
|
"nav.runs": "运行记录",
|
|
233
233
|
"nav.settings": "设置",
|
|
234
|
+
"period.daily": "日榜",
|
|
235
|
+
"period.weekly": "周榜",
|
|
236
|
+
"period.monthly": "月榜",
|
|
234
237
|
"shell.nav": "面板",
|
|
235
|
-
"shell.overview.dek": "
|
|
236
|
-
"shell.digest.dek": "
|
|
238
|
+
"shell.overview.dek": "按周期定时生成榜单;先看下次运行、就绪检查与上次交付。",
|
|
239
|
+
"shell.digest.dek": "按周期回看日榜 / 周榜 / 月榜;只有保留过预览副本的期数能读。",
|
|
237
240
|
"shell.runs.dek": "最近 30 次运行;展开看交付物、错误与日志。",
|
|
238
241
|
"shell.settings.dek": "沿用现有设置页;每个分区独立保存。",
|
|
239
242
|
"shell.nextRun": "下次运行",
|
|
@@ -262,7 +265,7 @@ var DICT = {
|
|
|
262
265
|
"time.in.days": "{days} 天后",
|
|
263
266
|
"overview.last.none": "还没有运行记录",
|
|
264
267
|
"overview.last.files": "{count} 个文件",
|
|
265
|
-
"overview.last.digest": "{date} · GitHub
|
|
268
|
+
"overview.last.digest": "{date} · GitHub 趋势榜单",
|
|
266
269
|
"overview.last.read": "阅读本期",
|
|
267
270
|
"overview.last.noPreview": "这次运行没有保留预览副本",
|
|
268
271
|
"overview.last.prPending": "待合并",
|
|
@@ -276,7 +279,7 @@ var DICT = {
|
|
|
276
279
|
"overview.ready.repo": "仓库",
|
|
277
280
|
"overview.ready.github": "GitHub",
|
|
278
281
|
"overview.ready.view": "查看",
|
|
279
|
-
"overview.week.title": "最近 7
|
|
282
|
+
"overview.week.title": "最近 7 天(日榜)",
|
|
280
283
|
"overview.week.all": "全部运行记录",
|
|
281
284
|
"overview.week.none": "无记录",
|
|
282
285
|
"overview.week.wait": "等待 {time}",
|
|
@@ -292,6 +295,9 @@ var DICT = {
|
|
|
292
295
|
"runs.dryHint": "试跑不写文件、不提交",
|
|
293
296
|
"runs.empty": "没有符合条件的记录",
|
|
294
297
|
"runs.filter.all": "全部",
|
|
298
|
+
"runs.filter.daily": "日榜",
|
|
299
|
+
"runs.filter.weekly": "周榜",
|
|
300
|
+
"runs.filter.monthly": "月榜",
|
|
295
301
|
"runs.filter.failed": "失败",
|
|
296
302
|
"runs.filter.dry": "试跑",
|
|
297
303
|
"runs.pendingPr": "待合并",
|
|
@@ -301,6 +307,7 @@ var DICT = {
|
|
|
301
307
|
"runs.legacyHint": "旧记录没有预览副本,内容哈希使用旧算法,不能与 v2 直接比较。",
|
|
302
308
|
"runs.detail.coreModel": "核心 / 模型",
|
|
303
309
|
"runs.detail.date": "运行日期",
|
|
310
|
+
"runs.detail.period": "周期",
|
|
304
311
|
"runs.detail.warnings": "警告",
|
|
305
312
|
"runs.detail.none": "无",
|
|
306
313
|
"runs.detail.files": "文件 / 耗时",
|
|
@@ -310,6 +317,10 @@ var DICT = {
|
|
|
310
317
|
"digest.allRuns": "全部运行记录",
|
|
311
318
|
"digest.window": "最近 30 天 · {days} 天有记录 · {previews} 期有预览",
|
|
312
319
|
"digest.window.empty": "最近 30 天没有运行记录",
|
|
320
|
+
"digest.window.period": "近 {count} 期 · {previews} 期有预览",
|
|
321
|
+
"digest.selectPeriod": "选择周期",
|
|
322
|
+
"digest.selectBucket": "选择期数",
|
|
323
|
+
"digest.bucketNavHint": "按周期分别回看;切换周期不影响其他周期的时间线",
|
|
313
324
|
"digest.prev": "上一期(更早)",
|
|
314
325
|
"digest.next": "下一期(更新)",
|
|
315
326
|
"digest.select": "选择日报日期",
|
|
@@ -356,27 +367,9 @@ var DICT = {
|
|
|
356
367
|
"about.repo.missing": "package.json 没有可解析的仓库地址",
|
|
357
368
|
"about.license": "许可",
|
|
358
369
|
"about.core": "核心",
|
|
370
|
+
"about.core.repo": "打开核心 GitHub 仓库",
|
|
359
371
|
"about.env": "运行环境",
|
|
360
|
-
"about.env.value": "DSH Web · Node 插件"
|
|
361
|
-
"about.update.title": "插件更新",
|
|
362
|
-
"about.update.check": "检查更新",
|
|
363
|
-
"about.update.checking": "正在检查最新版…",
|
|
364
|
-
"about.update.current": "已是最新(v{version})",
|
|
365
|
-
"about.update.available": "有新版本 v{latest}(当前 v{current})",
|
|
366
|
-
"about.update.apply": "更新到 v{version}",
|
|
367
|
-
"about.update.confirm": "确认更新到 v{version}?会重装本插件并重载面板,之后需要重启 DSH 生效。",
|
|
368
|
-
"about.update.confirmYes": "确认更新",
|
|
369
|
-
"about.update.cancel": "取消",
|
|
370
|
-
"about.update.applying": "正在更新到 v{version}…",
|
|
371
|
-
"about.update.done": "已更新到 v{version},重启 DSH 后生效。",
|
|
372
|
-
"about.update.applied": "已更新到 v{version}。",
|
|
373
|
-
"about.update.failed": "更新失败:{message}",
|
|
374
|
-
"about.update.checkFailed": "检查更新失败:拿不到 registry 上的最新版。可以稍后重试,或手动执行下面的命令。",
|
|
375
|
-
"about.update.manual": "当前是本地 {kind} 安装,不能一键更新(会把开发链接换成 npm 版)。手动更新:",
|
|
376
|
-
"about.update.copy": "复制命令",
|
|
377
|
-
"about.update.copied": "已复制",
|
|
378
|
-
"about.update.hint": "只检查 npm 上的 latest 稳定版;更新后需要重启 DSH。",
|
|
379
|
-
"update.badge": "有新版本可用"
|
|
372
|
+
"about.env.value": "DSH Web · Node 插件"
|
|
380
373
|
},
|
|
381
374
|
en: {
|
|
382
375
|
"section.title": "GitHub Trending",
|
|
@@ -561,12 +554,15 @@ var DICT = {
|
|
|
561
554
|
"skip.unchanged": "The branch already holds the same artifacts; no new commit.",
|
|
562
555
|
"label.optional": "optional",
|
|
563
556
|
"nav.overview": "Overview",
|
|
564
|
-
"nav.digest": "
|
|
557
|
+
"nav.digest": "Board",
|
|
565
558
|
"nav.runs": "Runs",
|
|
566
559
|
"nav.settings": "Settings",
|
|
560
|
+
"period.daily": "Daily",
|
|
561
|
+
"period.weekly": "Weekly",
|
|
562
|
+
"period.monthly": "Monthly",
|
|
567
563
|
"shell.nav": "Panel",
|
|
568
|
-
"shell.overview.dek": "
|
|
569
|
-
"shell.digest.dek": "Look back
|
|
564
|
+
"shell.overview.dek": "Periodic boards on a schedule; start with the next run, readiness and the last delivery.",
|
|
565
|
+
"shell.digest.dek": "Look back per period — daily / weekly / monthly; only issues with a saved preview copy can be read.",
|
|
570
566
|
"shell.runs.dek": "The last 30 runs; expand one for artifacts, errors and logs.",
|
|
571
567
|
"shell.settings.dek": "The existing settings page; each section saves on its own.",
|
|
572
568
|
"shell.nextRun": "Next run",
|
|
@@ -595,7 +591,7 @@ var DICT = {
|
|
|
595
591
|
"time.in.days": "in {days} d",
|
|
596
592
|
"overview.last.none": "No runs yet",
|
|
597
593
|
"overview.last.files": "{count} files",
|
|
598
|
-
"overview.last.digest": "{date} · GitHub Trending
|
|
594
|
+
"overview.last.digest": "{date} · GitHub Trending board",
|
|
599
595
|
"overview.last.read": "Read this issue",
|
|
600
596
|
"overview.last.noPreview": "This run has no saved preview copy",
|
|
601
597
|
"overview.last.prPending": "Pending merge",
|
|
@@ -609,7 +605,7 @@ var DICT = {
|
|
|
609
605
|
"overview.ready.repo": "Repository",
|
|
610
606
|
"overview.ready.github": "GitHub",
|
|
611
607
|
"overview.ready.view": "View",
|
|
612
|
-
"overview.week.title": "Last 7 days",
|
|
608
|
+
"overview.week.title": "Last 7 days (daily)",
|
|
613
609
|
"overview.week.all": "All runs",
|
|
614
610
|
"overview.week.none": "No record",
|
|
615
611
|
"overview.week.wait": "Waiting for {time}",
|
|
@@ -625,6 +621,9 @@ var DICT = {
|
|
|
625
621
|
"runs.dryHint": "dry run writes nothing and commits nothing",
|
|
626
622
|
"runs.empty": "No matching records",
|
|
627
623
|
"runs.filter.all": "All",
|
|
624
|
+
"runs.filter.daily": "Daily",
|
|
625
|
+
"runs.filter.weekly": "Weekly",
|
|
626
|
+
"runs.filter.monthly": "Monthly",
|
|
628
627
|
"runs.filter.failed": "Failed",
|
|
629
628
|
"runs.filter.dry": "Dry run",
|
|
630
629
|
"runs.pendingPr": "Pending merge",
|
|
@@ -634,6 +633,7 @@ var DICT = {
|
|
|
634
633
|
"runs.legacyHint": "Legacy records have no preview copy and use the old hash algorithm, so they cannot be compared with v2 directly.",
|
|
635
634
|
"runs.detail.coreModel": "Core / model",
|
|
636
635
|
"runs.detail.date": "Run date",
|
|
636
|
+
"runs.detail.period": "Period",
|
|
637
637
|
"runs.detail.warnings": "Warnings",
|
|
638
638
|
"runs.detail.none": "None",
|
|
639
639
|
"runs.detail.files": "Files / duration",
|
|
@@ -643,6 +643,10 @@ var DICT = {
|
|
|
643
643
|
"digest.allRuns": "All runs",
|
|
644
644
|
"digest.window": "Last 30 days · {days} days with runs · {previews} with previews",
|
|
645
645
|
"digest.window.empty": "No runs in the last 30 days",
|
|
646
|
+
"digest.window.period": "Last {count} issues · {previews} with previews",
|
|
647
|
+
"digest.selectPeriod": "Choose period",
|
|
648
|
+
"digest.selectBucket": "Choose issue",
|
|
649
|
+
"digest.bucketNavHint": "Each period keeps its own timeline; switching does not affect the others",
|
|
646
650
|
"digest.prev": "Previous (older)",
|
|
647
651
|
"digest.next": "Next (newer)",
|
|
648
652
|
"digest.select": "Choose a digest date",
|
|
@@ -689,27 +693,9 @@ var DICT = {
|
|
|
689
693
|
"about.repo.missing": "package.json has no resolvable repository URL",
|
|
690
694
|
"about.license": "License",
|
|
691
695
|
"about.core": "Core",
|
|
696
|
+
"about.core.repo": "Open core GitHub repository",
|
|
692
697
|
"about.env": "Runtime",
|
|
693
|
-
"about.env.value": "DSH Web · Node plugin"
|
|
694
|
-
"about.update.title": "Plugin update",
|
|
695
|
-
"about.update.check": "Check for updates",
|
|
696
|
-
"about.update.checking": "Checking the latest version…",
|
|
697
|
-
"about.update.current": "Up to date (v{version})",
|
|
698
|
-
"about.update.available": "v{latest} is available (current v{current})",
|
|
699
|
-
"about.update.apply": "Update to v{version}",
|
|
700
|
-
"about.update.confirm": "Update to v{version}? The plugin will be reinstalled and the panel reloaded; restart DSH afterwards.",
|
|
701
|
-
"about.update.confirmYes": "Update now",
|
|
702
|
-
"about.update.cancel": "Cancel",
|
|
703
|
-
"about.update.applying": "Updating to v{version}…",
|
|
704
|
-
"about.update.done": "Updated to v{version}; restart DSH to apply.",
|
|
705
|
-
"about.update.applied": "Updated to v{version}.",
|
|
706
|
-
"about.update.failed": "Update failed: {message}",
|
|
707
|
-
"about.update.checkFailed": "Update check failed: cannot reach the registry for the latest version. Retry later or run the command below.",
|
|
708
|
-
"about.update.manual": "Installed from a local {kind} spec; one-click update is disabled (it would replace the dev link). Update manually:",
|
|
709
|
-
"about.update.copy": "Copy command",
|
|
710
|
-
"about.update.copied": "Copied",
|
|
711
|
-
"about.update.hint": "Checks the npm latest stable tag only; applying requires a DSH restart.",
|
|
712
|
-
"update.badge": "Update available"
|
|
698
|
+
"about.env.value": "DSH Web · Node plugin"
|
|
713
699
|
}
|
|
714
700
|
};
|
|
715
701
|
function activeLang(locale) {
|
|
@@ -787,6 +773,9 @@ var CSS = `
|
|
|
787
773
|
.dshgt-table th,.dshgt-table td{text-align:left;padding:5px 8px;border-bottom:1px solid var(--gt-border);vertical-align:top;}
|
|
788
774
|
.dshgt-table th{color:var(--gt-muted);font-weight:500;}
|
|
789
775
|
.dshgt-chips{display:flex;gap:6px;flex-wrap:wrap;}
|
|
776
|
+
.dshgt-period-list{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0;}
|
|
777
|
+
.dshgt-period{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--gt-fg);}
|
|
778
|
+
.dshgt-period-check{color:var(--gt-ok);font-size:12px;line-height:1;}
|
|
790
779
|
.dshgt-chip{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--gt-border);background:var(--gt-bg);border-radius:999px;padding:2px 10px;font-size:12px;color:var(--gt-muted);}
|
|
791
780
|
.dshgt-chip[aria-pressed="true"]{background:color-mix(in srgb,var(--gt-accent) 14%,var(--gt-bg));border-color:var(--gt-accent);color:var(--gt-fg);}
|
|
792
781
|
.dshgt-switch{appearance:none;cursor:pointer;width:36px;height:20px;border-radius:999px;border:1px solid var(--gt-border);background:var(--gt-muted);position:relative;transition:background .15s;}
|
|
@@ -978,12 +967,24 @@ var CSS = `
|
|
|
978
967
|
.dshgt-md a{color:var(--gt-accent);text-decoration:none;}
|
|
979
968
|
.dshgt-md a:hover{text-decoration:underline;}
|
|
980
969
|
|
|
970
|
+
/* ——— 周期标签 / 分段 ——— */
|
|
971
|
+
.dshgt-pchip{display:inline-flex;align-items:center;height:20px;padding:0 8px;border-radius:999px;font-size:11px;font-weight:600;line-height:18px;white-space:nowrap;border:1px solid var(--gt-border);color:var(--gt-muted);background:var(--gt-bg);}
|
|
972
|
+
.dshgt-pchip.daily{color:var(--gt-accent);border-color:color-mix(in srgb,var(--gt-accent) 35%,var(--gt-border));background:color-mix(in srgb,var(--gt-accent) 9%,var(--gt-bg));}
|
|
973
|
+
.dshgt-pchip.weekly{color:#7c3aed;border-color:#ddd6fe;background:#f5f3ff;}
|
|
974
|
+
.dshgt-pchip.monthly{color:#0f766e;border-color:#99f6e4;background:#f0fdfa;}
|
|
975
|
+
.dshgt-period-seg{display:inline-flex;border:1px solid var(--gt-border);border-radius:9px;padding:3px;background:var(--gt-card);gap:3px;}
|
|
976
|
+
.dshgt-period-seg button{display:inline-flex;align-items:center;gap:7px;border:0;background:none;height:30px;padding:0 12px;border-radius:7px;font:inherit;font-size:13px;color:var(--gt-muted);cursor:pointer;}
|
|
977
|
+
.dshgt-period-seg button:hover{color:var(--gt-fg);}
|
|
978
|
+
.dshgt-period-seg button.on{background:var(--gt-bg);color:var(--gt-fg);font-weight:600;box-shadow:0 1px 2px rgba(15,23,42,.08);}
|
|
979
|
+
.dshgt-period-count{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--gt-muted);background:color-mix(in srgb,var(--gt-fg) 6%,var(--gt-bg));border-radius:999px;padding:0 6px;line-height:16px;}
|
|
980
|
+
.dshgt-period-seg button.on .dshgt-period-count{color:var(--gt-accent);background:color-mix(in srgb,var(--gt-accent) 12%,var(--gt-bg));}
|
|
981
|
+
|
|
981
982
|
/* ——— 运行记录 ——— */
|
|
982
983
|
.dshgt-runs-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
983
984
|
.dshgt-runs-filter{display:flex;gap:4px;margin-left:auto;}
|
|
984
985
|
.dshgt-run-list{border-top:1px solid var(--gt-border);}
|
|
985
986
|
.dshgt-run-item{border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
986
|
-
.dshgt-run-row{display:grid;grid-template-columns:18px
|
|
987
|
+
.dshgt-run-row{display:grid;grid-template-columns:18px 120px 56px minmax(0,1fr) 78px 74px 20px;align-items:center;gap:12px;min-height:52px;width:100%;padding:0 6px;border:0;background:none;text-align:left;font-family:inherit;color:var(--gt-fg);cursor:pointer;border-radius:6px;}
|
|
987
988
|
.dshgt-run-row:hover{background:color-mix(in srgb,var(--gt-fg) 4%,var(--gt-bg));}
|
|
988
989
|
.dshgt-run-date{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);white-space:nowrap;}
|
|
989
990
|
.dshgt-run-what{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;}
|
|
@@ -1010,26 +1011,25 @@ var CSS = `
|
|
|
1010
1011
|
.dshgt-about-head{display:flex;align-items:center;gap:10px;}
|
|
1011
1012
|
.dshgt-about-title{margin:0;font-size:16px;}
|
|
1012
1013
|
.dshgt-about-head .dshgt-btn{margin-left:auto;}
|
|
1013
|
-
.dshgt-about-pkg{display:flex;align-items:center;
|
|
1014
|
-
.dshgt-about-pkg:hover{border-color:color-mix(in srgb,var(--gt-accent) 40%,var(--gt-border));}
|
|
1015
|
-
.dshgt-about-pkg
|
|
1014
|
+
.dshgt-about-pkg{display:flex;align-items:center;width:100%;text-align:left;border:1px solid var(--gt-border);background:var(--gt-card);border-radius:8px;padding:9px 10px;cursor:pointer;font-family:inherit;color:inherit;transition:border-color .12s ease,background .12s ease;}
|
|
1015
|
+
.dshgt-about-pkg:hover{border-color:color-mix(in srgb,var(--gt-accent) 40%,var(--gt-border));background:color-mix(in srgb,var(--gt-fg) 4%,var(--gt-card));}
|
|
1016
|
+
.dshgt-about-pkg.is-copied{border-color:color-mix(in srgb,var(--gt-ok) 45%,var(--gt-border));}
|
|
1017
|
+
.dshgt-about-pkg .dshgt-mono{font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;user-select:text;}
|
|
1016
1018
|
.dshgt-about .dshgt-kv{grid-template-columns:110px 1fr;}
|
|
1017
|
-
.dshgt-about .dshgt-kv a{color:var(--gt-accent);text-decoration:none;
|
|
1019
|
+
.dshgt-about .dshgt-kv a{color:var(--gt-accent);text-decoration:none;}
|
|
1018
1020
|
.dshgt-about .dshgt-kv a:hover{text-decoration:underline;}
|
|
1019
|
-
.dshgt-
|
|
1020
|
-
.dshgt-
|
|
1021
|
-
.dshgt-
|
|
1022
|
-
.dshgt-
|
|
1023
|
-
|
|
1024
|
-
.dshgt-
|
|
1025
|
-
.dshgt-
|
|
1026
|
-
.dshgt-
|
|
1027
|
-
.dshgt-
|
|
1028
|
-
.dshgt-
|
|
1029
|
-
.dshgt-
|
|
1030
|
-
.dshgt-
|
|
1031
|
-
.dshgt-update-bare{margin-top:0;padding-top:0;border-top:0;}
|
|
1032
|
-
.dshgt-update-card .dshgt-card-h{margin-bottom:2px;}
|
|
1021
|
+
.dshgt-about-core{display:inline-flex;align-items:center;gap:7px;}
|
|
1022
|
+
.dshgt-about-gh{display:inline-flex;align-items:center;justify-content:center;color:var(--gt-muted);}
|
|
1023
|
+
.dshgt-about-gh:hover{color:var(--gt-fg);}
|
|
1024
|
+
.dshgt-gh{width:15px;height:15px;display:block;fill:currentColor;}
|
|
1025
|
+
/* 关于弹层的更新行:与身份条同构(左侧状态 + 右侧单按钮),无标题、无说明。 */
|
|
1026
|
+
.dshgt-about-upd{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:6px;padding-top:12px;border-top:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
1027
|
+
.dshgt-about-status{display:inline-flex;align-items:center;gap:7px;font-size:12px;color:var(--gt-muted);}
|
|
1028
|
+
.dshgt-about-status::before{content:"";width:7px;height:7px;border-radius:50%;background:currentColor;flex:none;opacity:.9;}
|
|
1029
|
+
.dshgt-about-status.ok{color:var(--gt-ok);}
|
|
1030
|
+
.dshgt-about-status.new{color:var(--gt-warn);}
|
|
1031
|
+
.dshgt-about-status.err{color:var(--gt-err);}
|
|
1032
|
+
.dshgt-about-actions{display:flex;align-items:center;gap:8px;flex:none;}
|
|
1033
1033
|
|
|
1034
1034
|
@media (max-width:1100px){
|
|
1035
1035
|
.dshgt-app{grid-template-columns:190px minmax(0,1fr);}
|
|
@@ -1039,7 +1039,7 @@ var CSS = `
|
|
|
1039
1039
|
.dshgt-fact:nth-child(3){padding-left:0;border-left:0;}
|
|
1040
1040
|
.dshgt-week{flex-wrap:wrap;}
|
|
1041
1041
|
.dshgt-day{flex:1 1 88px;}
|
|
1042
|
-
.dshgt-run-row{grid-template-columns:18px
|
|
1042
|
+
.dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 70px 20px;}
|
|
1043
1043
|
.dshgt-run-files{display:none;}
|
|
1044
1044
|
.dshgt-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
|
|
1045
1045
|
.dshgt-dateselect{min-width:180px;}
|
|
@@ -1732,18 +1732,22 @@ function SettingsView(props) {
|
|
|
1732
1732
|
h(
|
|
1733
1733
|
Row,
|
|
1734
1734
|
{ label: t("scope.period") },
|
|
1735
|
-
h(
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1735
|
+
h(
|
|
1736
|
+
"div",
|
|
1737
|
+
{ className: "dshgt-period-list" },
|
|
1738
|
+
...["daily", "weekly", "monthly"].map(
|
|
1739
|
+
(period) => h(
|
|
1740
|
+
"div",
|
|
1741
|
+
{ key: period, className: "dshgt-period" },
|
|
1742
|
+
h("span", { className: "dshgt-period-check" }, "✓"),
|
|
1743
|
+
h("span", null, t(`scope.${period}`))
|
|
1744
|
+
)
|
|
1745
|
+
)
|
|
1746
|
+
)
|
|
1747
|
+
),
|
|
1748
|
+
h(
|
|
1749
|
+
Row,
|
|
1750
|
+
{ label: t("scope.topN") },
|
|
1747
1751
|
h(Input, { mono: true, width: 70, value: String(draft.trending.topN), onInput: (value) => update((next) => {
|
|
1748
1752
|
next.trending.topN = Math.round(Number(value) || 0);
|
|
1749
1753
|
}) })
|
|
@@ -2091,193 +2095,9 @@ function LiveRun(props) {
|
|
|
2091
2095
|
);
|
|
2092
2096
|
}
|
|
2093
2097
|
|
|
2094
|
-
// node_modules/@morehao/dsh-plugin-kit/dist/update-client.js
|
|
2095
|
-
var IDLE = { status: "idle", view: null, error: null };
|
|
2096
|
-
function errorOf(error) {
|
|
2097
|
-
if (error !== null && typeof error === "object") {
|
|
2098
|
-
const value = error;
|
|
2099
|
-
const message = typeof value.message === "string" && value.message !== "" ? value.message : "操作失败";
|
|
2100
|
-
return typeof value.code === "string" ? { code: value.code, message } : { message };
|
|
2101
|
-
}
|
|
2102
|
-
return { message: String(error ?? "操作失败") };
|
|
2103
|
-
}
|
|
2104
|
-
function createUpdateController(options) {
|
|
2105
|
-
const now = options.now ?? Date.now;
|
|
2106
|
-
let state = { ...IDLE };
|
|
2107
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2108
|
-
let inFlight = null;
|
|
2109
|
-
function emit(next) {
|
|
2110
|
-
state = next;
|
|
2111
|
-
options.onChange?.(state);
|
|
2112
|
-
for (const listener of listeners) listener(state);
|
|
2113
|
-
}
|
|
2114
|
-
async function check(checkOptions = {}) {
|
|
2115
|
-
if (inFlight !== null) return;
|
|
2116
|
-
inFlight = "check";
|
|
2117
|
-
emit({ ...state, status: "checking", error: null });
|
|
2118
|
-
try {
|
|
2119
|
-
const view = await options.request.check(checkOptions);
|
|
2120
|
-
const checkedAt = new Date(now()).toISOString();
|
|
2121
|
-
if (view.checkFailed) {
|
|
2122
|
-
emit({
|
|
2123
|
-
status: "failed",
|
|
2124
|
-
view,
|
|
2125
|
-
error: { code: "CHECK_FAILED", message: "检查更新失败:拿不到 registry 上的最新版本" },
|
|
2126
|
-
checkedAt
|
|
2127
|
-
});
|
|
2128
|
-
} else {
|
|
2129
|
-
emit({ status: view.updateAvailable ? "available" : "current", view, error: null, checkedAt });
|
|
2130
|
-
}
|
|
2131
|
-
} catch (error) {
|
|
2132
|
-
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
2133
|
-
} finally {
|
|
2134
|
-
inFlight = null;
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
async function apply2() {
|
|
2138
|
-
if (inFlight !== null) return;
|
|
2139
|
-
const view = state.view;
|
|
2140
|
-
if (view === null || !view.updateAvailable) {
|
|
2141
|
-
emit({ ...state, status: "failed", error: { code: "NO_UPDATE", message: "没有可更新的版本,请先检查更新" } });
|
|
2142
|
-
return;
|
|
2143
|
-
}
|
|
2144
|
-
if (!view.canApply) {
|
|
2145
|
-
emit({
|
|
2146
|
-
...state,
|
|
2147
|
-
status: "failed",
|
|
2148
|
-
error: { code: "NO_APPLY", message: `当前环境不支持一键更新,请执行:${view.manualCommand}` }
|
|
2149
|
-
});
|
|
2150
|
-
return;
|
|
2151
|
-
}
|
|
2152
|
-
inFlight = "apply";
|
|
2153
|
-
emit({ ...state, status: "applying", error: null });
|
|
2154
|
-
try {
|
|
2155
|
-
const result = await options.request.apply();
|
|
2156
|
-
const restartRequired = result.restartRequired ?? result.application !== "applied";
|
|
2157
|
-
emit({ ...state, status: restartRequired ? "restart-required" : "applied", error: null });
|
|
2158
|
-
} catch (error) {
|
|
2159
|
-
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
2160
|
-
} finally {
|
|
2161
|
-
inFlight = null;
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
return {
|
|
2165
|
-
getState: () => state,
|
|
2166
|
-
subscribe: (listener) => {
|
|
2167
|
-
listeners.add(listener);
|
|
2168
|
-
return () => {
|
|
2169
|
-
listeners.delete(listener);
|
|
2170
|
-
};
|
|
2171
|
-
},
|
|
2172
|
-
check,
|
|
2173
|
-
apply: apply2,
|
|
2174
|
-
reset: () => emit({ ...IDLE })
|
|
2175
|
-
};
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
// client/update-panel.ts
|
|
2179
|
-
var singleton = null;
|
|
2180
|
-
function getUpdateController() {
|
|
2181
|
-
if (singleton === null) {
|
|
2182
|
-
singleton = createUpdateController({
|
|
2183
|
-
request: {
|
|
2184
|
-
check: (options) => getPluginUpdate(options.fresh === true ? { fresh: true } : {}),
|
|
2185
|
-
apply: () => applyPluginUpdate()
|
|
2186
|
-
}
|
|
2187
|
-
});
|
|
2188
|
-
}
|
|
2189
|
-
return singleton;
|
|
2190
|
-
}
|
|
2191
|
-
function usePluginUpdate() {
|
|
2192
|
-
const controller = getUpdateController();
|
|
2193
|
-
const [state, setState] = import_react.default.useState(() => controller.getState());
|
|
2194
|
-
import_react.default.useEffect(() => {
|
|
2195
|
-
const unsubscribe = controller.subscribe(setState);
|
|
2196
|
-
if (controller.getState().status === "idle") void controller.check();
|
|
2197
|
-
return unsubscribe;
|
|
2198
|
-
}, [controller]);
|
|
2199
|
-
return [state, controller];
|
|
2200
|
-
}
|
|
2201
|
-
function PluginUpdateSection(props) {
|
|
2202
|
-
const { t } = props;
|
|
2203
|
-
const [state, controller] = usePluginUpdate();
|
|
2204
|
-
const [confirming, setConfirming] = import_react.default.useState(false);
|
|
2205
|
-
const [copied, setCopied] = import_react.default.useState(false);
|
|
2206
|
-
import_react.default.useEffect(() => {
|
|
2207
|
-
if (state.status === "applying" || state.status === "restart-required" || state.status === "applied") setConfirming(false);
|
|
2208
|
-
}, [state.status]);
|
|
2209
|
-
const copyCommand = () => {
|
|
2210
|
-
const command = state.view?.manualCommand;
|
|
2211
|
-
if (command === void 0) return;
|
|
2212
|
-
void copyText(command).then((ok) => {
|
|
2213
|
-
if (!ok) return;
|
|
2214
|
-
setCopied(true);
|
|
2215
|
-
setTimeout(() => setCopied(false), 1600);
|
|
2216
|
-
});
|
|
2217
|
-
};
|
|
2218
|
-
const view = state.view;
|
|
2219
|
-
const status = state.status;
|
|
2220
|
-
const target = view !== null && view.updateAvailable ? view.latestVersion ?? "" : "";
|
|
2221
|
-
const busy = status === "checking" || status === "applying";
|
|
2222
|
-
const settled = status === "restart-required" || status === "applied";
|
|
2223
|
-
const actionable = view !== null && view.updateAvailable && view.canApply && !settled && !busy;
|
|
2224
|
-
const manual = view !== null && (!view.canApply || view.checkFailed) ? view.manualCommand : null;
|
|
2225
|
-
const statusLine = () => {
|
|
2226
|
-
if (status === "checking" || view === null) return t("about.update.checking");
|
|
2227
|
-
if (status === "applying") return t("about.update.applying", { version: target });
|
|
2228
|
-
if (status === "restart-required") return t("about.update.done", { version: view.latestVersion ?? target });
|
|
2229
|
-
if (status === "applied") return t("about.update.applied", { version: view.latestVersion ?? target });
|
|
2230
|
-
if (status === "failed") {
|
|
2231
|
-
if (state.error?.code === "CHECK_FAILED") return t("about.update.checkFailed");
|
|
2232
|
-
return t("about.update.failed", { message: state.error?.message ?? "" });
|
|
2233
|
-
}
|
|
2234
|
-
if (view.checkFailed) return t("about.update.checkFailed");
|
|
2235
|
-
if (view.updateAvailable) return t("about.update.available", { latest: view.latestVersion ?? "", current: view.currentVersion });
|
|
2236
|
-
return t("about.update.current", { version: view.currentVersion });
|
|
2237
|
-
};
|
|
2238
|
-
const actions = [
|
|
2239
|
-
h(Btn, { key: "check", small: true, disabled: busy, onClick: () => void controller.check({ fresh: true }) }, t("about.update.check")),
|
|
2240
|
-
manual === null ? null : h(Btn, { key: "copy", small: true, onClick: copyCommand }, copied ? t("about.update.copied") : t("about.update.copy")),
|
|
2241
|
-
actionable ? confirming ? [
|
|
2242
|
-
h(
|
|
2243
|
-
Btn,
|
|
2244
|
-
{
|
|
2245
|
-
key: "confirm",
|
|
2246
|
-
small: true,
|
|
2247
|
-
variant: "danger",
|
|
2248
|
-
onClick: () => {
|
|
2249
|
-
setConfirming(false);
|
|
2250
|
-
void controller.apply();
|
|
2251
|
-
}
|
|
2252
|
-
},
|
|
2253
|
-
t("about.update.confirmYes")
|
|
2254
|
-
),
|
|
2255
|
-
h(Btn, { key: "cancel", small: true, onClick: () => setConfirming(false) }, t("about.update.cancel"))
|
|
2256
|
-
] : h(Btn, { key: "apply", small: true, variant: "primary", onClick: () => setConfirming(true) }, t("about.update.apply", { version: target })) : null
|
|
2257
|
-
].filter((item) => item !== null);
|
|
2258
|
-
return h(
|
|
2259
|
-
"div",
|
|
2260
|
-
{ className: `dshgt-update${props.bare === true ? " dshgt-update-bare" : ""}` },
|
|
2261
|
-
props.bare === true ? null : h(
|
|
2262
|
-
"div",
|
|
2263
|
-
{ className: "dshgt-update-head" },
|
|
2264
|
-
h("h4", null, t("about.update.title")),
|
|
2265
|
-
h("span", { className: "dshgt-hint" }, t("about.update.hint"))
|
|
2266
|
-
),
|
|
2267
|
-
h("p", { className: `dshgt-update-line${status === "failed" ? " dshgt-update-err" : ""}` }, statusLine()),
|
|
2268
|
-
confirming ? h("p", { className: "dshgt-update-warn" }, t("about.update.confirm", { version: target })) : null,
|
|
2269
|
-
h("div", { className: "dshgt-update-actions" }, actions),
|
|
2270
|
-
manual === null ? null : h(
|
|
2271
|
-
"div",
|
|
2272
|
-
{ className: "dshgt-update-manual" },
|
|
2273
|
-
h("p", { className: "dshgt-update-warn" }, t("about.update.manual", { kind: view?.installKind ?? "unknown" })),
|
|
2274
|
-
h("code", { className: "dshgt-update-cmd" }, manual)
|
|
2275
|
-
)
|
|
2276
|
-
);
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
2098
|
// client/digest-core.ts
|
|
2280
2099
|
var DIGEST_WINDOW_DAYS = 30;
|
|
2100
|
+
var PERIODS = ["daily", "weekly", "monthly"];
|
|
2281
2101
|
var DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2282
2102
|
function isValidDate(value) {
|
|
2283
2103
|
if (typeof value !== "string") return false;
|
|
@@ -2325,12 +2145,66 @@ function digestStatus(record) {
|
|
|
2325
2145
|
if (record.legacy === true) return "legacy";
|
|
2326
2146
|
return "missing";
|
|
2327
2147
|
}
|
|
2148
|
+
function recordPeriod(record) {
|
|
2149
|
+
return record.period === "weekly" || record.period === "monthly" ? record.period : "daily";
|
|
2150
|
+
}
|
|
2151
|
+
function isoWeekName(date) {
|
|
2152
|
+
const match = DATE_RE.exec(date);
|
|
2153
|
+
if (match === null) return date;
|
|
2154
|
+
const d = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
|
|
2155
|
+
if (Number.isNaN(d.getTime())) return date;
|
|
2156
|
+
const dayIdx = (d.getUTCDay() + 6) % 7;
|
|
2157
|
+
d.setUTCDate(d.getUTCDate() - dayIdx + 3);
|
|
2158
|
+
const isoYear = d.getUTCFullYear();
|
|
2159
|
+
const firstThursday = new Date(Date.UTC(isoYear, 0, 4));
|
|
2160
|
+
const firstIdx = (firstThursday.getUTCDay() + 6) % 7;
|
|
2161
|
+
firstThursday.setUTCDate(firstThursday.getUTCDate() - firstIdx + 3);
|
|
2162
|
+
const week = 1 + Math.round((d.getTime() - firstThursday.getTime()) / (7 * 864e5));
|
|
2163
|
+
return `${isoYear}-W${String(week).padStart(2, "0")}`;
|
|
2164
|
+
}
|
|
2165
|
+
function periodBucket(period, date) {
|
|
2166
|
+
if (period === "monthly") return date.slice(0, 7);
|
|
2167
|
+
if (period === "weekly") return isoWeekName(date);
|
|
2168
|
+
return date;
|
|
2169
|
+
}
|
|
2170
|
+
function isoWeekRange(bucket) {
|
|
2171
|
+
const match = /^(\d{4})-W(\d{2})$/.exec(bucket);
|
|
2172
|
+
if (match === null) return void 0;
|
|
2173
|
+
const year = Number(match[1]);
|
|
2174
|
+
const week = Number(match[2]);
|
|
2175
|
+
const jan4 = new Date(Date.UTC(year, 0, 4));
|
|
2176
|
+
const dayIdx = (jan4.getUTCDay() + 6) % 7;
|
|
2177
|
+
const monday = new Date(jan4);
|
|
2178
|
+
monday.setUTCDate(jan4.getUTCDate() - dayIdx + (week - 1) * 7);
|
|
2179
|
+
const sunday = new Date(monday);
|
|
2180
|
+
sunday.setUTCDate(monday.getUTCDate() + 6);
|
|
2181
|
+
return { start: monday.toISOString().slice(0, 10), end: sunday.toISOString().slice(0, 10) };
|
|
2182
|
+
}
|
|
2183
|
+
function formatBucketLabel(period, bucket, lang) {
|
|
2184
|
+
if (period === "daily") return formatDayLabel(bucket, lang);
|
|
2185
|
+
if (period === "weekly") {
|
|
2186
|
+
const range = isoWeekRange(bucket);
|
|
2187
|
+
if (range === void 0) return bucket;
|
|
2188
|
+
const md = (d) => `${Number(d.slice(5, 7))}/${Number(d.slice(8, 10))}`;
|
|
2189
|
+
return `${bucket} ${lang === "en" ? `(${md(range.start)}–${md(range.end)})` : `(${md(range.start)}–${md(range.end)})`}`;
|
|
2190
|
+
}
|
|
2191
|
+
const match = /^(\d{4})-(\d{2})$/.exec(bucket);
|
|
2192
|
+
if (match === null) return bucket;
|
|
2193
|
+
return lang === "en" ? bucket : `${match[1]} 年 ${Number(match[2])} 月`;
|
|
2194
|
+
}
|
|
2195
|
+
function digestTarget(record, timeZone) {
|
|
2196
|
+
const info = recordDate(record, timeZone);
|
|
2197
|
+
if (info === void 0) return void 0;
|
|
2198
|
+
const period = recordPeriod(record);
|
|
2199
|
+
return { period, bucket: periodBucket(period, info.date) };
|
|
2200
|
+
}
|
|
2328
2201
|
function buildDigestDates(records, options) {
|
|
2329
2202
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2330
2203
|
const today = zonedDateString(now, options.timeZone);
|
|
2331
2204
|
const earliest = addDays(today, -(DIGEST_WINDOW_DAYS - 1));
|
|
2332
2205
|
const groups = /* @__PURE__ */ new Map();
|
|
2333
2206
|
for (const record of records) {
|
|
2207
|
+
if (recordPeriod(record) !== "daily") continue;
|
|
2334
2208
|
const info = recordDate(record, options.timeZone);
|
|
2335
2209
|
if (info === void 0) continue;
|
|
2336
2210
|
if (info.date < earliest || info.date > today) continue;
|
|
@@ -2356,6 +2230,51 @@ function buildDigestDates(records, options) {
|
|
|
2356
2230
|
days.sort((a, b) => b.date.localeCompare(a.date));
|
|
2357
2231
|
return days;
|
|
2358
2232
|
}
|
|
2233
|
+
function buildPeriodGroups(records, options) {
|
|
2234
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2235
|
+
const today = zonedDateString(now, options.timeZone);
|
|
2236
|
+
const dailyEarliest = addDays(today, -(DIGEST_WINDOW_DAYS - 1));
|
|
2237
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2238
|
+
for (const record of records) {
|
|
2239
|
+
const info = recordDate(record, options.timeZone);
|
|
2240
|
+
if (info === void 0) continue;
|
|
2241
|
+
const period = recordPeriod(record);
|
|
2242
|
+
if (period === "daily" && (info.date < dailyEarliest || info.date > today)) continue;
|
|
2243
|
+
const bucket = periodBucket(period, info.date);
|
|
2244
|
+
const key = `${period}|${bucket}`;
|
|
2245
|
+
const group = groups.get(key);
|
|
2246
|
+
if (group === void 0) groups.set(key, { period, bucket, records: [record], derivedFromAt: info.derivedFromAt });
|
|
2247
|
+
else {
|
|
2248
|
+
group.records.push(record);
|
|
2249
|
+
group.derivedFromAt = group.derivedFromAt || info.derivedFromAt;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
const byPeriod = /* @__PURE__ */ new Map();
|
|
2253
|
+
for (const group of groups.values()) {
|
|
2254
|
+
const sorted = [...group.records].sort((a, b) => b.at.localeCompare(a.at));
|
|
2255
|
+
const preferred = sorted.find(
|
|
2256
|
+
(record2) => record2.preview !== void 0 && record2.ok && record2.kind !== "dry-run" && !record2.skipped
|
|
2257
|
+
);
|
|
2258
|
+
const record = preferred ?? sorted[0];
|
|
2259
|
+
if (record === void 0) continue;
|
|
2260
|
+
const info = recordDate(record, options.timeZone);
|
|
2261
|
+
const legacy = record.legacy === true || info?.derivedFromAt === true || group.derivedFromAt;
|
|
2262
|
+
const list = byPeriod.get(group.period) ?? [];
|
|
2263
|
+
list.push({
|
|
2264
|
+
period: group.period,
|
|
2265
|
+
bucket: group.bucket,
|
|
2266
|
+
date: info?.date ?? group.bucket.slice(0, 10),
|
|
2267
|
+
record,
|
|
2268
|
+
status: digestStatus(record),
|
|
2269
|
+
legacy
|
|
2270
|
+
});
|
|
2271
|
+
byPeriod.set(group.period, list);
|
|
2272
|
+
}
|
|
2273
|
+
return PERIODS.map((period) => {
|
|
2274
|
+
const days = (byPeriod.get(period) ?? []).sort((a, b) => b.bucket.localeCompare(a.bucket));
|
|
2275
|
+
return { period, days, previewCount: days.filter((day) => day.status === "preview").length };
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2359
2278
|
function recentDates(today, count) {
|
|
2360
2279
|
const dates = [];
|
|
2361
2280
|
for (let offset = count - 1; offset >= 0; offset -= 1) dates.push(addDays(today, -offset));
|
|
@@ -2472,6 +2391,7 @@ function OverviewView(props) {
|
|
|
2472
2391
|
const days = buildDigestDates(state.status.history, { timeZone });
|
|
2473
2392
|
const byDate = new Map(days.map((day) => [day.date, day]));
|
|
2474
2393
|
const week = recentDates(today, 7);
|
|
2394
|
+
const lastTarget = last === null ? void 0 : digestTarget(last, timeZone);
|
|
2475
2395
|
return h(
|
|
2476
2396
|
"div",
|
|
2477
2397
|
{ className: "dshgt-view dshgt-overview" },
|
|
@@ -2488,6 +2408,7 @@ function OverviewView(props) {
|
|
|
2488
2408
|
"div",
|
|
2489
2409
|
{ className: "dshgt-delivery-top" },
|
|
2490
2410
|
statusPill(t, last),
|
|
2411
|
+
h("span", { className: `dshgt-pchip ${last.period ?? "daily"}` }, t(`period.${last.period ?? "daily"}`)),
|
|
2491
2412
|
h("span", { className: "dshgt-hint" }, last.date ?? localTime(last.at)),
|
|
2492
2413
|
h(
|
|
2493
2414
|
"span",
|
|
@@ -2519,11 +2440,15 @@ function OverviewView(props) {
|
|
|
2519
2440
|
{
|
|
2520
2441
|
type: "button",
|
|
2521
2442
|
className: "dshgt-filechip",
|
|
2522
|
-
onClick: () =>
|
|
2443
|
+
onClick: () => {
|
|
2444
|
+
if (lastTarget !== void 0) props.onOpenDigest(lastTarget);
|
|
2445
|
+
}
|
|
2523
2446
|
},
|
|
2524
2447
|
h("span", { className: "dshgt-mono" }, last.preview.file)
|
|
2525
2448
|
),
|
|
2526
|
-
last.preview === void 0 ? null : h(Btn, { small: true, onClick: () =>
|
|
2449
|
+
last.preview === void 0 ? null : h(Btn, { small: true, onClick: () => {
|
|
2450
|
+
if (lastTarget !== void 0) props.onOpenDigest(lastTarget);
|
|
2451
|
+
} }, t("overview.last.read")),
|
|
2527
2452
|
pr === null || pr.url === void 0 ? null : h(
|
|
2528
2453
|
"a",
|
|
2529
2454
|
{ className: "dshgt-btn dshgt-btn-sm", href: pr.url, target: "_blank", rel: "noreferrer" },
|
|
@@ -2597,7 +2522,7 @@ function OverviewView(props) {
|
|
|
2597
2522
|
type: "button",
|
|
2598
2523
|
className: "dshgt-day dshgt-day-clickable",
|
|
2599
2524
|
key: date,
|
|
2600
|
-
onClick: () => props.onOpenDigest(date),
|
|
2525
|
+
onClick: () => props.onOpenDigest({ period: "daily", bucket: date }),
|
|
2601
2526
|
title: day.record.errorCode === void 0 ? formatDayLabel(date, lang) : `${formatDayLabel(date, lang)} · ${day.record.errorCode}`
|
|
2602
2527
|
},
|
|
2603
2528
|
h("div", { className: "dshgt-day-date" }, date.slice(5).replace("-", "/")),
|
|
@@ -2609,12 +2534,6 @@ function OverviewView(props) {
|
|
|
2609
2534
|
)
|
|
2610
2535
|
);
|
|
2611
2536
|
})
|
|
2612
|
-
),
|
|
2613
|
-
h(
|
|
2614
|
-
"section",
|
|
2615
|
-
{ className: "dshgt-card dshgt-update-card" },
|
|
2616
|
-
h("div", { className: "dshgt-card-h" }, h("h3", null, t("about.update.title"))),
|
|
2617
|
-
h(PluginUpdateSection, { t, bare: true })
|
|
2618
2537
|
)
|
|
2619
2538
|
)
|
|
2620
2539
|
);
|
|
@@ -2623,6 +2542,9 @@ function OverviewView(props) {
|
|
|
2623
2542
|
// client/runs.ts
|
|
2624
2543
|
var FILTERS = [
|
|
2625
2544
|
{ id: "all", key: "runs.filter.all" },
|
|
2545
|
+
{ id: "daily", key: "runs.filter.daily" },
|
|
2546
|
+
{ id: "weekly", key: "runs.filter.weekly" },
|
|
2547
|
+
{ id: "monthly", key: "runs.filter.monthly" },
|
|
2626
2548
|
{ id: "failed", key: "runs.filter.failed" },
|
|
2627
2549
|
{ id: "dry", key: "runs.filter.dry" }
|
|
2628
2550
|
];
|
|
@@ -2728,6 +2650,7 @@ function RunsView(props) {
|
|
|
2728
2650
|
const records = history.filter((record) => {
|
|
2729
2651
|
if (filter === "failed") return !record.ok;
|
|
2730
2652
|
if (filter === "dry") return record.kind === "dry-run";
|
|
2653
|
+
if (filter === "daily" || filter === "weekly" || filter === "monthly") return (record.period ?? "daily") === filter;
|
|
2731
2654
|
return true;
|
|
2732
2655
|
});
|
|
2733
2656
|
return h(
|
|
@@ -2776,6 +2699,7 @@ function RunsView(props) {
|
|
|
2776
2699
|
},
|
|
2777
2700
|
h("span", { className: `dshgt-lamp ${record.ok ? record.skipped || record.kind === "dry-run" ? "warn" : "ok" : "err"}` }),
|
|
2778
2701
|
h("span", { className: "dshgt-run-date" }, shortTime(record.at)),
|
|
2702
|
+
h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`)),
|
|
2779
2703
|
h(
|
|
2780
2704
|
"span",
|
|
2781
2705
|
{ className: "dshgt-run-what" },
|
|
@@ -2804,6 +2728,7 @@ function RunsView(props) {
|
|
|
2804
2728
|
detailItem(t, "run.usage.branch", record.branch === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.branch)),
|
|
2805
2729
|
detailItem(t, "runs.detail.coreModel", `${record.coreVersion || "—"} · ${record.model?.model ?? "—"}`),
|
|
2806
2730
|
detailItem(t, "runs.detail.date", record.date ?? "—"),
|
|
2731
|
+
detailItem(t, "runs.detail.period", h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`))),
|
|
2807
2732
|
detailItem(
|
|
2808
2733
|
t,
|
|
2809
2734
|
"run.usage.pr",
|
|
@@ -2821,7 +2746,17 @@ function RunsView(props) {
|
|
|
2821
2746
|
h(
|
|
2822
2747
|
"div",
|
|
2823
2748
|
{ className: "dshgt-run-actions" },
|
|
2824
|
-
record.preview === void 0 ? h("span", { className: "dshgt-hint" }, t("runs.detail.noPreview")) : h(
|
|
2749
|
+
record.preview === void 0 ? h("span", { className: "dshgt-hint" }, t("runs.detail.noPreview")) : h(
|
|
2750
|
+
Btn,
|
|
2751
|
+
{
|
|
2752
|
+
small: true,
|
|
2753
|
+
onClick: () => {
|
|
2754
|
+
const target = digestTarget(record, state.schedule.timezone);
|
|
2755
|
+
if (target !== void 0) props.onOpenDigest(target);
|
|
2756
|
+
}
|
|
2757
|
+
},
|
|
2758
|
+
t("runs.detail.readDigest")
|
|
2759
|
+
),
|
|
2825
2760
|
h(Btn, { small: true, onClick: () => setLogId(record.id) }, t("runs.detail.log")),
|
|
2826
2761
|
record.preview === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, record.preview.file)
|
|
2827
2762
|
)
|
|
@@ -3202,9 +3137,8 @@ var STATUS_LAMP2 = {
|
|
|
3202
3137
|
};
|
|
3203
3138
|
var META_KEYS = ["date", "period", "languages", "count", "degraded", "coreVersion", "contentHash", "generatedAt"];
|
|
3204
3139
|
function EmptyDigest(props) {
|
|
3205
|
-
const { t, day, nearest } = props;
|
|
3140
|
+
const { t, lang, day, nearest } = props;
|
|
3206
3141
|
const status = props.error === void 0 ? day.status : "missing";
|
|
3207
|
-
const key = status === "legacy" ? "legacy" : status === "missing" ? "missing" : status;
|
|
3208
3142
|
return h(
|
|
3209
3143
|
"div",
|
|
3210
3144
|
{ className: "dshgt-digest-empty" },
|
|
@@ -3213,10 +3147,10 @@ function EmptyDigest(props) {
|
|
|
3213
3147
|
{ className: "dshgt-status-line" },
|
|
3214
3148
|
h("span", { className: `dshgt-lamp ${STATUS_LAMP2[status]}` }),
|
|
3215
3149
|
h("b", null, t(STATUS_LABEL[status])),
|
|
3216
|
-
h("span", { className: "dshgt-dim" },
|
|
3150
|
+
h("span", { className: "dshgt-dim" }, formatBucketLabel(day.period, day.bucket, lang))
|
|
3217
3151
|
),
|
|
3218
|
-
h("h2", null, t(`digest.empty.${
|
|
3219
|
-
h("p", null, t(`digest.empty.${
|
|
3152
|
+
h("h2", null, t(`digest.empty.${status}.title`)),
|
|
3153
|
+
h("p", null, t(`digest.empty.${status}.reason`)),
|
|
3220
3154
|
day.record.errorCode === void 0 && props.error === void 0 ? null : h(
|
|
3221
3155
|
"p",
|
|
3222
3156
|
{ className: "dshgt-mono dshgt-digest-error" },
|
|
@@ -3226,12 +3160,16 @@ function EmptyDigest(props) {
|
|
|
3226
3160
|
"div",
|
|
3227
3161
|
{ className: "dshgt-actions" },
|
|
3228
3162
|
h(Btn, { small: true, onClick: props.onOpenRuns }, t("digest.empty.viewRuns")),
|
|
3229
|
-
nearest === void 0 ? null : h(
|
|
3163
|
+
nearest === void 0 ? null : h(
|
|
3164
|
+
Btn,
|
|
3165
|
+
{ small: true, onClick: () => props.onSelect({ period: nearest.period, bucket: nearest.bucket }) },
|
|
3166
|
+
t("digest.empty.latest", { date: formatBucketLabel(nearest.period, nearest.bucket, lang) })
|
|
3167
|
+
)
|
|
3230
3168
|
)
|
|
3231
3169
|
);
|
|
3232
3170
|
}
|
|
3233
3171
|
function DigestView(props) {
|
|
3234
|
-
const { t, lang, store,
|
|
3172
|
+
const { t, lang, store, selected } = props;
|
|
3235
3173
|
const [mode, setMode] = import_react.default.useState("render");
|
|
3236
3174
|
const [payload, setPayload] = import_react.default.useState(null);
|
|
3237
3175
|
const [loading, setLoading] = import_react.default.useState(false);
|
|
@@ -3240,19 +3178,26 @@ function DigestView(props) {
|
|
|
3240
3178
|
const state = store.state;
|
|
3241
3179
|
const history = state?.status.history ?? [];
|
|
3242
3180
|
const timeZone = state?.schedule.timezone ?? "UTC";
|
|
3243
|
-
const
|
|
3244
|
-
const
|
|
3245
|
-
const
|
|
3246
|
-
const
|
|
3181
|
+
const groups = buildPeriodGroups(history, { timeZone });
|
|
3182
|
+
const groupMap = new Map(groups.map((group) => [group.period, group]));
|
|
3183
|
+
const activePeriod = selected?.period ?? "daily";
|
|
3184
|
+
const activeGroup = groupMap.get(activePeriod) ?? { period: activePeriod, days: [], previewCount: 0 };
|
|
3185
|
+
const days = activeGroup.days;
|
|
3186
|
+
const fallbackBucket = days.find((item) => item.status === "preview")?.bucket ?? days[0]?.bucket;
|
|
3187
|
+
const requestedBucket = selected?.period === activePeriod ? selected.bucket : void 0;
|
|
3188
|
+
const effectiveBucket = requestedBucket !== void 0 && days.some((day2) => day2.bucket === requestedBucket) ? requestedBucket : fallbackBucket;
|
|
3189
|
+
const day = days.find((item) => item.bucket === effectiveBucket);
|
|
3247
3190
|
const index = day === void 0 ? -1 : days.indexOf(day);
|
|
3248
|
-
const previewCount = days.filter((item) => item.status === "preview").length;
|
|
3249
3191
|
const previewRunId = day !== void 0 && day.status === "preview" && day.record.preview !== void 0 ? day.record.id : void 0;
|
|
3250
3192
|
import_react.default.useEffect(() => {
|
|
3251
|
-
if (
|
|
3252
|
-
|
|
3193
|
+
if (effectiveBucket === void 0) return;
|
|
3194
|
+
if (selected?.period !== activePeriod || selected?.bucket !== effectiveBucket) {
|
|
3195
|
+
props.onSelect({ period: activePeriod, bucket: effectiveBucket });
|
|
3196
|
+
}
|
|
3197
|
+
}, [activePeriod, effectiveBucket, selected?.period, selected?.bucket, props.onSelect]);
|
|
3253
3198
|
import_react.default.useEffect(() => {
|
|
3254
3199
|
setMode("render");
|
|
3255
|
-
}, [
|
|
3200
|
+
}, [activePeriod, effectiveBucket]);
|
|
3256
3201
|
import_react.default.useEffect(() => {
|
|
3257
3202
|
if (previewRunId === void 0) {
|
|
3258
3203
|
setPayload(null);
|
|
@@ -3278,7 +3223,7 @@ function DigestView(props) {
|
|
|
3278
3223
|
if (state === null) {
|
|
3279
3224
|
return h("div", { className: "dshgt-empty" }, store.error ?? t("quickfill.loading"));
|
|
3280
3225
|
}
|
|
3281
|
-
const nearest = day === void 0 ? void 0 : days.find((item) => item.status === "preview" && item.
|
|
3226
|
+
const nearest = day === void 0 ? void 0 : days.find((item) => item.status === "preview" && item.bucket !== day.bucket);
|
|
3282
3227
|
let rendered = null;
|
|
3283
3228
|
let parseFailed = false;
|
|
3284
3229
|
if (payload !== null) {
|
|
@@ -3288,7 +3233,40 @@ function DigestView(props) {
|
|
|
3288
3233
|
parseFailed = true;
|
|
3289
3234
|
}
|
|
3290
3235
|
}
|
|
3291
|
-
const
|
|
3236
|
+
const periodSeg = h(
|
|
3237
|
+
"div",
|
|
3238
|
+
{ className: "dshgt-period-seg", role: "tablist", "aria-label": t("digest.selectPeriod") },
|
|
3239
|
+
groups.map((group) => {
|
|
3240
|
+
const on = group.period === activePeriod;
|
|
3241
|
+
const firstBucket = group.days.find((item) => item.status === "preview")?.bucket ?? group.days[0]?.bucket;
|
|
3242
|
+
return h(
|
|
3243
|
+
"button",
|
|
3244
|
+
{
|
|
3245
|
+
key: group.period,
|
|
3246
|
+
type: "button",
|
|
3247
|
+
role: "tab",
|
|
3248
|
+
"aria-selected": on ? "true" : "false",
|
|
3249
|
+
className: on ? "on" : "",
|
|
3250
|
+
onClick: () => props.onSelect({ period: group.period, bucket: firstBucket ?? "" })
|
|
3251
|
+
},
|
|
3252
|
+
h("span", null, t(`period.${group.period}`)),
|
|
3253
|
+
h("span", { className: "dshgt-period-count" }, String(group.days.length))
|
|
3254
|
+
);
|
|
3255
|
+
})
|
|
3256
|
+
);
|
|
3257
|
+
const periodBar = h(
|
|
3258
|
+
"div",
|
|
3259
|
+
{ className: "dshgt-digest-subbar" },
|
|
3260
|
+
periodSeg,
|
|
3261
|
+
h(
|
|
3262
|
+
"span",
|
|
3263
|
+
{ className: "dshgt-dim" },
|
|
3264
|
+
days.length === 0 ? t("digest.window.empty") : t("digest.window.period", { count: days.length, previews: activeGroup.previewCount })
|
|
3265
|
+
),
|
|
3266
|
+
h("span", { className: "dshgt-grow" }),
|
|
3267
|
+
h(Btn, { small: true, onClick: props.onOpenRuns }, t("digest.allRuns"))
|
|
3268
|
+
);
|
|
3269
|
+
const bucketBar = h(
|
|
3292
3270
|
"div",
|
|
3293
3271
|
{ className: "dshgt-digest-subbar" },
|
|
3294
3272
|
h(
|
|
@@ -3304,7 +3282,7 @@ function DigestView(props) {
|
|
|
3304
3282
|
disabled: index < 0 || index >= days.length - 1,
|
|
3305
3283
|
onClick: () => {
|
|
3306
3284
|
const target = days[index + 1];
|
|
3307
|
-
if (target !== void 0) props.
|
|
3285
|
+
if (target !== void 0) props.onSelect({ period: activePeriod, bucket: target.bucket });
|
|
3308
3286
|
}
|
|
3309
3287
|
},
|
|
3310
3288
|
"‹"
|
|
@@ -3313,12 +3291,18 @@ function DigestView(props) {
|
|
|
3313
3291
|
"select",
|
|
3314
3292
|
{
|
|
3315
3293
|
className: "dshgt-dateselect",
|
|
3316
|
-
"aria-label": t("digest.
|
|
3317
|
-
value:
|
|
3318
|
-
onChange: (event) => props.
|
|
3294
|
+
"aria-label": t("digest.selectBucket"),
|
|
3295
|
+
value: effectiveBucket ?? "",
|
|
3296
|
+
onChange: (event) => props.onSelect({ period: activePeriod, bucket: event.target.value }),
|
|
3319
3297
|
disabled: days.length === 0
|
|
3320
3298
|
},
|
|
3321
|
-
days.
|
|
3299
|
+
days.length === 0 ? h("option", { value: "" }, t("digest.window.empty")) : days.map(
|
|
3300
|
+
(item) => h(
|
|
3301
|
+
"option",
|
|
3302
|
+
{ key: item.bucket, value: item.bucket },
|
|
3303
|
+
`${formatBucketLabel(activePeriod, item.bucket, lang)} · ${t(STATUS_TAG[item.status])}`
|
|
3304
|
+
)
|
|
3305
|
+
)
|
|
3322
3306
|
),
|
|
3323
3307
|
h(
|
|
3324
3308
|
"button",
|
|
@@ -3330,25 +3314,20 @@ function DigestView(props) {
|
|
|
3330
3314
|
disabled: index <= 0,
|
|
3331
3315
|
onClick: () => {
|
|
3332
3316
|
const target = days[index - 1];
|
|
3333
|
-
if (target !== void 0) props.
|
|
3317
|
+
if (target !== void 0) props.onSelect({ period: activePeriod, bucket: target.bucket });
|
|
3334
3318
|
}
|
|
3335
3319
|
},
|
|
3336
3320
|
"›"
|
|
3337
3321
|
)
|
|
3338
3322
|
),
|
|
3339
|
-
h(
|
|
3340
|
-
"span",
|
|
3341
|
-
{ className: "dshgt-dim" },
|
|
3342
|
-
days.length === 0 ? t("digest.window.empty") : t("digest.window", { days: days.length, previews: previewCount })
|
|
3343
|
-
),
|
|
3344
|
-
h("span", { className: "dshgt-grow" }),
|
|
3345
|
-
h(Btn, { small: true, onClick: props.onOpenRuns }, t("digest.allRuns"))
|
|
3323
|
+
h("span", { className: "dshgt-dim" }, t("digest.bucketNavHint"))
|
|
3346
3324
|
);
|
|
3347
3325
|
if (day === void 0) {
|
|
3348
3326
|
return h(
|
|
3349
3327
|
"div",
|
|
3350
3328
|
{ className: "dshgt-view dshgt-digest" },
|
|
3351
|
-
|
|
3329
|
+
periodBar,
|
|
3330
|
+
bucketBar,
|
|
3352
3331
|
h(
|
|
3353
3332
|
"div",
|
|
3354
3333
|
{ className: "dshgt-digest-empty" },
|
|
@@ -3363,7 +3342,8 @@ function DigestView(props) {
|
|
|
3363
3342
|
return h(
|
|
3364
3343
|
"div",
|
|
3365
3344
|
{ className: "dshgt-view dshgt-digest" },
|
|
3366
|
-
|
|
3345
|
+
periodBar,
|
|
3346
|
+
bucketBar,
|
|
3367
3347
|
h(
|
|
3368
3348
|
"div",
|
|
3369
3349
|
{ className: "dshgt-digest-sheet" },
|
|
@@ -3374,13 +3354,14 @@ function DigestView(props) {
|
|
|
3374
3354
|
...nearest === void 0 ? {} : { nearest },
|
|
3375
3355
|
...error === null ? {} : { error },
|
|
3376
3356
|
onOpenRuns: props.onOpenRuns,
|
|
3377
|
-
|
|
3357
|
+
onSelect: props.onSelect
|
|
3378
3358
|
}) : h(
|
|
3379
3359
|
"div",
|
|
3380
3360
|
{ className: "dshgt-digest-body" },
|
|
3381
3361
|
h(
|
|
3382
3362
|
"div",
|
|
3383
3363
|
{ className: "dshgt-digest-bar" },
|
|
3364
|
+
h("span", { className: `dshgt-pchip ${activePeriod}` }, t(`period.${activePeriod}`)),
|
|
3384
3365
|
h(
|
|
3385
3366
|
"span",
|
|
3386
3367
|
{ className: "dshgt-filechip dshgt-filechip-static" },
|
|
@@ -3466,15 +3447,198 @@ function metaLine(rendered) {
|
|
|
3466
3447
|
);
|
|
3467
3448
|
}
|
|
3468
3449
|
|
|
3450
|
+
// node_modules/@morehao/dsh-plugin-kit/dist/update-client.js
|
|
3451
|
+
var IDLE = { status: "idle", view: null, error: null };
|
|
3452
|
+
function errorOf(error) {
|
|
3453
|
+
if (error !== null && typeof error === "object") {
|
|
3454
|
+
const value = error;
|
|
3455
|
+
const message = typeof value.message === "string" && value.message !== "" ? value.message : "操作失败";
|
|
3456
|
+
return typeof value.code === "string" ? { code: value.code, message } : { message };
|
|
3457
|
+
}
|
|
3458
|
+
return { message: String(error ?? "操作失败") };
|
|
3459
|
+
}
|
|
3460
|
+
function createUpdateController(options) {
|
|
3461
|
+
const now = options.now ?? Date.now;
|
|
3462
|
+
let state = { ...IDLE };
|
|
3463
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
3464
|
+
let inFlight = null;
|
|
3465
|
+
function emit(next) {
|
|
3466
|
+
state = next;
|
|
3467
|
+
options.onChange?.(state);
|
|
3468
|
+
for (const listener of listeners) listener(state);
|
|
3469
|
+
}
|
|
3470
|
+
async function check(checkOptions = {}) {
|
|
3471
|
+
if (inFlight !== null) return;
|
|
3472
|
+
inFlight = "check";
|
|
3473
|
+
emit({ ...state, status: "checking", error: null });
|
|
3474
|
+
try {
|
|
3475
|
+
const view = await options.request.check(checkOptions);
|
|
3476
|
+
const checkedAt = new Date(now()).toISOString();
|
|
3477
|
+
if (view.checkFailed) {
|
|
3478
|
+
emit({
|
|
3479
|
+
status: "failed",
|
|
3480
|
+
view,
|
|
3481
|
+
error: { code: "CHECK_FAILED", message: "检查更新失败:拿不到 registry 上的最新版本" },
|
|
3482
|
+
checkedAt
|
|
3483
|
+
});
|
|
3484
|
+
} else {
|
|
3485
|
+
emit({ status: view.updateAvailable ? "available" : "current", view, error: null, checkedAt });
|
|
3486
|
+
}
|
|
3487
|
+
} catch (error) {
|
|
3488
|
+
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
3489
|
+
} finally {
|
|
3490
|
+
inFlight = null;
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
async function apply2() {
|
|
3494
|
+
if (inFlight !== null) return;
|
|
3495
|
+
const view = state.view;
|
|
3496
|
+
if (view === null || !view.updateAvailable) {
|
|
3497
|
+
emit({ ...state, status: "failed", error: { code: "NO_UPDATE", message: "没有可更新的版本,请先检查更新" } });
|
|
3498
|
+
return;
|
|
3499
|
+
}
|
|
3500
|
+
if (!view.canApply) {
|
|
3501
|
+
emit({
|
|
3502
|
+
...state,
|
|
3503
|
+
status: "failed",
|
|
3504
|
+
error: { code: "NO_APPLY", message: `当前环境不支持一键更新,请执行:${view.manualCommand}` }
|
|
3505
|
+
});
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3508
|
+
inFlight = "apply";
|
|
3509
|
+
emit({ ...state, status: "applying", error: null });
|
|
3510
|
+
try {
|
|
3511
|
+
const result = await options.request.apply();
|
|
3512
|
+
const restartRequired = result.restartRequired ?? result.application !== "applied";
|
|
3513
|
+
emit({ ...state, status: restartRequired ? "restart-required" : "applied", error: null });
|
|
3514
|
+
} catch (error) {
|
|
3515
|
+
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
3516
|
+
} finally {
|
|
3517
|
+
inFlight = null;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
return {
|
|
3521
|
+
getState: () => state,
|
|
3522
|
+
subscribe: (listener) => {
|
|
3523
|
+
listeners.add(listener);
|
|
3524
|
+
return () => {
|
|
3525
|
+
listeners.delete(listener);
|
|
3526
|
+
};
|
|
3527
|
+
},
|
|
3528
|
+
check,
|
|
3529
|
+
apply: apply2,
|
|
3530
|
+
reset: () => emit({ ...IDLE })
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// client/update-panel.ts
|
|
3535
|
+
var singleton = null;
|
|
3536
|
+
function getUpdateController() {
|
|
3537
|
+
if (singleton === null) {
|
|
3538
|
+
singleton = createUpdateController({
|
|
3539
|
+
request: {
|
|
3540
|
+
check: (options) => getPluginUpdate(options.fresh === true ? { fresh: true } : {}),
|
|
3541
|
+
apply: () => applyPluginUpdate()
|
|
3542
|
+
}
|
|
3543
|
+
});
|
|
3544
|
+
}
|
|
3545
|
+
return singleton;
|
|
3546
|
+
}
|
|
3547
|
+
function usePluginUpdate() {
|
|
3548
|
+
const controller = getUpdateController();
|
|
3549
|
+
const [state, setState] = import_react.default.useState(() => controller.getState());
|
|
3550
|
+
import_react.default.useEffect(() => {
|
|
3551
|
+
const unsubscribe = controller.subscribe(setState);
|
|
3552
|
+
if (controller.getState().status === "idle") void controller.check();
|
|
3553
|
+
return unsubscribe;
|
|
3554
|
+
}, [controller]);
|
|
3555
|
+
return [state, controller];
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3469
3558
|
// client/about.ts
|
|
3559
|
+
function githubIcon() {
|
|
3560
|
+
return h("svg", {
|
|
3561
|
+
className: "dshgt-gh",
|
|
3562
|
+
viewBox: "0 0 16 16",
|
|
3563
|
+
"aria-hidden": "true",
|
|
3564
|
+
dangerouslySetInnerHTML: {
|
|
3565
|
+
__html: '<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"/>'
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
function updateLine(t, state, fallbackVersion) {
|
|
3570
|
+
const { status, view, error } = state;
|
|
3571
|
+
if (status === "checking" || view === null) return { text: t("shell.update.checking"), kind: "muted" };
|
|
3572
|
+
if (status === "applying") return { text: t("shell.update.applying", { version: view.latestVersion ?? "" }), kind: "muted" };
|
|
3573
|
+
if (status === "restart-required" || status === "applied") return { text: t("shell.update.done", { version: view.latestVersion ?? "" }), kind: "ok" };
|
|
3574
|
+
if (status === "failed") return { text: error?.code === "CHECK_FAILED" ? t("shell.update.checkFailed") : t("shell.update.failed"), kind: "err" };
|
|
3575
|
+
if (view.checkFailed) return { text: t("shell.update.checkFailed"), kind: "err" };
|
|
3576
|
+
if (view.updateAvailable) return { text: t("shell.update.available", { latest: view.latestVersion ?? "" }), kind: "new" };
|
|
3577
|
+
return { text: t("shell.update.latest", { version: view.currentVersion ?? fallbackVersion }), kind: "ok" };
|
|
3578
|
+
}
|
|
3579
|
+
function UpdateRow(props) {
|
|
3580
|
+
const { t, update, controller, fallbackVersion } = props;
|
|
3581
|
+
const [confirming, setConfirming] = import_react.default.useState(false);
|
|
3582
|
+
const [cmdCopied, setCmdCopied] = import_react.default.useState(false);
|
|
3583
|
+
import_react.default.useEffect(() => {
|
|
3584
|
+
if (update.status === "applying" || update.status === "restart-required" || update.status === "applied") setConfirming(false);
|
|
3585
|
+
}, [update.status]);
|
|
3586
|
+
const view = update.view;
|
|
3587
|
+
const status = update.status;
|
|
3588
|
+
const busy = status === "checking" || status === "applying";
|
|
3589
|
+
const settled = status === "restart-required" || status === "applied";
|
|
3590
|
+
const latestVersion = view === null ? "" : view.latestVersion ?? "";
|
|
3591
|
+
const actionable = view !== null && view.updateAvailable && view.canApply && !settled && !busy;
|
|
3592
|
+
const manual = view !== null && (!view.canApply || view.checkFailed) ? view.manualCommand ?? null : null;
|
|
3593
|
+
const line = updateLine(t, update, fallbackVersion);
|
|
3594
|
+
const copyCmd = () => {
|
|
3595
|
+
if (manual === null) return;
|
|
3596
|
+
void copyText(manual).then((ok) => {
|
|
3597
|
+
if (!ok) return;
|
|
3598
|
+
setCmdCopied(true);
|
|
3599
|
+
setTimeout(() => setCmdCopied(false), 1400);
|
|
3600
|
+
});
|
|
3601
|
+
};
|
|
3602
|
+
function action() {
|
|
3603
|
+
if (status === "applying") return h(Btn, { small: true, disabled: true }, t("shell.update.applyingShort"));
|
|
3604
|
+
if (actionable) {
|
|
3605
|
+
if (confirming) {
|
|
3606
|
+
return [
|
|
3607
|
+
h(Btn, { key: "yes", small: true, variant: "danger", onClick: () => {
|
|
3608
|
+
setConfirming(false);
|
|
3609
|
+
void controller.apply();
|
|
3610
|
+
} }, t("shell.update.confirmYes")),
|
|
3611
|
+
h(Btn, { key: "no", small: true, onClick: () => setConfirming(false) }, t("shell.update.cancel"))
|
|
3612
|
+
];
|
|
3613
|
+
}
|
|
3614
|
+
return h(Btn, { small: true, variant: "primary", onClick: () => setConfirming(true) }, t("shell.update.apply", { version: latestVersion }));
|
|
3615
|
+
}
|
|
3616
|
+
if (manual !== null) return h(Btn, { small: true, onClick: copyCmd }, cmdCopied ? t("shell.update.copied") : t("shell.update.copyCmd"));
|
|
3617
|
+
return h(Btn, { small: true, disabled: busy, onClick: () => void controller.check({ fresh: true }) }, t("shell.update.check"));
|
|
3618
|
+
}
|
|
3619
|
+
return h(
|
|
3620
|
+
"div",
|
|
3621
|
+
{ className: "dshgt-about-upd" },
|
|
3622
|
+
h(
|
|
3623
|
+
"span",
|
|
3624
|
+
{ className: `dshgt-about-status ${confirming ? "new" : line.kind}` },
|
|
3625
|
+
confirming ? t("shell.update.confirmHint") : line.text
|
|
3626
|
+
),
|
|
3627
|
+
h("span", { className: "dshgt-about-actions" }, action())
|
|
3628
|
+
);
|
|
3629
|
+
}
|
|
3470
3630
|
function AboutDialog(props) {
|
|
3471
3631
|
const { t, state } = props;
|
|
3472
3632
|
const [copied, setCopied] = import_react.default.useState(false);
|
|
3633
|
+
const [updateState, updateController] = usePluginUpdate();
|
|
3473
3634
|
const plugin = state.plugin;
|
|
3474
3635
|
const fullName = `${plugin.name}@v${plugin.version}`;
|
|
3475
3636
|
const repository = plugin.repository;
|
|
3476
3637
|
const ownerRepo = repository === void 0 ? void 0 : repository.replace(/^https?:\/\/github\.com\//, "");
|
|
3477
3638
|
const repoVersion = ownerRepo === void 0 ? void 0 : `${ownerRepo}@v${plugin.version}`;
|
|
3639
|
+
const core = state.core;
|
|
3640
|
+
const coreVersion = core.version === void 0 ? "" : `trendradar ${core.version}`;
|
|
3641
|
+
const coreRepo = core.repository;
|
|
3478
3642
|
import_react.default.useEffect(() => {
|
|
3479
3643
|
const onKey = (event) => {
|
|
3480
3644
|
if (event.key === "Escape") props.onClose();
|
|
@@ -3486,9 +3650,23 @@ function AboutDialog(props) {
|
|
|
3486
3650
|
void copyText(fullName).then((ok) => {
|
|
3487
3651
|
if (!ok) return;
|
|
3488
3652
|
setCopied(true);
|
|
3489
|
-
setTimeout(() => setCopied(false),
|
|
3653
|
+
setTimeout(() => setCopied(false), 1400);
|
|
3490
3654
|
});
|
|
3491
3655
|
};
|
|
3656
|
+
const coreValue = () => {
|
|
3657
|
+
if (coreVersion === "") return "—";
|
|
3658
|
+
if (coreRepo === void 0) return coreVersion;
|
|
3659
|
+
return h(
|
|
3660
|
+
"span",
|
|
3661
|
+
{ className: "dshgt-about-core" },
|
|
3662
|
+
h("a", { href: coreRepo, target: "_blank", rel: "noreferrer" }, coreVersion),
|
|
3663
|
+
h(
|
|
3664
|
+
"a",
|
|
3665
|
+
{ className: "dshgt-about-gh", href: coreRepo, target: "_blank", rel: "noreferrer", title: t("about.core.repo"), "aria-label": t("about.core.repo") },
|
|
3666
|
+
githubIcon()
|
|
3667
|
+
)
|
|
3668
|
+
);
|
|
3669
|
+
};
|
|
3492
3670
|
const dialog = h(
|
|
3493
3671
|
"div",
|
|
3494
3672
|
{ className: "dshgt-modal-mask", onClick: (event) => {
|
|
@@ -3505,9 +3683,8 @@ function AboutDialog(props) {
|
|
|
3505
3683
|
),
|
|
3506
3684
|
h(
|
|
3507
3685
|
"button",
|
|
3508
|
-
{ type: "button", className:
|
|
3509
|
-
h("span", { className: "dshgt-mono" }, fullName)
|
|
3510
|
-
h("span", { className: "dshgt-hint" }, copied ? t("about.copied") : t("about.copy"))
|
|
3686
|
+
{ type: "button", className: `dshgt-about-pkg${copied ? " is-copied" : ""}`, onClick: copy },
|
|
3687
|
+
h("span", { className: "dshgt-mono" }, fullName)
|
|
3511
3688
|
),
|
|
3512
3689
|
h(KV, {
|
|
3513
3690
|
items: [
|
|
@@ -3516,11 +3693,11 @@ function AboutDialog(props) {
|
|
|
3516
3693
|
repository === void 0 || repoVersion === void 0 ? h("span", { className: "dshgt-hint" }, t("about.repo.missing")) : h("a", { href: repository, target: "_blank", rel: "noreferrer" }, repoVersion)
|
|
3517
3694
|
],
|
|
3518
3695
|
[t("about.license"), "MIT"],
|
|
3519
|
-
[t("about.core"),
|
|
3696
|
+
[t("about.core"), coreValue()],
|
|
3520
3697
|
[t("about.env"), t("about.env.value")]
|
|
3521
3698
|
]
|
|
3522
3699
|
}),
|
|
3523
|
-
h(
|
|
3700
|
+
h(UpdateRow, { t, update: updateState, controller: updateController, fallbackVersion: plugin.version })
|
|
3524
3701
|
)
|
|
3525
3702
|
);
|
|
3526
3703
|
return h("div", { className: "dshgt-root" }, dialog);
|
|
@@ -3536,7 +3713,7 @@ function logo() {
|
|
|
3536
3713
|
h("circle", { cx: 32, cy: 45, r: 3, fill: "#3fb950" })
|
|
3537
3714
|
);
|
|
3538
3715
|
}
|
|
3539
|
-
function
|
|
3716
|
+
function githubIcon2() {
|
|
3540
3717
|
return h("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true" }, h("path", {
|
|
3541
3718
|
d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"
|
|
3542
3719
|
}));
|
|
@@ -3615,7 +3792,7 @@ function IdentityBar(props) {
|
|
|
3615
3792
|
h(
|
|
3616
3793
|
"div",
|
|
3617
3794
|
{ className: "dshgt-idbar-right" },
|
|
3618
|
-
plugin.repository === void 0 ? null : h("a", { className: "dshgt-id-gh", href: plugin.repository, target: "_blank", rel: "noreferrer", title: t("about.repo"), "aria-label": t("about.repo") },
|
|
3795
|
+
plugin.repository === void 0 ? null : h("a", { className: "dshgt-id-gh", href: plugin.repository, target: "_blank", rel: "noreferrer", title: t("about.repo"), "aria-label": t("about.repo") }, githubIcon2()),
|
|
3619
3796
|
h(
|
|
3620
3797
|
"span",
|
|
3621
3798
|
{ className: "dshgt-id-upd" },
|
|
@@ -3746,10 +3923,10 @@ function apply(ctx) {
|
|
|
3746
3923
|
const value = store();
|
|
3747
3924
|
const controller = useRunController(value);
|
|
3748
3925
|
const [view, setView] = import_react.default.useState("overview");
|
|
3749
|
-
const [
|
|
3926
|
+
const [digestTarget2, setDigestTarget] = import_react.default.useState(void 0);
|
|
3750
3927
|
const [aboutOpen, setAboutOpen] = import_react.default.useState(false);
|
|
3751
|
-
const openDigest = import_react.default.useCallback((
|
|
3752
|
-
if (
|
|
3928
|
+
const openDigest = import_react.default.useCallback((target) => {
|
|
3929
|
+
if (target !== void 0) setDigestTarget(target);
|
|
3753
3930
|
setView("digest");
|
|
3754
3931
|
}, []);
|
|
3755
3932
|
const openRuns = import_react.default.useCallback(() => setView("runs"), []);
|
|
@@ -3765,7 +3942,7 @@ function apply(ctx) {
|
|
|
3765
3942
|
state.settings.repo.path.trim() !== "",
|
|
3766
3943
|
state.github.configured
|
|
3767
3944
|
].filter(Boolean).length;
|
|
3768
|
-
const digestTail =
|
|
3945
|
+
const digestTail = state?.status.lastResult?.date ?? state?.status.history[0]?.date;
|
|
3769
3946
|
const showActions = view === "overview" || view === "runs";
|
|
3770
3947
|
const nextRun = schedule === void 0 || !schedule.enabled ? t("shell.scheduleOff") : schedule.nextRunAt === void 0 ? `${schedule.time} · ${schedule.timezone}` : nextRunText(schedule.nextRunAt);
|
|
3771
3948
|
const relNext = schedule !== void 0 && schedule.enabled && schedule.nextRunAt !== void 0 ? relativeFuture(schedule.nextRunAt, t) : void 0;
|
|
@@ -3781,8 +3958,8 @@ function apply(ctx) {
|
|
|
3781
3958
|
t,
|
|
3782
3959
|
lang,
|
|
3783
3960
|
store: value,
|
|
3784
|
-
...
|
|
3785
|
-
|
|
3961
|
+
...digestTarget2 === void 0 ? {} : { selected: digestTarget2 },
|
|
3962
|
+
onSelect: setDigestTarget,
|
|
3786
3963
|
onOpenRuns: openRuns
|
|
3787
3964
|
}) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : h(SettingsView, { t, store: value, pickDirectory });
|
|
3788
3965
|
return h(
|