@morehao/dsh-github-trending 0.4.0 → 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 +29 -0
- package/README.md +7 -7
- package/client.js +691 -415
- 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": "下次运行",
|
|
@@ -241,12 +244,28 @@ var DICT = {
|
|
|
241
244
|
"shell.ready": "就绪 {ready} / {total}",
|
|
242
245
|
"shell.github": "GitHub",
|
|
243
246
|
"shell.package.copy": "复制完整包名",
|
|
247
|
+
"shell.update.check": "检查更新",
|
|
248
|
+
"shell.update.checking": "正在检查…",
|
|
249
|
+
"shell.update.applying": "正在更新到 v{version}…",
|
|
250
|
+
"shell.update.applyingShort": "更新中…",
|
|
251
|
+
"shell.update.done": "已更新,重启 DSH 生效",
|
|
252
|
+
"shell.update.failed": "更新失败",
|
|
253
|
+
"shell.update.checkFailed": "检查失败,可稍后重试",
|
|
254
|
+
"shell.update.available": "有新版本 v{latest}",
|
|
255
|
+
"shell.update.latest": "已是最新 v{version}",
|
|
256
|
+
"shell.update.apply": "更新到 v{version}",
|
|
257
|
+
"shell.update.confirmHint": "更新会重装插件,需重启 DSH 生效",
|
|
258
|
+
"shell.update.confirmYes": "确认更新",
|
|
259
|
+
"shell.update.cancel": "取消",
|
|
260
|
+
"shell.update.copyCmd": "复制更新命令",
|
|
261
|
+
"shell.update.copied": "已复制",
|
|
262
|
+
"shell.update.manual": "本地安装,需手动更新",
|
|
244
263
|
"time.in.minutes": "{minutes} 分钟后",
|
|
245
264
|
"time.in.hours": "{hours} 小时 {minutes} 分后",
|
|
246
265
|
"time.in.days": "{days} 天后",
|
|
247
266
|
"overview.last.none": "还没有运行记录",
|
|
248
267
|
"overview.last.files": "{count} 个文件",
|
|
249
|
-
"overview.last.digest": "{date} · GitHub
|
|
268
|
+
"overview.last.digest": "{date} · GitHub 趋势榜单",
|
|
250
269
|
"overview.last.read": "阅读本期",
|
|
251
270
|
"overview.last.noPreview": "这次运行没有保留预览副本",
|
|
252
271
|
"overview.last.prPending": "待合并",
|
|
@@ -260,7 +279,7 @@ var DICT = {
|
|
|
260
279
|
"overview.ready.repo": "仓库",
|
|
261
280
|
"overview.ready.github": "GitHub",
|
|
262
281
|
"overview.ready.view": "查看",
|
|
263
|
-
"overview.week.title": "最近 7
|
|
282
|
+
"overview.week.title": "最近 7 天(日榜)",
|
|
264
283
|
"overview.week.all": "全部运行记录",
|
|
265
284
|
"overview.week.none": "无记录",
|
|
266
285
|
"overview.week.wait": "等待 {time}",
|
|
@@ -276,6 +295,9 @@ var DICT = {
|
|
|
276
295
|
"runs.dryHint": "试跑不写文件、不提交",
|
|
277
296
|
"runs.empty": "没有符合条件的记录",
|
|
278
297
|
"runs.filter.all": "全部",
|
|
298
|
+
"runs.filter.daily": "日榜",
|
|
299
|
+
"runs.filter.weekly": "周榜",
|
|
300
|
+
"runs.filter.monthly": "月榜",
|
|
279
301
|
"runs.filter.failed": "失败",
|
|
280
302
|
"runs.filter.dry": "试跑",
|
|
281
303
|
"runs.pendingPr": "待合并",
|
|
@@ -285,6 +307,7 @@ var DICT = {
|
|
|
285
307
|
"runs.legacyHint": "旧记录没有预览副本,内容哈希使用旧算法,不能与 v2 直接比较。",
|
|
286
308
|
"runs.detail.coreModel": "核心 / 模型",
|
|
287
309
|
"runs.detail.date": "运行日期",
|
|
310
|
+
"runs.detail.period": "周期",
|
|
288
311
|
"runs.detail.warnings": "警告",
|
|
289
312
|
"runs.detail.none": "无",
|
|
290
313
|
"runs.detail.files": "文件 / 耗时",
|
|
@@ -294,6 +317,10 @@ var DICT = {
|
|
|
294
317
|
"digest.allRuns": "全部运行记录",
|
|
295
318
|
"digest.window": "最近 30 天 · {days} 天有记录 · {previews} 期有预览",
|
|
296
319
|
"digest.window.empty": "最近 30 天没有运行记录",
|
|
320
|
+
"digest.window.period": "近 {count} 期 · {previews} 期有预览",
|
|
321
|
+
"digest.selectPeriod": "选择周期",
|
|
322
|
+
"digest.selectBucket": "选择期数",
|
|
323
|
+
"digest.bucketNavHint": "按周期分别回看;切换周期不影响其他周期的时间线",
|
|
297
324
|
"digest.prev": "上一期(更早)",
|
|
298
325
|
"digest.next": "下一期(更新)",
|
|
299
326
|
"digest.select": "选择日报日期",
|
|
@@ -340,27 +367,9 @@ var DICT = {
|
|
|
340
367
|
"about.repo.missing": "package.json 没有可解析的仓库地址",
|
|
341
368
|
"about.license": "许可",
|
|
342
369
|
"about.core": "核心",
|
|
370
|
+
"about.core.repo": "打开核心 GitHub 仓库",
|
|
343
371
|
"about.env": "运行环境",
|
|
344
|
-
"about.env.value": "DSH Web · Node 插件"
|
|
345
|
-
"about.update.title": "插件更新",
|
|
346
|
-
"about.update.check": "检查更新",
|
|
347
|
-
"about.update.checking": "正在检查最新版…",
|
|
348
|
-
"about.update.current": "已是最新(v{version})",
|
|
349
|
-
"about.update.available": "有新版本 v{latest}(当前 v{current})",
|
|
350
|
-
"about.update.apply": "更新到 v{version}",
|
|
351
|
-
"about.update.confirm": "确认更新到 v{version}?会重装本插件并重载面板,之后需要重启 DSH 生效。",
|
|
352
|
-
"about.update.confirmYes": "确认更新",
|
|
353
|
-
"about.update.cancel": "取消",
|
|
354
|
-
"about.update.applying": "正在更新到 v{version}…",
|
|
355
|
-
"about.update.done": "已更新到 v{version},重启 DSH 后生效。",
|
|
356
|
-
"about.update.applied": "已更新到 v{version}。",
|
|
357
|
-
"about.update.failed": "更新失败:{message}",
|
|
358
|
-
"about.update.checkFailed": "检查更新失败:拿不到 registry 上的最新版。可以稍后重试,或手动执行下面的命令。",
|
|
359
|
-
"about.update.manual": "当前是本地 {kind} 安装,不能一键更新(会把开发链接换成 npm 版)。手动更新:",
|
|
360
|
-
"about.update.copy": "复制命令",
|
|
361
|
-
"about.update.copied": "已复制",
|
|
362
|
-
"about.update.hint": "只检查 npm 上的 latest 稳定版;更新后需要重启 DSH。",
|
|
363
|
-
"update.badge": "有新版本可用"
|
|
372
|
+
"about.env.value": "DSH Web · Node 插件"
|
|
364
373
|
},
|
|
365
374
|
en: {
|
|
366
375
|
"section.title": "GitHub Trending",
|
|
@@ -545,12 +554,15 @@ var DICT = {
|
|
|
545
554
|
"skip.unchanged": "The branch already holds the same artifacts; no new commit.",
|
|
546
555
|
"label.optional": "optional",
|
|
547
556
|
"nav.overview": "Overview",
|
|
548
|
-
"nav.digest": "
|
|
557
|
+
"nav.digest": "Board",
|
|
549
558
|
"nav.runs": "Runs",
|
|
550
559
|
"nav.settings": "Settings",
|
|
560
|
+
"period.daily": "Daily",
|
|
561
|
+
"period.weekly": "Weekly",
|
|
562
|
+
"period.monthly": "Monthly",
|
|
551
563
|
"shell.nav": "Panel",
|
|
552
|
-
"shell.overview.dek": "
|
|
553
|
-
"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.",
|
|
554
566
|
"shell.runs.dek": "The last 30 runs; expand one for artifacts, errors and logs.",
|
|
555
567
|
"shell.settings.dek": "The existing settings page; each section saves on its own.",
|
|
556
568
|
"shell.nextRun": "Next run",
|
|
@@ -558,12 +570,28 @@ var DICT = {
|
|
|
558
570
|
"shell.ready": "Ready {ready} / {total}",
|
|
559
571
|
"shell.github": "GitHub",
|
|
560
572
|
"shell.package.copy": "Copy full package name",
|
|
573
|
+
"shell.update.check": "Check for updates",
|
|
574
|
+
"shell.update.checking": "Checking…",
|
|
575
|
+
"shell.update.applying": "Updating to v{version}…",
|
|
576
|
+
"shell.update.applyingShort": "Updating…",
|
|
577
|
+
"shell.update.done": "Updated · restart DSH",
|
|
578
|
+
"shell.update.failed": "Update failed",
|
|
579
|
+
"shell.update.checkFailed": "Check failed, try again later",
|
|
580
|
+
"shell.update.available": "v{latest} available",
|
|
581
|
+
"shell.update.latest": "Up to date · v{version}",
|
|
582
|
+
"shell.update.apply": "Update to v{version}",
|
|
583
|
+
"shell.update.confirmHint": "Reinstalls the plugin; restart DSH to apply",
|
|
584
|
+
"shell.update.confirmYes": "Confirm",
|
|
585
|
+
"shell.update.cancel": "Cancel",
|
|
586
|
+
"shell.update.copyCmd": "Copy update command",
|
|
587
|
+
"shell.update.copied": "Copied",
|
|
588
|
+
"shell.update.manual": "Local install · update manually",
|
|
561
589
|
"time.in.minutes": "in {minutes} min",
|
|
562
590
|
"time.in.hours": "in {hours} h {minutes} min",
|
|
563
591
|
"time.in.days": "in {days} d",
|
|
564
592
|
"overview.last.none": "No runs yet",
|
|
565
593
|
"overview.last.files": "{count} files",
|
|
566
|
-
"overview.last.digest": "{date} · GitHub Trending
|
|
594
|
+
"overview.last.digest": "{date} · GitHub Trending board",
|
|
567
595
|
"overview.last.read": "Read this issue",
|
|
568
596
|
"overview.last.noPreview": "This run has no saved preview copy",
|
|
569
597
|
"overview.last.prPending": "Pending merge",
|
|
@@ -577,7 +605,7 @@ var DICT = {
|
|
|
577
605
|
"overview.ready.repo": "Repository",
|
|
578
606
|
"overview.ready.github": "GitHub",
|
|
579
607
|
"overview.ready.view": "View",
|
|
580
|
-
"overview.week.title": "Last 7 days",
|
|
608
|
+
"overview.week.title": "Last 7 days (daily)",
|
|
581
609
|
"overview.week.all": "All runs",
|
|
582
610
|
"overview.week.none": "No record",
|
|
583
611
|
"overview.week.wait": "Waiting for {time}",
|
|
@@ -593,6 +621,9 @@ var DICT = {
|
|
|
593
621
|
"runs.dryHint": "dry run writes nothing and commits nothing",
|
|
594
622
|
"runs.empty": "No matching records",
|
|
595
623
|
"runs.filter.all": "All",
|
|
624
|
+
"runs.filter.daily": "Daily",
|
|
625
|
+
"runs.filter.weekly": "Weekly",
|
|
626
|
+
"runs.filter.monthly": "Monthly",
|
|
596
627
|
"runs.filter.failed": "Failed",
|
|
597
628
|
"runs.filter.dry": "Dry run",
|
|
598
629
|
"runs.pendingPr": "Pending merge",
|
|
@@ -602,6 +633,7 @@ var DICT = {
|
|
|
602
633
|
"runs.legacyHint": "Legacy records have no preview copy and use the old hash algorithm, so they cannot be compared with v2 directly.",
|
|
603
634
|
"runs.detail.coreModel": "Core / model",
|
|
604
635
|
"runs.detail.date": "Run date",
|
|
636
|
+
"runs.detail.period": "Period",
|
|
605
637
|
"runs.detail.warnings": "Warnings",
|
|
606
638
|
"runs.detail.none": "None",
|
|
607
639
|
"runs.detail.files": "Files / duration",
|
|
@@ -611,6 +643,10 @@ var DICT = {
|
|
|
611
643
|
"digest.allRuns": "All runs",
|
|
612
644
|
"digest.window": "Last 30 days · {days} days with runs · {previews} with previews",
|
|
613
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",
|
|
614
650
|
"digest.prev": "Previous (older)",
|
|
615
651
|
"digest.next": "Next (newer)",
|
|
616
652
|
"digest.select": "Choose a digest date",
|
|
@@ -657,27 +693,9 @@ var DICT = {
|
|
|
657
693
|
"about.repo.missing": "package.json has no resolvable repository URL",
|
|
658
694
|
"about.license": "License",
|
|
659
695
|
"about.core": "Core",
|
|
696
|
+
"about.core.repo": "Open core GitHub repository",
|
|
660
697
|
"about.env": "Runtime",
|
|
661
|
-
"about.env.value": "DSH Web · Node plugin"
|
|
662
|
-
"about.update.title": "Plugin update",
|
|
663
|
-
"about.update.check": "Check for updates",
|
|
664
|
-
"about.update.checking": "Checking the latest version…",
|
|
665
|
-
"about.update.current": "Up to date (v{version})",
|
|
666
|
-
"about.update.available": "v{latest} is available (current v{current})",
|
|
667
|
-
"about.update.apply": "Update to v{version}",
|
|
668
|
-
"about.update.confirm": "Update to v{version}? The plugin will be reinstalled and the panel reloaded; restart DSH afterwards.",
|
|
669
|
-
"about.update.confirmYes": "Update now",
|
|
670
|
-
"about.update.cancel": "Cancel",
|
|
671
|
-
"about.update.applying": "Updating to v{version}…",
|
|
672
|
-
"about.update.done": "Updated to v{version}; restart DSH to apply.",
|
|
673
|
-
"about.update.applied": "Updated to v{version}.",
|
|
674
|
-
"about.update.failed": "Update failed: {message}",
|
|
675
|
-
"about.update.checkFailed": "Update check failed: cannot reach the registry for the latest version. Retry later or run the command below.",
|
|
676
|
-
"about.update.manual": "Installed from a local {kind} spec; one-click update is disabled (it would replace the dev link). Update manually:",
|
|
677
|
-
"about.update.copy": "Copy command",
|
|
678
|
-
"about.update.copied": "Copied",
|
|
679
|
-
"about.update.hint": "Checks the npm latest stable tag only; applying requires a DSH restart.",
|
|
680
|
-
"update.badge": "Update available"
|
|
698
|
+
"about.env.value": "DSH Web · Node plugin"
|
|
681
699
|
}
|
|
682
700
|
};
|
|
683
701
|
function activeLang(locale) {
|
|
@@ -755,6 +773,9 @@ var CSS = `
|
|
|
755
773
|
.dshgt-table th,.dshgt-table td{text-align:left;padding:5px 8px;border-bottom:1px solid var(--gt-border);vertical-align:top;}
|
|
756
774
|
.dshgt-table th{color:var(--gt-muted);font-weight:500;}
|
|
757
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;}
|
|
758
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);}
|
|
759
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);}
|
|
760
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;}
|
|
@@ -768,7 +789,7 @@ var CSS = `
|
|
|
768
789
|
|
|
769
790
|
/* ——— 01 工作台外壳 ——— */
|
|
770
791
|
.dshgt-shell{gap:0;height:100%;min-height:0;overflow:hidden;}
|
|
771
|
-
.dshgt-app{flex:1;min-height:0;display:
|
|
792
|
+
.dshgt-app{flex:1;min-height:0;display:flex;flex-direction:column;background:var(--gt-bg);}
|
|
772
793
|
.dshgt-rail{background:color-mix(in srgb,var(--gt-fg) 3%,var(--gt-bg));border-right:1px solid var(--gt-border);display:flex;flex-direction:column;padding:14px 10px 12px;min-height:0;overflow:hidden;}
|
|
773
794
|
.dshgt-brand{display:flex;align-items:center;gap:9px;padding:2px 6px 16px;}
|
|
774
795
|
.dshgt-brand svg{flex:none;border-radius:8px;}
|
|
@@ -797,7 +818,7 @@ var CSS = `
|
|
|
797
818
|
.dshgt-pkg-copy{width:22px;height:22px;margin-left:auto;display:grid;place-items:center;border:0;background:none;border-radius:4px;color:var(--gt-muted);cursor:pointer;}
|
|
798
819
|
.dshgt-pkg-copy:hover{background:color-mix(in srgb,var(--gt-fg) 7%,var(--gt-bg));color:var(--gt-fg);}
|
|
799
820
|
.dshgt-pkg-copy:disabled{opacity:.4;cursor:not-allowed;}
|
|
800
|
-
.dshgt-main{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--gt-bg);}
|
|
821
|
+
.dshgt-main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--gt-bg);}
|
|
801
822
|
.dshgt-page-head{display:flex;align-items:flex-start;gap:16px;padding:20px 30px 14px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);flex:none;}
|
|
802
823
|
.dshgt-page-heading{min-width:0;}
|
|
803
824
|
.dshgt-page-head h1{margin:0;font-size:21px;line-height:1.25;font-weight:650;letter-spacing:-.012em;}
|
|
@@ -813,6 +834,43 @@ var CSS = `
|
|
|
813
834
|
.dshgt-tag{display:inline-flex;align-items:center;height:20px;padding:0 7px;border:1px solid var(--gt-border);border-radius:999px;font-size:11px;color:var(--gt-muted);background:var(--gt-bg);white-space:nowrap;}
|
|
814
835
|
.dshgt-inline-tag{margin-left:6px;vertical-align:1px;}
|
|
815
836
|
|
|
837
|
+
/* ——— 顶部身份条(第一行):名称 / 版本 / 完整包名 / GitHub / 检查更新 ——— */
|
|
838
|
+
.dshgt-idbar{display:flex;align-items:center;gap:10px;height:48px;padding:0 18px;border-bottom:1px solid var(--gt-border);flex:none;background:var(--gt-bg);}
|
|
839
|
+
.dshgt-idbar .dshgt-brand{display:flex;align-items:center;gap:9px;padding:0;flex:none;}
|
|
840
|
+
.dshgt-idbar .dshgt-brand svg{width:22px;height:22px;flex:none;border-radius:6px;}
|
|
841
|
+
.dshgt-brand-name{font-size:13.5px;font-weight:650;letter-spacing:-.01em;white-space:nowrap;line-height:1.3;}
|
|
842
|
+
.dshgt-id-ver{appearance:none;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--gt-fg);background:var(--gt-card);border:1px solid var(--gt-border);border-radius:999px;padding:1px 7px;line-height:16px;cursor:pointer;flex:none;}
|
|
843
|
+
.dshgt-id-ver:hover{border-color:color-mix(in srgb,var(--gt-accent) 45%,var(--gt-border));}
|
|
844
|
+
.dshgt-id-sep{width:1px;height:16px;background:var(--gt-border);flex:none;}
|
|
845
|
+
.dshgt-id-pkg{appearance:none;border:0;background:none;padding:2px 4px;border-radius:5px;color:var(--gt-muted);cursor:pointer;font-size:12px;max-width:44vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:none;}
|
|
846
|
+
.dshgt-id-pkg:hover{color:var(--gt-fg);background:color-mix(in srgb,var(--gt-fg) 5%,var(--gt-bg));}
|
|
847
|
+
.dshgt-idbar-right{margin-left:auto;display:flex;align-items:center;gap:10px;flex:none;}
|
|
848
|
+
.dshgt-id-gh{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:7px;color:var(--gt-muted);border:1px solid transparent;}
|
|
849
|
+
.dshgt-id-gh:hover{color:var(--gt-fg);background:color-mix(in srgb,var(--gt-fg) 6%,var(--gt-bg));border-color:var(--gt-border);}
|
|
850
|
+
.dshgt-id-upd{display:flex;align-items:center;gap:10px;}
|
|
851
|
+
.dshgt-id-status{font-size:12px;color:var(--gt-muted);white-space:nowrap;display:inline-flex;align-items:center;gap:6px;}
|
|
852
|
+
.dshgt-id-status.ok{color:var(--gt-ok);}
|
|
853
|
+
.dshgt-id-status.new{color:var(--gt-warn);}
|
|
854
|
+
.dshgt-id-status.err{color:var(--gt-err);}
|
|
855
|
+
.dshgt-id-actions{display:flex;align-items:center;gap:8px;}
|
|
856
|
+
|
|
857
|
+
/* ——— 横向 tab(第二行)+ 右侧状态 ——— */
|
|
858
|
+
.dshgt-tabsbar{display:flex;align-items:stretch;gap:16px;height:46px;padding:0 24px;border-bottom:1px solid var(--gt-border);flex:none;background:var(--gt-bg);}
|
|
859
|
+
.dshgt-tabnav{display:flex;align-items:stretch;gap:2px;height:100%;}
|
|
860
|
+
.dshgt-tab{display:flex;align-items:center;gap:7px;padding:0 12px;border:0;background:none;color:var(--gt-muted);cursor:pointer;font:inherit;font-size:13.5px;position:relative;border-bottom:2px solid transparent;margin-bottom:-1px;}
|
|
861
|
+
.dshgt-tab svg{opacity:.8;}
|
|
862
|
+
.dshgt-tab:hover{color:var(--gt-fg);}
|
|
863
|
+
.dshgt-tab.on{color:var(--gt-fg);font-weight:600;border-bottom-color:var(--gt-accent);}
|
|
864
|
+
.dshgt-tab.on svg{opacity:1;color:var(--gt-accent);}
|
|
865
|
+
.dshgt-tab-tail{font-size:10.5px;color:var(--gt-muted);background:var(--gt-card);border:1px solid var(--gt-border);border-radius:999px;padding:0 5px;line-height:15px;}
|
|
866
|
+
.dshgt-tabsbar-status{margin-left:auto;display:flex;align-items:center;gap:16px;flex:none;}
|
|
867
|
+
.dshgt-status-item{display:inline-flex;align-items:center;gap:7px;font-size:12px;color:var(--gt-muted);white-space:nowrap;}
|
|
868
|
+
.dshgt-status-key{color:var(--gt-muted);}
|
|
869
|
+
.dshgt-status-val{color:var(--gt-fg);font-weight:600;}
|
|
870
|
+
.dshgt-status-sub{color:var(--gt-muted);}
|
|
871
|
+
@media (max-width:1100px){ .dshgt-id-pkg{max-width:26vw;} }
|
|
872
|
+
@media (max-width:860px){ .dshgt-id-pkg{display:none;} .dshgt-status-item.dshgt-next{display:none;} }
|
|
873
|
+
|
|
816
874
|
/* ——— 概览 ——— */
|
|
817
875
|
.dshgt-delivery{border:1px solid var(--gt-border);border-radius:12px;padding:18px 20px 16px;background:var(--gt-card);display:flex;flex-direction:column;gap:6px;}
|
|
818
876
|
.dshgt-delivery-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
@@ -909,12 +967,24 @@ var CSS = `
|
|
|
909
967
|
.dshgt-md a{color:var(--gt-accent);text-decoration:none;}
|
|
910
968
|
.dshgt-md a:hover{text-decoration:underline;}
|
|
911
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
|
+
|
|
912
982
|
/* ——— 运行记录 ——— */
|
|
913
983
|
.dshgt-runs-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
914
984
|
.dshgt-runs-filter{display:flex;gap:4px;margin-left:auto;}
|
|
915
985
|
.dshgt-run-list{border-top:1px solid var(--gt-border);}
|
|
916
986
|
.dshgt-run-item{border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
917
|
-
.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;}
|
|
918
988
|
.dshgt-run-row:hover{background:color-mix(in srgb,var(--gt-fg) 4%,var(--gt-bg));}
|
|
919
989
|
.dshgt-run-date{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);white-space:nowrap;}
|
|
920
990
|
.dshgt-run-what{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;}
|
|
@@ -941,26 +1011,25 @@ var CSS = `
|
|
|
941
1011
|
.dshgt-about-head{display:flex;align-items:center;gap:10px;}
|
|
942
1012
|
.dshgt-about-title{margin:0;font-size:16px;}
|
|
943
1013
|
.dshgt-about-head .dshgt-btn{margin-left:auto;}
|
|
944
|
-
.dshgt-about-pkg{display:flex;align-items:center;
|
|
945
|
-
.dshgt-about-pkg:hover{border-color:color-mix(in srgb,var(--gt-accent) 40%,var(--gt-border));}
|
|
946
|
-
.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;}
|
|
947
1018
|
.dshgt-about .dshgt-kv{grid-template-columns:110px 1fr;}
|
|
948
|
-
.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;}
|
|
949
1020
|
.dshgt-about .dshgt-kv a:hover{text-decoration:underline;}
|
|
950
|
-
.dshgt-
|
|
951
|
-
.dshgt-
|
|
952
|
-
.dshgt-
|
|
953
|
-
.dshgt-
|
|
954
|
-
|
|
955
|
-
.dshgt-
|
|
956
|
-
.dshgt-
|
|
957
|
-
.dshgt-
|
|
958
|
-
.dshgt-
|
|
959
|
-
.dshgt-
|
|
960
|
-
.dshgt-
|
|
961
|
-
.dshgt-
|
|
962
|
-
.dshgt-update-bare{margin-top:0;padding-top:0;border-top:0;}
|
|
963
|
-
.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;}
|
|
964
1033
|
|
|
965
1034
|
@media (max-width:1100px){
|
|
966
1035
|
.dshgt-app{grid-template-columns:190px minmax(0,1fr);}
|
|
@@ -970,7 +1039,7 @@ var CSS = `
|
|
|
970
1039
|
.dshgt-fact:nth-child(3){padding-left:0;border-left:0;}
|
|
971
1040
|
.dshgt-week{flex-wrap:wrap;}
|
|
972
1041
|
.dshgt-day{flex:1 1 88px;}
|
|
973
|
-
.dshgt-run-row{grid-template-columns:18px
|
|
1042
|
+
.dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 70px 20px;}
|
|
974
1043
|
.dshgt-run-files{display:none;}
|
|
975
1044
|
.dshgt-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
|
|
976
1045
|
.dshgt-dateselect{min-width:180px;}
|
|
@@ -1663,18 +1732,22 @@ function SettingsView(props) {
|
|
|
1663
1732
|
h(
|
|
1664
1733
|
Row,
|
|
1665
1734
|
{ label: t("scope.period") },
|
|
1666
|
-
h(
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
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") },
|
|
1678
1751
|
h(Input, { mono: true, width: 70, value: String(draft.trending.topN), onInput: (value) => update((next) => {
|
|
1679
1752
|
next.trending.topN = Math.round(Number(value) || 0);
|
|
1680
1753
|
}) })
|
|
@@ -2022,198 +2095,9 @@ function LiveRun(props) {
|
|
|
2022
2095
|
);
|
|
2023
2096
|
}
|
|
2024
2097
|
|
|
2025
|
-
// node_modules/@morehao/dsh-plugin-kit/dist/update-client.js
|
|
2026
|
-
var IDLE = { status: "idle", view: null, error: null };
|
|
2027
|
-
function errorOf(error) {
|
|
2028
|
-
if (error !== null && typeof error === "object") {
|
|
2029
|
-
const value = error;
|
|
2030
|
-
const message = typeof value.message === "string" && value.message !== "" ? value.message : "操作失败";
|
|
2031
|
-
return typeof value.code === "string" ? { code: value.code, message } : { message };
|
|
2032
|
-
}
|
|
2033
|
-
return { message: String(error ?? "操作失败") };
|
|
2034
|
-
}
|
|
2035
|
-
function createUpdateController(options) {
|
|
2036
|
-
const now = options.now ?? Date.now;
|
|
2037
|
-
let state = { ...IDLE };
|
|
2038
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2039
|
-
let inFlight = null;
|
|
2040
|
-
function emit(next) {
|
|
2041
|
-
state = next;
|
|
2042
|
-
options.onChange?.(state);
|
|
2043
|
-
for (const listener of listeners) listener(state);
|
|
2044
|
-
}
|
|
2045
|
-
async function check(checkOptions = {}) {
|
|
2046
|
-
if (inFlight !== null) return;
|
|
2047
|
-
inFlight = "check";
|
|
2048
|
-
emit({ ...state, status: "checking", error: null });
|
|
2049
|
-
try {
|
|
2050
|
-
const view = await options.request.check(checkOptions);
|
|
2051
|
-
const checkedAt = new Date(now()).toISOString();
|
|
2052
|
-
if (view.checkFailed) {
|
|
2053
|
-
emit({
|
|
2054
|
-
status: "failed",
|
|
2055
|
-
view,
|
|
2056
|
-
error: { code: "CHECK_FAILED", message: "检查更新失败:拿不到 registry 上的最新版本" },
|
|
2057
|
-
checkedAt
|
|
2058
|
-
});
|
|
2059
|
-
} else {
|
|
2060
|
-
emit({ status: view.updateAvailable ? "available" : "current", view, error: null, checkedAt });
|
|
2061
|
-
}
|
|
2062
|
-
} catch (error) {
|
|
2063
|
-
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
2064
|
-
} finally {
|
|
2065
|
-
inFlight = null;
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
async function apply2() {
|
|
2069
|
-
if (inFlight !== null) return;
|
|
2070
|
-
const view = state.view;
|
|
2071
|
-
if (view === null || !view.updateAvailable) {
|
|
2072
|
-
emit({ ...state, status: "failed", error: { code: "NO_UPDATE", message: "没有可更新的版本,请先检查更新" } });
|
|
2073
|
-
return;
|
|
2074
|
-
}
|
|
2075
|
-
if (!view.canApply) {
|
|
2076
|
-
emit({
|
|
2077
|
-
...state,
|
|
2078
|
-
status: "failed",
|
|
2079
|
-
error: { code: "NO_APPLY", message: `当前环境不支持一键更新,请执行:${view.manualCommand}` }
|
|
2080
|
-
});
|
|
2081
|
-
return;
|
|
2082
|
-
}
|
|
2083
|
-
inFlight = "apply";
|
|
2084
|
-
emit({ ...state, status: "applying", error: null });
|
|
2085
|
-
try {
|
|
2086
|
-
const result = await options.request.apply();
|
|
2087
|
-
const restartRequired = result.restartRequired ?? result.application !== "applied";
|
|
2088
|
-
emit({ ...state, status: restartRequired ? "restart-required" : "applied", error: null });
|
|
2089
|
-
} catch (error) {
|
|
2090
|
-
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
2091
|
-
} finally {
|
|
2092
|
-
inFlight = null;
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
return {
|
|
2096
|
-
getState: () => state,
|
|
2097
|
-
subscribe: (listener) => {
|
|
2098
|
-
listeners.add(listener);
|
|
2099
|
-
return () => {
|
|
2100
|
-
listeners.delete(listener);
|
|
2101
|
-
};
|
|
2102
|
-
},
|
|
2103
|
-
check,
|
|
2104
|
-
apply: apply2,
|
|
2105
|
-
reset: () => emit({ ...IDLE })
|
|
2106
|
-
};
|
|
2107
|
-
}
|
|
2108
|
-
|
|
2109
|
-
// client/update-panel.ts
|
|
2110
|
-
var singleton = null;
|
|
2111
|
-
function getUpdateController() {
|
|
2112
|
-
if (singleton === null) {
|
|
2113
|
-
singleton = createUpdateController({
|
|
2114
|
-
request: {
|
|
2115
|
-
check: (options) => getPluginUpdate(options.fresh === true ? { fresh: true } : {}),
|
|
2116
|
-
apply: () => applyPluginUpdate()
|
|
2117
|
-
}
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
return singleton;
|
|
2121
|
-
}
|
|
2122
|
-
function usePluginUpdate() {
|
|
2123
|
-
const controller = getUpdateController();
|
|
2124
|
-
const [state, setState] = import_react.default.useState(() => controller.getState());
|
|
2125
|
-
import_react.default.useEffect(() => {
|
|
2126
|
-
const unsubscribe = controller.subscribe(setState);
|
|
2127
|
-
if (controller.getState().status === "idle") void controller.check();
|
|
2128
|
-
return unsubscribe;
|
|
2129
|
-
}, [controller]);
|
|
2130
|
-
return [state, controller];
|
|
2131
|
-
}
|
|
2132
|
-
function UpdateDot(props) {
|
|
2133
|
-
const [state] = usePluginUpdate();
|
|
2134
|
-
if (state.view?.updateAvailable !== true) return null;
|
|
2135
|
-
return h("span", { className: "dshgt-update-dot", title: props.t("update.badge") });
|
|
2136
|
-
}
|
|
2137
|
-
function PluginUpdateSection(props) {
|
|
2138
|
-
const { t } = props;
|
|
2139
|
-
const [state, controller] = usePluginUpdate();
|
|
2140
|
-
const [confirming, setConfirming] = import_react.default.useState(false);
|
|
2141
|
-
const [copied, setCopied] = import_react.default.useState(false);
|
|
2142
|
-
import_react.default.useEffect(() => {
|
|
2143
|
-
if (state.status === "applying" || state.status === "restart-required" || state.status === "applied") setConfirming(false);
|
|
2144
|
-
}, [state.status]);
|
|
2145
|
-
const copyCommand = () => {
|
|
2146
|
-
const command = state.view?.manualCommand;
|
|
2147
|
-
if (command === void 0) return;
|
|
2148
|
-
void copyText(command).then((ok) => {
|
|
2149
|
-
if (!ok) return;
|
|
2150
|
-
setCopied(true);
|
|
2151
|
-
setTimeout(() => setCopied(false), 1600);
|
|
2152
|
-
});
|
|
2153
|
-
};
|
|
2154
|
-
const view = state.view;
|
|
2155
|
-
const status = state.status;
|
|
2156
|
-
const target = view !== null && view.updateAvailable ? view.latestVersion ?? "" : "";
|
|
2157
|
-
const busy = status === "checking" || status === "applying";
|
|
2158
|
-
const settled = status === "restart-required" || status === "applied";
|
|
2159
|
-
const actionable = view !== null && view.updateAvailable && view.canApply && !settled && !busy;
|
|
2160
|
-
const manual = view !== null && (!view.canApply || view.checkFailed) ? view.manualCommand : null;
|
|
2161
|
-
const statusLine = () => {
|
|
2162
|
-
if (status === "checking" || view === null) return t("about.update.checking");
|
|
2163
|
-
if (status === "applying") return t("about.update.applying", { version: target });
|
|
2164
|
-
if (status === "restart-required") return t("about.update.done", { version: view.latestVersion ?? target });
|
|
2165
|
-
if (status === "applied") return t("about.update.applied", { version: view.latestVersion ?? target });
|
|
2166
|
-
if (status === "failed") {
|
|
2167
|
-
if (state.error?.code === "CHECK_FAILED") return t("about.update.checkFailed");
|
|
2168
|
-
return t("about.update.failed", { message: state.error?.message ?? "" });
|
|
2169
|
-
}
|
|
2170
|
-
if (view.checkFailed) return t("about.update.checkFailed");
|
|
2171
|
-
if (view.updateAvailable) return t("about.update.available", { latest: view.latestVersion ?? "", current: view.currentVersion });
|
|
2172
|
-
return t("about.update.current", { version: view.currentVersion });
|
|
2173
|
-
};
|
|
2174
|
-
const actions = [
|
|
2175
|
-
h(Btn, { key: "check", small: true, disabled: busy, onClick: () => void controller.check({ fresh: true }) }, t("about.update.check")),
|
|
2176
|
-
manual === null ? null : h(Btn, { key: "copy", small: true, onClick: copyCommand }, copied ? t("about.update.copied") : t("about.update.copy")),
|
|
2177
|
-
actionable ? confirming ? [
|
|
2178
|
-
h(
|
|
2179
|
-
Btn,
|
|
2180
|
-
{
|
|
2181
|
-
key: "confirm",
|
|
2182
|
-
small: true,
|
|
2183
|
-
variant: "danger",
|
|
2184
|
-
onClick: () => {
|
|
2185
|
-
setConfirming(false);
|
|
2186
|
-
void controller.apply();
|
|
2187
|
-
}
|
|
2188
|
-
},
|
|
2189
|
-
t("about.update.confirmYes")
|
|
2190
|
-
),
|
|
2191
|
-
h(Btn, { key: "cancel", small: true, onClick: () => setConfirming(false) }, t("about.update.cancel"))
|
|
2192
|
-
] : h(Btn, { key: "apply", small: true, variant: "primary", onClick: () => setConfirming(true) }, t("about.update.apply", { version: target })) : null
|
|
2193
|
-
].filter((item) => item !== null);
|
|
2194
|
-
return h(
|
|
2195
|
-
"div",
|
|
2196
|
-
{ className: `dshgt-update${props.bare === true ? " dshgt-update-bare" : ""}` },
|
|
2197
|
-
props.bare === true ? null : h(
|
|
2198
|
-
"div",
|
|
2199
|
-
{ className: "dshgt-update-head" },
|
|
2200
|
-
h("h4", null, t("about.update.title")),
|
|
2201
|
-
h("span", { className: "dshgt-hint" }, t("about.update.hint"))
|
|
2202
|
-
),
|
|
2203
|
-
h("p", { className: `dshgt-update-line${status === "failed" ? " dshgt-update-err" : ""}` }, statusLine()),
|
|
2204
|
-
confirming ? h("p", { className: "dshgt-update-warn" }, t("about.update.confirm", { version: target })) : null,
|
|
2205
|
-
h("div", { className: "dshgt-update-actions" }, actions),
|
|
2206
|
-
manual === null ? null : h(
|
|
2207
|
-
"div",
|
|
2208
|
-
{ className: "dshgt-update-manual" },
|
|
2209
|
-
h("p", { className: "dshgt-update-warn" }, t("about.update.manual", { kind: view?.installKind ?? "unknown" })),
|
|
2210
|
-
h("code", { className: "dshgt-update-cmd" }, manual)
|
|
2211
|
-
)
|
|
2212
|
-
);
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
2098
|
// client/digest-core.ts
|
|
2216
2099
|
var DIGEST_WINDOW_DAYS = 30;
|
|
2100
|
+
var PERIODS = ["daily", "weekly", "monthly"];
|
|
2217
2101
|
var DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2218
2102
|
function isValidDate(value) {
|
|
2219
2103
|
if (typeof value !== "string") return false;
|
|
@@ -2261,12 +2145,66 @@ function digestStatus(record) {
|
|
|
2261
2145
|
if (record.legacy === true) return "legacy";
|
|
2262
2146
|
return "missing";
|
|
2263
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
|
+
}
|
|
2264
2201
|
function buildDigestDates(records, options) {
|
|
2265
2202
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2266
2203
|
const today = zonedDateString(now, options.timeZone);
|
|
2267
2204
|
const earliest = addDays(today, -(DIGEST_WINDOW_DAYS - 1));
|
|
2268
2205
|
const groups = /* @__PURE__ */ new Map();
|
|
2269
2206
|
for (const record of records) {
|
|
2207
|
+
if (recordPeriod(record) !== "daily") continue;
|
|
2270
2208
|
const info = recordDate(record, options.timeZone);
|
|
2271
2209
|
if (info === void 0) continue;
|
|
2272
2210
|
if (info.date < earliest || info.date > today) continue;
|
|
@@ -2292,6 +2230,51 @@ function buildDigestDates(records, options) {
|
|
|
2292
2230
|
days.sort((a, b) => b.date.localeCompare(a.date));
|
|
2293
2231
|
return days;
|
|
2294
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
|
+
}
|
|
2295
2278
|
function recentDates(today, count) {
|
|
2296
2279
|
const dates = [];
|
|
2297
2280
|
for (let offset = count - 1; offset >= 0; offset -= 1) dates.push(addDays(today, -offset));
|
|
@@ -2408,6 +2391,7 @@ function OverviewView(props) {
|
|
|
2408
2391
|
const days = buildDigestDates(state.status.history, { timeZone });
|
|
2409
2392
|
const byDate = new Map(days.map((day) => [day.date, day]));
|
|
2410
2393
|
const week = recentDates(today, 7);
|
|
2394
|
+
const lastTarget = last === null ? void 0 : digestTarget(last, timeZone);
|
|
2411
2395
|
return h(
|
|
2412
2396
|
"div",
|
|
2413
2397
|
{ className: "dshgt-view dshgt-overview" },
|
|
@@ -2424,6 +2408,7 @@ function OverviewView(props) {
|
|
|
2424
2408
|
"div",
|
|
2425
2409
|
{ className: "dshgt-delivery-top" },
|
|
2426
2410
|
statusPill(t, last),
|
|
2411
|
+
h("span", { className: `dshgt-pchip ${last.period ?? "daily"}` }, t(`period.${last.period ?? "daily"}`)),
|
|
2427
2412
|
h("span", { className: "dshgt-hint" }, last.date ?? localTime(last.at)),
|
|
2428
2413
|
h(
|
|
2429
2414
|
"span",
|
|
@@ -2455,11 +2440,15 @@ function OverviewView(props) {
|
|
|
2455
2440
|
{
|
|
2456
2441
|
type: "button",
|
|
2457
2442
|
className: "dshgt-filechip",
|
|
2458
|
-
onClick: () =>
|
|
2443
|
+
onClick: () => {
|
|
2444
|
+
if (lastTarget !== void 0) props.onOpenDigest(lastTarget);
|
|
2445
|
+
}
|
|
2459
2446
|
},
|
|
2460
2447
|
h("span", { className: "dshgt-mono" }, last.preview.file)
|
|
2461
2448
|
),
|
|
2462
|
-
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")),
|
|
2463
2452
|
pr === null || pr.url === void 0 ? null : h(
|
|
2464
2453
|
"a",
|
|
2465
2454
|
{ className: "dshgt-btn dshgt-btn-sm", href: pr.url, target: "_blank", rel: "noreferrer" },
|
|
@@ -2533,7 +2522,7 @@ function OverviewView(props) {
|
|
|
2533
2522
|
type: "button",
|
|
2534
2523
|
className: "dshgt-day dshgt-day-clickable",
|
|
2535
2524
|
key: date,
|
|
2536
|
-
onClick: () => props.onOpenDigest(date),
|
|
2525
|
+
onClick: () => props.onOpenDigest({ period: "daily", bucket: date }),
|
|
2537
2526
|
title: day.record.errorCode === void 0 ? formatDayLabel(date, lang) : `${formatDayLabel(date, lang)} · ${day.record.errorCode}`
|
|
2538
2527
|
},
|
|
2539
2528
|
h("div", { className: "dshgt-day-date" }, date.slice(5).replace("-", "/")),
|
|
@@ -2545,12 +2534,6 @@ function OverviewView(props) {
|
|
|
2545
2534
|
)
|
|
2546
2535
|
);
|
|
2547
2536
|
})
|
|
2548
|
-
),
|
|
2549
|
-
h(
|
|
2550
|
-
"section",
|
|
2551
|
-
{ className: "dshgt-card dshgt-update-card" },
|
|
2552
|
-
h("div", { className: "dshgt-card-h" }, h("h3", null, t("about.update.title"))),
|
|
2553
|
-
h(PluginUpdateSection, { t, bare: true })
|
|
2554
2537
|
)
|
|
2555
2538
|
)
|
|
2556
2539
|
);
|
|
@@ -2559,6 +2542,9 @@ function OverviewView(props) {
|
|
|
2559
2542
|
// client/runs.ts
|
|
2560
2543
|
var FILTERS = [
|
|
2561
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" },
|
|
2562
2548
|
{ id: "failed", key: "runs.filter.failed" },
|
|
2563
2549
|
{ id: "dry", key: "runs.filter.dry" }
|
|
2564
2550
|
];
|
|
@@ -2664,6 +2650,7 @@ function RunsView(props) {
|
|
|
2664
2650
|
const records = history.filter((record) => {
|
|
2665
2651
|
if (filter === "failed") return !record.ok;
|
|
2666
2652
|
if (filter === "dry") return record.kind === "dry-run";
|
|
2653
|
+
if (filter === "daily" || filter === "weekly" || filter === "monthly") return (record.period ?? "daily") === filter;
|
|
2667
2654
|
return true;
|
|
2668
2655
|
});
|
|
2669
2656
|
return h(
|
|
@@ -2712,6 +2699,7 @@ function RunsView(props) {
|
|
|
2712
2699
|
},
|
|
2713
2700
|
h("span", { className: `dshgt-lamp ${record.ok ? record.skipped || record.kind === "dry-run" ? "warn" : "ok" : "err"}` }),
|
|
2714
2701
|
h("span", { className: "dshgt-run-date" }, shortTime(record.at)),
|
|
2702
|
+
h("span", { className: `dshgt-pchip ${record.period ?? "daily"}` }, t(`period.${record.period ?? "daily"}`)),
|
|
2715
2703
|
h(
|
|
2716
2704
|
"span",
|
|
2717
2705
|
{ className: "dshgt-run-what" },
|
|
@@ -2740,6 +2728,7 @@ function RunsView(props) {
|
|
|
2740
2728
|
detailItem(t, "run.usage.branch", record.branch === void 0 ? "—" : h("span", { className: "dshgt-mono" }, record.branch)),
|
|
2741
2729
|
detailItem(t, "runs.detail.coreModel", `${record.coreVersion || "—"} · ${record.model?.model ?? "—"}`),
|
|
2742
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"}`))),
|
|
2743
2732
|
detailItem(
|
|
2744
2733
|
t,
|
|
2745
2734
|
"run.usage.pr",
|
|
@@ -2757,7 +2746,17 @@ function RunsView(props) {
|
|
|
2757
2746
|
h(
|
|
2758
2747
|
"div",
|
|
2759
2748
|
{ className: "dshgt-run-actions" },
|
|
2760
|
-
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
|
+
),
|
|
2761
2760
|
h(Btn, { small: true, onClick: () => setLogId(record.id) }, t("runs.detail.log")),
|
|
2762
2761
|
record.preview === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, record.preview.file)
|
|
2763
2762
|
)
|
|
@@ -3138,9 +3137,8 @@ var STATUS_LAMP2 = {
|
|
|
3138
3137
|
};
|
|
3139
3138
|
var META_KEYS = ["date", "period", "languages", "count", "degraded", "coreVersion", "contentHash", "generatedAt"];
|
|
3140
3139
|
function EmptyDigest(props) {
|
|
3141
|
-
const { t, day, nearest } = props;
|
|
3140
|
+
const { t, lang, day, nearest } = props;
|
|
3142
3141
|
const status = props.error === void 0 ? day.status : "missing";
|
|
3143
|
-
const key = status === "legacy" ? "legacy" : status === "missing" ? "missing" : status;
|
|
3144
3142
|
return h(
|
|
3145
3143
|
"div",
|
|
3146
3144
|
{ className: "dshgt-digest-empty" },
|
|
@@ -3149,10 +3147,10 @@ function EmptyDigest(props) {
|
|
|
3149
3147
|
{ className: "dshgt-status-line" },
|
|
3150
3148
|
h("span", { className: `dshgt-lamp ${STATUS_LAMP2[status]}` }),
|
|
3151
3149
|
h("b", null, t(STATUS_LABEL[status])),
|
|
3152
|
-
h("span", { className: "dshgt-dim" },
|
|
3150
|
+
h("span", { className: "dshgt-dim" }, formatBucketLabel(day.period, day.bucket, lang))
|
|
3153
3151
|
),
|
|
3154
|
-
h("h2", null, t(`digest.empty.${
|
|
3155
|
-
h("p", null, t(`digest.empty.${
|
|
3152
|
+
h("h2", null, t(`digest.empty.${status}.title`)),
|
|
3153
|
+
h("p", null, t(`digest.empty.${status}.reason`)),
|
|
3156
3154
|
day.record.errorCode === void 0 && props.error === void 0 ? null : h(
|
|
3157
3155
|
"p",
|
|
3158
3156
|
{ className: "dshgt-mono dshgt-digest-error" },
|
|
@@ -3162,12 +3160,16 @@ function EmptyDigest(props) {
|
|
|
3162
3160
|
"div",
|
|
3163
3161
|
{ className: "dshgt-actions" },
|
|
3164
3162
|
h(Btn, { small: true, onClick: props.onOpenRuns }, t("digest.empty.viewRuns")),
|
|
3165
|
-
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
|
+
)
|
|
3166
3168
|
)
|
|
3167
3169
|
);
|
|
3168
3170
|
}
|
|
3169
3171
|
function DigestView(props) {
|
|
3170
|
-
const { t, lang, store,
|
|
3172
|
+
const { t, lang, store, selected } = props;
|
|
3171
3173
|
const [mode, setMode] = import_react.default.useState("render");
|
|
3172
3174
|
const [payload, setPayload] = import_react.default.useState(null);
|
|
3173
3175
|
const [loading, setLoading] = import_react.default.useState(false);
|
|
@@ -3176,19 +3178,26 @@ function DigestView(props) {
|
|
|
3176
3178
|
const state = store.state;
|
|
3177
3179
|
const history = state?.status.history ?? [];
|
|
3178
3180
|
const timeZone = state?.schedule.timezone ?? "UTC";
|
|
3179
|
-
const
|
|
3180
|
-
const
|
|
3181
|
-
const
|
|
3182
|
-
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);
|
|
3183
3190
|
const index = day === void 0 ? -1 : days.indexOf(day);
|
|
3184
|
-
const previewCount = days.filter((item) => item.status === "preview").length;
|
|
3185
3191
|
const previewRunId = day !== void 0 && day.status === "preview" && day.record.preview !== void 0 ? day.record.id : void 0;
|
|
3186
3192
|
import_react.default.useEffect(() => {
|
|
3187
|
-
if (
|
|
3188
|
-
|
|
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]);
|
|
3189
3198
|
import_react.default.useEffect(() => {
|
|
3190
3199
|
setMode("render");
|
|
3191
|
-
}, [
|
|
3200
|
+
}, [activePeriod, effectiveBucket]);
|
|
3192
3201
|
import_react.default.useEffect(() => {
|
|
3193
3202
|
if (previewRunId === void 0) {
|
|
3194
3203
|
setPayload(null);
|
|
@@ -3214,7 +3223,7 @@ function DigestView(props) {
|
|
|
3214
3223
|
if (state === null) {
|
|
3215
3224
|
return h("div", { className: "dshgt-empty" }, store.error ?? t("quickfill.loading"));
|
|
3216
3225
|
}
|
|
3217
|
-
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);
|
|
3218
3227
|
let rendered = null;
|
|
3219
3228
|
let parseFailed = false;
|
|
3220
3229
|
if (payload !== null) {
|
|
@@ -3224,7 +3233,40 @@ function DigestView(props) {
|
|
|
3224
3233
|
parseFailed = true;
|
|
3225
3234
|
}
|
|
3226
3235
|
}
|
|
3227
|
-
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(
|
|
3228
3270
|
"div",
|
|
3229
3271
|
{ className: "dshgt-digest-subbar" },
|
|
3230
3272
|
h(
|
|
@@ -3240,7 +3282,7 @@ function DigestView(props) {
|
|
|
3240
3282
|
disabled: index < 0 || index >= days.length - 1,
|
|
3241
3283
|
onClick: () => {
|
|
3242
3284
|
const target = days[index + 1];
|
|
3243
|
-
if (target !== void 0) props.
|
|
3285
|
+
if (target !== void 0) props.onSelect({ period: activePeriod, bucket: target.bucket });
|
|
3244
3286
|
}
|
|
3245
3287
|
},
|
|
3246
3288
|
"‹"
|
|
@@ -3249,12 +3291,18 @@ function DigestView(props) {
|
|
|
3249
3291
|
"select",
|
|
3250
3292
|
{
|
|
3251
3293
|
className: "dshgt-dateselect",
|
|
3252
|
-
"aria-label": t("digest.
|
|
3253
|
-
value:
|
|
3254
|
-
onChange: (event) => props.
|
|
3294
|
+
"aria-label": t("digest.selectBucket"),
|
|
3295
|
+
value: effectiveBucket ?? "",
|
|
3296
|
+
onChange: (event) => props.onSelect({ period: activePeriod, bucket: event.target.value }),
|
|
3255
3297
|
disabled: days.length === 0
|
|
3256
3298
|
},
|
|
3257
|
-
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
|
+
)
|
|
3258
3306
|
),
|
|
3259
3307
|
h(
|
|
3260
3308
|
"button",
|
|
@@ -3266,25 +3314,20 @@ function DigestView(props) {
|
|
|
3266
3314
|
disabled: index <= 0,
|
|
3267
3315
|
onClick: () => {
|
|
3268
3316
|
const target = days[index - 1];
|
|
3269
|
-
if (target !== void 0) props.
|
|
3317
|
+
if (target !== void 0) props.onSelect({ period: activePeriod, bucket: target.bucket });
|
|
3270
3318
|
}
|
|
3271
3319
|
},
|
|
3272
3320
|
"›"
|
|
3273
3321
|
)
|
|
3274
3322
|
),
|
|
3275
|
-
h(
|
|
3276
|
-
"span",
|
|
3277
|
-
{ className: "dshgt-dim" },
|
|
3278
|
-
days.length === 0 ? t("digest.window.empty") : t("digest.window", { days: days.length, previews: previewCount })
|
|
3279
|
-
),
|
|
3280
|
-
h("span", { className: "dshgt-grow" }),
|
|
3281
|
-
h(Btn, { small: true, onClick: props.onOpenRuns }, t("digest.allRuns"))
|
|
3323
|
+
h("span", { className: "dshgt-dim" }, t("digest.bucketNavHint"))
|
|
3282
3324
|
);
|
|
3283
3325
|
if (day === void 0) {
|
|
3284
3326
|
return h(
|
|
3285
3327
|
"div",
|
|
3286
3328
|
{ className: "dshgt-view dshgt-digest" },
|
|
3287
|
-
|
|
3329
|
+
periodBar,
|
|
3330
|
+
bucketBar,
|
|
3288
3331
|
h(
|
|
3289
3332
|
"div",
|
|
3290
3333
|
{ className: "dshgt-digest-empty" },
|
|
@@ -3299,7 +3342,8 @@ function DigestView(props) {
|
|
|
3299
3342
|
return h(
|
|
3300
3343
|
"div",
|
|
3301
3344
|
{ className: "dshgt-view dshgt-digest" },
|
|
3302
|
-
|
|
3345
|
+
periodBar,
|
|
3346
|
+
bucketBar,
|
|
3303
3347
|
h(
|
|
3304
3348
|
"div",
|
|
3305
3349
|
{ className: "dshgt-digest-sheet" },
|
|
@@ -3310,13 +3354,14 @@ function DigestView(props) {
|
|
|
3310
3354
|
...nearest === void 0 ? {} : { nearest },
|
|
3311
3355
|
...error === null ? {} : { error },
|
|
3312
3356
|
onOpenRuns: props.onOpenRuns,
|
|
3313
|
-
|
|
3357
|
+
onSelect: props.onSelect
|
|
3314
3358
|
}) : h(
|
|
3315
3359
|
"div",
|
|
3316
3360
|
{ className: "dshgt-digest-body" },
|
|
3317
3361
|
h(
|
|
3318
3362
|
"div",
|
|
3319
3363
|
{ className: "dshgt-digest-bar" },
|
|
3364
|
+
h("span", { className: `dshgt-pchip ${activePeriod}` }, t(`period.${activePeriod}`)),
|
|
3320
3365
|
h(
|
|
3321
3366
|
"span",
|
|
3322
3367
|
{ className: "dshgt-filechip dshgt-filechip-static" },
|
|
@@ -3402,15 +3447,198 @@ function metaLine(rendered) {
|
|
|
3402
3447
|
);
|
|
3403
3448
|
}
|
|
3404
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
|
+
|
|
3405
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
|
+
}
|
|
3406
3630
|
function AboutDialog(props) {
|
|
3407
3631
|
const { t, state } = props;
|
|
3408
3632
|
const [copied, setCopied] = import_react.default.useState(false);
|
|
3633
|
+
const [updateState, updateController] = usePluginUpdate();
|
|
3409
3634
|
const plugin = state.plugin;
|
|
3410
3635
|
const fullName = `${plugin.name}@v${plugin.version}`;
|
|
3411
3636
|
const repository = plugin.repository;
|
|
3412
3637
|
const ownerRepo = repository === void 0 ? void 0 : repository.replace(/^https?:\/\/github\.com\//, "");
|
|
3413
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;
|
|
3414
3642
|
import_react.default.useEffect(() => {
|
|
3415
3643
|
const onKey = (event) => {
|
|
3416
3644
|
if (event.key === "Escape") props.onClose();
|
|
@@ -3422,9 +3650,23 @@ function AboutDialog(props) {
|
|
|
3422
3650
|
void copyText(fullName).then((ok) => {
|
|
3423
3651
|
if (!ok) return;
|
|
3424
3652
|
setCopied(true);
|
|
3425
|
-
setTimeout(() => setCopied(false),
|
|
3653
|
+
setTimeout(() => setCopied(false), 1400);
|
|
3426
3654
|
});
|
|
3427
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
|
+
};
|
|
3428
3670
|
const dialog = h(
|
|
3429
3671
|
"div",
|
|
3430
3672
|
{ className: "dshgt-modal-mask", onClick: (event) => {
|
|
@@ -3441,9 +3683,8 @@ function AboutDialog(props) {
|
|
|
3441
3683
|
),
|
|
3442
3684
|
h(
|
|
3443
3685
|
"button",
|
|
3444
|
-
{ type: "button", className:
|
|
3445
|
-
h("span", { className: "dshgt-mono" }, fullName)
|
|
3446
|
-
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)
|
|
3447
3688
|
),
|
|
3448
3689
|
h(KV, {
|
|
3449
3690
|
items: [
|
|
@@ -3452,16 +3693,119 @@ function AboutDialog(props) {
|
|
|
3452
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)
|
|
3453
3694
|
],
|
|
3454
3695
|
[t("about.license"), "MIT"],
|
|
3455
|
-
[t("about.core"),
|
|
3696
|
+
[t("about.core"), coreValue()],
|
|
3456
3697
|
[t("about.env"), t("about.env.value")]
|
|
3457
3698
|
]
|
|
3458
3699
|
}),
|
|
3459
|
-
h(
|
|
3700
|
+
h(UpdateRow, { t, update: updateState, controller: updateController, fallbackVersion: plugin.version })
|
|
3460
3701
|
)
|
|
3461
3702
|
);
|
|
3462
3703
|
return h("div", { className: "dshgt-root" }, dialog);
|
|
3463
3704
|
}
|
|
3464
3705
|
|
|
3706
|
+
// client/identity-bar.ts
|
|
3707
|
+
function logo() {
|
|
3708
|
+
return h(
|
|
3709
|
+
"svg",
|
|
3710
|
+
{ width: 22, height: 22, viewBox: "0 0 64 64", "aria-hidden": "true" },
|
|
3711
|
+
h("rect", { x: 4, y: 4, width: 56, height: 56, rx: 14, fill: "#0d1117" }),
|
|
3712
|
+
h("path", { d: "M18 46V22l14 12 14-12v24", fill: "none", stroke: "#58a6ff", strokeWidth: 4, strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
3713
|
+
h("circle", { cx: 32, cy: 45, r: 3, fill: "#3fb950" })
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
function githubIcon2() {
|
|
3717
|
+
return h("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true" }, h("path", {
|
|
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"
|
|
3719
|
+
}));
|
|
3720
|
+
}
|
|
3721
|
+
function IdentityBar(props) {
|
|
3722
|
+
const { t, plugin } = props;
|
|
3723
|
+
const [copied, setCopied] = import_react.default.useState(false);
|
|
3724
|
+
const [confirming, setConfirming] = import_react.default.useState(false);
|
|
3725
|
+
const [cmdCopied, setCmdCopied] = import_react.default.useState(false);
|
|
3726
|
+
const [updateState, controller] = usePluginUpdate();
|
|
3727
|
+
const view = updateState.view;
|
|
3728
|
+
const status = updateState.status;
|
|
3729
|
+
import_react.default.useEffect(() => {
|
|
3730
|
+
if (status === "applying" || status === "restart-required" || status === "applied") setConfirming(false);
|
|
3731
|
+
}, [status]);
|
|
3732
|
+
const copyPkg = () => {
|
|
3733
|
+
void copyText(plugin.name).then((ok) => {
|
|
3734
|
+
if (!ok) return;
|
|
3735
|
+
setCopied(true);
|
|
3736
|
+
setTimeout(() => setCopied(false), 1400);
|
|
3737
|
+
});
|
|
3738
|
+
};
|
|
3739
|
+
const busy = status === "checking" || status === "applying";
|
|
3740
|
+
const settled = status === "restart-required" || status === "applied";
|
|
3741
|
+
const latestVersion = view === null ? "" : view.latestVersion ?? "";
|
|
3742
|
+
const updateAvailable = view !== null && view.updateAvailable;
|
|
3743
|
+
const actionable = updateAvailable && view !== null && view.canApply && !settled && !busy;
|
|
3744
|
+
const manual = view !== null && (!view.canApply || view.checkFailed) ? view.manualCommand ?? null : null;
|
|
3745
|
+
const currentVersion = view === null ? plugin.version : view.currentVersion ?? plugin.version;
|
|
3746
|
+
const copyCmd = () => {
|
|
3747
|
+
if (manual === void 0 || manual === null) return;
|
|
3748
|
+
void copyText(manual).then((ok) => {
|
|
3749
|
+
if (!ok) return;
|
|
3750
|
+
setCmdCopied(true);
|
|
3751
|
+
setTimeout(() => setCmdCopied(false), 1400);
|
|
3752
|
+
});
|
|
3753
|
+
};
|
|
3754
|
+
function statusLine() {
|
|
3755
|
+
if (status === "checking" || view === null) return { text: t("shell.update.checking"), kind: "muted" };
|
|
3756
|
+
if (status === "applying") return { text: t("shell.update.applying", { version: latestVersion }), kind: "muted" };
|
|
3757
|
+
if (status === "restart-required" || status === "applied") return { text: t("shell.update.done", { version: latestVersion }), kind: "ok" };
|
|
3758
|
+
if (status === "failed") return { text: updateState.error?.code === "CHECK_FAILED" ? t("shell.update.checkFailed") : t("shell.update.failed"), kind: "err" };
|
|
3759
|
+
if (view.checkFailed) return { text: t("shell.update.checkFailed"), kind: "err" };
|
|
3760
|
+
if (view.updateAvailable) return { text: t("shell.update.available", { latest: view.latestVersion ?? "" }), kind: "new" };
|
|
3761
|
+
return { text: t("shell.update.latest", { version: currentVersion }), kind: "ok" };
|
|
3762
|
+
}
|
|
3763
|
+
function action() {
|
|
3764
|
+
if (status === "applying") return h(Btn, { small: true, disabled: true }, t("shell.update.applyingShort"));
|
|
3765
|
+
if (actionable) {
|
|
3766
|
+
if (confirming) {
|
|
3767
|
+
return [
|
|
3768
|
+
h(Btn, { key: "yes", small: true, variant: "danger", onClick: () => {
|
|
3769
|
+
setConfirming(false);
|
|
3770
|
+
void controller.apply();
|
|
3771
|
+
} }, t("shell.update.confirmYes")),
|
|
3772
|
+
h(Btn, { key: "no", small: true, onClick: () => setConfirming(false) }, t("shell.update.cancel"))
|
|
3773
|
+
];
|
|
3774
|
+
}
|
|
3775
|
+
return h(Btn, { small: true, variant: "primary", onClick: () => setConfirming(true) }, t("shell.update.apply", { version: latestVersion }));
|
|
3776
|
+
}
|
|
3777
|
+
if (manual !== null) return h(Btn, { small: true, onClick: copyCmd }, cmdCopied ? t("shell.update.copied") : t("shell.update.copyCmd"));
|
|
3778
|
+
return h(Btn, { small: true, disabled: busy, onClick: () => void controller.check({ fresh: true }) }, t("shell.update.check"));
|
|
3779
|
+
}
|
|
3780
|
+
const line = statusLine();
|
|
3781
|
+
return h(
|
|
3782
|
+
"div",
|
|
3783
|
+
{ className: "dshgt-idbar" },
|
|
3784
|
+
h("div", { className: "dshgt-brand" }, logo(), h("span", { className: "dshgt-brand-name" }, t("section.title"))),
|
|
3785
|
+
h("button", { type: "button", className: "dshgt-id-ver", title: t("about.title"), onClick: () => props.onOpenAbout() }, `v${plugin.version}`),
|
|
3786
|
+
h("span", { className: "dshgt-id-sep" }),
|
|
3787
|
+
h(
|
|
3788
|
+
"button",
|
|
3789
|
+
{ type: "button", className: "dshgt-id-pkg dshgt-mono", title: updatedCopyTitle(t, copied), onClick: copyPkg },
|
|
3790
|
+
copied ? t("about.copied") : plugin.name
|
|
3791
|
+
),
|
|
3792
|
+
h(
|
|
3793
|
+
"div",
|
|
3794
|
+
{ className: "dshgt-idbar-right" },
|
|
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()),
|
|
3796
|
+
h(
|
|
3797
|
+
"span",
|
|
3798
|
+
{ className: "dshgt-id-upd" },
|
|
3799
|
+
confirming ? h("span", { className: "dshgt-id-status new" }, t("shell.update.confirmHint")) : h("span", { className: `dshgt-id-status ${line.kind}` }, line.text),
|
|
3800
|
+
h("span", { className: "dshgt-id-actions" }, action())
|
|
3801
|
+
)
|
|
3802
|
+
)
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
function updatedCopyTitle(t, copied) {
|
|
3806
|
+
return copied ? t("about.copied") : t("about.copy");
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3465
3809
|
// client/panel-icon.ts
|
|
3466
3810
|
var TREND_LINE = "3 16.5 9 10.5 13 14.5 21 6.5";
|
|
3467
3811
|
var TREND_ARROW = "15.5 6.5 21 6.5 21 12";
|
|
@@ -3542,22 +3886,6 @@ function navIcon(name, size = 16) {
|
|
|
3542
3886
|
h("circle", { cx: 10, cy: 17, r: 2.2 })
|
|
3543
3887
|
);
|
|
3544
3888
|
}
|
|
3545
|
-
function brandLogo() {
|
|
3546
|
-
return h(
|
|
3547
|
-
"svg",
|
|
3548
|
-
{ width: 28, height: 28, viewBox: "0 0 64 64", "aria-hidden": "true" },
|
|
3549
|
-
h("rect", { x: 3, y: 3, width: 58, height: 58, rx: 15, fill: "#0d1117", stroke: "rgba(255,255,255,.14)", strokeWidth: 1 }),
|
|
3550
|
-
h("path", {
|
|
3551
|
-
d: "M18 46V22l14 12 14-12v24",
|
|
3552
|
-
fill: "none",
|
|
3553
|
-
stroke: "#58a6ff",
|
|
3554
|
-
strokeWidth: 4,
|
|
3555
|
-
strokeLinecap: "round",
|
|
3556
|
-
strokeLinejoin: "round"
|
|
3557
|
-
}),
|
|
3558
|
-
h("circle", { cx: 32, cy: 45, r: 3, fill: "#3fb950" })
|
|
3559
|
-
);
|
|
3560
|
-
}
|
|
3561
3889
|
function relativeFuture(iso, t) {
|
|
3562
3890
|
if (iso === void 0) return void 0;
|
|
3563
3891
|
const target = new Date(iso).getTime();
|
|
@@ -3595,14 +3923,15 @@ function apply(ctx) {
|
|
|
3595
3923
|
const value = store();
|
|
3596
3924
|
const controller = useRunController(value);
|
|
3597
3925
|
const [view, setView] = import_react.default.useState("overview");
|
|
3598
|
-
const [
|
|
3926
|
+
const [digestTarget2, setDigestTarget] = import_react.default.useState(void 0);
|
|
3599
3927
|
const [aboutOpen, setAboutOpen] = import_react.default.useState(false);
|
|
3600
|
-
const openDigest = import_react.default.useCallback((
|
|
3601
|
-
if (
|
|
3928
|
+
const openDigest = import_react.default.useCallback((target) => {
|
|
3929
|
+
if (target !== void 0) setDigestTarget(target);
|
|
3602
3930
|
setView("digest");
|
|
3603
3931
|
}, []);
|
|
3604
3932
|
const openRuns = import_react.default.useCallback(() => setView("runs"), []);
|
|
3605
3933
|
const openSettings = import_react.default.useCallback(() => setView("settings"), []);
|
|
3934
|
+
const openAbout = import_react.default.useCallback(() => setAboutOpen(true), []);
|
|
3606
3935
|
const state = value.state;
|
|
3607
3936
|
const plugin = state?.plugin;
|
|
3608
3937
|
const history = state?.status.history ?? [];
|
|
@@ -3613,9 +3942,10 @@ function apply(ctx) {
|
|
|
3613
3942
|
state.settings.repo.path.trim() !== "",
|
|
3614
3943
|
state.github.configured
|
|
3615
3944
|
].filter(Boolean).length;
|
|
3616
|
-
const
|
|
3617
|
-
const digestTail = digestDate ?? state?.status.lastResult?.date ?? state?.status.history[0]?.date;
|
|
3945
|
+
const digestTail = state?.status.lastResult?.date ?? state?.status.history[0]?.date;
|
|
3618
3946
|
const showActions = view === "overview" || view === "runs";
|
|
3947
|
+
const nextRun = schedule === void 0 || !schedule.enabled ? t("shell.scheduleOff") : schedule.nextRunAt === void 0 ? `${schedule.time} · ${schedule.timezone}` : nextRunText(schedule.nextRunAt);
|
|
3948
|
+
const relNext = schedule !== void 0 && schedule.enabled && schedule.nextRunAt !== void 0 ? relativeFuture(schedule.nextRunAt, t) : void 0;
|
|
3619
3949
|
const viewNode = view === "overview" ? h(OverviewView, {
|
|
3620
3950
|
t,
|
|
3621
3951
|
lang,
|
|
@@ -3628,8 +3958,8 @@ function apply(ctx) {
|
|
|
3628
3958
|
t,
|
|
3629
3959
|
lang,
|
|
3630
3960
|
store: value,
|
|
3631
|
-
...
|
|
3632
|
-
|
|
3961
|
+
...digestTarget2 === void 0 ? {} : { selected: digestTarget2 },
|
|
3962
|
+
onSelect: setDigestTarget,
|
|
3633
3963
|
onOpenRuns: openRuns
|
|
3634
3964
|
}) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : h(SettingsView, { t, store: value, pickDirectory });
|
|
3635
3965
|
return h(
|
|
@@ -3638,103 +3968,49 @@ function apply(ctx) {
|
|
|
3638
3968
|
h(
|
|
3639
3969
|
"div",
|
|
3640
3970
|
{ className: "dshgt-app" },
|
|
3971
|
+
plugin === void 0 ? null : h(IdentityBar, { t, plugin, onOpenAbout: openAbout }),
|
|
3641
3972
|
h(
|
|
3642
|
-
"
|
|
3643
|
-
{ className: "dshgt-
|
|
3644
|
-
h(
|
|
3645
|
-
"div",
|
|
3646
|
-
{ className: "dshgt-brand" },
|
|
3647
|
-
brandLogo(),
|
|
3648
|
-
h(
|
|
3649
|
-
"div",
|
|
3650
|
-
null,
|
|
3651
|
-
h("div", { className: "dshgt-brand-name" }, t("section.title")),
|
|
3652
|
-
h("div", { className: "dshgt-brand-ver" }, plugin === void 0 ? "" : `v${plugin.version}`)
|
|
3653
|
-
)
|
|
3654
|
-
),
|
|
3973
|
+
"div",
|
|
3974
|
+
{ className: "dshgt-tabsbar" },
|
|
3655
3975
|
h(
|
|
3656
3976
|
"nav",
|
|
3657
|
-
{ className: "dshgt-
|
|
3977
|
+
{ className: "dshgt-tabnav", "aria-label": t("shell.nav") },
|
|
3658
3978
|
NAV.map(
|
|
3659
3979
|
(item) => h(
|
|
3660
3980
|
"button",
|
|
3661
3981
|
{
|
|
3662
3982
|
key: item.id,
|
|
3663
3983
|
type: "button",
|
|
3664
|
-
className: `dshgt-
|
|
3984
|
+
className: `dshgt-tab${view === item.id ? " on" : ""}`,
|
|
3665
3985
|
"aria-current": view === item.id ? "page" : void 0,
|
|
3666
3986
|
onClick: () => setView(item.id)
|
|
3667
3987
|
},
|
|
3668
3988
|
navIcon(item.icon),
|
|
3669
3989
|
h("span", null, t(item.label)),
|
|
3670
|
-
item.id === "digest" && digestTail !== void 0 ? h("span", { className: "dshgt-
|
|
3990
|
+
item.id === "digest" && digestTail !== void 0 ? h("span", { className: "dshgt-tab-tail dshgt-mono" }, digestTail.slice(5)) : item.id === "runs" && history.length > 0 ? h("span", { className: "dshgt-tab-tail dshgt-mono" }, String(history.length)) : null
|
|
3671
3991
|
)
|
|
3672
3992
|
)
|
|
3673
3993
|
),
|
|
3674
|
-
h("div", { className: "dshgt-rail-spacer" }),
|
|
3675
3994
|
h(
|
|
3676
3995
|
"div",
|
|
3677
|
-
{ className: "dshgt-
|
|
3678
|
-
h("div", { className: "dshgt-rail-cap" }, t("shell.nextRun")),
|
|
3996
|
+
{ className: "dshgt-tabsbar-status" },
|
|
3679
3997
|
h(
|
|
3680
|
-
"
|
|
3681
|
-
{ className: "dshgt-
|
|
3682
|
-
schedule === void 0 || !schedule.enabled ? t("shell.scheduleOff") : schedule.nextRunAt === void 0 ? `${schedule.time} · ${schedule.timezone}` : nextRunText(schedule.nextRunAt)
|
|
3683
|
-
),
|
|
3684
|
-
h(
|
|
3685
|
-
"div",
|
|
3686
|
-
{ className: "dshgt-rail-count" },
|
|
3687
|
-
schedule !== void 0 && schedule.enabled && schedule.nextRunAt !== void 0 ? relativeFuture(schedule.nextRunAt, t) ?? "" : schedule === void 0 ? "" : `${schedule.time} · ${schedule.timezone}`
|
|
3688
|
-
),
|
|
3689
|
-
h(
|
|
3690
|
-
"div",
|
|
3691
|
-
{ className: "dshgt-rail-ready" },
|
|
3998
|
+
"span",
|
|
3999
|
+
{ className: "dshgt-status-item" },
|
|
3692
4000
|
h("span", { className: `dshgt-lamp ${ready === 4 ? "ok" : ready > 0 ? "warn" : "err"}` }),
|
|
3693
4001
|
t("shell.ready", { ready, total: 4 })
|
|
3694
|
-
)
|
|
3695
|
-
),
|
|
3696
|
-
h(
|
|
3697
|
-
"div",
|
|
3698
|
-
{ className: "dshgt-rail-pkg" },
|
|
3699
|
-
h(
|
|
3700
|
-
"button",
|
|
3701
|
-
{
|
|
3702
|
-
type: "button",
|
|
3703
|
-
className: "dshgt-pkg-name",
|
|
3704
|
-
onClick: () => setAboutOpen(true),
|
|
3705
|
-
title: plugin === void 0 ? "" : fullName
|
|
3706
|
-
},
|
|
3707
|
-
plugin?.name ?? t("section.title"),
|
|
3708
|
-
h(UpdateDot, { t })
|
|
3709
4002
|
),
|
|
3710
4003
|
h(
|
|
3711
|
-
"
|
|
3712
|
-
{ className: "dshgt-
|
|
3713
|
-
h("span", { className: "dshgt-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
{ href: plugin.repository, target: "_blank", rel: "noreferrer" },
|
|
3717
|
-
`${t("shell.github")} ↗`
|
|
3718
|
-
),
|
|
3719
|
-
h(
|
|
3720
|
-
"button",
|
|
3721
|
-
{
|
|
3722
|
-
type: "button",
|
|
3723
|
-
className: "dshgt-pkg-copy",
|
|
3724
|
-
title: t("shell.package.copy"),
|
|
3725
|
-
"aria-label": t("shell.package.copy"),
|
|
3726
|
-
disabled: fullName === void 0,
|
|
3727
|
-
onClick: () => {
|
|
3728
|
-
if (fullName !== void 0) void copyText(fullName);
|
|
3729
|
-
}
|
|
3730
|
-
},
|
|
3731
|
-
navIcon("doc", 13)
|
|
3732
|
-
)
|
|
4004
|
+
"span",
|
|
4005
|
+
{ className: "dshgt-status-item dshgt-next" },
|
|
4006
|
+
h("span", { className: "dshgt-status-key" }, t("shell.nextRun")),
|
|
4007
|
+
h("span", { className: "dshgt-status-val dshgt-mono" }, nextRun),
|
|
4008
|
+
relNext === void 0 ? null : h("span", { className: "dshgt-status-sub" }, relNext)
|
|
3733
4009
|
)
|
|
3734
4010
|
)
|
|
3735
4011
|
),
|
|
3736
4012
|
h(
|
|
3737
|
-
"
|
|
4013
|
+
"div",
|
|
3738
4014
|
{ className: "dshgt-main" },
|
|
3739
4015
|
h(
|
|
3740
4016
|
"header",
|