dsh-deeppilot 0.9.0 → 0.9.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/COMPATIBILITY.md +35 -2
- package/README.md +29 -18
- package/README.zh-CN.md +20 -13
- package/docs/DSH_RELEASE_MEMORY.md +256 -18
- package/lib/client.js +550 -203
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +234 -89
- package/lib/index.js +6892 -5995
- package/lib/index.js.map +1 -1
- package/package.json +16 -16
package/lib/client.js
CHANGED
|
@@ -263,7 +263,6 @@ window.__ModuleLoader__.load({
|
|
|
263
263
|
pairingReady: bool(s, "pairingReady", "pairingReady"),
|
|
264
264
|
activeConnections: int(s, "activeConnections", "activeConnections"),
|
|
265
265
|
historyBufferMax: int(s, "historyBufferMax", "historyBufferMax"),
|
|
266
|
-
debug: bool(s, "debug", "debug"),
|
|
267
266
|
lanAddresses,
|
|
268
267
|
local: parseLocal(s.local),
|
|
269
268
|
remote: parseRemote(s.remote),
|
|
@@ -457,6 +456,8 @@ window.__ModuleLoader__.load({
|
|
|
457
456
|
"troubleshooting.summary": "测试与故障排查",
|
|
458
457
|
"troubleshooting.title": "诊断工具",
|
|
459
458
|
"troubleshooting.description": "仅在排查连接或推送问题时使用。",
|
|
459
|
+
"troubleshooting.debugTitle": "调试日志",
|
|
460
|
+
"troubleshooting.debugDescription": "打开后在 DSH host 的终端输出里打印握手、推送等诊断信息;不会打印配对令牌、APNs token 或消息内容。改动立即生效,无需重启。",
|
|
460
461
|
"system.summary": "系统信息",
|
|
461
462
|
"system.title": "运行信息",
|
|
462
463
|
"system.description": "插件、协议与连接端点的技术信息。",
|
|
@@ -630,6 +631,7 @@ window.__ModuleLoader__.load({
|
|
|
630
631
|
"diag.missingLocalPortHook": "useDeepPilotLocalPort hook 缺失",
|
|
631
632
|
"diag.missingRemoteEnabledHook": "useDeepPilotRemoteEnabled hook 缺失",
|
|
632
633
|
"diag.missingRemoteLimitHook": "useDeepPilotRemoteConnectionLimit hook 缺失",
|
|
634
|
+
"diag.missingDebugHook": "useDeepPilotDebug hook 缺失",
|
|
633
635
|
"diag.missingRefresh": "refresh 回调缺失",
|
|
634
636
|
"diag.missingReveal": "beginPairing 回调缺失",
|
|
635
637
|
"diag.missingRotate": "revokeDevice 回调缺失",
|
|
@@ -641,6 +643,7 @@ window.__ModuleLoader__.load({
|
|
|
641
643
|
"diag.missingSetLocalPort": "setDeepPilotLocalPort 回调缺失",
|
|
642
644
|
"diag.missingSetRemote": "setDeepPilotRemoteEnabled 回调缺失",
|
|
643
645
|
"diag.missingSetRemoteLimit": "setDeepPilotRemoteConnectionLimit 回调缺失",
|
|
646
|
+
"diag.missingSetDebug": "setDeepPilotDebug 回调缺失",
|
|
644
647
|
"diag.renderError": "渲染异常: ",
|
|
645
648
|
"diag.prefix": "diag: ",
|
|
646
649
|
"clipboard.rejected": "浏览器拒绝了剪贴板写入",
|
|
@@ -671,6 +674,8 @@ window.__ModuleLoader__.load({
|
|
|
671
674
|
"troubleshooting.summary": "Tests and troubleshooting",
|
|
672
675
|
"troubleshooting.title": "Diagnostic tools",
|
|
673
676
|
"troubleshooting.description": "Use these only when diagnosing connection or push issues.",
|
|
677
|
+
"troubleshooting.debugTitle": "Debug logging",
|
|
678
|
+
"troubleshooting.debugDescription": "When on, prints handshake and push diagnostics to the DSH host’s terminal output; never prints pairing tokens, APNs tokens, or message content. Takes effect immediately, no restart needed.",
|
|
674
679
|
"system.summary": "System information",
|
|
675
680
|
"system.title": "Runtime information",
|
|
676
681
|
"system.description": "Technical details about the plugin, protocol, and endpoints.",
|
|
@@ -844,6 +849,7 @@ window.__ModuleLoader__.load({
|
|
|
844
849
|
"diag.missingLocalPortHook": "useDeepPilotLocalPort hook missing",
|
|
845
850
|
"diag.missingRemoteEnabledHook": "useDeepPilotRemoteEnabled hook missing",
|
|
846
851
|
"diag.missingRemoteLimitHook": "useDeepPilotRemoteConnectionLimit hook missing",
|
|
852
|
+
"diag.missingDebugHook": "useDeepPilotDebug hook missing",
|
|
847
853
|
"diag.missingRefresh": "refresh callback missing",
|
|
848
854
|
"diag.missingReveal": "beginPairing callback missing",
|
|
849
855
|
"diag.missingRotate": "revokeDevice callback missing",
|
|
@@ -855,6 +861,7 @@ window.__ModuleLoader__.load({
|
|
|
855
861
|
"diag.missingSetLocalPort": "setDeepPilotLocalPort callback missing",
|
|
856
862
|
"diag.missingSetRemote": "setDeepPilotRemoteEnabled callback missing",
|
|
857
863
|
"diag.missingSetRemoteLimit": "setDeepPilotRemoteConnectionLimit callback missing",
|
|
864
|
+
"diag.missingSetDebug": "setDeepPilotDebug callback missing",
|
|
858
865
|
"diag.renderError": "Render error: ",
|
|
859
866
|
"diag.prefix": "diag: ",
|
|
860
867
|
"clipboard.rejected": "Clipboard write rejected by the browser",
|
|
@@ -3660,7 +3667,330 @@ window.__ModuleLoader__.load({
|
|
|
3660
3667
|
return typeof value === "number" && Number.isInteger(value) && value >= 1024 && value <= 65535 ? value : DEFAULT_LOCAL_PORT;
|
|
3661
3668
|
}
|
|
3662
3669
|
//#endregion
|
|
3670
|
+
//#region src/client/settings-props.ts
|
|
3671
|
+
const MISSING_REPORT_HOOK = () => ({
|
|
3672
|
+
status: "loading",
|
|
3673
|
+
report: null,
|
|
3674
|
+
message: ""
|
|
3675
|
+
});
|
|
3676
|
+
const MISSING_ENABLED_HOOK = () => ({
|
|
3677
|
+
status: "unavailable",
|
|
3678
|
+
enabled: true
|
|
3679
|
+
});
|
|
3680
|
+
const MISSING_LOCAL_ENABLED_HOOK = () => ({
|
|
3681
|
+
status: "unavailable",
|
|
3682
|
+
enabled: true
|
|
3683
|
+
});
|
|
3684
|
+
const MISSING_LOCAL_PORT_HOOK = () => ({
|
|
3685
|
+
status: "unavailable",
|
|
3686
|
+
value: DEFAULT_LOCAL_PORT
|
|
3687
|
+
});
|
|
3688
|
+
const MISSING_REMOTE_ENABLED_HOOK = () => ({
|
|
3689
|
+
status: "unavailable",
|
|
3690
|
+
enabled: false
|
|
3691
|
+
});
|
|
3692
|
+
const MISSING_REMOTE_LIMIT_HOOK = () => ({
|
|
3693
|
+
status: "unavailable",
|
|
3694
|
+
value: 8
|
|
3695
|
+
});
|
|
3696
|
+
const MISSING_DEBUG_HOOK = () => ({
|
|
3697
|
+
status: "unavailable",
|
|
3698
|
+
enabled: false
|
|
3699
|
+
});
|
|
3700
|
+
/** 诊断行的 key,集中在此便于对账(tests/settings-props.test.ts 逐条断言)。 */
|
|
3701
|
+
const DIAG_KEY = {
|
|
3702
|
+
reportHook: "diag.missingReportHook",
|
|
3703
|
+
enabledHook: "diag.missingEnabledHook",
|
|
3704
|
+
localEnabledHook: "diag.missingLocalEnabledHook",
|
|
3705
|
+
localPortHook: "diag.missingLocalPortHook",
|
|
3706
|
+
remoteEnabledHook: "diag.missingRemoteEnabledHook",
|
|
3707
|
+
remoteLimitHook: "diag.missingRemoteLimitHook",
|
|
3708
|
+
debugHook: "diag.missingDebugHook",
|
|
3709
|
+
refresh: "diag.missingRefresh",
|
|
3710
|
+
reveal: "diag.missingReveal",
|
|
3711
|
+
rotate: "diag.missingRotate",
|
|
3712
|
+
rename: "diag.missingRename",
|
|
3713
|
+
testRelay: "diag.missingTestRelay",
|
|
3714
|
+
testPush: "diag.missingTestPush",
|
|
3715
|
+
setEnabled: "diag.missingSetEnabled",
|
|
3716
|
+
setLocal: "diag.missingSetLocal",
|
|
3717
|
+
setLocalPort: "diag.missingSetLocalPort",
|
|
3718
|
+
setRemote: "diag.missingSetRemote",
|
|
3719
|
+
setRemoteLimit: "diag.missingSetRemoteLimit",
|
|
3720
|
+
setDebug: "diag.missingSetDebug",
|
|
3721
|
+
settingsUnavailable: "diag.settingsUnavailable"
|
|
3722
|
+
};
|
|
3723
|
+
const CAPABILITY_BY_PROP = [
|
|
3724
|
+
["refresh", "refresh"],
|
|
3725
|
+
["beginPairing", "beginPairing"],
|
|
3726
|
+
["revokeDevice", "revokeDevice"],
|
|
3727
|
+
["setDeviceName", "setDeviceName"],
|
|
3728
|
+
["testRelay", "testRelay"],
|
|
3729
|
+
["testPush", "testPush"],
|
|
3730
|
+
["setEnabled", "setDeepPilotEnabled"],
|
|
3731
|
+
["setLocalEnabled", "setDeepPilotLocalEnabled"],
|
|
3732
|
+
["setLocalPort", "setDeepPilotLocalPort"],
|
|
3733
|
+
["setRemoteEnabled", "setDeepPilotRemoteEnabled"],
|
|
3734
|
+
["setRemoteLimit", "setDeepPilotRemoteConnectionLimit"],
|
|
3735
|
+
["setDebug", "setDeepPilotDebug"]
|
|
3736
|
+
];
|
|
3737
|
+
const isFn = (value) => typeof value === "function";
|
|
3738
|
+
/**
|
|
3739
|
+
* 把宿主注入的原始对象归一化成页面可消费的面。
|
|
3740
|
+
*
|
|
3741
|
+
* 逐项复刻迁移前页面内的行为:hook 缺失换 fallback 并记诊断;函数缺失则该
|
|
3742
|
+
* 能力不进 `can` 并记诊断;诊断顺序与原先的 `diag[]` 完全一致(宿主过期时
|
|
3743
|
+
* 用户看到的技术诊断因此一字不差)。
|
|
3744
|
+
*/
|
|
3745
|
+
function normalizeSettingsPageProps(raw) {
|
|
3746
|
+
const source = raw ?? {};
|
|
3747
|
+
const t = typeof source.t === "function" ? source.t : ((key) => key);
|
|
3748
|
+
const diagnostics = [];
|
|
3749
|
+
const can = /* @__PURE__ */ new Set();
|
|
3750
|
+
const useReport = isFn(source.useDeepPilotReport) ? source.useDeepPilotReport : MISSING_REPORT_HOOK;
|
|
3751
|
+
const useEnabled = isFn(source.useDeepPilotEnabled) ? source.useDeepPilotEnabled : MISSING_ENABLED_HOOK;
|
|
3752
|
+
const useLocalEnabled = isFn(source.useDeepPilotLocalEnabled) ? source.useDeepPilotLocalEnabled : MISSING_LOCAL_ENABLED_HOOK;
|
|
3753
|
+
const useLocalPort = isFn(source.useDeepPilotLocalPort) ? source.useDeepPilotLocalPort : MISSING_LOCAL_PORT_HOOK;
|
|
3754
|
+
const useRemoteEnabled = isFn(source.useDeepPilotRemoteEnabled) ? source.useDeepPilotRemoteEnabled : MISSING_REMOTE_ENABLED_HOOK;
|
|
3755
|
+
const useRemoteLimit = isFn(source.useDeepPilotRemoteConnectionLimit) ? source.useDeepPilotRemoteConnectionLimit : MISSING_REMOTE_LIMIT_HOOK;
|
|
3756
|
+
const useDebug = isFn(source.useDeepPilotDebug) ? source.useDeepPilotDebug : MISSING_DEBUG_HOOK;
|
|
3757
|
+
if (!isFn(source.useDeepPilotReport)) diagnostics.push(t(DIAG_KEY.reportHook));
|
|
3758
|
+
if (!isFn(source.useDeepPilotEnabled)) diagnostics.push(t(DIAG_KEY.enabledHook));
|
|
3759
|
+
if (!isFn(source.refresh)) diagnostics.push(t(DIAG_KEY.refresh));
|
|
3760
|
+
if (!isFn(source.beginPairing)) diagnostics.push(t(DIAG_KEY.reveal));
|
|
3761
|
+
if (!isFn(source.revokeDevice)) diagnostics.push(t(DIAG_KEY.rotate));
|
|
3762
|
+
if (!isFn(source.setDeviceName)) diagnostics.push(t(DIAG_KEY.rename));
|
|
3763
|
+
if (!isFn(source.testRelay)) diagnostics.push(t(DIAG_KEY.testRelay));
|
|
3764
|
+
if (!isFn(source.testPush)) diagnostics.push(t(DIAG_KEY.testPush));
|
|
3765
|
+
if (!isFn(source.setDeepPilotEnabled)) diagnostics.push(t(DIAG_KEY.setEnabled));
|
|
3766
|
+
if (!isFn(source.useDeepPilotLocalEnabled)) diagnostics.push(t(DIAG_KEY.localEnabledHook));
|
|
3767
|
+
if (!isFn(source.useDeepPilotLocalPort)) diagnostics.push(t(DIAG_KEY.localPortHook));
|
|
3768
|
+
if (!isFn(source.setDeepPilotLocalEnabled)) diagnostics.push(t(DIAG_KEY.setLocal));
|
|
3769
|
+
if (!isFn(source.setDeepPilotLocalPort)) diagnostics.push(t(DIAG_KEY.setLocalPort));
|
|
3770
|
+
if (!isFn(source.useDeepPilotRemoteEnabled)) diagnostics.push(t(DIAG_KEY.remoteEnabledHook));
|
|
3771
|
+
if (!isFn(source.setDeepPilotRemoteEnabled)) diagnostics.push(t(DIAG_KEY.setRemote));
|
|
3772
|
+
if (!isFn(source.useDeepPilotRemoteConnectionLimit)) diagnostics.push(t(DIAG_KEY.remoteLimitHook));
|
|
3773
|
+
if (!isFn(source.setDeepPilotRemoteConnectionLimit)) diagnostics.push(t(DIAG_KEY.setRemoteLimit));
|
|
3774
|
+
if (!isFn(source.useDeepPilotDebug)) diagnostics.push(t(DIAG_KEY.debugHook));
|
|
3775
|
+
if (!isFn(source.setDeepPilotDebug)) diagnostics.push(t(DIAG_KEY.setDebug));
|
|
3776
|
+
for (const [capability, prop] of CAPABILITY_BY_PROP) if (isFn(source[prop])) can.add(capability);
|
|
3777
|
+
return {
|
|
3778
|
+
props: {
|
|
3779
|
+
useDeepPilotReport: useReport,
|
|
3780
|
+
useDeepPilotEnabled: useEnabled,
|
|
3781
|
+
useDeepPilotLocalEnabled: useLocalEnabled,
|
|
3782
|
+
useDeepPilotLocalPort: useLocalPort,
|
|
3783
|
+
useDeepPilotRemoteEnabled: useRemoteEnabled,
|
|
3784
|
+
useDeepPilotRemoteConnectionLimit: useRemoteLimit,
|
|
3785
|
+
useDeepPilotDebug: useDebug,
|
|
3786
|
+
t,
|
|
3787
|
+
refresh: isFn(source.refresh) ? source.refresh : void 0,
|
|
3788
|
+
beginPairing: isFn(source.beginPairing) ? source.beginPairing : void 0,
|
|
3789
|
+
revokeDevice: isFn(source.revokeDevice) ? source.revokeDevice : void 0,
|
|
3790
|
+
setDeviceName: isFn(source.setDeviceName) ? source.setDeviceName : void 0,
|
|
3791
|
+
testRelay: isFn(source.testRelay) ? source.testRelay : void 0,
|
|
3792
|
+
testPush: isFn(source.testPush) ? source.testPush : void 0,
|
|
3793
|
+
setDeepPilotEnabled: isFn(source.setDeepPilotEnabled) ? source.setDeepPilotEnabled : void 0,
|
|
3794
|
+
setDeepPilotLocalEnabled: isFn(source.setDeepPilotLocalEnabled) ? source.setDeepPilotLocalEnabled : void 0,
|
|
3795
|
+
setDeepPilotLocalPort: isFn(source.setDeepPilotLocalPort) ? source.setDeepPilotLocalPort : void 0,
|
|
3796
|
+
setDeepPilotRemoteEnabled: isFn(source.setDeepPilotRemoteEnabled) ? source.setDeepPilotRemoteEnabled : void 0,
|
|
3797
|
+
setDeepPilotRemoteConnectionLimit: isFn(source.setDeepPilotRemoteConnectionLimit) ? source.setDeepPilotRemoteConnectionLimit : void 0,
|
|
3798
|
+
setDeepPilotDebug: isFn(source.setDeepPilotDebug) ? source.setDeepPilotDebug : void 0
|
|
3799
|
+
},
|
|
3800
|
+
can,
|
|
3801
|
+
diagnostics,
|
|
3802
|
+
reportHookMissing: !isFn(source.useDeepPilotReport)
|
|
3803
|
+
};
|
|
3804
|
+
}
|
|
3805
|
+
//#endregion
|
|
3806
|
+
//#region src/client/settings-view-models.ts
|
|
3807
|
+
/**
|
|
3808
|
+
* 设置页的 view model:把原先住在渲染函数里的三块逻辑变成可单测的纯模块。
|
|
3809
|
+
*
|
|
3810
|
+
* 迁移前 `settings-page.ts` 是一个 1059 行的组件,funnel phase → {dot, label}、
|
|
3811
|
+
端口/连接数草稿的编辑与合法性、serviceStatus 派生全在渲染函数里,没有任何
|
|
3812
|
+
直接测试。这里按 pairing-panel.ts 的形状把它们拆成 state / action / reduce /
|
|
3813
|
+
view 四件套——shape 与该先例一致,但**不继承它唯一的泄漏**:view model 只返回
|
|
3814
|
+
语义值,i18n key 的映射留在页面(措辞归页面,测试不跟着措辞漂)。
|
|
3815
|
+
*/
|
|
3816
|
+
const REMOTE_PHASE_META = {
|
|
3817
|
+
disabled: {
|
|
3818
|
+
dot: "",
|
|
3819
|
+
label: "disabled"
|
|
3820
|
+
},
|
|
3821
|
+
starting: {
|
|
3822
|
+
dot: " pbb-dotWarn",
|
|
3823
|
+
label: "starting"
|
|
3824
|
+
},
|
|
3825
|
+
login_required: {
|
|
3826
|
+
dot: " pbb-dotWarn",
|
|
3827
|
+
label: "login_required"
|
|
3828
|
+
},
|
|
3829
|
+
online: {
|
|
3830
|
+
dot: " pbb-dotOk",
|
|
3831
|
+
label: "online"
|
|
3832
|
+
},
|
|
3833
|
+
error: {
|
|
3834
|
+
dot: " pbb-dotBad",
|
|
3835
|
+
label: "error"
|
|
3836
|
+
},
|
|
3837
|
+
unavailable: {
|
|
3838
|
+
dot: " pbb-dotBad",
|
|
3839
|
+
label: "unavailable"
|
|
3840
|
+
},
|
|
3841
|
+
stopped: {
|
|
3842
|
+
dot: "",
|
|
3843
|
+
label: "stopped"
|
|
3844
|
+
}
|
|
3845
|
+
};
|
|
3846
|
+
const LOCAL_PHASE_META = {
|
|
3847
|
+
disabled: {
|
|
3848
|
+
dot: "",
|
|
3849
|
+
label: "disabled"
|
|
3850
|
+
},
|
|
3851
|
+
starting: {
|
|
3852
|
+
dot: " pbb-dotWarn",
|
|
3853
|
+
label: "starting"
|
|
3854
|
+
},
|
|
3855
|
+
online: {
|
|
3856
|
+
dot: " pbb-dotOk",
|
|
3857
|
+
label: "online"
|
|
3858
|
+
},
|
|
3859
|
+
error: {
|
|
3860
|
+
dot: " pbb-dotBad",
|
|
3861
|
+
label: "error"
|
|
3862
|
+
},
|
|
3863
|
+
stopped: {
|
|
3864
|
+
dot: "",
|
|
3865
|
+
label: "stopped"
|
|
3866
|
+
}
|
|
3867
|
+
};
|
|
3868
|
+
/** 从点位反推「需要注意 / 已在线」——原先页面用字符串 includes 猜类名。 */
|
|
3869
|
+
function dotState(dot) {
|
|
3870
|
+
return {
|
|
3871
|
+
attention: dot?.includes("pbb-dotBad") === true,
|
|
3872
|
+
online: dot?.includes("pbb-dotOk") === true
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
function serviceStatus(input) {
|
|
3876
|
+
const local = dotState(input.localDot);
|
|
3877
|
+
const remote = dotState(input.remoteDot);
|
|
3878
|
+
const attention = local.attention || remote.attention;
|
|
3879
|
+
const online = local.online || remote.online;
|
|
3880
|
+
return {
|
|
3881
|
+
kind: !input.switchReady ? "loading" : !input.enabled ? "off" : attention ? "attention" : online ? "ready" : "loading",
|
|
3882
|
+
dot: !input.enabled ? "" : attention ? " pbb-dotBad" : online ? " pbb-dotOk" : " pbb-dotWarn"
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
const LOCAL_PORT_RANGE = {
|
|
3886
|
+
min: MIN_LOCAL_PORT,
|
|
3887
|
+
max: MAX_LOCAL_PORT,
|
|
3888
|
+
fallback: DEFAULT_LOCAL_PORT
|
|
3889
|
+
};
|
|
3890
|
+
const REMOTE_LIMIT_RANGE = {
|
|
3891
|
+
min: 1,
|
|
3892
|
+
max: 16,
|
|
3893
|
+
fallback: 8
|
|
3894
|
+
};
|
|
3895
|
+
function initialNumericDraft(range) {
|
|
3896
|
+
return {
|
|
3897
|
+
draft: String(range.fallback),
|
|
3898
|
+
message: "",
|
|
3899
|
+
failed: false
|
|
3900
|
+
};
|
|
3901
|
+
}
|
|
3902
|
+
function numericDraftReduce(state, action, range) {
|
|
3903
|
+
switch (action.type) {
|
|
3904
|
+
case "edit": return {
|
|
3905
|
+
...state,
|
|
3906
|
+
draft: action.draft
|
|
3907
|
+
};
|
|
3908
|
+
case "sync": return {
|
|
3909
|
+
...state,
|
|
3910
|
+
draft: String(action.value),
|
|
3911
|
+
message: "",
|
|
3912
|
+
failed: false
|
|
3913
|
+
};
|
|
3914
|
+
case "applied": return {
|
|
3915
|
+
...state,
|
|
3916
|
+
message: "",
|
|
3917
|
+
failed: false
|
|
3918
|
+
};
|
|
3919
|
+
case "succeeded": return {
|
|
3920
|
+
...state,
|
|
3921
|
+
message: action.message,
|
|
3922
|
+
failed: false
|
|
3923
|
+
};
|
|
3924
|
+
case "failed": return {
|
|
3925
|
+
...state,
|
|
3926
|
+
message: action.message,
|
|
3927
|
+
failed: true
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
function numericDraftView(state, current, range) {
|
|
3932
|
+
const value = Number(state.draft);
|
|
3933
|
+
const valid = Number.isInteger(value) && value >= range.min && value <= range.max;
|
|
3934
|
+
return {
|
|
3935
|
+
value,
|
|
3936
|
+
valid,
|
|
3937
|
+
unchanged: valid && value === current
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
/** 已撤销的设备不展示。 */
|
|
3941
|
+
function visibleDevices(report) {
|
|
3942
|
+
return (report?.devices ?? []).filter((device) => device.revokedAt === void 0);
|
|
3943
|
+
}
|
|
3944
|
+
/** 设备展示名:自定义名优先,都没有则空串(兜底文案归页面)。 */
|
|
3945
|
+
function deviceLabel(device) {
|
|
3946
|
+
return (device.customName ?? device.deviceName).trim();
|
|
3947
|
+
}
|
|
3948
|
+
/** 渲染一块连接磁贴。纯数据函数:九参进,元素树出。 */
|
|
3949
|
+
function renderConnectionTile(key, title, description, checked, ready, dot, statusLabel, onToggle, extra = null) {
|
|
3950
|
+
return (0, react.createElement)("div", {
|
|
3951
|
+
className: "pbb-connectionTile",
|
|
3952
|
+
key
|
|
3953
|
+
}, (0, react.createElement)("div", { className: "pbb-connectionTileHeader" }, (0, react.createElement)("span", { className: "pbb-switchTitle pbb-dotRow" }, (0, react.createElement)("span", {
|
|
3954
|
+
className: "pbb-dot" + dot,
|
|
3955
|
+
role: "img",
|
|
3956
|
+
"aria-label": statusLabel,
|
|
3957
|
+
title: statusLabel
|
|
3958
|
+
}), title), (0, react.createElement)("button", {
|
|
3959
|
+
type: "button",
|
|
3960
|
+
role: "switch",
|
|
3961
|
+
"aria-checked": checked,
|
|
3962
|
+
"aria-label": title,
|
|
3963
|
+
disabled: !ready,
|
|
3964
|
+
className: "pbb-switch" + (checked ? " pbb-switchOn" : ""),
|
|
3965
|
+
onClick: onToggle
|
|
3966
|
+
})), (0, react.createElement)("span", { className: "pbb-connectionState" }, statusLabel), (0, react.createElement)("p", { className: "pbb-connectionDescription" }, description), extra);
|
|
3967
|
+
}
|
|
3968
|
+
//#endregion
|
|
3663
3969
|
//#region src/client/settings-page.ts
|
|
3970
|
+
/** phase 语义标签 → i18n key。措辞归页面,view model 只认语义。 */
|
|
3971
|
+
const REMOTE_LABEL_KEY = {
|
|
3972
|
+
disabled: "phase.disabled",
|
|
3973
|
+
starting: "phase.starting",
|
|
3974
|
+
login_required: "phase.login_required",
|
|
3975
|
+
online: "phase.online",
|
|
3976
|
+
error: "phase.error",
|
|
3977
|
+
unavailable: "phase.unavailable",
|
|
3978
|
+
stopped: "phase.stopped"
|
|
3979
|
+
};
|
|
3980
|
+
const LOCAL_LABEL_KEY = {
|
|
3981
|
+
disabled: "local.phaseDisabled",
|
|
3982
|
+
starting: "local.phaseStarting",
|
|
3983
|
+
online: "local.phaseOnline",
|
|
3984
|
+
error: "local.phaseError",
|
|
3985
|
+
stopped: "local.phaseStopped"
|
|
3986
|
+
};
|
|
3987
|
+
/** 服务状态 → i18n key。 */
|
|
3988
|
+
const SERVICE_STATUS_KEY = {
|
|
3989
|
+
loading: "status.loading",
|
|
3990
|
+
off: "status.off",
|
|
3991
|
+
attention: "status.attention",
|
|
3992
|
+
ready: "status.ready"
|
|
3993
|
+
};
|
|
3664
3994
|
/** Inline trash icon for the compact destructive row action. Kept as a tiny
|
|
3665
3995
|
* element (no icon dependency) so the client bundle stays dependency-free
|
|
3666
3996
|
* apart from React. */
|
|
@@ -3714,68 +4044,19 @@ window.__ModuleLoader__.load({
|
|
|
3714
4044
|
textarea.remove();
|
|
3715
4045
|
if (!copied) throw new Error(t("clipboard.rejected"));
|
|
3716
4046
|
}
|
|
3717
|
-
/**
|
|
3718
|
-
*
|
|
3719
|
-
*
|
|
3720
|
-
*
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
login_required: {
|
|
3731
|
-
dot: " pbb-dotWarn",
|
|
3732
|
-
labelKey: "phase.login_required"
|
|
3733
|
-
},
|
|
3734
|
-
online: {
|
|
3735
|
-
dot: " pbb-dotOk",
|
|
3736
|
-
labelKey: "phase.online"
|
|
3737
|
-
},
|
|
3738
|
-
error: {
|
|
3739
|
-
dot: " pbb-dotBad",
|
|
3740
|
-
labelKey: "phase.error"
|
|
3741
|
-
},
|
|
3742
|
-
unavailable: {
|
|
3743
|
-
dot: " pbb-dotBad",
|
|
3744
|
-
labelKey: "phase.unavailable"
|
|
3745
|
-
},
|
|
3746
|
-
stopped: {
|
|
3747
|
-
dot: "",
|
|
3748
|
-
labelKey: "phase.stopped"
|
|
3749
|
-
}
|
|
3750
|
-
};
|
|
3751
|
-
const LOCAL_PHASE_META = {
|
|
3752
|
-
disabled: {
|
|
3753
|
-
dot: "",
|
|
3754
|
-
labelKey: "local.phaseDisabled"
|
|
3755
|
-
},
|
|
3756
|
-
starting: {
|
|
3757
|
-
dot: " pbb-dotWarn",
|
|
3758
|
-
labelKey: "local.phaseStarting"
|
|
3759
|
-
},
|
|
3760
|
-
online: {
|
|
3761
|
-
dot: " pbb-dotOk",
|
|
3762
|
-
labelKey: "local.phaseOnline"
|
|
3763
|
-
},
|
|
3764
|
-
error: {
|
|
3765
|
-
dot: " pbb-dotBad",
|
|
3766
|
-
labelKey: "local.phaseError"
|
|
3767
|
-
},
|
|
3768
|
-
stopped: {
|
|
3769
|
-
dot: "",
|
|
3770
|
-
labelKey: "local.phaseStopped"
|
|
3771
|
-
}
|
|
3772
|
-
};
|
|
3773
|
-
/** Slot component: hooks come from the slot renderer, named use<Key>. */
|
|
3774
|
-
function DeepPilotSettingsPage(props) {
|
|
3775
|
-
const [remoteLimitDraft, setRemoteLimitDraft] = (0, react.useState)(String(8));
|
|
3776
|
-
const [remoteLimitMessage, setRemoteLimitMessage] = (0, react.useState)("");
|
|
3777
|
-
const [localPortDraft, setLocalPortDraft] = (0, react.useState)(String(DEFAULT_LOCAL_PORT));
|
|
3778
|
-
const [localPortMessage, setLocalPortMessage] = (0, react.useState)("");
|
|
4047
|
+
/**
|
|
4048
|
+
* Slot component: hooks come from the slot renderer, named use<Key>.
|
|
4049
|
+
*
|
|
4050
|
+
* 组件的接口是 `SettingsPageProps`(见 settings-props.ts):宿主注入面与页面
|
|
4051
|
+
* 共享同一份类型。这里只做一次归一化,之后全程消费类型化对象——页面里不再
|
|
4052
|
+
* 出现任何 typeof 守卫,也不再自己拼诊断行。
|
|
4053
|
+
*/
|
|
4054
|
+
function DeepPilotSettingsPage(rawProps) {
|
|
4055
|
+
const surface = normalizeSettingsPageProps(rawProps);
|
|
4056
|
+
const props = surface.props;
|
|
4057
|
+
const can = (capability) => surface.can.has(capability);
|
|
4058
|
+
const [remoteLimitDraft, dispatchRemoteLimitDraft] = (0, react.useReducer)((state, action) => numericDraftReduce(state, action, REMOTE_LIMIT_RANGE), initialNumericDraft(REMOTE_LIMIT_RANGE));
|
|
4059
|
+
const [localPortDraft, dispatchLocalPortDraft] = (0, react.useReducer)((state, action) => numericDraftReduce(state, action, LOCAL_PORT_RANGE), initialNumericDraft(LOCAL_PORT_RANGE));
|
|
3779
4060
|
const [selectedPairingHost, setSelectedPairingHost] = (0, react.useState)(null);
|
|
3780
4061
|
const [pairingPanel, dispatchPairingPanel] = (0, react.useReducer)(pairingPanelReduce, initialPairingPanelState);
|
|
3781
4062
|
const qrRequestId = (0, react.useRef)(0);
|
|
@@ -3792,14 +4073,15 @@ window.__ModuleLoader__.load({
|
|
|
3792
4073
|
const [editingDeviceId, setEditingDeviceId] = (0, react.useState)(null);
|
|
3793
4074
|
const [deviceNameDraft, setDeviceNameDraft] = (0, react.useState)("");
|
|
3794
4075
|
(0, react.useEffect)(() => {
|
|
3795
|
-
if (
|
|
3796
|
-
props.refresh
|
|
3797
|
-
|
|
4076
|
+
if (!can("refresh")) return;
|
|
4077
|
+
const refresh = props.refresh;
|
|
4078
|
+
refresh();
|
|
4079
|
+
const timer = globalThis.setInterval(() => refresh(), 3e3);
|
|
3798
4080
|
return () => globalThis.clearInterval(timer);
|
|
3799
4081
|
}, [props.refresh]);
|
|
3800
4082
|
const sendPushTest = () => {
|
|
3801
4083
|
if (pushTestBusy) return;
|
|
3802
|
-
if (
|
|
4084
|
+
if (!can("testPush")) {
|
|
3803
4085
|
setPushTestError(translateWith(props.t, "push.staleHost"));
|
|
3804
4086
|
return;
|
|
3805
4087
|
}
|
|
@@ -3816,7 +4098,7 @@ window.__ModuleLoader__.load({
|
|
|
3816
4098
|
};
|
|
3817
4099
|
const runRelayTest = () => {
|
|
3818
4100
|
if (relayTestBusy) return;
|
|
3819
|
-
if (
|
|
4101
|
+
if (!can("testRelay")) {
|
|
3820
4102
|
setRelayTestError(translateWith(props.t, "push.staleHostRelay"));
|
|
3821
4103
|
return;
|
|
3822
4104
|
}
|
|
@@ -3832,15 +4114,15 @@ window.__ModuleLoader__.load({
|
|
|
3832
4114
|
});
|
|
3833
4115
|
};
|
|
3834
4116
|
(0, react.useEffect)(() => {
|
|
3835
|
-
if (
|
|
3836
|
-
const timer = globalThis.setTimeout(() =>
|
|
4117
|
+
if (remoteLimitDraft.message === "") return;
|
|
4118
|
+
const timer = globalThis.setTimeout(() => dispatchRemoteLimitDraft({ type: "applied" }), 4e3);
|
|
3837
4119
|
return () => globalThis.clearTimeout(timer);
|
|
3838
|
-
}, [
|
|
4120
|
+
}, [remoteLimitDraft.message]);
|
|
3839
4121
|
(0, react.useEffect)(() => {
|
|
3840
|
-
if (
|
|
3841
|
-
const timer = globalThis.setTimeout(() =>
|
|
4122
|
+
if (localPortDraft.message === "") return;
|
|
4123
|
+
const timer = globalThis.setTimeout(() => dispatchLocalPortDraft({ type: "applied" }), 4e3);
|
|
3842
4124
|
return () => globalThis.clearTimeout(timer);
|
|
3843
|
-
}, [
|
|
4125
|
+
}, [localPortDraft.message]);
|
|
3844
4126
|
(0, react.useEffect)(() => {
|
|
3845
4127
|
if (pairingPanel.grant === null) return;
|
|
3846
4128
|
const remaining = Math.max(0, pairingPanel.grant.expiresAt - Date.now());
|
|
@@ -3857,104 +4139,123 @@ window.__ModuleLoader__.load({
|
|
|
3857
4139
|
const timer = globalThis.setTimeout(() => dispatchPairingPanel({ type: "dismissNotice" }), 2500);
|
|
3858
4140
|
return () => globalThis.clearTimeout(timer);
|
|
3859
4141
|
}, [pairingPanel.notice]);
|
|
3860
|
-
const diag =
|
|
3861
|
-
let
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
let localPortReady = false;
|
|
3868
|
-
let remoteEnabled = false;
|
|
3869
|
-
let remoteSwitchReady = false;
|
|
3870
|
-
let remoteConnectionLimit = 8;
|
|
3871
|
-
let remoteConnectionLimitReady = false;
|
|
3872
|
-
let failed = false;
|
|
3873
|
-
try {
|
|
3874
|
-
if (typeof props.useDeepPilotReport !== "function") {
|
|
3875
|
-
diag.push(translateWith(props.t, "diag.missingReportHook"));
|
|
4142
|
+
const diag = surface.diagnostics;
|
|
4143
|
+
let failed = surface.reportHookMissing;
|
|
4144
|
+
const readHooks = () => {
|
|
4145
|
+
const reportState = props.useDeepPilotReport((s) => s);
|
|
4146
|
+
hooks.report = reportState.report;
|
|
4147
|
+
if (reportState.status === "error" && reportState.message) {
|
|
4148
|
+
diag.push(reportState.message);
|
|
3876
4149
|
failed = true;
|
|
3877
|
-
} else {
|
|
3878
|
-
const state = props.useDeepPilotReport((s) => s);
|
|
3879
|
-
report = state.report;
|
|
3880
|
-
if (state.status === "error" && state.message) {
|
|
3881
|
-
diag.push(state.message);
|
|
3882
|
-
failed = true;
|
|
3883
|
-
}
|
|
3884
4150
|
}
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
4151
|
+
const enabledState = props.useDeepPilotEnabled((s) => s);
|
|
4152
|
+
hooks.enabled = enabledState.enabled;
|
|
4153
|
+
hooks.switchReady = enabledState.status === "ready";
|
|
4154
|
+
if (enabledState.status === "unavailable") diag.push(translateWith(props.t, "diag.settingsUnavailable"));
|
|
4155
|
+
const localEnabledState = props.useDeepPilotLocalEnabled((s) => s);
|
|
4156
|
+
hooks.localEnabled = localEnabledState.enabled;
|
|
4157
|
+
hooks.localSwitchReady = localEnabledState.status === "ready";
|
|
4158
|
+
const localPortState = props.useDeepPilotLocalPort((s) => s);
|
|
4159
|
+
hooks.localPort = localPortState.value;
|
|
4160
|
+
hooks.localPortReady = localPortState.status === "ready";
|
|
4161
|
+
const remoteEnabledState = props.useDeepPilotRemoteEnabled((s) => s);
|
|
4162
|
+
hooks.remoteEnabled = remoteEnabledState.enabled;
|
|
4163
|
+
hooks.remoteSwitchReady = remoteEnabledState.status === "ready";
|
|
4164
|
+
const remoteLimitState = props.useDeepPilotRemoteConnectionLimit((s) => s);
|
|
4165
|
+
hooks.remoteConnectionLimit = remoteLimitState.value;
|
|
4166
|
+
hooks.remoteConnectionLimitReady = remoteLimitState.status === "ready";
|
|
4167
|
+
const debugState = props.useDeepPilotDebug((s) => s);
|
|
4168
|
+
hooks.debugEnabled = debugState.enabled;
|
|
4169
|
+
hooks.debugSwitchReady = debugState.status === "ready";
|
|
4170
|
+
};
|
|
4171
|
+
const hooks = {
|
|
4172
|
+
report: null,
|
|
4173
|
+
enabled: true,
|
|
4174
|
+
switchReady: false,
|
|
4175
|
+
localEnabled: true,
|
|
4176
|
+
localSwitchReady: false,
|
|
4177
|
+
localPort: DEFAULT_LOCAL_PORT,
|
|
4178
|
+
localPortReady: false,
|
|
4179
|
+
remoteEnabled: false,
|
|
4180
|
+
remoteSwitchReady: false,
|
|
4181
|
+
remoteConnectionLimit: 8,
|
|
4182
|
+
remoteConnectionLimitReady: false,
|
|
4183
|
+
debugEnabled: false,
|
|
4184
|
+
debugSwitchReady: false
|
|
4185
|
+
};
|
|
4186
|
+
try {
|
|
4187
|
+
readHooks();
|
|
3922
4188
|
} catch (error) {
|
|
3923
4189
|
diag.push(translateWith(props.t, "diag.renderError") + (error instanceof Error ? error.message : String(error)));
|
|
3924
4190
|
failed = true;
|
|
3925
4191
|
}
|
|
4192
|
+
const report = hooks.report;
|
|
4193
|
+
const enabled = hooks.enabled;
|
|
4194
|
+
const switchReady = hooks.switchReady;
|
|
4195
|
+
const localEnabled = hooks.localEnabled;
|
|
4196
|
+
const localSwitchReady = hooks.localSwitchReady;
|
|
4197
|
+
const localPort = hooks.localPort;
|
|
4198
|
+
const localPortReady = hooks.localPortReady;
|
|
4199
|
+
const remoteEnabled = hooks.remoteEnabled;
|
|
4200
|
+
const remoteSwitchReady = hooks.remoteSwitchReady;
|
|
4201
|
+
const remoteConnectionLimit = hooks.remoteConnectionLimit;
|
|
4202
|
+
const remoteConnectionLimitReady = hooks.remoteConnectionLimitReady;
|
|
4203
|
+
const debugEnabled = hooks.debugEnabled;
|
|
4204
|
+
const debugSwitchReady = hooks.debugSwitchReady;
|
|
3926
4205
|
(0, react.useEffect)(() => {
|
|
3927
|
-
|
|
4206
|
+
dispatchRemoteLimitDraft({
|
|
4207
|
+
type: "sync",
|
|
4208
|
+
value: remoteConnectionLimit
|
|
4209
|
+
});
|
|
3928
4210
|
}, [remoteConnectionLimit]);
|
|
3929
4211
|
(0, react.useEffect)(() => {
|
|
3930
|
-
|
|
4212
|
+
dispatchLocalPortDraft({
|
|
4213
|
+
type: "sync",
|
|
4214
|
+
value: localPort
|
|
4215
|
+
});
|
|
3931
4216
|
}, [localPort]);
|
|
3932
|
-
const
|
|
3933
|
-
const
|
|
4217
|
+
const localPortView = numericDraftView(localPortDraft, localPort, LOCAL_PORT_RANGE);
|
|
4218
|
+
const remoteLimitView = numericDraftView(remoteLimitDraft, remoteConnectionLimit, REMOTE_LIMIT_RANGE);
|
|
3934
4219
|
const applyLocalPort = () => {
|
|
3935
|
-
if (!
|
|
3936
|
-
|
|
4220
|
+
if (!localPortView.valid || !can("setLocalPort")) {
|
|
4221
|
+
dispatchLocalPortDraft({
|
|
4222
|
+
type: "failed",
|
|
4223
|
+
message: translateWith(props.t, "local.portInvalid")
|
|
4224
|
+
});
|
|
3937
4225
|
return;
|
|
3938
4226
|
}
|
|
3939
|
-
|
|
3940
|
-
props.setDeepPilotLocalPort(
|
|
3941
|
-
|
|
4227
|
+
dispatchLocalPortDraft({ type: "applied" });
|
|
4228
|
+
Promise.resolve(props.setDeepPilotLocalPort(localPortView.value)).then(() => {
|
|
4229
|
+
dispatchLocalPortDraft({
|
|
4230
|
+
type: "succeeded",
|
|
4231
|
+
message: translateWith(props.t, "local.portApplied")
|
|
4232
|
+
});
|
|
3942
4233
|
}, (error) => {
|
|
3943
|
-
|
|
4234
|
+
dispatchLocalPortDraft({
|
|
4235
|
+
type: "failed",
|
|
4236
|
+
message: translateWith(props.t, "local.portFailed") + (error instanceof Error ? error.message : String(error))
|
|
4237
|
+
});
|
|
3944
4238
|
});
|
|
3945
4239
|
};
|
|
3946
|
-
const parsedRemoteLimit = Number(remoteLimitDraft);
|
|
3947
|
-
const remoteLimitValid = Number.isInteger(parsedRemoteLimit) && parsedRemoteLimit >= 1 && parsedRemoteLimit <= 16;
|
|
3948
4240
|
const applyRemoteLimit = () => {
|
|
3949
|
-
if (!
|
|
3950
|
-
|
|
4241
|
+
if (!remoteLimitView.valid || !can("setRemoteLimit")) {
|
|
4242
|
+
dispatchRemoteLimitDraft({
|
|
4243
|
+
type: "failed",
|
|
4244
|
+
message: translateWith(props.t, "remote.limitInvalid")
|
|
4245
|
+
});
|
|
3951
4246
|
return;
|
|
3952
4247
|
}
|
|
3953
|
-
|
|
3954
|
-
props.setDeepPilotRemoteConnectionLimit(
|
|
3955
|
-
|
|
4248
|
+
dispatchRemoteLimitDraft({ type: "applied" });
|
|
4249
|
+
Promise.resolve(props.setDeepPilotRemoteConnectionLimit(remoteLimitView.value)).then(() => {
|
|
4250
|
+
dispatchRemoteLimitDraft({
|
|
4251
|
+
type: "succeeded",
|
|
4252
|
+
message: translateWith(props.t, "remote.limitApplied")
|
|
4253
|
+
});
|
|
3956
4254
|
}, (error) => {
|
|
3957
|
-
|
|
4255
|
+
dispatchRemoteLimitDraft({
|
|
4256
|
+
type: "failed",
|
|
4257
|
+
message: translateWith(props.t, "remote.limitFailed") + (error instanceof Error ? error.message : String(error))
|
|
4258
|
+
});
|
|
3958
4259
|
});
|
|
3959
4260
|
};
|
|
3960
4261
|
const pairingTargets = report === null ? [] : selectPairingTargets(report.local, report.remote);
|
|
@@ -3969,7 +4270,7 @@ window.__ModuleLoader__.load({
|
|
|
3969
4270
|
* switching between LAN and public always mints a fresh one.
|
|
3970
4271
|
*/
|
|
3971
4272
|
const showPairingQR = (target) => {
|
|
3972
|
-
if (
|
|
4273
|
+
if (!can("beginPairing")) return;
|
|
3973
4274
|
const requestId = qrRequestId.current + 1;
|
|
3974
4275
|
qrRequestId.current = requestId;
|
|
3975
4276
|
dispatchPairingPanel({
|
|
@@ -4059,7 +4360,7 @@ window.__ModuleLoader__.load({
|
|
|
4059
4360
|
}, (0, react.createElement)("div", { className: "pbb-row" }, (0, react.createElement)("span", { className: "pbb-label" }, translateWith(props.t, "advanced.bufferMax")), (0, react.createElement)("span", { className: "pbb-value" }, String(report.historyBufferMax) + translateWith(props.t, "advanced.frames")))));
|
|
4060
4361
|
}
|
|
4061
4362
|
const revokeDevice = (deviceId, name) => {
|
|
4062
|
-
if (
|
|
4363
|
+
if (!can("revokeDevice")) return;
|
|
4063
4364
|
if (typeof window !== "undefined" && !window.confirm(translateWith(props.t, "devices.revokeConfirm", { name }))) return;
|
|
4064
4365
|
setDeviceBusy(deviceId);
|
|
4065
4366
|
setDeviceBusyAction("revoke");
|
|
@@ -4073,7 +4374,7 @@ window.__ModuleLoader__.load({
|
|
|
4073
4374
|
setDeviceBusyAction(null);
|
|
4074
4375
|
});
|
|
4075
4376
|
};
|
|
4076
|
-
const deviceLabel = (device) => (device
|
|
4377
|
+
const deviceLabel$1 = (device) => deviceLabel(device) || translateWith(props.t, "devices.unnamed");
|
|
4077
4378
|
const beginDeviceRename = (device) => {
|
|
4078
4379
|
setEditingDeviceId(device.deviceId);
|
|
4079
4380
|
setDeviceNameDraft(device.customName ?? device.deviceName);
|
|
@@ -4085,7 +4386,7 @@ window.__ModuleLoader__.load({
|
|
|
4085
4386
|
setDeviceMessage("");
|
|
4086
4387
|
};
|
|
4087
4388
|
const saveDeviceName = (deviceId) => {
|
|
4088
|
-
if (
|
|
4389
|
+
if (!can("setDeviceName")) return;
|
|
4089
4390
|
const normalized = deviceNameDraft.trim();
|
|
4090
4391
|
if (normalized.length > 64) {
|
|
4091
4392
|
setDeviceMessage(translateWith(props.t, "devices.nameInvalid"));
|
|
@@ -4105,11 +4406,11 @@ window.__ModuleLoader__.load({
|
|
|
4105
4406
|
setDeviceBusyAction(null);
|
|
4106
4407
|
});
|
|
4107
4408
|
};
|
|
4108
|
-
const visibleDevices = report
|
|
4109
|
-
const deviceTable = visibleDevices.length > 0 ? (0, react.createElement)("div", { className: "pbb-tableWrap" }, (0, react.createElement)("table", { className: "pbb-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, translateWith(props.t, "devices.col.name")), (0, react.createElement)("th", null, translateWith(props.t, "devices.col.lastSeen")), (0, react.createElement)("th", { className: "pbb-tableActionHead" }, translateWith(props.t, "devices.col.actions")))), (0, react.createElement)("tbody", null, visibleDevices.map((d) => {
|
|
4409
|
+
const visibleDevices$1 = visibleDevices(report);
|
|
4410
|
+
const deviceTable = visibleDevices$1.length > 0 ? (0, react.createElement)("div", { className: "pbb-tableWrap" }, (0, react.createElement)("table", { className: "pbb-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, translateWith(props.t, "devices.col.name")), (0, react.createElement)("th", null, translateWith(props.t, "devices.col.lastSeen")), (0, react.createElement)("th", { className: "pbb-tableActionHead" }, translateWith(props.t, "devices.col.actions")))), (0, react.createElement)("tbody", null, visibleDevices$1.map((d) => {
|
|
4110
4411
|
const editing = editingDeviceId === d.deviceId;
|
|
4111
4412
|
const busy = deviceBusy === d.deviceId;
|
|
4112
|
-
const label = deviceLabel(d);
|
|
4413
|
+
const label = deviceLabel$1(d);
|
|
4113
4414
|
return (0, react.createElement)("tr", {
|
|
4114
4415
|
key: d.deviceId,
|
|
4115
4416
|
"aria-busy": busy
|
|
@@ -4154,10 +4455,10 @@ window.__ModuleLoader__.load({
|
|
|
4154
4455
|
title: translateWith(props.t, "devices.nameCancel"),
|
|
4155
4456
|
"aria-label": translateWith(props.t, "devices.nameCancel"),
|
|
4156
4457
|
onClick: cancelDeviceRename
|
|
4157
|
-
}, CloseIcon()))), deviceNameDraft.length > 64 ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "devices.nameInvalid")) : null) : (0, react.createElement)("div", null, (0, react.createElement)("div", { className: "pbb-deviceNameRow" }, (0, react.createElement)("span", { className: "pbb-deviceName" }, label), d.customName ? (0, react.createElement)("span", { className: "pbb-badge" }, translateWith(props.t, "devices.customBadge")) : null), (0, react.createElement)("span", { className: "pbb-deviceMeta" }, d.appVersion, " · ", (0, react.createElement)("code", null, d.fingerprint.slice(0, 12))))), (0, react.createElement)("td", { className: "pbb-lastSeen" }, new Date(d.lastSeenTs).toLocaleString()), (0, react.createElement)("td", { className: "pbb-tableActionCell" }, !editing ? (0, react.createElement)("button", {
|
|
4458
|
+
}, CloseIcon()))), deviceNameDraft.length > 64 ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "devices.nameInvalid")) : null) : (0, react.createElement)("div", null, (0, react.createElement)("div", { className: "pbb-deviceNameRow" }, (0, react.createElement)("span", { className: "pbb-deviceName" }, label), d.customName ? (0, react.createElement)("span", { className: "pbb-badge" }, translateWith(props.t, "devices.customBadge")) : null), (0, react.createElement)("span", { className: "pbb-deviceMeta" }, d.appVersion, " · ", (0, react.createElement)("code", null, (d.fingerprint ?? "").slice(0, 12))))), (0, react.createElement)("td", { className: "pbb-lastSeen" }, new Date(d.lastSeenTs ?? 0).toLocaleString()), (0, react.createElement)("td", { className: "pbb-tableActionCell" }, !editing ? (0, react.createElement)("button", {
|
|
4158
4459
|
type: "button",
|
|
4159
4460
|
className: "pbb-action",
|
|
4160
|
-
disabled: busy || editingDeviceId !== null ||
|
|
4461
|
+
disabled: busy || editingDeviceId !== null || !can("setDeviceName"),
|
|
4161
4462
|
"aria-label": translateWith(props.t, "devices.renameAria", { name: label }),
|
|
4162
4463
|
onClick: () => beginDeviceRename(d)
|
|
4163
4464
|
}, translateWith(props.t, "devices.rename")) : null, (0, react.createElement)("button", {
|
|
@@ -4172,34 +4473,21 @@ window.__ModuleLoader__.load({
|
|
|
4172
4473
|
const switchDesc = switchReady ? enabled ? translateWith(props.t, "master.on") : translateWith(props.t, "master.off") : translateWith(props.t, "master.loading");
|
|
4173
4474
|
const localMeta = report === null ? null : LOCAL_PHASE_META[report.local.phase];
|
|
4174
4475
|
const remoteMeta = report === null ? null : REMOTE_PHASE_META[report.remote.phase];
|
|
4175
|
-
const
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
className: "pbb-dot" + dot,
|
|
4184
|
-
role: "img",
|
|
4185
|
-
"aria-label": statusLabel,
|
|
4186
|
-
title: statusLabel
|
|
4187
|
-
}), title), (0, react.createElement)("button", {
|
|
4188
|
-
type: "button",
|
|
4189
|
-
role: "switch",
|
|
4190
|
-
"aria-checked": checked,
|
|
4191
|
-
"aria-label": title,
|
|
4192
|
-
disabled: !ready,
|
|
4193
|
-
className: "pbb-switch" + (checked ? " pbb-switchOn" : ""),
|
|
4194
|
-
onClick: onToggle
|
|
4195
|
-
})), (0, react.createElement)("span", { className: "pbb-connectionState" }, statusLabel), (0, react.createElement)("p", { className: "pbb-connectionDescription" }, description), extra);
|
|
4476
|
+
const service = serviceStatus({
|
|
4477
|
+
enabled,
|
|
4478
|
+
switchReady,
|
|
4479
|
+
localDot: localMeta?.dot,
|
|
4480
|
+
remoteDot: remoteMeta?.dot
|
|
4481
|
+
});
|
|
4482
|
+
const serviceStatusText = translateWith(props.t, SERVICE_STATUS_KEY[service.kind]);
|
|
4483
|
+
const serviceDot = service.dot;
|
|
4196
4484
|
return (0, react.createElement)("div", { className: "pbb-section" }, (0, react.createElement)("header", { className: "pbb-pageHeader" }, (0, react.createElement)("div", null, (0, react.createElement)("h2", { className: "pbb-title" }, "DeepPilot"), (0, react.createElement)("p", { className: "pbb-intro" }, translateWith(props.t, "meta.intro"))), (0, react.createElement)("button", {
|
|
4197
4485
|
type: "button",
|
|
4198
4486
|
className: "pbb-refresh",
|
|
4199
4487
|
onClick: () => {
|
|
4200
|
-
if (
|
|
4488
|
+
if (can("refresh")) props.refresh();
|
|
4201
4489
|
}
|
|
4202
|
-
}, translateWith(props.t, "meta.refresh"))), (0, react.createElement)("div", { className: "pbb-card pbb-primaryCard" }, (0, react.createElement)("div", { className: "pbb-cardHeader" }, (0, react.createElement)("div", null, (0, react.createElement)("h3", { className: "pbb-cardTitle" }, translateWith(props.t, "connection.title")), (0, react.createElement)("p", { className: "pbb-cardDescription" }, translateWith(props.t, "connection.description"))), (0, react.createElement)("span", { className: "pbb-statusBadge" }, (0, react.createElement)("span", { className: "pbb-dot" + serviceDot }),
|
|
4490
|
+
}, translateWith(props.t, "meta.refresh"))), (0, react.createElement)("div", { className: "pbb-card pbb-primaryCard" }, (0, react.createElement)("div", { className: "pbb-cardHeader" }, (0, react.createElement)("div", null, (0, react.createElement)("h3", { className: "pbb-cardTitle" }, translateWith(props.t, "connection.title")), (0, react.createElement)("p", { className: "pbb-cardDescription" }, translateWith(props.t, "connection.description"))), (0, react.createElement)("span", { className: "pbb-statusBadge" }, (0, react.createElement)("span", { className: "pbb-dot" + serviceDot }), serviceStatusText)), (0, react.createElement)("div", { className: "pbb-masterRow" }, (0, react.createElement)("div", { className: "pbb-switchText" }, (0, react.createElement)("span", { className: "pbb-switchTitle" }, switchTitle), (0, react.createElement)("span", { className: "pbb-switchDesc" }, switchDesc)), (0, react.createElement)("button", {
|
|
4203
4491
|
type: "button",
|
|
4204
4492
|
role: "switch",
|
|
4205
4493
|
"aria-checked": enabled,
|
|
@@ -4207,12 +4495,12 @@ window.__ModuleLoader__.load({
|
|
|
4207
4495
|
disabled: !switchReady,
|
|
4208
4496
|
className: "pbb-switch" + (enabled ? " pbb-switchOn" : ""),
|
|
4209
4497
|
onClick: () => {
|
|
4210
|
-
if (
|
|
4498
|
+
if (can("setEnabled")) props.setDeepPilotEnabled(!enabled);
|
|
4211
4499
|
}
|
|
4212
|
-
})), (0, react.createElement)("div", { className: "pbb-connectionGrid" }, renderConnectionTile("local", translateWith(props.t, "local.title"), localSwitchReady ? localEnabled ? translateWith(props.t, "local.on", { port: localPort }) : translateWith(props.t, "local.off") : translateWith(props.t, "master.loading"), localEnabled, localSwitchReady, localMeta?.dot ?? "", localMeta === null ? translateWith(props.t, "phase.unknown") : translateWith(props.t, localMeta.
|
|
4213
|
-
if (
|
|
4214
|
-
}, (0, react.createElement)(react.Fragment, null, report !== null && report.local.message && report.local.phase === "error" ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, report.local.message) : null, report !== null && report.local.tlsIdentityRegenerated === true ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "local.tlsRegenerated")) : null)), renderConnectionTile("remote", translateWith(props.t, "remote.title"), remoteSwitchReady ? remoteEnabled ? translateWith(props.t, "remote.on") : translateWith(props.t, "remote.off") : translateWith(props.t, "master.loading"), remoteEnabled, remoteSwitchReady, remoteMeta?.dot ?? "", remoteMeta === null ? translateWith(props.t, "phase.unknown") : translateWith(props.t, remoteMeta.
|
|
4215
|
-
if (
|
|
4500
|
+
})), (0, react.createElement)("div", { className: "pbb-connectionGrid" }, renderConnectionTile("local", translateWith(props.t, "local.title"), localSwitchReady ? localEnabled ? translateWith(props.t, "local.on", { port: localPort }) : translateWith(props.t, "local.off") : translateWith(props.t, "master.loading"), localEnabled, localSwitchReady, localMeta?.dot ?? "", localMeta === null ? translateWith(props.t, "phase.unknown") : translateWith(props.t, LOCAL_LABEL_KEY[localMeta.label]), () => {
|
|
4501
|
+
if (can("setLocalEnabled")) props.setDeepPilotLocalEnabled(!localEnabled);
|
|
4502
|
+
}, (0, react.createElement)(react.Fragment, null, report !== null && report.local.message && report.local.phase === "error" ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, report.local.message) : null, report !== null && report.local.tlsIdentityRegenerated === true ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "local.tlsRegenerated")) : null)), renderConnectionTile("remote", translateWith(props.t, "remote.title"), remoteSwitchReady ? remoteEnabled ? translateWith(props.t, "remote.on") : translateWith(props.t, "remote.off") : translateWith(props.t, "master.loading"), remoteEnabled, remoteSwitchReady, remoteMeta?.dot ?? "", remoteMeta === null ? translateWith(props.t, "phase.unknown") : translateWith(props.t, REMOTE_LABEL_KEY[remoteMeta.label]), () => {
|
|
4503
|
+
if (can("setRemoteEnabled")) props.setDeepPilotRemoteEnabled(!remoteEnabled);
|
|
4216
4504
|
}, (0, react.createElement)(react.Fragment, null, report !== null && report.remote.phase === "login_required" && typeof report.remote.authURL === "string" && report.remote.authURL.startsWith("https://") ? (0, react.createElement)("div", { className: "pbb-rowAction" }, (0, react.createElement)("a", {
|
|
4217
4505
|
className: "pbb-action pbb-buttonPrimary",
|
|
4218
4506
|
href: report.remote.authURL,
|
|
@@ -4221,18 +4509,21 @@ window.__ModuleLoader__.load({
|
|
|
4221
4509
|
}, translateWith(props.t, "remote.openAuth"))) : null, report !== null && report.remote.message && (report.remote.phase === "error" || report.remote.phase === "unavailable") ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, report.remote.message) : null))), report === null ? null : (0, react.createElement)("div", { className: "pbb-statGrid" }, primaryRows), (0, react.createElement)("details", { className: "pbb-inlineDetails" }, (0, react.createElement)("summary", null, translateWith(props.t, "connection.optionsSummary")), (0, react.createElement)("div", { className: "pbb-helpBody" }, (0, react.createElement)("div", { className: "pbb-limitRow pbb-limitNested" }, (0, react.createElement)("div", { className: "pbb-switchText" }, (0, react.createElement)("label", {
|
|
4222
4510
|
className: "pbb-switchTitle",
|
|
4223
4511
|
htmlFor: "deeppilot-local-port"
|
|
4224
|
-
}, translateWith(props.t, "local.portTitle")), (0, react.createElement)("span", { className: "pbb-switchDesc" }, translateWith(props.t, "local.portDescription")), !
|
|
4512
|
+
}, translateWith(props.t, "local.portTitle")), (0, react.createElement)("span", { className: "pbb-switchDesc" }, translateWith(props.t, "local.portDescription")), !localPortView.valid ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "local.portInvalid")) : localPortDraft.message ? (0, react.createElement)("p", { className: "pbb-diag" + (localPortDraft.failed ? " pbb-diagBad" : "") }, localPortDraft.message) : null), (0, react.createElement)("div", { className: "pbb-limitControl" }, (0, react.createElement)("input", {
|
|
4225
4513
|
id: "deeppilot-local-port",
|
|
4226
4514
|
className: "pbb-numberInput",
|
|
4227
4515
|
type: "number",
|
|
4228
|
-
min:
|
|
4229
|
-
max:
|
|
4516
|
+
min: LOCAL_PORT_RANGE.min,
|
|
4517
|
+
max: LOCAL_PORT_RANGE.max,
|
|
4230
4518
|
step: 1,
|
|
4231
4519
|
inputMode: "numeric",
|
|
4232
|
-
value: localPortDraft,
|
|
4520
|
+
value: localPortDraft.draft,
|
|
4233
4521
|
disabled: !localPortReady,
|
|
4234
4522
|
"aria-label": translateWith(props.t, "local.portTitle"),
|
|
4235
|
-
onChange: (event) =>
|
|
4523
|
+
onChange: (event) => dispatchLocalPortDraft({
|
|
4524
|
+
type: "edit",
|
|
4525
|
+
draft: event.currentTarget.value
|
|
4526
|
+
}),
|
|
4236
4527
|
onKeyDown: (event) => {
|
|
4237
4528
|
if (event.key === "Enter") {
|
|
4238
4529
|
event.preventDefault();
|
|
@@ -4242,23 +4533,26 @@ window.__ModuleLoader__.load({
|
|
|
4242
4533
|
}), (0, react.createElement)("button", {
|
|
4243
4534
|
type: "button",
|
|
4244
4535
|
className: "pbb-action",
|
|
4245
|
-
disabled: !localPortReady || !
|
|
4536
|
+
disabled: !localPortReady || !localPortView.valid || localPortView.unchanged,
|
|
4246
4537
|
onClick: applyLocalPort
|
|
4247
4538
|
}, translateWith(props.t, "remote.limitApply")))), (0, react.createElement)("div", { className: "pbb-limitRow pbb-limitNested" }, (0, react.createElement)("div", { className: "pbb-switchText" }, (0, react.createElement)("label", {
|
|
4248
4539
|
className: "pbb-switchTitle",
|
|
4249
4540
|
htmlFor: "deeppilot-funnel-source-limit"
|
|
4250
|
-
}, translateWith(props.t, "remote.limitTitle")), (0, react.createElement)("span", { className: "pbb-switchDesc" }, translateWith(props.t, "remote.limitDescription")), !
|
|
4541
|
+
}, translateWith(props.t, "remote.limitTitle")), (0, react.createElement)("span", { className: "pbb-switchDesc" }, translateWith(props.t, "remote.limitDescription")), !remoteLimitView.valid ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, translateWith(props.t, "remote.limitInvalid")) : remoteLimitDraft.message ? (0, react.createElement)("p", { className: "pbb-diag" + (remoteLimitDraft.failed ? " pbb-diagBad" : "") }, remoteLimitDraft.message) : null), (0, react.createElement)("div", { className: "pbb-limitControl" }, (0, react.createElement)("input", {
|
|
4251
4542
|
id: "deeppilot-funnel-source-limit",
|
|
4252
4543
|
className: "pbb-numberInput",
|
|
4253
4544
|
type: "number",
|
|
4254
4545
|
min: 1,
|
|
4255
|
-
max:
|
|
4546
|
+
max: REMOTE_LIMIT_RANGE.max,
|
|
4256
4547
|
step: 1,
|
|
4257
4548
|
inputMode: "numeric",
|
|
4258
|
-
value: remoteLimitDraft,
|
|
4549
|
+
value: remoteLimitDraft.draft,
|
|
4259
4550
|
disabled: !remoteConnectionLimitReady,
|
|
4260
4551
|
"aria-label": translateWith(props.t, "remote.limitTitle"),
|
|
4261
|
-
onChange: (event) =>
|
|
4552
|
+
onChange: (event) => dispatchRemoteLimitDraft({
|
|
4553
|
+
type: "edit",
|
|
4554
|
+
draft: event.currentTarget.value
|
|
4555
|
+
}),
|
|
4262
4556
|
onKeyDown: (event) => {
|
|
4263
4557
|
if (event.key === "Enter") {
|
|
4264
4558
|
event.preventDefault();
|
|
@@ -4268,7 +4562,7 @@ window.__ModuleLoader__.load({
|
|
|
4268
4562
|
}), (0, react.createElement)("button", {
|
|
4269
4563
|
type: "button",
|
|
4270
4564
|
className: "pbb-action",
|
|
4271
|
-
disabled: !remoteConnectionLimitReady || !
|
|
4565
|
+
disabled: !remoteConnectionLimitReady || !remoteLimitView.valid || remoteLimitView.unchanged,
|
|
4272
4566
|
onClick: applyRemoteLimit
|
|
4273
4567
|
}, translateWith(props.t, "remote.limitApply")))))), (0, react.createElement)("details", { className: "pbb-help" }, (0, react.createElement)("summary", null, translateWith(props.t, "help.remoteTitle")), (0, react.createElement)("div", { className: "pbb-helpBody" }, (0, react.createElement)("div", { className: "pbb-helpSection" }, (0, react.createElement)("div", { className: "pbb-helpHeading" }, translateWith(props.t, "help.recommended")), (0, react.createElement)("ol", { className: "pbb-helpList" }, (0, react.createElement)("li", null, translateWith(props.t, "help.step1")), (0, react.createElement)("li", null, translateWith(props.t, "help.step2")), (0, react.createElement)("li", null, translateWith(props.t, "help.step3")), (0, react.createElement)("li", null, translateWith(props.t, "help.step4"))), (0, react.createElement)("p", { className: "pbb-helpText" }, translateWith(props.t, "help.funnelHint"))), (0, react.createElement)("div", { className: "pbb-helpSection" }, (0, react.createElement)("div", { className: "pbb-helpHeading" }, translateWith(props.t, "help.httpsTitle")), (0, react.createElement)("ol", { className: "pbb-helpList" }, (0, react.createElement)("li", null, translateWith(props.t, "help.httpsStep1")), (0, react.createElement)("li", null, translateWith(props.t, "help.httpsStep2")), (0, react.createElement)("li", null, translateWith(props.t, "help.httpsStep3"))), (0, react.createElement)("p", { className: "pbb-helpText" }, translateWith(props.t, "help.httpsHint"))), (0, react.createElement)("div", { className: "pbb-helpSection" }, (0, react.createElement)("div", { className: "pbb-helpHeading" }, translateWith(props.t, "help.allowTitle")), (0, react.createElement)("p", { className: "pbb-helpText" }, translateWith(props.t, "help.allowBody")), (0, react.createElement)("code", { className: "pbb-helpCode" }, "\"nodeAttrs\": [\n {\n \"target\": [\"autogroup:member\"],\n \"attr\": [\"funnel\"],\n },\n],"), (0, react.createElement)("p", { className: "pbb-helpText" }, translateWith(props.t, "help.allowHint"))), (0, react.createElement)("div", { className: "pbb-helpSection" }, (0, react.createElement)("div", { className: "pbb-helpHeading" }, translateWith(props.t, "help.faqTitle")), (0, react.createElement)("ul", { className: "pbb-helpList" }, (0, react.createElement)("li", null, translateWith(props.t, "help.faq1")), (0, react.createElement)("li", null, translateWith(props.t, "help.faq2")), (0, react.createElement)("li", null, translateWith(props.t, "help.faq3")), (0, react.createElement)("li", null, translateWith(props.t, "help.faq4")))), (0, react.createElement)("div", { className: "pbb-helpSection" }, (0, react.createElement)("div", { className: "pbb-helpHeading" }, translateWith(props.t, "help.securityTitle")), (0, react.createElement)("ul", { className: "pbb-helpList" }, (0, react.createElement)("li", null, translateWith(props.t, "help.security1")), (0, react.createElement)("li", null, translateWith(props.t, "help.security2")), (0, react.createElement)("li", null, translateWith(props.t, "help.security3")), (0, react.createElement)("li", null, translateWith(props.t, "help.security4")), (0, react.createElement)("li", null, translateWith(props.t, "help.security5"))), (0, react.createElement)("p", { className: "pbb-helpText" }, translateWith(props.t, "help.docsPrefix"), (0, react.createElement)("a", {
|
|
4274
4568
|
className: "pbb-helpLink",
|
|
@@ -4307,7 +4601,7 @@ window.__ModuleLoader__.load({
|
|
|
4307
4601
|
className: "pbb-action pbb-buttonPrimary",
|
|
4308
4602
|
onClick: copyPairingInfo,
|
|
4309
4603
|
"data-testid": "pairingInfoCopy"
|
|
4310
|
-
}, translateWith(props.t, "panel.tokenAction.copy")))), (0, react.createElement)("p", { className: "pbb-qrHint" }, translateWith(props.t, "pair.qrHint", { kind: panel.target?.kind === "public" ? translateWith(props.t, "pair.kind.public") : translateWith(props.t, "pair.kind.lan") }))) : null)), (0, react.createElement)("div", { className: "pbb-card" }, (0, react.createElement)("div", { className: "pbb-cardHeader" }, (0, react.createElement)("div", null, (0, react.createElement)("h3", { className: "pbb-cardTitle" }, translateWith(props.t, "devices.title")), (0, react.createElement)("p", { className: "pbb-cardDescription" }, translateWith(props.t, "devices.description"))), (0, react.createElement)("span", { className: "pbb-countBadge" }, String(visibleDevices.length))), (0, react.createElement)("div", { className: "pbb-cardBody" }, deviceMessage ? (0, react.createElement)("p", { className: "pbb-diag" + (deviceMessage.startsWith(translateWith(props.t, "devices.renameFailed")) || deviceMessage.startsWith(translateWith(props.t, "devices.revokeFailed")) ? " pbb-diagBad" : "") }, deviceMessage) : null, deviceTable)), (0, react.createElement)("details", {
|
|
4604
|
+
}, translateWith(props.t, "panel.tokenAction.copy")))), (0, react.createElement)("p", { className: "pbb-qrHint" }, translateWith(props.t, "pair.qrHint", { kind: panel.target?.kind === "public" ? translateWith(props.t, "pair.kind.public") : translateWith(props.t, "pair.kind.lan") }))) : null)), (0, react.createElement)("div", { className: "pbb-card" }, (0, react.createElement)("div", { className: "pbb-cardHeader" }, (0, react.createElement)("div", null, (0, react.createElement)("h3", { className: "pbb-cardTitle" }, translateWith(props.t, "devices.title")), (0, react.createElement)("p", { className: "pbb-cardDescription" }, translateWith(props.t, "devices.description"))), (0, react.createElement)("span", { className: "pbb-countBadge" }, String(visibleDevices$1.length))), (0, react.createElement)("div", { className: "pbb-cardBody" }, deviceMessage ? (0, react.createElement)("p", { className: "pbb-diag" + (deviceMessage.startsWith(translateWith(props.t, "devices.renameFailed")) || deviceMessage.startsWith(translateWith(props.t, "devices.revokeFailed")) ? " pbb-diagBad" : "") }, deviceMessage) : null, deviceTable)), (0, react.createElement)("details", {
|
|
4311
4605
|
className: "pbb-card pbb-disclosure",
|
|
4312
4606
|
open: troubleshootingOpen,
|
|
4313
4607
|
onToggle: (event) => setTroubleshootingOpen(event.currentTarget.open)
|
|
@@ -4321,7 +4615,17 @@ window.__ModuleLoader__.load({
|
|
|
4321
4615
|
className: "pbb-action",
|
|
4322
4616
|
disabled: pushTestBusy,
|
|
4323
4617
|
onClick: sendPushTest
|
|
4324
|
-
}, pushTestBusy ? translateWith(props.t, "push.pushSending") : translateWith(props.t, "push.testPush")))
|
|
4618
|
+
}, pushTestBusy ? translateWith(props.t, "push.pushSending") : translateWith(props.t, "push.testPush"))), (0, react.createElement)("div", { className: "pbb-testItem" }, (0, react.createElement)("div", { className: "pbb-switchText" }, (0, react.createElement)("span", { className: "pbb-testTitle" }, translateWith(props.t, "troubleshooting.debugTitle")), (0, react.createElement)("span", { className: "pbb-testDescription" }, translateWith(props.t, "troubleshooting.debugDescription"))), (0, react.createElement)("button", {
|
|
4619
|
+
type: "button",
|
|
4620
|
+
role: "switch",
|
|
4621
|
+
"aria-checked": debugEnabled,
|
|
4622
|
+
"aria-label": translateWith(props.t, "troubleshooting.debugTitle"),
|
|
4623
|
+
disabled: !debugSwitchReady,
|
|
4624
|
+
className: "pbb-switch" + (debugEnabled ? " pbb-switchOn" : ""),
|
|
4625
|
+
onClick: () => {
|
|
4626
|
+
if (can("setDebug")) props.setDeepPilotDebug(!debugEnabled);
|
|
4627
|
+
}
|
|
4628
|
+
}))), relayTestError ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, relayTestError) : null, relayTestResult === null ? (0, react.createElement)("p", { className: "pbb-diag" }, translateWith(props.t, "push.relayDefault")) : (0, react.createElement)("div", { className: "pbb-helpBody" }, (0, react.createElement)("div", { className: "pbb-row" }, (0, react.createElement)("span", { className: "pbb-label" }, relayTestResult.url || translateWith(props.t, "push.relayUrlEmpty")), (0, react.createElement)("code", { className: "pbb-token " + (relayTestResult.overall === "ok" ? "pbb-ok" : "pbb-bad") }, relayTestResult.overall === "ok" ? translateWith(props.t, "push.relayOk") : translateWith(props.t, "push.relayBad"))), relayTestResult.steps.map((step, index) => (0, react.createElement)("p", {
|
|
4325
4629
|
className: "pbb-diag",
|
|
4326
4630
|
key: String(index)
|
|
4327
4631
|
}, (step.ok ? "✓ " : "✗ ") + (step.id === "health" ? translateWith(props.t, "push.relayStep.health") : translateWith(props.t, "push.relayStep.enroll")) + (step.latencyMs !== void 0 ? ` (${String(step.latencyMs)}ms)` : "") + " — " + step.message))), pushTestError ? (0, react.createElement)("p", { className: "pbb-diag pbb-diagBad" }, pushTestError) : null, pushTestResult === null ? (0, react.createElement)("p", { className: "pbb-diag" }, translateWith(props.t, "push.pushDefault")) : (0, react.createElement)("div", { className: "pbb-helpBody" }, (0, react.createElement)("div", { className: "pbb-row" }, (0, react.createElement)("code", { className: "pbb-token " + (pushTestResult.overall === "sent" ? "pbb-ok" : pushTestResult.overall === "failed" ? "pbb-bad" : "") }, pushTestResult.overall === "sent" ? translateWith(props.t, "push.pushSent") : pushTestResult.overall === "failed" ? translateWith(props.t, "push.pushFailed") : pushTestResult.overall === "no-targets" ? translateWith(props.t, "push.pushNoTargets") : translateWith(props.t, "push.pushNotEnabled"))), pushTestResult.message ? (0, react.createElement)("p", { className: "pbb-diag" }, pushTestResult.message) : null, pushTestResult.results.map((r, index) => (0, react.createElement)("p", {
|
|
@@ -4671,6 +4975,47 @@ window.__ModuleLoader__.load({
|
|
|
4671
4975
|
throw error;
|
|
4672
4976
|
}
|
|
4673
4977
|
};
|
|
4978
|
+
const debugStore = createSnapshotStore({
|
|
4979
|
+
status: "loading",
|
|
4980
|
+
enabled: false
|
|
4981
|
+
});
|
|
4982
|
+
const adoptDebug = () => {
|
|
4983
|
+
if (scope === void 0) return;
|
|
4984
|
+
const snap = scope.getSnapshot();
|
|
4985
|
+
if (snap.status === "ready") debugStore.set({
|
|
4986
|
+
status: "ready",
|
|
4987
|
+
enabled: snap.value?.diagnostics?.debug === true
|
|
4988
|
+
});
|
|
4989
|
+
else if (snap.status === "unavailable") debugStore.set({
|
|
4990
|
+
status: "unavailable",
|
|
4991
|
+
enabled: false
|
|
4992
|
+
});
|
|
4993
|
+
};
|
|
4994
|
+
scopeAdoptions.push(adoptDebug);
|
|
4995
|
+
const lastConfirmedDebug = () => {
|
|
4996
|
+
const snap = scope?.getSnapshot();
|
|
4997
|
+
if (snap?.status === "ready") return snap.value?.diagnostics?.debug === true;
|
|
4998
|
+
return debugStore.getSnapshot().enabled;
|
|
4999
|
+
};
|
|
5000
|
+
const setDeepPilotDebug = (value) => {
|
|
5001
|
+
const previous = lastConfirmedDebug();
|
|
5002
|
+
debugStore.set({
|
|
5003
|
+
status: "ready",
|
|
5004
|
+
enabled: value
|
|
5005
|
+
});
|
|
5006
|
+
if (scope === void 0) return;
|
|
5007
|
+
const currentDiagnostics = scope.getSnapshot().value?.diagnostics ?? {};
|
|
5008
|
+
scope.set("diagnostics", {
|
|
5009
|
+
...currentDiagnostics,
|
|
5010
|
+
debug: value
|
|
5011
|
+
}).then(() => {}, (error) => {
|
|
5012
|
+
debugStore.set({
|
|
5013
|
+
status: "ready",
|
|
5014
|
+
enabled: previous
|
|
5015
|
+
});
|
|
5016
|
+
console.error("[deeppilot] failed to persist diagnostics.debug=" + String(value) + ": " + (error instanceof Error ? error.message : String(error)));
|
|
5017
|
+
});
|
|
5018
|
+
};
|
|
4674
5019
|
const remoteEnabledStore = createSnapshotStore({
|
|
4675
5020
|
status: "loading",
|
|
4676
5021
|
enabled: false
|
|
@@ -4783,7 +5128,8 @@ window.__ModuleLoader__.load({
|
|
|
4783
5128
|
deepPilotLocalEnabled: localEnabledStore,
|
|
4784
5129
|
deepPilotLocalPort: localPortStore,
|
|
4785
5130
|
deepPilotRemoteEnabled: remoteEnabledStore,
|
|
4786
|
-
deepPilotRemoteConnectionLimit: remoteConnectionLimitStore
|
|
5131
|
+
deepPilotRemoteConnectionLimit: remoteConnectionLimitStore,
|
|
5132
|
+
deepPilotDebug: debugStore
|
|
4787
5133
|
},
|
|
4788
5134
|
refresh: () => {
|
|
4789
5135
|
controller.refresh();
|
|
@@ -4798,6 +5144,7 @@ window.__ModuleLoader__.load({
|
|
|
4798
5144
|
setDeepPilotLocalPort,
|
|
4799
5145
|
setDeepPilotRemoteEnabled,
|
|
4800
5146
|
setDeepPilotRemoteConnectionLimit,
|
|
5147
|
+
setDeepPilotDebug,
|
|
4801
5148
|
t: (key, vars) => t(ctx, key, vars)
|
|
4802
5149
|
})
|
|
4803
5150
|
}, DeepPilotSettingsPage));
|