dsh-config-manager 0.1.36 → 0.1.37
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/lib/client.js +221 -220
- package/lib/client.js.map +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
- package/src/client/market/MarketPanel.tsx +16 -11
- package/src/client/run-store.test.ts +7 -0
- package/src/client/run-store.ts +29 -6
- package/src/client/snapshots/SnapshotsPanel.tsx +28 -22
- package/src/client/sync/SyncSettingsView.tsx +63 -60
- package/src/index.ts +1 -1
package/lib/client.js
CHANGED
|
@@ -2209,6 +2209,8 @@ function defaultSyncState() {
|
|
|
2209
2209
|
git: defaultChannelSyncState(),
|
|
2210
2210
|
webdav: defaultChannelSyncState()
|
|
2211
2211
|
},
|
|
2212
|
+
busy: null,
|
|
2213
|
+
savingConfig: false,
|
|
2212
2214
|
pushReport: null,
|
|
2213
2215
|
pullReport: null,
|
|
2214
2216
|
confirmSession: null,
|
|
@@ -2252,8 +2254,9 @@ function defaultState() {
|
|
|
2252
2254
|
}
|
|
2253
2255
|
/**
|
|
2254
2256
|
* 从视图状态提取同步切片(结构兼容:传入 SyncUiState 亦可;只保留切片字段,
|
|
2255
|
-
* github 流程态/loading/
|
|
2256
|
-
*
|
|
2257
|
+
* github 流程态/loading 等瞬态不进入切片;busy/savingConfig 为「内存切片」瞬态——
|
|
2258
|
+
* 切 tab 由模块级单例保留,刷新时被 toPersistedState 白名单剔除)。组件每次状态
|
|
2259
|
+
* 变化后(含异步回调)调用,把非敏感 + 仅内存字段镜像进 store。
|
|
2257
2260
|
* byChannel 的快照数组复制引用(避免跨切片共享可变数组)。
|
|
2258
2261
|
*/
|
|
2259
2262
|
function toSyncStoreSlice(s) {
|
|
@@ -2274,6 +2277,8 @@ function toSyncStoreSlice(s) {
|
|
|
2274
2277
|
snapshots: [...s.byChannel.webdav.snapshots]
|
|
2275
2278
|
}
|
|
2276
2279
|
},
|
|
2280
|
+
busy: s.busy,
|
|
2281
|
+
savingConfig: s.savingConfig,
|
|
2277
2282
|
pushReport: s.pushReport,
|
|
2278
2283
|
pullReport: s.pullReport,
|
|
2279
2284
|
confirmSession: s.confirmSession,
|
|
@@ -2309,13 +2314,14 @@ function toSnapshotsStoreSlice(s) {
|
|
|
2309
2314
|
* 持久化白名单:解构剔除敏感字段(password/passwordConfirm/secretInputs/decryptPassword)
|
|
2310
2315
|
* 与不可序列化的实例字段(conflictCollector),以及同步面板的凭据字段
|
|
2311
2316
|
* (token/webdavPassword/encryptPassword/encryptPasswordConfirm/decryptPassword ——
|
|
2312
|
-
* 含 byChannel
|
|
2317
|
+
* 含 byChannel 内每通道的加密/解密密码)与瞬态字段(busy/savingConfig —— 刷新后
|
|
2318
|
+
* 回复空闲,不把「进行中」状态带到新页面),其余原样落入 sessionStorage。
|
|
2313
2319
|
* 这是 sessionStorage 的唯一写入路径 —— 敏感值在此被硬性隔离。
|
|
2314
2320
|
*/
|
|
2315
2321
|
function toPersistedState(state) {
|
|
2316
2322
|
const { password: _password, passwordConfirm: _passwordConfirm, ...exportRest } = state.export;
|
|
2317
2323
|
const { secretInputs: _secretInputs, decryptPassword: _decryptPassword, decryptRefs: _decryptRefs, archiveUnlocked: _archiveUnlocked, conflictCollector: _conflictCollector, ...importRest } = state.import;
|
|
2318
|
-
const { token: _token, webdavPassword: _webdavPassword, ...syncRest } = state.sync;
|
|
2324
|
+
const { token: _token, webdavPassword: _webdavPassword, busy: _busy, savingConfig: _savingConfig, ...syncRest } = state.sync;
|
|
2319
2325
|
const stripChannelSensitive = (c) => {
|
|
2320
2326
|
const { encryptPassword: _ep, encryptPasswordConfirm: _epc, decryptPassword: _dp, ...rest } = c;
|
|
2321
2327
|
return rest;
|
|
@@ -2586,6 +2592,8 @@ var RunStore = class {
|
|
|
2586
2592
|
...parsed.sync,
|
|
2587
2593
|
token: "",
|
|
2588
2594
|
webdavPassword: "",
|
|
2595
|
+
busy: null,
|
|
2596
|
+
savingConfig: false,
|
|
2589
2597
|
byChannel: {
|
|
2590
2598
|
git: {
|
|
2591
2599
|
...defaultChannelSyncState(),
|
|
@@ -2898,111 +2906,111 @@ if (typeof document !== "undefined" && document.querySelector("style[data-tag=\"
|
|
|
2898
2906
|
document.head.appendChild(tag);
|
|
2899
2907
|
}
|
|
2900
2908
|
var config_manager_module_css_default = {
|
|
2909
|
+
"dangerButton": "_367UGW_dangerButton",
|
|
2901
2910
|
"errorAction": "_367UGW_errorAction",
|
|
2902
|
-
"
|
|
2903
|
-
"
|
|
2911
|
+
"planScroll": "_367UGW_planScroll",
|
|
2912
|
+
"badgeOk": "_367UGW_badgeOk",
|
|
2913
|
+
"dshCmIndeterminate": "_367UGW_dshCmIndeterminate",
|
|
2914
|
+
"viewBody": "_367UGW_viewBody",
|
|
2915
|
+
"progressTrack": "_367UGW_progressTrack",
|
|
2916
|
+
"reportView": "_367UGW_reportView",
|
|
2917
|
+
"severityError": "_367UGW_severityError",
|
|
2918
|
+
"progressBadge": "_367UGW_progressBadge",
|
|
2919
|
+
"conflictHead": "_367UGW_conflictHead",
|
|
2920
|
+
"categoryName": "_367UGW_categoryName",
|
|
2921
|
+
"errorTitle": "_367UGW_errorTitle",
|
|
2922
|
+
"banner": "_367UGW_banner",
|
|
2923
|
+
"pathNew": "_367UGW_pathNew",
|
|
2924
|
+
"warnText": "_367UGW_warnText",
|
|
2925
|
+
"kindTag": "_367UGW_kindTag",
|
|
2926
|
+
"pathOld": "_367UGW_pathOld",
|
|
2927
|
+
"section": "_367UGW_section",
|
|
2928
|
+
"sectionTitle": "_367UGW_sectionTitle",
|
|
2929
|
+
"modeTab": "_367UGW_modeTab",
|
|
2930
|
+
"progressMeta": "_367UGW_progressMeta",
|
|
2931
|
+
"categoryDesc": "_367UGW_categoryDesc",
|
|
2932
|
+
"conflictId": "_367UGW_conflictId",
|
|
2933
|
+
"primaryButton": "_367UGW_primaryButton",
|
|
2934
|
+
"pathMappingList": "_367UGW_pathMappingList",
|
|
2935
|
+
"pathRow": "_367UGW_pathRow",
|
|
2936
|
+
"diffScroll": "_367UGW_diffScroll",
|
|
2937
|
+
"input": "_367UGW_input",
|
|
2938
|
+
"errorFooter": "_367UGW_errorFooter",
|
|
2939
|
+
"pullScroll": "_367UGW_pullScroll",
|
|
2940
|
+
"reportFooter": "_367UGW_reportFooter",
|
|
2941
|
+
"badge": "_367UGW_badge",
|
|
2942
|
+
"snapshotList": "_367UGW_snapshotList",
|
|
2943
|
+
"viewTabs": "_367UGW_viewTabs",
|
|
2944
|
+
"sectionSubtitle": "_367UGW_sectionSubtitle",
|
|
2945
|
+
"groupNote": "_367UGW_groupNote",
|
|
2904
2946
|
"radioLabel": "_367UGW_radioLabel",
|
|
2947
|
+
"pathValue": "_367UGW_pathValue",
|
|
2948
|
+
"spinner": "_367UGW_spinner",
|
|
2949
|
+
"reportScroll": "_367UGW_reportScroll",
|
|
2950
|
+
"aboutLinkRow": "_367UGW_aboutLinkRow",
|
|
2905
2951
|
"aboutAuthor": "_367UGW_aboutAuthor",
|
|
2906
|
-
"
|
|
2907
|
-
"
|
|
2908
|
-
"snapshotRow": "_367UGW_snapshotRow",
|
|
2952
|
+
"progressBarDone": "_367UGW_progressBarDone",
|
|
2953
|
+
"progressDetail": "_367UGW_progressDetail",
|
|
2909
2954
|
"card": "_367UGW_card",
|
|
2910
|
-
"
|
|
2955
|
+
"errorActionLabel": "_367UGW_errorActionLabel",
|
|
2956
|
+
"conflictOptions": "_367UGW_conflictOptions",
|
|
2957
|
+
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
2958
|
+
"empty": "_367UGW_empty",
|
|
2959
|
+
"select": "_367UGW_select",
|
|
2960
|
+
"secretsList": "_367UGW_secretsList",
|
|
2961
|
+
"fieldLabel": "_367UGW_fieldLabel",
|
|
2911
2962
|
"formError": "_367UGW_formError",
|
|
2912
|
-
"
|
|
2963
|
+
"spinnerWrap": "_367UGW_spinnerWrap",
|
|
2913
2964
|
"warnList": "_367UGW_warnList",
|
|
2914
|
-
"
|
|
2965
|
+
"sectionBody": "_367UGW_sectionBody",
|
|
2966
|
+
"groupItems": "_367UGW_groupItems",
|
|
2915
2967
|
"snapshotRowHeader": "_367UGW_snapshotRowHeader",
|
|
2916
|
-
"
|
|
2968
|
+
"rowActions": "_367UGW_rowActions",
|
|
2969
|
+
"spinnerLabel": "_367UGW_spinnerLabel",
|
|
2917
2970
|
"optionsCard": "_367UGW_optionsCard",
|
|
2918
|
-
"reportText": "_367UGW_reportText",
|
|
2919
|
-
"spinnerWrap": "_367UGW_spinnerWrap",
|
|
2920
|
-
"groupLabel": "_367UGW_groupLabel",
|
|
2921
|
-
"spinner": "_367UGW_spinner",
|
|
2922
|
-
"ghostButton": "_367UGW_ghostButton",
|
|
2923
|
-
"primaryButton": "_367UGW_primaryButton",
|
|
2924
|
-
"progressPercent": "_367UGW_progressPercent",
|
|
2925
2971
|
"progressBlock": "_367UGW_progressBlock",
|
|
2926
|
-
"
|
|
2927
|
-
"dangerButton": "_367UGW_dangerButton",
|
|
2928
|
-
"badge": "_367UGW_badge",
|
|
2972
|
+
"progressPercent": "_367UGW_progressPercent",
|
|
2929
2973
|
"conflictDetail": "_367UGW_conflictDetail",
|
|
2930
|
-
"spinnerLabel": "_367UGW_spinnerLabel",
|
|
2931
|
-
"conflictItem": "_367UGW_conflictItem",
|
|
2932
|
-
"sectionBody": "_367UGW_sectionBody",
|
|
2933
|
-
"badgeWarn": "_367UGW_badgeWarn",
|
|
2934
|
-
"input": "_367UGW_input",
|
|
2935
|
-
"progressBadgeSection": "_367UGW_progressBadgeSection",
|
|
2936
|
-
"errorItem": "_367UGW_errorItem",
|
|
2937
|
-
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
2938
|
-
"progressTrack": "_367UGW_progressTrack",
|
|
2939
|
-
"rowActions": "_367UGW_rowActions",
|
|
2940
|
-
"progressBarDone": "_367UGW_progressBarDone",
|
|
2941
|
-
"actionRow": "_367UGW_actionRow",
|
|
2942
|
-
"pullScroll": "_367UGW_pullScroll",
|
|
2943
|
-
"checkboxRow": "_367UGW_checkboxRow",
|
|
2944
2974
|
"progressLabel": "_367UGW_progressLabel",
|
|
2945
|
-
"
|
|
2946
|
-
"
|
|
2947
|
-
"
|
|
2948
|
-
"
|
|
2975
|
+
"badgeInfo": "_367UGW_badgeInfo",
|
|
2976
|
+
"statRow": "_367UGW_statRow",
|
|
2977
|
+
"modeTabs": "_367UGW_modeTabs",
|
|
2978
|
+
"viewTab": "_367UGW_viewTab",
|
|
2949
2979
|
"field": "_367UGW_field",
|
|
2950
|
-
"
|
|
2951
|
-
"dshCmIndeterminate": "_367UGW_dshCmIndeterminate",
|
|
2952
|
-
"errorBanner": "_367UGW_errorBanner",
|
|
2953
|
-
"conflictHead": "_367UGW_conflictHead",
|
|
2954
|
-
"banner": "_367UGW_banner",
|
|
2980
|
+
"sectionHeader": "_367UGW_sectionHeader",
|
|
2955
2981
|
"badgeError": "_367UGW_badgeError",
|
|
2956
|
-
"hiddenFile": "_367UGW_hiddenFile",
|
|
2957
|
-
"modeTab": "_367UGW_modeTab",
|
|
2958
|
-
"viewBody": "_367UGW_viewBody",
|
|
2959
|
-
"groupCard": "_367UGW_groupCard",
|
|
2960
|
-
"groupItems": "_367UGW_groupItems",
|
|
2961
|
-
"viewTab": "_367UGW_viewTab",
|
|
2962
|
-
"groupNote": "_367UGW_groupNote",
|
|
2963
|
-
"badgeInfo": "_367UGW_badgeInfo",
|
|
2964
|
-
"categoryName": "_367UGW_categoryName",
|
|
2965
2982
|
"optionsHeader": "_367UGW_optionsHeader",
|
|
2966
|
-
"progressDetail": "_367UGW_progressDetail",
|
|
2967
|
-
"progressBadgeCount": "_367UGW_progressBadgeCount",
|
|
2968
2983
|
"groupList": "_367UGW_groupList",
|
|
2969
|
-
"progressBar": "_367UGW_progressBar",
|
|
2970
|
-
"errorFooter": "_367UGW_errorFooter",
|
|
2971
|
-
"severityError": "_367UGW_severityError",
|
|
2972
|
-
"snapshotList": "_367UGW_snapshotList",
|
|
2973
|
-
"warnText": "_367UGW_warnText",
|
|
2974
|
-
"kindTag": "_367UGW_kindTag",
|
|
2975
|
-
"secretFields": "_367UGW_secretFields",
|
|
2976
|
-
"viewTabs": "_367UGW_viewTabs",
|
|
2977
|
-
"select": "_367UGW_select",
|
|
2978
|
-
"reportFooter": "_367UGW_reportFooter",
|
|
2979
|
-
"modeTabs": "_367UGW_modeTabs",
|
|
2980
|
-
"errorLine": "_367UGW_errorLine",
|
|
2981
|
-
"confirmScroll": "_367UGW_confirmScroll",
|
|
2982
|
-
"sectionHeader": "_367UGW_sectionHeader",
|
|
2983
|
-
"reportView": "_367UGW_reportView",
|
|
2984
2984
|
"conflictList": "_367UGW_conflictList",
|
|
2985
|
-
"
|
|
2986
|
-
"
|
|
2985
|
+
"groupHeader": "_367UGW_groupHeader",
|
|
2986
|
+
"errorLine": "_367UGW_errorLine",
|
|
2987
|
+
"conflictItem": "_367UGW_conflictItem",
|
|
2988
|
+
"snapshotRow": "_367UGW_snapshotRow",
|
|
2989
|
+
"errorBanner": "_367UGW_errorBanner",
|
|
2990
|
+
"hiddenFile": "_367UGW_hiddenFile",
|
|
2987
2991
|
"progressIndeterminate": "_367UGW_progressIndeterminate",
|
|
2988
|
-
"conflictOptions": "_367UGW_conflictOptions",
|
|
2989
|
-
"diffScroll": "_367UGW_diffScroll",
|
|
2990
|
-
"planScroll": "_367UGW_planScroll",
|
|
2991
|
-
"errorTitle": "_367UGW_errorTitle",
|
|
2992
|
-
"sectionTitle": "_367UGW_sectionTitle",
|
|
2993
|
-
"conflictId": "_367UGW_conflictId",
|
|
2994
|
-
"reportList": "_367UGW_reportList",
|
|
2995
2992
|
"rollbackBox": "_367UGW_rollbackBox",
|
|
2996
|
-
"
|
|
2997
|
-
"
|
|
2998
|
-
"
|
|
2999
|
-
"
|
|
2993
|
+
"confirmScroll": "_367UGW_confirmScroll",
|
|
2994
|
+
"actionRow": "_367UGW_actionRow",
|
|
2995
|
+
"progressBar": "_367UGW_progressBar",
|
|
2996
|
+
"hint": "_367UGW_hint",
|
|
3000
2997
|
"errorList": "_367UGW_errorList",
|
|
3001
|
-
"
|
|
3002
|
-
"
|
|
3003
|
-
"
|
|
3004
|
-
"
|
|
3005
|
-
"
|
|
2998
|
+
"reportList": "_367UGW_reportList",
|
|
2999
|
+
"ghostButton": "_367UGW_ghostButton",
|
|
3000
|
+
"groupLabel": "_367UGW_groupLabel",
|
|
3001
|
+
"badgeWarn": "_367UGW_badgeWarn",
|
|
3002
|
+
"checkboxRow": "_367UGW_checkboxRow",
|
|
3003
|
+
"progressBadgeCount": "_367UGW_progressBadgeCount",
|
|
3004
|
+
"errorReason": "_367UGW_errorReason",
|
|
3005
|
+
"groupCard": "_367UGW_groupCard",
|
|
3006
|
+
"categoryItem": "_367UGW_categoryItem",
|
|
3007
|
+
"modeHint": "_367UGW_modeHint",
|
|
3008
|
+
"reportText": "_367UGW_reportText",
|
|
3009
|
+
"sectionTitleBlock": "_367UGW_sectionTitleBlock",
|
|
3010
|
+
"dshCmSpin": "_367UGW_dshCmSpin",
|
|
3011
|
+
"errorItem": "_367UGW_errorItem",
|
|
3012
|
+
"secretFields": "_367UGW_secretFields",
|
|
3013
|
+
"progressBadgeSection": "_367UGW_progressBadgeSection"
|
|
3006
3014
|
};
|
|
3007
3015
|
//#endregion
|
|
3008
3016
|
//#region src/client/common/ui.tsx
|
|
@@ -4775,83 +4783,84 @@ function initFromStore$2() {
|
|
|
4775
4783
|
}
|
|
4776
4784
|
function SnapshotsPanel({ api, t }) {
|
|
4777
4785
|
const [state, setState] = (0, react.useState)(initFromStore$2);
|
|
4778
|
-
/** 最新 state
|
|
4786
|
+
/** 最新 state 镜像(commit/卸载 flush 读取,避免闭包过期值) */
|
|
4779
4787
|
const stateRef = (0, react.useRef)(state);
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
+
/** 挂载守卫:卸载后不再 setState(store 镜像仍执行,异步结果照常落库) */
|
|
4789
|
+
const mountedRef = (0, react.useRef)(true);
|
|
4790
|
+
/**
|
|
4791
|
+
* 统一提交入口:更新 stateRef → 挂载时 setState → **总是**镜像进 runStore。
|
|
4792
|
+
* 关键:镜像不依赖 effect flush —— 异步操作(dry-run 计划/执行恢复)完成回调
|
|
4793
|
+
* 在组件已卸载(切走 tab)时也能把结果(plan/report)写进 store,切回恢复。
|
|
4794
|
+
*/
|
|
4795
|
+
const commit = (next) => {
|
|
4796
|
+
stateRef.current = next;
|
|
4797
|
+
if (mountedRef.current) setState(next);
|
|
4798
|
+
runStore.patch({ snapshots: toSnapshotsStoreSlice(next) });
|
|
4799
|
+
};
|
|
4800
|
+
const patch = (p) => commit({
|
|
4801
|
+
...stateRef.current,
|
|
4802
|
+
...p
|
|
4803
|
+
});
|
|
4804
|
+
/** 卸载时置挂载守卫 + 最后镜像一次(防止「最后一次改动后立即切 tab」时丢状态)。 */
|
|
4788
4805
|
(0, react.useEffect)(() => () => {
|
|
4806
|
+
mountedRef.current = false;
|
|
4789
4807
|
runStore.patch({ snapshots: toSnapshotsStoreSlice(stateRef.current) });
|
|
4790
4808
|
}, []);
|
|
4791
4809
|
const load = () => {
|
|
4792
|
-
|
|
4793
|
-
...s,
|
|
4810
|
+
patch({
|
|
4794
4811
|
status: "loading",
|
|
4795
4812
|
error: null
|
|
4796
|
-
})
|
|
4813
|
+
});
|
|
4797
4814
|
api.snapshots().then((metas) => {
|
|
4798
|
-
|
|
4799
|
-
...s,
|
|
4815
|
+
patch({
|
|
4800
4816
|
status: "ready",
|
|
4801
4817
|
metas
|
|
4802
|
-
})
|
|
4818
|
+
});
|
|
4803
4819
|
}, (err) => {
|
|
4804
|
-
|
|
4805
|
-
...s,
|
|
4820
|
+
patch({
|
|
4806
4821
|
status: "error",
|
|
4807
4822
|
error: err instanceof Error ? err.message : String(err)
|
|
4808
|
-
})
|
|
4823
|
+
});
|
|
4809
4824
|
});
|
|
4810
4825
|
};
|
|
4811
4826
|
(0, react.useEffect)(load, [api]);
|
|
4812
4827
|
const select = (id) => {
|
|
4813
|
-
|
|
4814
|
-
...s,
|
|
4828
|
+
patch({
|
|
4815
4829
|
selectedId: id,
|
|
4816
4830
|
plan: null,
|
|
4817
4831
|
report: null,
|
|
4818
4832
|
actionError: null,
|
|
4819
4833
|
planning: true
|
|
4820
|
-
})
|
|
4834
|
+
});
|
|
4821
4835
|
api.restoreSnapshot(id, true).then((res) => {
|
|
4822
|
-
|
|
4823
|
-
...s,
|
|
4836
|
+
patch({
|
|
4824
4837
|
planning: false,
|
|
4825
4838
|
plan: res.plan ?? null
|
|
4826
|
-
})
|
|
4839
|
+
});
|
|
4827
4840
|
}, (err) => {
|
|
4828
|
-
|
|
4829
|
-
...s,
|
|
4841
|
+
patch({
|
|
4830
4842
|
planning: false,
|
|
4831
4843
|
actionError: err instanceof Error ? err.message : String(err)
|
|
4832
|
-
})
|
|
4844
|
+
});
|
|
4833
4845
|
});
|
|
4834
4846
|
};
|
|
4835
4847
|
const execute = () => {
|
|
4836
4848
|
if (state.selectedId === null || state.running) return;
|
|
4837
|
-
|
|
4838
|
-
...s,
|
|
4849
|
+
patch({
|
|
4839
4850
|
running: true,
|
|
4840
4851
|
report: null,
|
|
4841
4852
|
actionError: null
|
|
4842
|
-
})
|
|
4853
|
+
});
|
|
4843
4854
|
api.restoreSnapshot(state.selectedId, false).then((res) => {
|
|
4844
|
-
|
|
4845
|
-
...s,
|
|
4855
|
+
patch({
|
|
4846
4856
|
running: false,
|
|
4847
4857
|
report: res.report ?? null
|
|
4848
|
-
})
|
|
4858
|
+
});
|
|
4849
4859
|
}, (err) => {
|
|
4850
|
-
|
|
4851
|
-
...s,
|
|
4860
|
+
patch({
|
|
4852
4861
|
running: false,
|
|
4853
4862
|
actionError: err instanceof Error ? err.message : String(err)
|
|
4854
|
-
})
|
|
4863
|
+
});
|
|
4855
4864
|
});
|
|
4856
4865
|
};
|
|
4857
4866
|
const summary = () => {
|
|
@@ -5786,6 +5795,8 @@ const initial$2 = {
|
|
|
5786
5795
|
* 从 runStore 恢复上次的同步 UI 状态(切 tab 回 / 刷新后挂载)。
|
|
5787
5796
|
* 敏感字段(token/webdav 密码/加密与解密密码)只在内存切片里保留:切 tab 保留;
|
|
5788
5797
|
* 刷新后已被持久化白名单清空(applyPersisted 强制归零)→ 需要时重新输入。
|
|
5798
|
+
* busy/savingConfig 为瞬态:切 tab 由模块级单例保留(切回仍显示进行中);
|
|
5799
|
+
* 刷新后白名单剔除 → 回复空闲。
|
|
5789
5800
|
*/
|
|
5790
5801
|
function initFromStore$1() {
|
|
5791
5802
|
const s = runStore.getSnapshot().sync;
|
|
@@ -5807,6 +5818,8 @@ function initFromStore$1() {
|
|
|
5807
5818
|
...s.byChannel.webdav
|
|
5808
5819
|
}
|
|
5809
5820
|
},
|
|
5821
|
+
busy: s.busy,
|
|
5822
|
+
savingConfig: s.savingConfig,
|
|
5810
5823
|
pushReport: s.pushReport,
|
|
5811
5824
|
pullReport: s.pullReport,
|
|
5812
5825
|
confirmSession: s.confirmSession,
|
|
@@ -5818,47 +5831,46 @@ function initFromStore$1() {
|
|
|
5818
5831
|
function SyncSettingsView({ api, t }) {
|
|
5819
5832
|
const [state, setState] = (0, react.useState)(initFromStore$1);
|
|
5820
5833
|
const uiT = api.t;
|
|
5821
|
-
/** 最新 state
|
|
5834
|
+
/** 最新 state 镜像(commit/自动保存 flush 读取,避免闭包过期值) */
|
|
5822
5835
|
const stateRef = (0, react.useRef)(state);
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5836
|
+
/** 挂载守卫:卸载后不再 setState(store 镜像仍执行,异步结果照常落库) */
|
|
5837
|
+
const mountedRef = (0, react.useRef)(true);
|
|
5838
|
+
/**
|
|
5839
|
+
* 统一提交入口:更新 stateRef → 挂载时 setState → **总是**镜像进 runStore。
|
|
5840
|
+
* 关键:镜像不依赖 effect flush —— 异步操作(push/pull/sync)完成回调在组件
|
|
5841
|
+
* 已卸载(切走 tab)时也能把结果写进 store,切回 tab 时 initFromStore 恢复。
|
|
5842
|
+
*/
|
|
5843
|
+
const commit = (next) => {
|
|
5844
|
+
stateRef.current = next;
|
|
5845
|
+
if (mountedRef.current) setState(next);
|
|
5846
|
+
runStore.patch({ sync: toSyncStoreSlice(next) });
|
|
5832
5847
|
};
|
|
5848
|
+
const patch = (p) => commit({
|
|
5849
|
+
...stateRef.current,
|
|
5850
|
+
...p
|
|
5851
|
+
});
|
|
5833
5852
|
/** 更新指定通道的 byChannel 状态(子 tab 切换后 loadSnapshots 等场景用)。 */
|
|
5834
|
-
const patchChannelState = (ch, p) =>
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
byChannel
|
|
5838
|
-
|
|
5839
|
-
[ch]
|
|
5840
|
-
|
|
5841
|
-
...p
|
|
5842
|
-
}
|
|
5853
|
+
const patchChannelState = (ch, p) => commit({
|
|
5854
|
+
...stateRef.current,
|
|
5855
|
+
byChannel: {
|
|
5856
|
+
...stateRef.current.byChannel,
|
|
5857
|
+
[ch]: {
|
|
5858
|
+
...stateRef.current.byChannel[ch],
|
|
5859
|
+
...p
|
|
5843
5860
|
}
|
|
5844
|
-
}
|
|
5845
|
-
stateRef.current = next;
|
|
5846
|
-
return next;
|
|
5861
|
+
}
|
|
5847
5862
|
});
|
|
5848
5863
|
/** 更新当前激活通道的 byChannel 状态。 */
|
|
5849
5864
|
const patchChannel = (p) => patchChannelState(state.channel, p);
|
|
5850
5865
|
/** 当前激活通道的设置状态(自动同步/模式/加密/快照)。 */
|
|
5851
5866
|
const chState = state.byChannel[state.channel];
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
};
|
|
5860
|
-
stateRef.current = next;
|
|
5861
|
-
return next;
|
|
5867
|
+
/** GitHub 流程态(不进 store 切片;commit 的镜像写幂等无害)。 */
|
|
5868
|
+
const patchGithub = (p) => commit({
|
|
5869
|
+
...stateRef.current,
|
|
5870
|
+
github: {
|
|
5871
|
+
...stateRef.current.github,
|
|
5872
|
+
...p
|
|
5873
|
+
}
|
|
5862
5874
|
});
|
|
5863
5875
|
/** GitHub 轮询定时器(卸载/取消时清理,防止泄漏与跨流程串扰) */
|
|
5864
5876
|
const githubPollTimer = (0, react.useRef)(null);
|
|
@@ -5931,26 +5943,15 @@ function SyncSettingsView({ api, t }) {
|
|
|
5931
5943
|
const loadAutosync = async () => {
|
|
5932
5944
|
try {
|
|
5933
5945
|
const all = await api.autosyncStatusAll();
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
},
|
|
5944
|
-
webdav: {
|
|
5945
|
-
...s.byChannel.webdav,
|
|
5946
|
-
autosync: all.webdav,
|
|
5947
|
-
autosyncEnabled: all.webdav.enabled,
|
|
5948
|
-
autosyncInterval: all.webdav.interval
|
|
5949
|
-
}
|
|
5950
|
-
}
|
|
5951
|
-
};
|
|
5952
|
-
stateRef.current = next;
|
|
5953
|
-
return next;
|
|
5946
|
+
patchChannelState("git", {
|
|
5947
|
+
autosync: all.git,
|
|
5948
|
+
autosyncEnabled: all.git.enabled,
|
|
5949
|
+
autosyncInterval: all.git.interval
|
|
5950
|
+
});
|
|
5951
|
+
patchChannelState("webdav", {
|
|
5952
|
+
autosync: all.webdav,
|
|
5953
|
+
autosyncEnabled: all.webdav.enabled,
|
|
5954
|
+
autosyncInterval: all.webdav.interval
|
|
5954
5955
|
});
|
|
5955
5956
|
} catch (err) {
|
|
5956
5957
|
patch({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -5989,14 +5990,11 @@ function SyncSettingsView({ api, t }) {
|
|
|
5989
5990
|
(0, react.useEffect)(() => {
|
|
5990
5991
|
loadStatus();
|
|
5991
5992
|
}, []);
|
|
5992
|
-
/**
|
|
5993
|
-
*
|
|
5994
|
-
|
|
5995
|
-
runStore.patch({ sync: toSyncStoreSlice(state) });
|
|
5996
|
-
}, [state]);
|
|
5997
|
-
/** 卸载时清理轮询定时器 + 补发未落盘的通道配置改动 + 最后镜像一次状态
|
|
5998
|
-
* (组件销毁后不得再 setState/发请求;store 镜像为纯内存/白名单写,安全) */
|
|
5993
|
+
/** 卸载时置挂载守卫 + 清理轮询定时器 + 补发未落盘的通道配置改动 + 最后镜像一次状态
|
|
5994
|
+
* (组件销毁后不得再 setState/发请求;store 镜像为纯内存/白名单写,安全)。
|
|
5995
|
+
* 异步操作完成回调仍会走 commit 写 store(见 commit 注释),结果不丢。 */
|
|
5999
5996
|
(0, react.useEffect)(() => () => {
|
|
5997
|
+
mountedRef.current = false;
|
|
6000
5998
|
if (githubPollTimer.current !== null) clearTimeout(githubPollTimer.current);
|
|
6001
5999
|
if (saveTimer.current !== null) {
|
|
6002
6000
|
clearTimeout(saveTimer.current);
|
|
@@ -6055,30 +6053,28 @@ function SyncSettingsView({ api, t }) {
|
|
|
6055
6053
|
});
|
|
6056
6054
|
try {
|
|
6057
6055
|
const saved = await api.saveConfig(payloadToSave);
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6056
|
+
const s = stateRef.current;
|
|
6057
|
+
const next = {
|
|
6058
|
+
...s,
|
|
6059
|
+
savingConfig: false
|
|
6060
|
+
};
|
|
6061
|
+
next.webdavPassword = s.webdavPassword !== "" && s.webdavPassword !== payloadToSave.password ? s.webdavPassword : "";
|
|
6062
|
+
next.token = s.token !== "" && s.token !== payloadToSave.token ? s.token : "";
|
|
6063
|
+
if (s.statusInfo !== null) {
|
|
6064
|
+
const info = {
|
|
6065
|
+
...s.statusInfo,
|
|
6066
|
+
configured: true,
|
|
6067
|
+
credentialConfigured: saved.credentialConfigured
|
|
6062
6068
|
};
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
url: s.statusInfo.webdav?.url,
|
|
6073
|
-
username: s.statusInfo.webdav?.username,
|
|
6074
|
-
usernameConfigured: saved.webdav.usernameConfigured,
|
|
6075
|
-
passwordConfigured: saved.webdav.passwordConfigured
|
|
6076
|
-
};
|
|
6077
|
-
next.statusInfo = info;
|
|
6078
|
-
}
|
|
6079
|
-
stateRef.current = next;
|
|
6080
|
-
return next;
|
|
6081
|
-
});
|
|
6069
|
+
if (saved.webdav !== void 0) info.webdav = {
|
|
6070
|
+
url: s.statusInfo.webdav?.url,
|
|
6071
|
+
username: s.statusInfo.webdav?.username,
|
|
6072
|
+
usernameConfigured: saved.webdav.usernameConfigured,
|
|
6073
|
+
passwordConfigured: saved.webdav.passwordConfigured
|
|
6074
|
+
};
|
|
6075
|
+
next.statusInfo = info;
|
|
6076
|
+
}
|
|
6077
|
+
commit(next);
|
|
6082
6078
|
} catch (err) {
|
|
6083
6079
|
patch({
|
|
6084
6080
|
savingConfig: false,
|
|
@@ -8153,22 +8149,27 @@ function MarketPanel({ api, importApi, t }) {
|
|
|
8153
8149
|
/** 发布向导开关(组件内状态,不进 sessionStorage —— 发布为一次性低频率流程) */
|
|
8154
8150
|
const [publishOpen, setPublishOpen] = (0, react.useState)(false);
|
|
8155
8151
|
const [state, setState] = (0, react.useState)(initFromStore);
|
|
8156
|
-
/** 最新 state
|
|
8152
|
+
/** 最新 state 镜像(commit/卸载 flush 读取,避免闭包过期值) */
|
|
8157
8153
|
const stateRef = (0, react.useRef)(state);
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8154
|
+
/** 挂载守卫:卸载后不再 setState(store 镜像仍执行,异步结果照常落库) */
|
|
8155
|
+
const mountedRef = (0, react.useRef)(true);
|
|
8156
|
+
/**
|
|
8157
|
+
* 统一提交入口:更新 stateRef → 挂载时 setState → **总是**镜像进 runStore。
|
|
8158
|
+
* 关键:镜像不依赖 effect flush —— 异步操作(下载/确认导入)完成回调在组件
|
|
8159
|
+
* 已卸载(切走 tab)时也能把结果(detail/importResult)写进 store,切回恢复。
|
|
8160
|
+
*/
|
|
8161
|
+
const commit = (next) => {
|
|
8163
8162
|
stateRef.current = next;
|
|
8164
|
-
|
|
8163
|
+
if (mountedRef.current) setState(next);
|
|
8164
|
+
runStore.patch({ market: toMarketStoreSlice(next) });
|
|
8165
|
+
};
|
|
8166
|
+
const patch = (p) => commit({
|
|
8167
|
+
...stateRef.current,
|
|
8168
|
+
...p
|
|
8165
8169
|
});
|
|
8166
|
-
/**
|
|
8167
|
-
(0, react.useEffect)(() => {
|
|
8168
|
-
runStore.patch({ market: toMarketStoreSlice(state) });
|
|
8169
|
-
}, [state]);
|
|
8170
|
-
/** 卸载时最后镜像一次(防止「最后一次改动后立即切 tab」时镜像 effect 尚未 flush)。 */
|
|
8170
|
+
/** 卸载时置挂载守卫 + 最后镜像一次(防止「最后一次改动后立即切 tab」时丢状态)。 */
|
|
8171
8171
|
(0, react.useEffect)(() => () => {
|
|
8172
|
+
mountedRef.current = false;
|
|
8172
8173
|
runStore.patch({ market: toMarketStoreSlice(stateRef.current) });
|
|
8173
8174
|
}, []);
|
|
8174
8175
|
/** 内置市场 URL(单一权威;来自 Host 内置常量) */
|