dsh-config-manager 0.1.39 → 0.1.41
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.d.ts +90 -8
- package/lib/client.js +1904 -1086
- package/lib/client.js.map +1 -1
- package/lib/core/cache-cleaner.d.ts +39 -0
- package/lib/core/cache-cleaner.js +164 -0
- package/lib/core/cache-cleaner.js.map +1 -0
- package/lib/index.js +172 -3
- package/lib/index.js.map +1 -1
- package/lib/market/github-repos.d.ts +19 -8
- package/lib/market/github-repos.js +62 -33
- package/lib/market/github-repos.js.map +1 -1
- package/lib/market/my-repo.d.ts +111 -3
- package/lib/market/my-repo.js +309 -26
- package/lib/market/my-repo.js.map +1 -1
- package/lib/market/prepare.js +3 -2
- package/lib/market/prepare.js.map +1 -1
- package/lib/market/types.d.ts +2 -0
- package/lib/security/secret-scanner.d.ts +18 -3
- package/lib/security/secret-scanner.js +144 -20
- package/lib/security/secret-scanner.js.map +1 -1
- package/package.json +1 -1
- package/src/client/common/ConfirmDialog.tsx +135 -0
- package/src/client/config-manager.module.css +101 -0
- package/src/client/market/MarketPanel.tsx +138 -45
- package/src/client/market/MyConfigsView.tsx +515 -132
- package/src/client/market/disclaimer.test.ts +57 -0
- package/src/client/market/disclaimer.ts +43 -0
- package/src/client/market/market-api.test.ts +3 -0
- package/src/client/market/market-locales.ts +37 -13
- package/src/client/market/my-configs-api.ts +20 -2
- package/src/client/market/my-configs-view.test.ts +137 -2
- package/src/client/market/my-configs-view.ts +174 -2
- package/src/client/run-store.test.ts +40 -2
- package/src/client/run-store.ts +70 -10
- package/src/client/sync/SyncConfirmView.tsx +28 -22
- package/src/client/sync/SyncSettingsView.tsx +175 -65
- package/src/client/sync/sync-api.ts +19 -0
- package/src/client/sync/sync-locales.ts +14 -2
- package/src/core/cache-cleaner.test.ts +333 -0
- package/src/core/cache-cleaner.ts +196 -0
- package/src/index.ts +165 -5
- package/src/market/github-repos.test.ts +99 -8
- package/src/market/github-repos.ts +67 -35
- package/src/market/my-repo.test.ts +218 -27
- package/src/market/my-repo.ts +403 -30
- package/src/market/prepare.test.ts +71 -1
- package/src/market/prepare.ts +3 -2
- package/src/market/types.ts +2 -0
- package/src/security/secret-scanner.ts +139 -22
- package/src/security/security.test.ts +111 -2
package/lib/client.js
CHANGED
|
@@ -1880,25 +1880,6 @@ function computeSyncButtons(busy, remoteReady, t = zhUiT) {
|
|
|
1880
1880
|
pullLabel: busy === "pull" ? t("sync.pulling") : busy === "sync" ? t("sync.syncing") : t("sync.pullLabel")
|
|
1881
1881
|
};
|
|
1882
1882
|
}
|
|
1883
|
-
/** 状态行渲染模型:加载 / 未配置 / 就绪(凭据 + 上次同步 + 通道)/ 错误 */
|
|
1884
|
-
function computeSyncStatus(statusInfo, loading, error, t = zhUiT) {
|
|
1885
|
-
if (loading) return {
|
|
1886
|
-
kind: "loading",
|
|
1887
|
-
text: t("sync.statusLoading")
|
|
1888
|
-
};
|
|
1889
|
-
if (error !== null) return {
|
|
1890
|
-
kind: "error",
|
|
1891
|
-
text: error
|
|
1892
|
-
};
|
|
1893
|
-
if (statusInfo === null || !statusInfo.configured) return {
|
|
1894
|
-
kind: "unconfigured",
|
|
1895
|
-
text: t("sync.statusUnconfigured")
|
|
1896
|
-
};
|
|
1897
|
-
return {
|
|
1898
|
-
kind: "ready",
|
|
1899
|
-
text: `${(statusInfo.transport?.type === "webdav" ? statusInfo.webdav?.passwordConfigured ?? false : statusInfo.credentialConfigured) ? t("sync.credConfigured") : t("sync.credMissing")} · ${statusInfo.lastSyncAt !== void 0 && statusInfo.lastSyncAt !== "" ? t("sync.lastSync", { time: formatDateTime$1(statusInfo.lastSyncAt) }) : t("sync.neverSynced")}${statusInfo.transport !== void 0 ? ` · ${statusInfo.transport.type}${statusInfo.transport.ref !== "" ? `/${statusInfo.transport.ref}` : ""}` : ""}`
|
|
1900
|
-
};
|
|
1901
|
-
}
|
|
1902
1883
|
/** ISO-8601 → 本地可读时间(YYYY-MM-DD HH:mm;非法输入原样返回) */
|
|
1903
1884
|
function formatDateTime$1(iso) {
|
|
1904
1885
|
const d = new Date(iso);
|
|
@@ -2212,6 +2193,7 @@ function defaultSyncState() {
|
|
|
2212
2193
|
pushReport: null,
|
|
2213
2194
|
pullReport: null,
|
|
2214
2195
|
confirmSession: null,
|
|
2196
|
+
confirmDecisions: null,
|
|
2215
2197
|
lastRestoreId: null,
|
|
2216
2198
|
error: null,
|
|
2217
2199
|
loadError: null
|
|
@@ -2229,7 +2211,10 @@ function defaultMarketState() {
|
|
|
2229
2211
|
error: null,
|
|
2230
2212
|
loadError: null,
|
|
2231
2213
|
myItems: null,
|
|
2232
|
-
myItemsError: null
|
|
2214
|
+
myItemsError: null,
|
|
2215
|
+
myWizard: null,
|
|
2216
|
+
myInstall: null,
|
|
2217
|
+
myConfirmDeleteId: null
|
|
2233
2218
|
};
|
|
2234
2219
|
}
|
|
2235
2220
|
function defaultSnapshotsState() {
|
|
@@ -2283,6 +2268,7 @@ function toSyncStoreSlice(s) {
|
|
|
2283
2268
|
pushReport: s.pushReport,
|
|
2284
2269
|
pullReport: s.pullReport,
|
|
2285
2270
|
confirmSession: s.confirmSession,
|
|
2271
|
+
confirmDecisions: s.confirmDecisions,
|
|
2286
2272
|
lastRestoreId: s.lastRestoreId,
|
|
2287
2273
|
error: s.error,
|
|
2288
2274
|
loadError: s.loadError
|
|
@@ -2301,7 +2287,10 @@ function toMarketStoreSlice(s) {
|
|
|
2301
2287
|
error: s.error,
|
|
2302
2288
|
loadError: s.loadError,
|
|
2303
2289
|
myItems: s.myItems,
|
|
2304
|
-
myItemsError: s.myItemsError
|
|
2290
|
+
myItemsError: s.myItemsError,
|
|
2291
|
+
myWizard: s.myWizard,
|
|
2292
|
+
myInstall: s.myInstall,
|
|
2293
|
+
myConfirmDeleteId: s.myConfirmDeleteId
|
|
2305
2294
|
};
|
|
2306
2295
|
}
|
|
2307
2296
|
/** 从快照面板状态提取切片(结构兼容:传入 PanelState 亦可)。 */
|
|
@@ -2319,11 +2308,13 @@ function toSnapshotsStoreSlice(s) {
|
|
|
2319
2308
|
* 与不可序列化的实例字段(conflictCollector),以及同步面板的凭据字段
|
|
2320
2309
|
* (token/webdavPassword/encryptPassword/encryptPasswordConfirm/decryptPassword ——
|
|
2321
2310
|
* 含 byChannel 内每通道的加密/解密密码)与瞬态字段(busy/savingConfig —— 刷新后
|
|
2322
|
-
*
|
|
2311
|
+
* 回复空闲,不把「进行中」状态带到新页面);导出面板的结果字段(result/downloaded)
|
|
2312
|
+
* 与进行中/进度(running/progress/runId)同为内存切片瞬态一并剔除(刷新/关闭 DSH
|
|
2313
|
+
* 后不残留上次导出报告),其余原样落入 sessionStorage。
|
|
2323
2314
|
* 这是 sessionStorage 的唯一写入路径 —— 敏感值在此被硬性隔离。
|
|
2324
2315
|
*/
|
|
2325
2316
|
function toPersistedState(state) {
|
|
2326
|
-
const { password: _password, passwordConfirm: _passwordConfirm, ...exportRest } = state.export;
|
|
2317
|
+
const { password: _password, passwordConfirm: _passwordConfirm, result: _result, downloaded: _downloaded, running: _running, progress: _progress, runId: _runId, ...exportRest } = state.export;
|
|
2327
2318
|
const { secretInputs: _secretInputs, decryptPassword: _decryptPassword, decryptRefs: _decryptRefs, archiveUnlocked: _archiveUnlocked, conflictCollector: _conflictCollector, ...importRest } = state.import;
|
|
2328
2319
|
const { token: _token, webdavPassword: _webdavPassword, busy: _busy, savingConfig: _savingConfig, ...syncRest } = state.sync;
|
|
2329
2320
|
const stripChannelSensitive = (c) => {
|
|
@@ -2565,7 +2556,12 @@ var RunStore = class {
|
|
|
2565
2556
|
...defaultExportState(),
|
|
2566
2557
|
...parsed.export,
|
|
2567
2558
|
password: "",
|
|
2568
|
-
passwordConfirm: ""
|
|
2559
|
+
passwordConfirm: "",
|
|
2560
|
+
result: null,
|
|
2561
|
+
downloaded: false,
|
|
2562
|
+
running: false,
|
|
2563
|
+
progress: null,
|
|
2564
|
+
runId: null
|
|
2569
2565
|
},
|
|
2570
2566
|
import: {
|
|
2571
2567
|
...defaultImportState(),
|
|
@@ -2900,7 +2896,7 @@ var RunStore = class {
|
|
|
2900
2896
|
const runStore = new RunStore();
|
|
2901
2897
|
//#endregion
|
|
2902
2898
|
//#region \0config-manager-css:/home/runner/work/dsh-config-manager/dsh-config-manager/src/client/config-manager.module.css.js
|
|
2903
|
-
const css = "._367UGW_section{height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;font-size:13px;display:flex}._367UGW_sectionHeader{flex:none;align-items:center;gap:10px;display:flex}._367UGW_viewTabs{border-bottom:1px solid var(--dsw-alias-border-l1);flex:1;gap:2px;display:flex}._367UGW_viewTab{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;border-radius:6px 6px 0 0;padding:7px 14px;font-size:13px}._367UGW_viewTab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._367UGW_viewTab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}._367UGW_sectionBody{flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}._367UGW_viewBody{flex-direction:column;gap:12px;padding:4px 2px 16px;display:flex}._367UGW_sectionTitleBlock{flex-direction:column;gap:2px;display:flex}._367UGW_sectionTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:15px;font-weight:700}._367UGW_sectionSubtitle{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}._367UGW_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;align-items:center;gap:6px;padding:6px 14px;font-size:13px;font-weight:600;display:inline-flex}._367UGW_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._367UGW_primaryButton:disabled{opacity:.5;cursor:default}._367UGW_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;align-items:center;gap:6px;padding:5px 12px;font-size:12px;display:inline-flex}._367UGW_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._367UGW_ghostButton:disabled{opacity:.45;cursor:default}._367UGW_dangerButton{color:var(--dsw-alias-state-error-primary);border:1px solid var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._367UGW_dangerButton:hover:not(:disabled){background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground)}._367UGW_dangerButton:disabled{opacity:.45;cursor:default}._367UGW_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;line-height:1.6;display:inline-block}._367UGW_badgeInfo{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}._367UGW_badgeOk{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._367UGW_badgeWarn{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._367UGW_badgeError{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._367UGW_banner{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;border-radius:8px;padding:8px 12px;font-size:12.5px;line-height:1.5}._367UGW_banner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._367UGW_banner[data-kind=error]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._367UGW_banner[data-kind=info]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}._367UGW_banner[data-kind=warn]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._367UGW_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}._367UGW_field{flex-direction:column;gap:5px;display:flex}._367UGW_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._367UGW_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._367UGW_input:focus{border-color:var(--dsw-alias-state-business-primary)}._367UGW_input::placeholder{color:var(--dsw-alias-label-tertiary)}._367UGW_input:disabled{opacity:.55}._367UGW_select{-webkit-appearance:none;appearance:none;color:var(--dsw-alias-label-primary);background-color:var(--dsw-specific-input-major);background-image:linear-gradient(45deg, transparent 50%, var(--dsw-alias-label-secondary) 50%), linear-gradient(135deg, var(--dsw-alias-label-secondary) 50%, transparent 50%);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background-position:calc(100% - 17px) calc(50% - 1px),calc(100% - 12px) calc(50% - 1px);background-repeat:no-repeat;background-size:5px 5px,5px 5px;border-radius:8px;outline:none;max-width:100%;padding:7px 30px 7px 10px;font-family:inherit;font-size:13px}._367UGW_select:hover:not(:disabled){border-color:var(--dsw-alias-border-l1)}._367UGW_select:focus{border-color:var(--dsw-alias-state-business-primary)}._367UGW_select:disabled{opacity:.55;cursor:default}._367UGW_select option{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}._367UGW_hint{color:var(--dsw-alias-label-tertiary);font-size:11.5px;line-height:1.5}._367UGW_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._367UGW_checkboxRow{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:flex-start;gap:8px;font-size:13px;display:flex}._367UGW_checkboxRow input{flex:none;margin-top:2px}._367UGW_radioLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:13px;display:inline-flex}._367UGW_secretFields{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px 12px;padding-top:4px;display:grid}._367UGW_hiddenFile{display:none}._367UGW_modeTabs{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;gap:2px;display:flex}._367UGW_modeTab{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px;font-size:12.5px}._367UGW_modeTab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._367UGW_modeTab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}._367UGW_modeHint{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}._367UGW_groupList{flex-direction:column;gap:10px;display:flex}._367UGW_groupCard{gap:8px}._367UGW_groupHeader{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}._367UGW_groupLabel{color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:700}._367UGW_groupNote{color:var(--dsw-alias-label-tertiary);font-size:11.5px}._367UGW_groupItems{flex-direction:column;gap:6px;display:flex}._367UGW_categoryItem{flex-wrap:wrap;align-items:center;gap:8px;display:inline-flex}._367UGW_categoryName{font-weight:500}._367UGW_categoryDesc{color:var(--dsw-alias-label-tertiary);font-size:11.5px}._367UGW_optionsCard{gap:8px}._367UGW_optionsHeader{color:var(--dsw-alias-label-primary);letter-spacing:.02em;margin-bottom:2px;font-size:12px;font-weight:600}._367UGW_warnList{margin:4px 0 0;padding-left:18px}._367UGW_actionRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._367UGW_progressBlock{flex-direction:column;flex:none;gap:6px;display:flex}._367UGW_progressMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:12px;font-size:12px;display:flex}._367UGW_progressLabel{font-weight:600}._367UGW_progressDetail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;max-width:320px;overflow:hidden}._367UGW_progressBadge{font-variant-numeric:tabular-nums;white-space:nowrap;border-radius:999px;align-items:center;gap:2px;padding:1px 8px;font-size:11px;line-height:18px;display:inline-flex}._367UGW_progressBadgeSection{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);color:var(--dsw-alias-state-business-primary)}._367UGW_progressBadgeCount{background:color-mix(in srgb, var(--dsw-alias-state-info-primary) 14%, transparent);color:var(--dsw-alias-state-info-primary)}._367UGW_progressPercent{font-variant-numeric:tabular-nums;margin-left:auto}._367UGW_progressTrack{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;height:8px;overflow:hidden}._367UGW_progressBar{background:var(--dsw-alias-state-business-primary);border-radius:999px;height:100%;transition:width .12s linear}._367UGW_progressBarDone{background:var(--dsw-alias-state-success-primary)}._367UGW_progressIndeterminate{width:40%;animation:1s ease-in-out infinite _367UGW_dshCmIndeterminate}@keyframes _367UGW_dshCmIndeterminate{0%{margin-left:-40%}to{margin-left:100%}}._367UGW_reportView{flex-direction:column;gap:10px;display:flex}._367UGW_statRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}._367UGW_reportText{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;max-height:260px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;line-height:1.6;overflow:auto}._367UGW_reportFooter{justify-content:flex-end;gap:8px;display:flex}._367UGW_rollbackBox{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_rollbackBox ._367UGW_reportText{border-color:var(--dsw-alias-border-l2)}._367UGW_errorBanner{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_errorTitle{color:var(--dsw-alias-state-error-primary);font-size:13px;font-weight:700}._367UGW_errorReason{white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-label-secondary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px}._367UGW_errorAction{color:var(--dsw-alias-label-secondary);font-size:12.5px}._367UGW_errorActionLabel{color:var(--dsw-alias-state-business-primary)}._367UGW_errorItem{color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px}._367UGW_errorFooter{justify-content:flex-end;display:flex}._367UGW_errorList{flex-direction:column;gap:4px;display:flex}._367UGW_errorLine{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-state-error-primary);border-radius:6px;margin:0;padding:6px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}._367UGW_conflictList{flex-direction:column;gap:10px;display:flex}._367UGW_conflictItem{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_conflictHead{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._367UGW_conflictId{color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:600}._367UGW_severityError{color:var(--dsw-alias-state-error-primary);border:1px solid var(--dsw-alias-state-error-primary);border-radius:999px;padding:0 6px;font-size:10.5px}._367UGW_conflictDetail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-label-secondary);border-radius:6px;margin:0;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}._367UGW_conflictOptions{flex-wrap:wrap;gap:14px;display:flex}._367UGW_pathMappingList{flex-direction:column;gap:8px;display:flex}._367UGW_pathRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;padding:10px 12px;display:grid}._367UGW_pathOld,._367UGW_pathNew{flex-direction:column;gap:4px;min-width:0;display:flex}._367UGW_pathValue{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;overflow:hidden}._367UGW_pathIssueKind{color:var(--dsw-alias-state-warn-primary);font-size:10.5px}._367UGW_secretsList{flex-direction:column;gap:10px;display:flex}._367UGW_empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:22px 12px;font-size:12.5px}._367UGW_spinnerWrap{align-items:center;gap:6px;display:inline-flex}._367UGW_spinner{border:2px solid var(--dsw-alias-state-business-primary);vertical-align:-1px;border-top-color:#0000;border-radius:50%;flex:none;width:11px;height:11px;animation:.8s linear infinite _367UGW_dshCmSpin;display:inline-block}._367UGW_spinnerLabel{color:var(--dsw-alias-label-secondary);font-size:12px}@keyframes _367UGW_dshCmSpin{to{transform:rotate(360deg)}}._367UGW_snapshotList{flex-direction:column;gap:2px;display:flex}._367UGW_snapshotRowHeader,._367UGW_snapshotRow{grid-template-columns:minmax(120px,1.2fr) minmax(140px,1.6fr) 90px 56px 56px;align-items:center;gap:8px;padding:6px 10px;font-size:12px;display:grid}._367UGW_snapshotRowHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-border-l1);font-size:11px}._367UGW_snapshotRow{text-align:left;width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px}._367UGW_snapshotRow:hover{background:var(--dsw-alias-interactive-bg-hover)}._367UGW_snapshotRow[data-active]{border-color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent)}._367UGW_warnText{color:var(--dsw-alias-state-warn-primary)}._367UGW_reportList{color:var(--dsw-alias-label-primary);flex-direction:column;gap:3px;margin:8px 0 4px;padding-left:18px;font-size:12px;display:flex}._367UGW_kindTag{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 6px;font-size:10.5px;display:inline-block}._367UGW_planScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;height:280px;padding:2px 10px 8px;overflow-y:auto}._367UGW_planScroll ._367UGW_reportList{margin-top:6px}._367UGW_reportScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;max-height:220px;padding:2px 10px 6px;overflow-y:auto}._367UGW_reportScroll ._367UGW_reportList{margin-top:4px}._367UGW_confirmScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;max-height:280px;padding:2px 10px 6px;overflow-y:auto}._367UGW_confirmScroll ._367UGW_reportList{margin-top:4px;margin-bottom:0}._367UGW_pullScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;height:280px;padding:2px 10px 6px;overflow-y:auto}._367UGW_pullScroll ._367UGW_reportList{margin-top:4px;margin-bottom:0}._367UGW_rowActions{gap:8px;margin-top:10px;display:flex}._367UGW_diffScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;max-height:240px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;line-height:1.6;overflow:auto}._367UGW_aboutLinkRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._367UGW_aboutAuthor{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:4px 8px;font-size:13px;text-decoration:none;display:inline-flex}._367UGW_aboutAuthor:hover{background:var(--dsw-alias-interactive-bg-hover)}";
|
|
2899
|
+
const css = "._367UGW_section{height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;font-size:13px;display:flex}._367UGW_sectionHeader{flex:none;align-items:center;gap:10px;display:flex}._367UGW_viewTabs{border-bottom:1px solid var(--dsw-alias-border-l1);flex:1;gap:2px;display:flex}._367UGW_viewTab{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;border-radius:6px 6px 0 0;padding:7px 14px;font-size:13px}._367UGW_viewTab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._367UGW_viewTab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}._367UGW_sectionBody{flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}._367UGW_viewBody{flex-direction:column;gap:12px;padding:4px 2px 16px;display:flex}._367UGW_sectionTitleBlock{flex-direction:column;gap:2px;display:flex}._367UGW_sectionTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:15px;font-weight:700}._367UGW_sectionSubtitle{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}._367UGW_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;align-items:center;gap:6px;padding:6px 14px;font-size:13px;font-weight:600;display:inline-flex}._367UGW_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._367UGW_primaryButton:disabled{opacity:.5;cursor:default}._367UGW_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;align-items:center;gap:6px;padding:5px 12px;font-size:12px;display:inline-flex}._367UGW_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._367UGW_ghostButton:disabled{opacity:.45;cursor:default}._367UGW_dangerButton{color:var(--dsw-alias-state-error-primary);border:1px solid var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._367UGW_dangerButton:hover:not(:disabled){background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground)}._367UGW_dangerButton:disabled{opacity:.45;cursor:default}._367UGW_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;line-height:1.6;display:inline-block}._367UGW_badgeInfo{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}._367UGW_badgeOk{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._367UGW_badgeWarn{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._367UGW_badgeError{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._367UGW_banner{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;border-radius:8px;padding:8px 12px;font-size:12.5px;line-height:1.5}._367UGW_banner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._367UGW_banner[data-kind=error]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._367UGW_banner[data-kind=info]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}._367UGW_banner[data-kind=warn]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._367UGW_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}._367UGW_wizardCard{gap:14px}._367UGW_wizardCard ._367UGW_field{gap:8px}._367UGW_field{flex-direction:column;gap:5px;display:flex}._367UGW_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._367UGW_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._367UGW_input:focus{border-color:var(--dsw-alias-state-business-primary)}._367UGW_input::placeholder{color:var(--dsw-alias-label-tertiary)}._367UGW_input:disabled{opacity:.55}._367UGW_select{-webkit-appearance:none;appearance:none;color:var(--dsw-alias-label-primary);background-color:var(--dsw-specific-input-major);background-image:linear-gradient(45deg, transparent 50%, var(--dsw-alias-label-secondary) 50%), linear-gradient(135deg, var(--dsw-alias-label-secondary) 50%, transparent 50%);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background-position:calc(100% - 17px) calc(50% - 1px),calc(100% - 12px) calc(50% - 1px);background-repeat:no-repeat;background-size:5px 5px,5px 5px;border-radius:8px;outline:none;max-width:100%;padding:7px 30px 7px 10px;font-family:inherit;font-size:13px}._367UGW_select:hover:not(:disabled){border-color:var(--dsw-alias-border-l1)}._367UGW_select:focus{border-color:var(--dsw-alias-state-business-primary)}._367UGW_select:disabled{opacity:.55;cursor:default}._367UGW_select option{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}._367UGW_hint{color:var(--dsw-alias-label-tertiary);font-size:11.5px;line-height:1.5}._367UGW_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._367UGW_checkboxRow{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:flex-start;gap:8px;font-size:13px;display:flex}._367UGW_checkboxRow input{flex:none;margin-top:2px}._367UGW_radioLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:13px;display:inline-flex}._367UGW_secretFields{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px 12px;padding-top:4px;display:grid}._367UGW_hiddenFile{display:none}._367UGW_modeTabs{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;gap:2px;display:flex}._367UGW_modeTab{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px;font-size:12.5px}._367UGW_modeTab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._367UGW_modeTab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}._367UGW_modeHint{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}._367UGW_groupList{flex-direction:column;gap:10px;display:flex}._367UGW_groupCard{gap:8px}._367UGW_groupHeader{flex-wrap:wrap;align-items:baseline;gap:8px;display:flex}._367UGW_groupLabel{color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:700}._367UGW_groupNote{color:var(--dsw-alias-label-tertiary);font-size:11.5px}._367UGW_groupItems{flex-direction:column;gap:6px;display:flex}._367UGW_categoryItem{flex-wrap:wrap;align-items:center;gap:8px;display:inline-flex}._367UGW_categoryName{font-weight:500}._367UGW_categoryDesc{color:var(--dsw-alias-label-tertiary);font-size:11.5px}._367UGW_optionsCard{gap:8px}._367UGW_optionsHeader{color:var(--dsw-alias-label-primary);letter-spacing:.02em;margin-bottom:2px;font-size:12px;font-weight:600}._367UGW_warnList{margin:4px 0 0;padding-left:18px}._367UGW_actionRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._367UGW_progressBlock{flex-direction:column;flex:none;gap:6px;display:flex}._367UGW_progressMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:12px;font-size:12px;display:flex}._367UGW_progressLabel{font-weight:600}._367UGW_progressDetail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;max-width:320px;overflow:hidden}._367UGW_progressBadge{font-variant-numeric:tabular-nums;white-space:nowrap;border-radius:999px;align-items:center;gap:2px;padding:1px 8px;font-size:11px;line-height:18px;display:inline-flex}._367UGW_progressBadgeSection{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);color:var(--dsw-alias-state-business-primary)}._367UGW_progressBadgeCount{background:color-mix(in srgb, var(--dsw-alias-state-info-primary) 14%, transparent);color:var(--dsw-alias-state-info-primary)}._367UGW_progressPercent{font-variant-numeric:tabular-nums;margin-left:auto}._367UGW_progressTrack{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;height:8px;overflow:hidden}._367UGW_progressBar{background:var(--dsw-alias-state-business-primary);border-radius:999px;height:100%;transition:width .12s linear}._367UGW_progressBarDone{background:var(--dsw-alias-state-success-primary)}._367UGW_progressIndeterminate{width:40%;animation:1s ease-in-out infinite _367UGW_dshCmIndeterminate}@keyframes _367UGW_dshCmIndeterminate{0%{margin-left:-40%}to{margin-left:100%}}._367UGW_reportView{flex-direction:column;gap:10px;display:flex}._367UGW_statRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}._367UGW_reportText{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;max-height:260px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;line-height:1.6;overflow:auto}._367UGW_reportFooter{justify-content:flex-end;gap:8px;display:flex}._367UGW_rollbackBox{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_rollbackBox ._367UGW_reportText{border-color:var(--dsw-alias-border-l2)}._367UGW_errorBanner{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_errorTitle{color:var(--dsw-alias-state-error-primary);font-size:13px;font-weight:700}._367UGW_errorReason{white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-label-secondary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px}._367UGW_errorAction{color:var(--dsw-alias-label-secondary);font-size:12.5px}._367UGW_errorActionLabel{color:var(--dsw-alias-state-business-primary)}._367UGW_errorItem{color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px}._367UGW_errorFooter{justify-content:flex-end;display:flex}._367UGW_errorList{flex-direction:column;gap:4px;display:flex}._367UGW_errorLine{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-state-error-primary);border-radius:6px;margin:0;padding:6px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}._367UGW_conflictList{flex-direction:column;gap:10px;display:flex}._367UGW_conflictItem{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._367UGW_conflictHead{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._367UGW_conflictId{color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:600}._367UGW_severityError{color:var(--dsw-alias-state-error-primary);border:1px solid var(--dsw-alias-state-error-primary);border-radius:999px;padding:0 6px;font-size:10.5px}._367UGW_conflictDetail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;color:var(--dsw-alias-label-secondary);border-radius:6px;margin:0;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}._367UGW_conflictOptions{flex-wrap:wrap;gap:14px;display:flex}._367UGW_pathMappingList{flex-direction:column;gap:8px;display:flex}._367UGW_pathRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;padding:10px 12px;display:grid}._367UGW_pathOld,._367UGW_pathNew{flex-direction:column;gap:4px;min-width:0;display:flex}._367UGW_pathValue{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;overflow:hidden}._367UGW_pathIssueKind{color:var(--dsw-alias-state-warn-primary);font-size:10.5px}._367UGW_secretsList{flex-direction:column;gap:10px;display:flex}._367UGW_empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:22px 12px;font-size:12.5px}._367UGW_spinnerWrap{align-items:center;gap:6px;display:inline-flex}._367UGW_spinner{border:2px solid var(--dsw-alias-state-business-primary);vertical-align:-1px;border-top-color:#0000;border-radius:50%;flex:none;width:11px;height:11px;animation:.8s linear infinite _367UGW_dshCmSpin;display:inline-block}._367UGW_spinnerLabel{color:var(--dsw-alias-label-secondary);font-size:12px}@keyframes _367UGW_dshCmSpin{to{transform:rotate(360deg)}}._367UGW_snapshotList{flex-direction:column;gap:2px;display:flex}._367UGW_snapshotRowHeader,._367UGW_snapshotRow{grid-template-columns:minmax(120px,1.2fr) minmax(140px,1.6fr) 90px 56px 56px;align-items:center;gap:8px;padding:6px 10px;font-size:12px;display:grid}._367UGW_snapshotRowHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-border-l1);font-size:11px}._367UGW_snapshotRow{text-align:left;width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px}._367UGW_snapshotRow:hover{background:var(--dsw-alias-interactive-bg-hover)}._367UGW_snapshotRow[data-active]{border-color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent)}._367UGW_warnText{color:var(--dsw-alias-state-warn-primary)}._367UGW_reportList{color:var(--dsw-alias-label-primary);flex-direction:column;gap:3px;margin:8px 0 4px;padding-left:18px;font-size:12px;display:flex}._367UGW_kindTag{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 6px;font-size:10.5px;display:inline-block}._367UGW_planScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;height:280px;padding:2px 10px 8px;overflow-y:auto}._367UGW_planScroll ._367UGW_reportList{margin-top:6px}._367UGW_reportScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;max-height:220px;padding:2px 10px 6px;overflow-y:auto}._367UGW_reportScroll ._367UGW_reportList{margin-top:4px}._367UGW_confirmScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;max-height:280px;padding:2px 10px 6px;overflow-y:auto}._367UGW_confirmScroll ._367UGW_reportList{margin-top:4px;margin-bottom:0}._367UGW_pullScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;height:280px;padding:2px 10px 6px;overflow-y:auto}._367UGW_pullScroll ._367UGW_reportList{margin-top:4px;margin-bottom:0}._367UGW_rowActions{gap:8px;margin-top:10px;display:flex}._367UGW_diffScroll{overscroll-behavior:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;max-height:240px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;line-height:1.6;overflow:auto}._367UGW_aboutLinkRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}._367UGW_aboutAuthor{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:4px 8px;font-size:13px;text-decoration:none;display:inline-flex}._367UGW_aboutAuthor:hover{background:var(--dsw-alias-interactive-bg-hover)}._367UGW_dialogMask{z-index:100;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:20px;display:flex;position:fixed;inset:0}._367UGW_dialogCard{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:min(420px,100%);max-height:80vh;box-shadow:0 8px 24px color-mix(in srgb, var(--dsw-alias-bg-base) 40%, transparent);border-radius:10px;flex-direction:column;gap:10px;padding:14px;display:flex}._367UGW_dialogHeader{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:600}._367UGW_dialogBody{overscroll-behavior:contain;max-height:240px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;font-size:13px;line-height:1.6;overflow-y:auto}._367UGW_dialogWide{width:min(560px,100%)}._367UGW_dialogBodyScroll{overscroll-behavior:contain;max-height:70vh;color:var(--dsw-alias-label-primary);white-space:normal;font-size:13px;line-height:1.6;overflow-y:auto}._367UGW_dialogHeaderRow{justify-content:space-between;align-items:center;gap:10px;display:flex}._367UGW_dialogClose{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:2px 8px;font-size:16px;line-height:1}._367UGW_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-hover)}";
|
|
2904
2900
|
const tagId = "dsh-config-manager/config-manager.module.css";
|
|
2905
2901
|
if (typeof document !== "undefined" && document.querySelector("style[data-tag=\"dsh-config-manager/config-manager.module.css\"]") === null) {
|
|
2906
2902
|
const tag = document.createElement("style");
|
|
@@ -2910,111 +2906,120 @@ if (typeof document !== "undefined" && document.querySelector("style[data-tag=\"
|
|
|
2910
2906
|
document.head.appendChild(tag);
|
|
2911
2907
|
}
|
|
2912
2908
|
var config_manager_module_css_default = {
|
|
2913
|
-
"
|
|
2914
|
-
"
|
|
2915
|
-
"planScroll": "_367UGW_planScroll",
|
|
2916
|
-
"pullScroll": "_367UGW_pullScroll",
|
|
2917
|
-
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
2918
|
-
"reportScroll": "_367UGW_reportScroll",
|
|
2919
|
-
"primaryButton": "_367UGW_primaryButton",
|
|
2920
|
-
"progressMeta": "_367UGW_progressMeta",
|
|
2921
|
-
"errorLine": "_367UGW_errorLine",
|
|
2922
|
-
"progressBadgeSection": "_367UGW_progressBadgeSection",
|
|
2909
|
+
"secretFields": "_367UGW_secretFields",
|
|
2910
|
+
"warnList": "_367UGW_warnList",
|
|
2923
2911
|
"reportView": "_367UGW_reportView",
|
|
2924
|
-
"
|
|
2925
|
-
"
|
|
2926
|
-
"
|
|
2927
|
-
"
|
|
2928
|
-
"
|
|
2929
|
-
"
|
|
2912
|
+
"categoryDesc": "_367UGW_categoryDesc",
|
|
2913
|
+
"aboutLinkRow": "_367UGW_aboutLinkRow",
|
|
2914
|
+
"dialogClose": "_367UGW_dialogClose",
|
|
2915
|
+
"dialogHeaderRow": "_367UGW_dialogHeaderRow",
|
|
2916
|
+
"dshCmIndeterminate": "_367UGW_dshCmIndeterminate",
|
|
2917
|
+
"formError": "_367UGW_formError",
|
|
2918
|
+
"primaryButton": "_367UGW_primaryButton",
|
|
2919
|
+
"dshCmSpin": "_367UGW_dshCmSpin",
|
|
2920
|
+
"progressBar": "_367UGW_progressBar",
|
|
2921
|
+
"groupHeader": "_367UGW_groupHeader",
|
|
2930
2922
|
"select": "_367UGW_select",
|
|
2931
|
-
"
|
|
2932
|
-
"
|
|
2933
|
-
"
|
|
2934
|
-
"
|
|
2935
|
-
"
|
|
2936
|
-
"
|
|
2923
|
+
"optionsHeader": "_367UGW_optionsHeader",
|
|
2924
|
+
"progressMeta": "_367UGW_progressMeta",
|
|
2925
|
+
"progressIndeterminate": "_367UGW_progressIndeterminate",
|
|
2926
|
+
"reportText": "_367UGW_reportText",
|
|
2927
|
+
"planScroll": "_367UGW_planScroll",
|
|
2928
|
+
"errorTitle": "_367UGW_errorTitle",
|
|
2929
|
+
"sectionHeader": "_367UGW_sectionHeader",
|
|
2937
2930
|
"reportList": "_367UGW_reportList",
|
|
2938
|
-
"
|
|
2939
|
-
"
|
|
2940
|
-
"
|
|
2941
|
-
"badgeOk": "_367UGW_badgeOk",
|
|
2942
|
-
"conflictItem": "_367UGW_conflictItem",
|
|
2943
|
-
"errorBanner": "_367UGW_errorBanner",
|
|
2944
|
-
"conflictId": "_367UGW_conflictId",
|
|
2931
|
+
"conflictHead": "_367UGW_conflictHead",
|
|
2932
|
+
"progressBadgeSection": "_367UGW_progressBadgeSection",
|
|
2933
|
+
"rollbackBox": "_367UGW_rollbackBox",
|
|
2945
2934
|
"secretsList": "_367UGW_secretsList",
|
|
2946
|
-
"
|
|
2935
|
+
"sectionTitle": "_367UGW_sectionTitle",
|
|
2936
|
+
"hiddenFile": "_367UGW_hiddenFile",
|
|
2937
|
+
"errorLine": "_367UGW_errorLine",
|
|
2947
2938
|
"input": "_367UGW_input",
|
|
2948
|
-
"
|
|
2949
|
-
"
|
|
2950
|
-
"
|
|
2951
|
-
"
|
|
2952
|
-
"
|
|
2953
|
-
"
|
|
2939
|
+
"conflictOptions": "_367UGW_conflictOptions",
|
|
2940
|
+
"viewBody": "_367UGW_viewBody",
|
|
2941
|
+
"dialogBodyScroll": "_367UGW_dialogBodyScroll",
|
|
2942
|
+
"errorActionLabel": "_367UGW_errorActionLabel",
|
|
2943
|
+
"pathValue": "_367UGW_pathValue",
|
|
2944
|
+
"pathNew": "_367UGW_pathNew",
|
|
2954
2945
|
"progressTrack": "_367UGW_progressTrack",
|
|
2946
|
+
"wizardCard": "_367UGW_wizardCard",
|
|
2947
|
+
"snapshotRowHeader": "_367UGW_snapshotRowHeader",
|
|
2948
|
+
"progressBadge": "_367UGW_progressBadge",
|
|
2949
|
+
"pathMappingList": "_367UGW_pathMappingList",
|
|
2950
|
+
"snapshotRow": "_367UGW_snapshotRow",
|
|
2951
|
+
"dialogMask": "_367UGW_dialogMask",
|
|
2952
|
+
"categoryItem": "_367UGW_categoryItem",
|
|
2953
|
+
"sectionBody": "_367UGW_sectionBody",
|
|
2955
2954
|
"conflictDetail": "_367UGW_conflictDetail",
|
|
2956
|
-
"
|
|
2957
|
-
"kindTag": "_367UGW_kindTag",
|
|
2958
|
-
"progressBlock": "_367UGW_progressBlock",
|
|
2959
|
-
"badgeWarn": "_367UGW_badgeWarn",
|
|
2960
|
-
"groupNote": "_367UGW_groupNote",
|
|
2961
|
-
"groupHeader": "_367UGW_groupHeader",
|
|
2962
|
-
"actionRow": "_367UGW_actionRow",
|
|
2963
|
-
"optionsCard": "_367UGW_optionsCard",
|
|
2964
|
-
"pathOld": "_367UGW_pathOld",
|
|
2965
|
-
"errorItem": "_367UGW_errorItem",
|
|
2955
|
+
"progressBadgeCount": "_367UGW_progressBadgeCount",
|
|
2966
2956
|
"snapshotList": "_367UGW_snapshotList",
|
|
2967
|
-
"pathNew": "_367UGW_pathNew",
|
|
2968
2957
|
"confirmScroll": "_367UGW_confirmScroll",
|
|
2969
|
-
"conflictList": "_367UGW_conflictList",
|
|
2970
|
-
"categoryName": "_367UGW_categoryName",
|
|
2971
|
-
"groupLabel": "_367UGW_groupLabel",
|
|
2972
|
-
"errorList": "_367UGW_errorList",
|
|
2973
|
-
"card": "_367UGW_card",
|
|
2974
|
-
"sectionTitle": "_367UGW_sectionTitle",
|
|
2975
|
-
"optionsHeader": "_367UGW_optionsHeader",
|
|
2976
2958
|
"aboutAuthor": "_367UGW_aboutAuthor",
|
|
2977
|
-
"progressBadgeCount": "_367UGW_progressBadgeCount",
|
|
2978
|
-
"fieldLabel": "_367UGW_fieldLabel",
|
|
2979
|
-
"reportText": "_367UGW_reportText",
|
|
2980
|
-
"severityError": "_367UGW_severityError",
|
|
2981
|
-
"formError": "_367UGW_formError",
|
|
2982
|
-
"pathMappingList": "_367UGW_pathMappingList",
|
|
2983
|
-
"empty": "_367UGW_empty",
|
|
2984
|
-
"spinnerWrap": "_367UGW_spinnerWrap",
|
|
2985
|
-
"field": "_367UGW_field",
|
|
2986
|
-
"secretFields": "_367UGW_secretFields",
|
|
2987
|
-
"rollbackBox": "_367UGW_rollbackBox",
|
|
2988
2959
|
"rowActions": "_367UGW_rowActions",
|
|
2989
|
-
"
|
|
2990
|
-
"
|
|
2991
|
-
"
|
|
2992
|
-
"
|
|
2993
|
-
"
|
|
2994
|
-
"radioLabel": "_367UGW_radioLabel",
|
|
2995
|
-
"groupCard": "_367UGW_groupCard",
|
|
2960
|
+
"dialogCard": "_367UGW_dialogCard",
|
|
2961
|
+
"groupLabel": "_367UGW_groupLabel",
|
|
2962
|
+
"modeHint": "_367UGW_modeHint",
|
|
2963
|
+
"actionRow": "_367UGW_actionRow",
|
|
2964
|
+
"statRow": "_367UGW_statRow",
|
|
2996
2965
|
"reportFooter": "_367UGW_reportFooter",
|
|
2997
|
-
"
|
|
2998
|
-
"
|
|
2999
|
-
"
|
|
3000
|
-
"
|
|
2966
|
+
"errorBanner": "_367UGW_errorBanner",
|
|
2967
|
+
"diffScroll": "_367UGW_diffScroll",
|
|
2968
|
+
"badgeOk": "_367UGW_badgeOk",
|
|
2969
|
+
"optionsCard": "_367UGW_optionsCard",
|
|
3001
2970
|
"hint": "_367UGW_hint",
|
|
3002
|
-
"
|
|
3003
|
-
"
|
|
2971
|
+
"card": "_367UGW_card",
|
|
2972
|
+
"badgeWarn": "_367UGW_badgeWarn",
|
|
2973
|
+
"pullScroll": "_367UGW_pullScroll",
|
|
2974
|
+
"pathIssueKind": "_367UGW_pathIssueKind",
|
|
2975
|
+
"ghostButton": "_367UGW_ghostButton",
|
|
2976
|
+
"conflictId": "_367UGW_conflictId",
|
|
2977
|
+
"severityError": "_367UGW_severityError",
|
|
2978
|
+
"radioLabel": "_367UGW_radioLabel",
|
|
2979
|
+
"checkboxRow": "_367UGW_checkboxRow",
|
|
2980
|
+
"categoryName": "_367UGW_categoryName",
|
|
2981
|
+
"pathOld": "_367UGW_pathOld",
|
|
2982
|
+
"errorList": "_367UGW_errorList",
|
|
2983
|
+
"conflictList": "_367UGW_conflictList",
|
|
2984
|
+
"progressLabel": "_367UGW_progressLabel",
|
|
2985
|
+
"sectionTitleBlock": "_367UGW_sectionTitleBlock",
|
|
2986
|
+
"section": "_367UGW_section",
|
|
2987
|
+
"viewTabs": "_367UGW_viewTabs",
|
|
3004
2988
|
"errorFooter": "_367UGW_errorFooter",
|
|
2989
|
+
"dialogWide": "_367UGW_dialogWide",
|
|
2990
|
+
"dialogBody": "_367UGW_dialogBody",
|
|
2991
|
+
"modeTabs": "_367UGW_modeTabs",
|
|
2992
|
+
"progressBlock": "_367UGW_progressBlock",
|
|
2993
|
+
"errorItem": "_367UGW_errorItem",
|
|
2994
|
+
"empty": "_367UGW_empty",
|
|
2995
|
+
"kindTag": "_367UGW_kindTag",
|
|
2996
|
+
"progressPercent": "_367UGW_progressPercent",
|
|
2997
|
+
"fieldLabel": "_367UGW_fieldLabel",
|
|
2998
|
+
"groupNote": "_367UGW_groupNote",
|
|
2999
|
+
"errorReason": "_367UGW_errorReason",
|
|
3000
|
+
"viewTab": "_367UGW_viewTab",
|
|
3001
|
+
"spinner": "_367UGW_spinner",
|
|
3002
|
+
"sectionSubtitle": "_367UGW_sectionSubtitle",
|
|
3003
|
+
"spinnerLabel": "_367UGW_spinnerLabel",
|
|
3004
|
+
"badgeError": "_367UGW_badgeError",
|
|
3005
|
+
"warnText": "_367UGW_warnText",
|
|
3006
|
+
"field": "_367UGW_field",
|
|
3007
|
+
"reportScroll": "_367UGW_reportScroll",
|
|
3005
3008
|
"pathRow": "_367UGW_pathRow",
|
|
3009
|
+
"badgeInfo": "_367UGW_badgeInfo",
|
|
3010
|
+
"modeTab": "_367UGW_modeTab",
|
|
3011
|
+
"progressBarDone": "_367UGW_progressBarDone",
|
|
3012
|
+
"badge": "_367UGW_badge",
|
|
3013
|
+
"groupList": "_367UGW_groupList",
|
|
3014
|
+
"dialogHeader": "_367UGW_dialogHeader",
|
|
3006
3015
|
"progressDetail": "_367UGW_progressDetail",
|
|
3007
|
-
"
|
|
3008
|
-
"snapshotRowHeader": "_367UGW_snapshotRowHeader",
|
|
3009
|
-
"viewBody": "_367UGW_viewBody",
|
|
3010
|
-
"modeTabs": "_367UGW_modeTabs",
|
|
3011
|
-
"errorTitle": "_367UGW_errorTitle",
|
|
3016
|
+
"spinnerWrap": "_367UGW_spinnerWrap",
|
|
3012
3017
|
"errorAction": "_367UGW_errorAction",
|
|
3013
|
-
"
|
|
3014
|
-
"
|
|
3015
|
-
"
|
|
3016
|
-
"
|
|
3017
|
-
"
|
|
3018
|
+
"groupItems": "_367UGW_groupItems",
|
|
3019
|
+
"dangerButton": "_367UGW_dangerButton",
|
|
3020
|
+
"banner": "_367UGW_banner",
|
|
3021
|
+
"groupCard": "_367UGW_groupCard",
|
|
3022
|
+
"conflictItem": "_367UGW_conflictItem"
|
|
3018
3023
|
};
|
|
3019
3024
|
//#endregion
|
|
3020
3025
|
//#region src/client/common/ui.tsx
|
|
@@ -5020,6 +5025,7 @@ const SYNC_API = {
|
|
|
5020
5025
|
githubStart: "/api/dsh-config-manager/sync/github/start",
|
|
5021
5026
|
githubPoll: "/api/dsh-config-manager/sync/github/poll",
|
|
5022
5027
|
githubCancel: "/api/dsh-config-manager/sync/github/cancel",
|
|
5028
|
+
githubValidate: "/api/dsh-config-manager/sync/github/validate",
|
|
5023
5029
|
history: "/api/dsh-config-manager/sync/history",
|
|
5024
5030
|
snapshotsList: "/api/dsh-config-manager/sync/snapshots-list",
|
|
5025
5031
|
sync: "/api/dsh-config-manager/sync/sync",
|
|
@@ -5094,6 +5100,11 @@ var SyncApi = class {
|
|
|
5094
5100
|
async githubCancel(flowId) {
|
|
5095
5101
|
return postJson$2(SYNC_API.githubCancel, { flowId }, this.t);
|
|
5096
5102
|
}
|
|
5103
|
+
/** GitHub token 有效性校验(判定「是否已登录」:token 存在且 GitHub API 接受;
|
|
5104
|
+
* 401 → valid:false 引导重新登录;非 401 错误向上抛,UI 兜底不误判登出) */
|
|
5105
|
+
async githubValidate() {
|
|
5106
|
+
return postJson$2(SYNC_API.githubValidate, {}, this.t);
|
|
5107
|
+
}
|
|
5097
5108
|
/** 同步历史:列出本地祖先快照 + 自动同步执行记录(按 createdAt 倒序合并)。 */
|
|
5098
5109
|
async history() {
|
|
5099
5110
|
return readJson$2(await fetch(SYNC_API.history), this.t);
|
|
@@ -5373,15 +5384,20 @@ function AutosyncRow({ entry, t }) {
|
|
|
5373
5384
|
* 全部渲染模型来自 ./sync-view.ts 纯函数(node 单测覆盖),组件只做装配 + 交互状态。
|
|
5374
5385
|
*/
|
|
5375
5386
|
function SyncConfirmView(props) {
|
|
5376
|
-
const { api, syncSessionId, snapshotId, items, needsReview, compatibility, t, onCancel, onRollbackDone } = props;
|
|
5377
|
-
const
|
|
5378
|
-
const
|
|
5379
|
-
for (const it of items)
|
|
5387
|
+
const { api, syncSessionId, snapshotId, items, needsReview, compatibility, t, decisions, onDecisionsChange, onCancel, onRollbackDone } = props;
|
|
5388
|
+
const states = (0, react.useMemo)(() => {
|
|
5389
|
+
const base = {};
|
|
5390
|
+
for (const it of items) base[it.itemId] = {
|
|
5380
5391
|
adopted: it.defaultAdopt,
|
|
5381
5392
|
resolution: void 0
|
|
5382
5393
|
};
|
|
5383
|
-
return
|
|
5384
|
-
|
|
5394
|
+
if (decisions === null) return base;
|
|
5395
|
+
for (const [id, d] of Object.entries(decisions)) if (base[id] !== void 0) base[id] = {
|
|
5396
|
+
adopted: d.adopted,
|
|
5397
|
+
resolution: d.resolution
|
|
5398
|
+
};
|
|
5399
|
+
return base;
|
|
5400
|
+
}, [items, decisions]);
|
|
5385
5401
|
const [phase, setPhase] = (0, react.useState)("idle");
|
|
5386
5402
|
const [applyResult, setApplyResult] = (0, react.useState)(null);
|
|
5387
5403
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -5391,46 +5407,46 @@ function SyncConfirmView(props) {
|
|
|
5391
5407
|
}))), [items, states]);
|
|
5392
5408
|
const displayItems = (0, react.useMemo)(() => reviewItems(items), [items]);
|
|
5393
5409
|
const setAdopted = (itemId, adopted) => {
|
|
5394
|
-
|
|
5395
|
-
|
|
5410
|
+
const existing = states[itemId] ?? {
|
|
5411
|
+
adopted: false,
|
|
5412
|
+
resolution: void 0
|
|
5413
|
+
};
|
|
5414
|
+
onDecisionsChange({
|
|
5415
|
+
...decisions ?? {},
|
|
5396
5416
|
[itemId]: {
|
|
5397
|
-
|
|
5398
|
-
|
|
5417
|
+
adopted,
|
|
5418
|
+
resolution: existing.resolution
|
|
5399
5419
|
}
|
|
5400
|
-
})
|
|
5420
|
+
});
|
|
5401
5421
|
};
|
|
5402
5422
|
const setResolution = (itemId, resolution) => {
|
|
5403
|
-
|
|
5404
|
-
|
|
5423
|
+
const existing = states[itemId] ?? {
|
|
5424
|
+
adopted: false,
|
|
5425
|
+
resolution: void 0
|
|
5426
|
+
};
|
|
5427
|
+
onDecisionsChange({
|
|
5428
|
+
...decisions ?? {},
|
|
5429
|
+
[itemId]: {
|
|
5430
|
+
adopted: existing.adopted,
|
|
5431
|
+
resolution
|
|
5432
|
+
}
|
|
5433
|
+
});
|
|
5434
|
+
};
|
|
5435
|
+
const applyBulkDecision = (bulk) => {
|
|
5436
|
+
if (bulk.length === 0) return;
|
|
5437
|
+
const next = { ...decisions ?? {} };
|
|
5438
|
+
for (const d of bulk) {
|
|
5439
|
+
const existing = states[d.itemId] ?? {
|
|
5405
5440
|
adopted: false,
|
|
5406
5441
|
resolution: void 0
|
|
5407
5442
|
};
|
|
5408
|
-
|
|
5409
|
-
...
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
resolution
|
|
5413
|
-
}
|
|
5443
|
+
next[d.itemId] = {
|
|
5444
|
+
...existing,
|
|
5445
|
+
resolution: d.resolution,
|
|
5446
|
+
adopted: d.adopt
|
|
5414
5447
|
};
|
|
5415
|
-
}
|
|
5416
|
-
|
|
5417
|
-
const applyBulkDecision = (decisions) => {
|
|
5418
|
-
if (decisions.length === 0) return;
|
|
5419
|
-
setStates((prev) => {
|
|
5420
|
-
const next = { ...prev };
|
|
5421
|
-
for (const d of decisions) {
|
|
5422
|
-
const existing = prev[d.itemId] ?? {
|
|
5423
|
-
adopted: false,
|
|
5424
|
-
resolution: void 0
|
|
5425
|
-
};
|
|
5426
|
-
next[d.itemId] = {
|
|
5427
|
-
...existing,
|
|
5428
|
-
resolution: d.resolution,
|
|
5429
|
-
adopted: d.adopt
|
|
5430
|
-
};
|
|
5431
|
-
}
|
|
5432
|
-
return next;
|
|
5433
|
-
});
|
|
5448
|
+
}
|
|
5449
|
+
onDecisionsChange(next);
|
|
5434
5450
|
};
|
|
5435
5451
|
const runApply = async () => {
|
|
5436
5452
|
const unresolved = items.find((it) => it.kind === "Conflict" && states[it.itemId]?.adopted === true && states[it.itemId]?.resolution === void 0);
|
|
@@ -5735,10 +5751,16 @@ function ApplyResultCard({ result, busy, t, onRollback }) {
|
|
|
5735
5751
|
*
|
|
5736
5752
|
* 独立设置页壳(sectionHeader/close/自身 tab)已移除 —— tab 容器由
|
|
5737
5753
|
* ConfigManagerSection 统一渲染,本组件只输出内容体:
|
|
5738
|
-
* -
|
|
5739
|
-
*
|
|
5754
|
+
* - **同步通道入口卡**:展示当前通道 + 配置状态 + 凭据徽章;点「配置同步通道」
|
|
5755
|
+
* → 弹出**通道配置弹窗**(弹窗体系与市场操作弹窗一致,DESIGN.md §8.12:
|
|
5756
|
+
* dialogMask + dialogCard dialogWide + dialogHeaderRow + dialogClose +
|
|
5757
|
+
* dialogBodyScroll,零新增样式);
|
|
5758
|
+
* - **通道配置弹窗**:通道子 tab(GitHub(git)/ WebDAV)切换,两个通道的
|
|
5759
|
+
* 配置表单、自动同步、同步模式、是否加密、远端快照**各自独立**;关闭弹窗
|
|
5760
|
+
* = 放弃本次操作(GitHub 登录流程进行中则一并取消,§8.12 约定);
|
|
5740
5761
|
* - GitHub 子 tab:repoUrl(必填)+ 认证 token(可选,写入 DSH credentials 的提示)
|
|
5741
|
-
* + GitHub OAuth device flow
|
|
5762
|
+
* + **GitHub OAuth device flow 登录**(登录块跟随 git 通道配置放在弹窗内:
|
|
5763
|
+
* 未登录/失效时显示;git 可执行文件固定使用系统 PATH 中的 git);
|
|
5742
5764
|
* - WebDAV 子 tab:url + username + password(密码写入 DSH credentials)+ 常见服务器预设;
|
|
5743
5765
|
* - 私有仓库强制提示横幅(仅 git 子 tab 常驻);
|
|
5744
5766
|
* - 推送按钮 → SyncPushReport;拉取按钮 → SyncPullReport.changes 差异摘要;
|
|
@@ -5791,9 +5813,11 @@ const initial$2 = {
|
|
|
5791
5813
|
pushReport: null,
|
|
5792
5814
|
pullReport: null,
|
|
5793
5815
|
confirmSession: null,
|
|
5816
|
+
confirmDecisions: null,
|
|
5794
5817
|
lastRestoreId: null,
|
|
5795
5818
|
error: null,
|
|
5796
|
-
github: initialGithub
|
|
5819
|
+
github: initialGithub,
|
|
5820
|
+
githubSignedIn: null
|
|
5797
5821
|
};
|
|
5798
5822
|
/**
|
|
5799
5823
|
* 从 runStore 恢复上次的同步 UI 状态(切 tab 回 / 刷新后挂载)。
|
|
@@ -5827,6 +5851,7 @@ function initFromStore$1() {
|
|
|
5827
5851
|
pushReport: s.pushReport,
|
|
5828
5852
|
pullReport: s.pullReport,
|
|
5829
5853
|
confirmSession: s.confirmSession,
|
|
5854
|
+
confirmDecisions: s.confirmDecisions,
|
|
5830
5855
|
lastRestoreId: s.lastRestoreId,
|
|
5831
5856
|
error: s.error,
|
|
5832
5857
|
loadError: s.loadError
|
|
@@ -5839,6 +5864,8 @@ function SyncSettingsView({ api, t }) {
|
|
|
5839
5864
|
const stateRef = (0, react.useRef)(state);
|
|
5840
5865
|
/** 挂载守卫:卸载后不再 setState(store 镜像仍执行,异步结果照常落库) */
|
|
5841
5866
|
const mountedRef = (0, react.useRef)(true);
|
|
5867
|
+
/** 通道配置弹窗开关(瞬态 UI:切 tab/刷新不持久化,弹窗不自动重开;DESIGN.md §8.12 约定) */
|
|
5868
|
+
const [channelOpen, setChannelOpen] = (0, react.useState)(false);
|
|
5842
5869
|
/**
|
|
5843
5870
|
* 统一提交入口:更新 stateRef → 挂载时 setState → **总是**镜像进 runStore。
|
|
5844
5871
|
* 关键:镜像不依赖 effect flush —— 异步操作(push/pull/sync)完成回调在组件
|
|
@@ -5936,6 +5963,7 @@ function SyncSettingsView({ api, t }) {
|
|
|
5936
5963
|
const activeCh = remembered ?? savedChannel;
|
|
5937
5964
|
const preset = activeCh === "webdav" ? info.webdav?.url ?? "" : info.repoUrl ?? "";
|
|
5938
5965
|
if (info.configured && preset.trim() !== "") loadSnapshots(preset, activeCh);
|
|
5966
|
+
validateGithub();
|
|
5939
5967
|
} catch (err) {
|
|
5940
5968
|
patch({
|
|
5941
5969
|
loading: false,
|
|
@@ -6079,6 +6107,7 @@ function SyncSettingsView({ api, t }) {
|
|
|
6079
6107
|
next.statusInfo = info;
|
|
6080
6108
|
}
|
|
6081
6109
|
commit(next);
|
|
6110
|
+
if (payloadToSave.transport !== "webdav" && saved.credentialConfigured) validateGithub();
|
|
6082
6111
|
} catch (err) {
|
|
6083
6112
|
patch({
|
|
6084
6113
|
savingConfig: false,
|
|
@@ -6161,9 +6190,13 @@ function SyncSettingsView({ api, t }) {
|
|
|
6161
6190
|
}
|
|
6162
6191
|
const message = githubPollMessage(poll, uiT);
|
|
6163
6192
|
if (poll.status === "success") {
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6193
|
+
patch({
|
|
6194
|
+
githubSignedIn: true,
|
|
6195
|
+
github: {
|
|
6196
|
+
...stateRef.current.github,
|
|
6197
|
+
phase: "success",
|
|
6198
|
+
error: null
|
|
6199
|
+
}
|
|
6167
6200
|
});
|
|
6168
6201
|
loadStatus();
|
|
6169
6202
|
} else patchGithub({
|
|
@@ -6189,6 +6222,34 @@ function SyncSettingsView({ api, t }) {
|
|
|
6189
6222
|
await api.githubCancel(flowId);
|
|
6190
6223
|
} catch {}
|
|
6191
6224
|
};
|
|
6225
|
+
/**
|
|
6226
|
+
* 校验 GitHub token 是否有效(「已登录」判定 → 决定登录块显隐)。
|
|
6227
|
+
* 挂载 / 登录成功 / 保存凭据后调用;已确认登录(githubSignedIn===true)时跳过
|
|
6228
|
+
* (避免反复网络调用)。401 → 未登录:显示登录块并提示重新登录;网络等其余
|
|
6229
|
+
* 错误 → 保持现状(不误判登出,已登录用户不被打扰;下次进入页面会再校验)。
|
|
6230
|
+
*/
|
|
6231
|
+
const validateGithub = async () => {
|
|
6232
|
+
if (stateRef.current.githubSignedIn === true) return;
|
|
6233
|
+
try {
|
|
6234
|
+
const res = await api.githubValidate();
|
|
6235
|
+
patch({ githubSignedIn: res.configured && res.valid });
|
|
6236
|
+
} catch {}
|
|
6237
|
+
};
|
|
6238
|
+
/** 打开通道配置弹窗:登录态尚未校验时补一次校验(决定 Git 子 tab 登录块显隐)。 */
|
|
6239
|
+
const openChannelDialog = () => {
|
|
6240
|
+
setChannelOpen(true);
|
|
6241
|
+
if (stateRef.current.githubSignedIn === null) validateGithub();
|
|
6242
|
+
};
|
|
6243
|
+
/**
|
|
6244
|
+
* 关闭通道配置弹窗 = 放弃本次操作(§8.12 约定):GitHub 登录流程进行中则取消
|
|
6245
|
+
* (停轮询 + 通知宿主丢弃设备码登记),保存中(savingConfig)时禁止关闭。
|
|
6246
|
+
*/
|
|
6247
|
+
const closeChannelDialog = () => {
|
|
6248
|
+
if (stateRef.current.savingConfig) return;
|
|
6249
|
+
const phase = stateRef.current.github.phase;
|
|
6250
|
+
if (phase === "starting" || phase === "waiting" || phase === "polling") runGithubCancel();
|
|
6251
|
+
setChannelOpen(false);
|
|
6252
|
+
};
|
|
6192
6253
|
const runPush = async () => {
|
|
6193
6254
|
patch({
|
|
6194
6255
|
busy: "push",
|
|
@@ -6312,6 +6373,7 @@ function SyncSettingsView({ api, t }) {
|
|
|
6312
6373
|
busy: "sync",
|
|
6313
6374
|
error: null,
|
|
6314
6375
|
confirmSession: null,
|
|
6376
|
+
confirmDecisions: null,
|
|
6315
6377
|
lastRestoreId: null
|
|
6316
6378
|
});
|
|
6317
6379
|
try {
|
|
@@ -6331,6 +6393,7 @@ function SyncSettingsView({ api, t }) {
|
|
|
6331
6393
|
patch({
|
|
6332
6394
|
busy: null,
|
|
6333
6395
|
confirmSession: session,
|
|
6396
|
+
confirmDecisions: null,
|
|
6334
6397
|
token: "",
|
|
6335
6398
|
webdavPassword: ""
|
|
6336
6399
|
});
|
|
@@ -6345,7 +6408,10 @@ function SyncSettingsView({ api, t }) {
|
|
|
6345
6408
|
};
|
|
6346
6409
|
/** 用户取消差异确认:清除会话,复位到空闲。 */
|
|
6347
6410
|
const cancelConfirm = () => {
|
|
6348
|
-
patch({
|
|
6411
|
+
patch({
|
|
6412
|
+
confirmSession: null,
|
|
6413
|
+
confirmDecisions: null
|
|
6414
|
+
});
|
|
6349
6415
|
};
|
|
6350
6416
|
/** 从 SyncConfirmView 透传的一键回滚完成信号。 */
|
|
6351
6417
|
const onRollbackApplied = () => {
|
|
@@ -6395,7 +6461,6 @@ function SyncSettingsView({ api, t }) {
|
|
|
6395
6461
|
patch({ error: err instanceof Error ? err.message : String(err) });
|
|
6396
6462
|
}
|
|
6397
6463
|
};
|
|
6398
|
-
const status = computeSyncStatus(state.statusInfo, state.loading, state.loadError, uiT);
|
|
6399
6464
|
/** 活动通道的远端地址是否就绪(git=repoUrl 非空;webdav=webdavUrl 非空) */
|
|
6400
6465
|
const remoteReady = computeRemoteReady(state.channel, state.repoUrl, state.webdavUrl);
|
|
6401
6466
|
const buttons = computeSyncButtons(state.busy, remoteReady, uiT);
|
|
@@ -6418,30 +6483,6 @@ function SyncSettingsView({ api, t }) {
|
|
|
6418
6483
|
title: t("section.label"),
|
|
6419
6484
|
subtitle: t("section.description")
|
|
6420
6485
|
}),
|
|
6421
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6422
|
-
className: config_manager_module_css_default.modeTabs,
|
|
6423
|
-
role: "tablist",
|
|
6424
|
-
children: channelTabModels(state.channel, state.busy !== null).map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6425
|
-
type: "button",
|
|
6426
|
-
role: "tab",
|
|
6427
|
-
"aria-selected": tab.active,
|
|
6428
|
-
"data-active": tab.active ? "" : void 0,
|
|
6429
|
-
className: config_manager_module_css_default.modeTab,
|
|
6430
|
-
disabled: tab.disabled,
|
|
6431
|
-
onClick: () => {
|
|
6432
|
-
switchChannel(tab.channel);
|
|
6433
|
-
},
|
|
6434
|
-
children: tab.channel === "webdav" ? t("channel.webdav") : t("channel.git")
|
|
6435
|
-
}, tab.channel))
|
|
6436
|
-
}),
|
|
6437
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6438
|
-
className: config_manager_module_css_default.modeHint,
|
|
6439
|
-
children: t("channel.perChannelHint")
|
|
6440
|
-
}),
|
|
6441
|
-
state.channel === "git" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
6442
|
-
kind: "warn",
|
|
6443
|
-
children: privateRepoHint(uiT)
|
|
6444
|
-
}),
|
|
6445
6486
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [
|
|
6446
6487
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6447
6488
|
className: config_manager_module_css_default.groupLabel,
|
|
@@ -6449,265 +6490,349 @@ function SyncSettingsView({ api, t }) {
|
|
|
6449
6490
|
}),
|
|
6450
6491
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6451
6492
|
className: config_manager_module_css_default.hint,
|
|
6452
|
-
children: t("channel.
|
|
6493
|
+
children: t("channel.openHint")
|
|
6453
6494
|
}),
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
}),
|
|
6459
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6460
|
-
className: config_manager_module_css_default.field,
|
|
6461
|
-
children: [
|
|
6462
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6463
|
-
className: config_manager_module_css_default.fieldLabel,
|
|
6464
|
-
children: t("config.repoUrl")
|
|
6465
|
-
}),
|
|
6466
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6467
|
-
type: "text",
|
|
6468
|
-
className: config_manager_module_css_default.input,
|
|
6469
|
-
value: state.repoUrl,
|
|
6470
|
-
placeholder: "https://github.com/user/private-repo.git",
|
|
6471
|
-
disabled: state.busy !== null,
|
|
6472
|
-
onChange: (e) => {
|
|
6473
|
-
patch({ repoUrl: e.target.value });
|
|
6474
|
-
scheduleConfigSave();
|
|
6475
|
-
}
|
|
6476
|
-
}),
|
|
6477
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6478
|
-
className: config_manager_module_css_default.hint,
|
|
6479
|
-
children: t("config.repoUrlHint")
|
|
6480
|
-
})
|
|
6481
|
-
]
|
|
6482
|
-
}),
|
|
6483
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6484
|
-
className: config_manager_module_css_default.field,
|
|
6485
|
-
children: [
|
|
6486
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6487
|
-
className: config_manager_module_css_default.fieldLabel,
|
|
6488
|
-
children: [
|
|
6489
|
-
t("config.token"),
|
|
6490
|
-
" ",
|
|
6491
|
-
state.statusInfo?.credentialConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6492
|
-
kind: "ok",
|
|
6493
|
-
children: t("config.tokenSaved")
|
|
6494
|
-
})
|
|
6495
|
-
]
|
|
6496
|
-
}),
|
|
6497
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6498
|
-
type: "password",
|
|
6499
|
-
className: config_manager_module_css_default.input,
|
|
6500
|
-
value: state.token,
|
|
6501
|
-
autoComplete: "off",
|
|
6502
|
-
placeholder: t("config.tokenPlaceholder"),
|
|
6503
|
-
disabled: state.busy !== null,
|
|
6504
|
-
onChange: (e) => {
|
|
6505
|
-
patch({ token: e.target.value });
|
|
6506
|
-
scheduleConfigSave();
|
|
6507
|
-
}
|
|
6508
|
-
}),
|
|
6509
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6510
|
-
className: config_manager_module_css_default.hint,
|
|
6511
|
-
children: t("config.tokenHint", { ref: "DSH_CONFIG_MANAGER_SYNC_TOKEN" })
|
|
6512
|
-
})
|
|
6513
|
-
]
|
|
6514
|
-
}),
|
|
6515
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6516
|
-
className: config_manager_module_css_default.groupLabel,
|
|
6517
|
-
children: t("github.title")
|
|
6518
|
-
}),
|
|
6519
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6520
|
-
className: config_manager_module_css_default.hint,
|
|
6521
|
-
children: t("github.description")
|
|
6522
|
-
}),
|
|
6523
|
-
githubView.showCode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6524
|
-
className: config_manager_module_css_default.statRow,
|
|
6525
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Badge, {
|
|
6495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6496
|
+
className: config_manager_module_css_default.statRow,
|
|
6497
|
+
children: [
|
|
6498
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6526
6499
|
kind: "info",
|
|
6527
|
-
children:
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
}),
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
}),
|
|
6541
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6542
|
-
className: config_manager_module_css_default.actionRow,
|
|
6543
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6544
|
-
variant: "primary",
|
|
6545
|
-
disabled: !githubView.canStart || state.busy !== null,
|
|
6546
|
-
onClick: () => {
|
|
6547
|
-
runGithubStart();
|
|
6548
|
-
},
|
|
6549
|
-
children: githubView.startLabel
|
|
6550
|
-
}), githubView.canCancel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6551
|
-
disabled: state.busy !== null,
|
|
6552
|
-
onClick: () => {
|
|
6553
|
-
runGithubCancel();
|
|
6554
|
-
},
|
|
6555
|
-
children: t("github.cancel")
|
|
6556
|
-
})]
|
|
6557
|
-
}),
|
|
6558
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6559
|
-
className: config_manager_module_css_default.statRow,
|
|
6560
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6561
|
-
kind: githubView.phase === "success" ? "ok" : githubView.phase === "error" ? "error" : "warn",
|
|
6562
|
-
children: githubView.statusText
|
|
6500
|
+
children: state.channel === "webdav" ? t("channel.webdav") : t("channel.git")
|
|
6501
|
+
}),
|
|
6502
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6503
|
+
kind: remoteReady ? "ok" : "warn",
|
|
6504
|
+
children: remoteReady ? t("channel.configured") : t("channel.notConfigured")
|
|
6505
|
+
}),
|
|
6506
|
+
state.channel === "git" && state.statusInfo?.credentialConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6507
|
+
kind: "ok",
|
|
6508
|
+
children: t("config.tokenSaved")
|
|
6509
|
+
}),
|
|
6510
|
+
state.channel === "webdav" && state.statusInfo?.webdav?.passwordConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6511
|
+
kind: "ok",
|
|
6512
|
+
children: t("webdav.passwordSaved")
|
|
6563
6513
|
})
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6514
|
+
]
|
|
6515
|
+
}),
|
|
6516
|
+
remoteReady && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6517
|
+
className: config_manager_module_css_default.hint,
|
|
6518
|
+
children: [
|
|
6519
|
+
t("channel.currentUrl"),
|
|
6520
|
+
":",
|
|
6521
|
+
state.channel === "webdav" ? state.webdavUrl : state.repoUrl
|
|
6522
|
+
]
|
|
6523
|
+
}),
|
|
6524
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6525
|
+
className: config_manager_module_css_default.actionRow,
|
|
6526
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6527
|
+
variant: "primary",
|
|
6528
|
+
onClick: openChannelDialog,
|
|
6529
|
+
children: t("channel.open")
|
|
6568
6530
|
})
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6531
|
+
})
|
|
6532
|
+
] }),
|
|
6533
|
+
channelOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6534
|
+
className: config_manager_module_css_default.dialogMask,
|
|
6535
|
+
onMouseDown: (e) => {
|
|
6536
|
+
if (e.target === e.currentTarget && !state.savingConfig) closeChannelDialog();
|
|
6537
|
+
},
|
|
6538
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6539
|
+
className: `${config_manager_module_css_default.dialogCard} ${config_manager_module_css_default.dialogWide}`,
|
|
6540
|
+
role: "dialog",
|
|
6541
|
+
"aria-modal": "true",
|
|
6542
|
+
"aria-label": t("channel.title"),
|
|
6543
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6544
|
+
className: config_manager_module_css_default.dialogHeaderRow,
|
|
6545
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6546
|
+
className: config_manager_module_css_default.dialogHeader,
|
|
6547
|
+
children: t("channel.title")
|
|
6548
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6549
|
+
type: "button",
|
|
6550
|
+
className: config_manager_module_css_default.dialogClose,
|
|
6551
|
+
"aria-label": t("common.close"),
|
|
6552
|
+
disabled: state.savingConfig,
|
|
6553
|
+
onClick: closeChannelDialog,
|
|
6554
|
+
children: "×"
|
|
6555
|
+
})]
|
|
6556
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6557
|
+
className: config_manager_module_css_default.dialogBodyScroll,
|
|
6595
6558
|
children: [
|
|
6596
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
6597
|
-
className: config_manager_module_css_default.
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6559
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6560
|
+
className: config_manager_module_css_default.modeTabs,
|
|
6561
|
+
role: "tablist",
|
|
6562
|
+
children: channelTabModels(state.channel, state.busy !== null || state.savingConfig).map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6563
|
+
type: "button",
|
|
6564
|
+
role: "tab",
|
|
6565
|
+
"aria-selected": tab.active,
|
|
6566
|
+
"data-active": tab.active ? "" : void 0,
|
|
6567
|
+
className: config_manager_module_css_default.modeTab,
|
|
6568
|
+
disabled: tab.disabled,
|
|
6569
|
+
onClick: () => {
|
|
6570
|
+
switchChannel(tab.channel);
|
|
6571
|
+
},
|
|
6572
|
+
children: tab.channel === "webdav" ? t("channel.webdav") : t("channel.git")
|
|
6573
|
+
}, tab.channel))
|
|
6610
6574
|
}),
|
|
6611
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
6612
|
-
className: config_manager_module_css_default.
|
|
6613
|
-
children: t("
|
|
6614
|
-
})
|
|
6615
|
-
]
|
|
6616
|
-
}),
|
|
6617
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6618
|
-
className: config_manager_module_css_default.field,
|
|
6619
|
-
children: [
|
|
6620
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6621
|
-
className: config_manager_module_css_default.fieldLabel,
|
|
6622
|
-
children: [
|
|
6623
|
-
t("webdav.username"),
|
|
6624
|
-
" ",
|
|
6625
|
-
state.statusInfo?.webdav?.usernameConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6626
|
-
kind: "ok",
|
|
6627
|
-
children: t("config.tokenSaved")
|
|
6628
|
-
})
|
|
6629
|
-
]
|
|
6575
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6576
|
+
className: config_manager_module_css_default.modeHint,
|
|
6577
|
+
children: t("channel.perChannelHint")
|
|
6630
6578
|
}),
|
|
6631
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
value: state.webdavUsername,
|
|
6635
|
-
autoComplete: "off",
|
|
6636
|
-
placeholder: "alice",
|
|
6637
|
-
disabled: state.busy !== null,
|
|
6638
|
-
onChange: (e) => {
|
|
6639
|
-
patch({ webdavUsername: e.target.value });
|
|
6640
|
-
scheduleConfigSave();
|
|
6641
|
-
}
|
|
6579
|
+
state.channel === "git" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
6580
|
+
kind: "warn",
|
|
6581
|
+
children: privateRepoHint(uiT)
|
|
6642
6582
|
}),
|
|
6643
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6583
|
+
state.channel === "git" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6584
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6585
|
+
className: config_manager_module_css_default.groupLabel,
|
|
6586
|
+
children: t("config.title")
|
|
6587
|
+
}),
|
|
6588
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6589
|
+
className: config_manager_module_css_default.field,
|
|
6590
|
+
children: [
|
|
6591
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6592
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
6593
|
+
children: t("config.repoUrl")
|
|
6594
|
+
}),
|
|
6595
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6596
|
+
type: "text",
|
|
6597
|
+
className: config_manager_module_css_default.input,
|
|
6598
|
+
value: state.repoUrl,
|
|
6599
|
+
placeholder: "https://github.com/user/private-repo.git",
|
|
6600
|
+
disabled: state.busy !== null,
|
|
6601
|
+
onChange: (e) => {
|
|
6602
|
+
patch({ repoUrl: e.target.value });
|
|
6603
|
+
scheduleConfigSave();
|
|
6604
|
+
}
|
|
6605
|
+
}),
|
|
6606
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6607
|
+
className: config_manager_module_css_default.hint,
|
|
6608
|
+
children: t("config.repoUrlHint")
|
|
6609
|
+
})
|
|
6610
|
+
]
|
|
6611
|
+
}),
|
|
6612
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6613
|
+
className: config_manager_module_css_default.field,
|
|
6614
|
+
children: [
|
|
6615
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6616
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
6617
|
+
children: [
|
|
6618
|
+
t("config.token"),
|
|
6619
|
+
" ",
|
|
6620
|
+
state.statusInfo?.credentialConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6621
|
+
kind: "ok",
|
|
6622
|
+
children: t("config.tokenSaved")
|
|
6623
|
+
})
|
|
6624
|
+
]
|
|
6625
|
+
}),
|
|
6626
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6627
|
+
type: "password",
|
|
6628
|
+
className: config_manager_module_css_default.input,
|
|
6629
|
+
value: state.token,
|
|
6630
|
+
autoComplete: "off",
|
|
6631
|
+
placeholder: t("config.tokenPlaceholder"),
|
|
6632
|
+
disabled: state.busy !== null,
|
|
6633
|
+
onChange: (e) => {
|
|
6634
|
+
patch({ token: e.target.value });
|
|
6635
|
+
scheduleConfigSave();
|
|
6636
|
+
}
|
|
6637
|
+
}),
|
|
6638
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6639
|
+
className: config_manager_module_css_default.hint,
|
|
6640
|
+
children: t("config.tokenHint", { ref: "DSH_CONFIG_MANAGER_SYNC_TOKEN" })
|
|
6641
|
+
})
|
|
6642
|
+
]
|
|
6643
|
+
}),
|
|
6644
|
+
state.githubSignedIn === false && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6645
|
+
state.statusInfo?.credentialConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
6646
|
+
kind: "warn",
|
|
6647
|
+
children: t("github.tokenInvalid")
|
|
6648
|
+
}),
|
|
6649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6650
|
+
className: config_manager_module_css_default.groupLabel,
|
|
6651
|
+
children: t("github.title")
|
|
6652
|
+
}),
|
|
6653
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6654
|
+
className: config_manager_module_css_default.hint,
|
|
6655
|
+
children: t("github.description")
|
|
6656
|
+
}),
|
|
6657
|
+
githubView.showCode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6658
|
+
className: config_manager_module_css_default.statRow,
|
|
6659
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Badge, {
|
|
6660
|
+
kind: "info",
|
|
6661
|
+
children: [
|
|
6662
|
+
t("github.userCode"),
|
|
6663
|
+
":",
|
|
6664
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: githubView.userCode })
|
|
6665
|
+
]
|
|
6666
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
6667
|
+
className: config_manager_module_css_default.ghostButton,
|
|
6668
|
+
href: githubView.verificationUri,
|
|
6669
|
+
target: "_blank",
|
|
6670
|
+
rel: "noreferrer",
|
|
6671
|
+
style: { textDecoration: "none" },
|
|
6672
|
+
children: t("github.openAuth")
|
|
6673
|
+
})]
|
|
6674
|
+
}),
|
|
6675
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6676
|
+
className: config_manager_module_css_default.actionRow,
|
|
6677
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6678
|
+
variant: "primary",
|
|
6679
|
+
disabled: !githubView.canStart || state.busy !== null,
|
|
6680
|
+
onClick: () => {
|
|
6681
|
+
runGithubStart();
|
|
6682
|
+
},
|
|
6683
|
+
children: githubView.startLabel
|
|
6684
|
+
}), githubView.canCancel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6685
|
+
disabled: state.busy !== null,
|
|
6686
|
+
onClick: () => {
|
|
6687
|
+
runGithubCancel();
|
|
6688
|
+
},
|
|
6689
|
+
children: t("github.cancel")
|
|
6690
|
+
})]
|
|
6691
|
+
}),
|
|
6692
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6693
|
+
className: config_manager_module_css_default.statRow,
|
|
6694
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6695
|
+
kind: githubView.phase === "success" ? "ok" : githubView.phase === "error" ? "error" : "warn",
|
|
6696
|
+
children: githubView.statusText
|
|
6697
|
+
})
|
|
6698
|
+
}),
|
|
6699
|
+
githubView.phase === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6700
|
+
className: config_manager_module_css_default.hint,
|
|
6701
|
+
children: t("config.tokenHint", { ref: "DSH_CONFIG_MANAGER_SYNC_TOKEN" })
|
|
6660
6702
|
})
|
|
6661
|
-
]
|
|
6662
|
-
}),
|
|
6663
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6703
|
+
] })
|
|
6704
|
+
] }),
|
|
6705
|
+
state.channel === "webdav" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6706
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6707
|
+
className: config_manager_module_css_default.groupLabel,
|
|
6708
|
+
children: t("webdav.title")
|
|
6709
|
+
}),
|
|
6710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6711
|
+
className: config_manager_module_css_default.hint,
|
|
6712
|
+
children: t("webdav.presetHint")
|
|
6713
|
+
}),
|
|
6714
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
6715
|
+
className: config_manager_module_css_default.select,
|
|
6716
|
+
value: presetIdForUrl(state.webdavUrl),
|
|
6717
|
+
disabled: state.busy !== null,
|
|
6718
|
+
onChange: (e) => {
|
|
6719
|
+
const p = presetById(e.target.value);
|
|
6720
|
+
patch({ webdavUrl: p.url });
|
|
6721
|
+
scheduleConfigSave();
|
|
6722
|
+
},
|
|
6723
|
+
children: WEBDAV_PRESETS.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6724
|
+
value: p.id,
|
|
6725
|
+
children: p.label
|
|
6726
|
+
}, p.id))
|
|
6727
|
+
}),
|
|
6728
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6729
|
+
className: config_manager_module_css_default.field,
|
|
6730
|
+
children: [
|
|
6731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6732
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
6733
|
+
children: t("webdav.url")
|
|
6734
|
+
}),
|
|
6735
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6736
|
+
type: "text",
|
|
6737
|
+
className: config_manager_module_css_default.input,
|
|
6738
|
+
value: state.webdavUrl,
|
|
6739
|
+
placeholder: "https://dav.example.com/dav/config",
|
|
6740
|
+
disabled: state.busy !== null,
|
|
6741
|
+
onChange: (e) => {
|
|
6742
|
+
patch({ webdavUrl: e.target.value });
|
|
6743
|
+
scheduleConfigSave();
|
|
6744
|
+
}
|
|
6745
|
+
}),
|
|
6746
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6747
|
+
className: config_manager_module_css_default.hint,
|
|
6748
|
+
children: t("webdav.urlHint")
|
|
6749
|
+
})
|
|
6750
|
+
]
|
|
6751
|
+
}),
|
|
6752
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6753
|
+
className: config_manager_module_css_default.field,
|
|
6754
|
+
children: [
|
|
6755
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6756
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
6757
|
+
children: [
|
|
6758
|
+
t("webdav.username"),
|
|
6759
|
+
" ",
|
|
6760
|
+
state.statusInfo?.webdav?.usernameConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6761
|
+
kind: "ok",
|
|
6762
|
+
children: t("config.tokenSaved")
|
|
6763
|
+
})
|
|
6764
|
+
]
|
|
6765
|
+
}),
|
|
6766
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6767
|
+
type: "text",
|
|
6768
|
+
className: config_manager_module_css_default.input,
|
|
6769
|
+
value: state.webdavUsername,
|
|
6770
|
+
autoComplete: "off",
|
|
6771
|
+
placeholder: "alice",
|
|
6772
|
+
disabled: state.busy !== null,
|
|
6773
|
+
onChange: (e) => {
|
|
6774
|
+
patch({ webdavUsername: e.target.value });
|
|
6775
|
+
scheduleConfigSave();
|
|
6776
|
+
}
|
|
6777
|
+
}),
|
|
6778
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6779
|
+
className: config_manager_module_css_default.hint,
|
|
6780
|
+
children: t("webdav.usernameHint")
|
|
6781
|
+
})
|
|
6782
|
+
]
|
|
6783
|
+
}),
|
|
6784
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
6785
|
+
className: config_manager_module_css_default.field,
|
|
6786
|
+
children: [
|
|
6787
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6788
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
6789
|
+
children: [
|
|
6790
|
+
t("webdav.password"),
|
|
6791
|
+
" ",
|
|
6792
|
+
state.statusInfo?.webdav?.passwordConfigured === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6793
|
+
kind: "ok",
|
|
6794
|
+
children: t("webdav.passwordSaved")
|
|
6795
|
+
})
|
|
6796
|
+
]
|
|
6797
|
+
}),
|
|
6798
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6799
|
+
type: "password",
|
|
6800
|
+
className: config_manager_module_css_default.input,
|
|
6801
|
+
value: state.webdavPassword,
|
|
6802
|
+
autoComplete: "off",
|
|
6803
|
+
placeholder: t("webdav.passwordPlaceholder"),
|
|
6804
|
+
disabled: state.busy !== null,
|
|
6805
|
+
onChange: (e) => {
|
|
6806
|
+
patch({ webdavPassword: e.target.value });
|
|
6807
|
+
scheduleConfigSave();
|
|
6808
|
+
}
|
|
6809
|
+
}),
|
|
6810
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6811
|
+
className: config_manager_module_css_default.hint,
|
|
6812
|
+
children: t("webdav.passwordHint", { ref: "DSH_CONFIG_MANAGER_SYNC_WEBDAV_PASSWORD" })
|
|
6813
|
+
})
|
|
6814
|
+
]
|
|
6815
|
+
})
|
|
6816
|
+
] }),
|
|
6817
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6818
|
+
className: config_manager_module_css_default.actionRow,
|
|
6819
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6820
|
+
variant: "primary",
|
|
6821
|
+
disabled: state.busy !== null || state.savingConfig || !remoteReady,
|
|
6822
|
+
onClick: () => {
|
|
6823
|
+
flushConfigSave();
|
|
6824
|
+
},
|
|
6825
|
+
children: state.savingConfig ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("config.saving") }) : t("config.save")
|
|
6826
|
+
})
|
|
6674
6827
|
}),
|
|
6675
6828
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6676
6829
|
className: config_manager_module_css_default.hint,
|
|
6677
|
-
children: t("
|
|
6830
|
+
children: t("config.saveHint")
|
|
6678
6831
|
})
|
|
6679
6832
|
]
|
|
6680
|
-
})
|
|
6681
|
-
] }),
|
|
6682
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6683
|
-
className: config_manager_module_css_default.actionRow,
|
|
6684
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
6685
|
-
variant: "primary",
|
|
6686
|
-
disabled: state.busy !== null || state.savingConfig || !remoteReady,
|
|
6687
|
-
onClick: () => {
|
|
6688
|
-
flushConfigSave();
|
|
6689
|
-
},
|
|
6690
|
-
children: state.savingConfig ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("config.saving") }) : t("config.save")
|
|
6691
|
-
})
|
|
6692
|
-
}),
|
|
6693
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6694
|
-
className: config_manager_module_css_default.hint,
|
|
6695
|
-
children: t("config.saveHint")
|
|
6833
|
+
})]
|
|
6696
6834
|
})
|
|
6697
|
-
|
|
6698
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6699
|
-
className: config_manager_module_css_default.groupLabel,
|
|
6700
|
-
children: t("status.title")
|
|
6701
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6702
|
-
className: config_manager_module_css_default.statRow,
|
|
6703
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6704
|
-
kind: status.kind === "ready" ? "ok" : status.kind === "error" ? "error" : "warn",
|
|
6705
|
-
children: status.text
|
|
6706
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
6707
|
-
kind: "info",
|
|
6708
|
-
children: state.channel === "webdav" ? t("channel.webdav") : t("channel.git")
|
|
6709
|
-
})]
|
|
6710
|
-
})] }),
|
|
6835
|
+
}),
|
|
6711
6836
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [
|
|
6712
6837
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6713
6838
|
className: config_manager_module_css_default.groupLabel,
|
|
@@ -6990,6 +7115,10 @@ function SyncSettingsView({ api, t }) {
|
|
|
6990
7115
|
needsReview: state.confirmSession.needsReview,
|
|
6991
7116
|
compatibility: state.confirmSession.compatibility,
|
|
6992
7117
|
t,
|
|
7118
|
+
decisions: state.confirmDecisions,
|
|
7119
|
+
onDecisionsChange: (d) => {
|
|
7120
|
+
patch({ confirmDecisions: d });
|
|
7121
|
+
},
|
|
6993
7122
|
onCancel: cancelConfirm,
|
|
6994
7123
|
onRollbackDone: onRollbackApplied
|
|
6995
7124
|
}),
|
|
@@ -7203,50 +7332,186 @@ const MARKET_UPSTREAM_OWNER = "xiajiajun516";
|
|
|
7203
7332
|
/** 官方收录目标仓库名(见 MARKET_UPSTREAM_OWNER) */
|
|
7204
7333
|
const MARKET_UPSTREAM_REPO = "dsh-config-market";
|
|
7205
7334
|
//#endregion
|
|
7206
|
-
//#region src/client/
|
|
7335
|
+
//#region src/client/common/ConfirmDialog.tsx
|
|
7207
7336
|
/**
|
|
7208
|
-
*
|
|
7337
|
+
* ConfirmDialog —— 确认弹窗(危险/重要操作的二次确认,DESIGN.md §8.11 / §14)。
|
|
7209
7338
|
*
|
|
7210
|
-
*
|
|
7211
|
-
*
|
|
7212
|
-
*
|
|
7213
|
-
*
|
|
7214
|
-
* categories(可选);id / author / version / updatedAt 均为系统自动生成,
|
|
7215
|
-
* 界面以「系统自动」徽章展示(MY_CONFIG_AUTO_FIELDS);
|
|
7216
|
-
* - 收录状态三态(§4.5):未收录(本地独有)| PR 待审核(带 PR 链接)| 已收录
|
|
7217
|
-
* (官方 dsh-config-market/index.json 含该 id);已收录 > PR 待审核 > 未收录
|
|
7218
|
-
* (官方已收录时即使存在 open PR 也以收录为准——PR 已合并后不应再显示待审核);
|
|
7219
|
-
* - open PR 匹配按固定分支 `dsh-market-sync/<itemId>`(§2.4 自动 PR 分支约定);
|
|
7220
|
-
* - 文案走 src/ui/i18n.ts 的 UiT('myConfigs.*' 键,zh 源 / en 镜像),不硬编码中文。
|
|
7339
|
+
* 背景(2026-08-20):用户要求「删除按钮需要弹窗弹出二次确认」,替代原先的
|
|
7340
|
+
* 「行内两步确认」(已从 DESIGN.md §14 移除,见 t8 设计)。本项目此前无任何
|
|
7341
|
+
* modal / fixed / z-index 元素,本组件是首个浮动层 —— DESIGN.md §15 Anti-pattern #7
|
|
7342
|
+
* 已登记豁免(z-index 100;浮动层必须先设计进 DESIGN.md 的流程满足)。
|
|
7221
7343
|
*
|
|
7222
|
-
*
|
|
7223
|
-
*
|
|
7344
|
+
* 交互约定:
|
|
7345
|
+
* - 受控组件:open=false 时不渲染;open=true 渲染遮罩 + 居中卡片;
|
|
7346
|
+
* - 关闭三途径:遮罩点击(仅 e.target === currentTarget)、Esc 键、取消按钮;
|
|
7347
|
+
* - busy=true(或 onConfirm 返回 Promise 的自管 busy)时禁用一切关闭途径与确认按钮,
|
|
7348
|
+
* 防重复提交;
|
|
7349
|
+
* - 初始焦点在取消按钮(危险确认不默认落破坏性按钮);关闭后还原焦点到触发按钮
|
|
7350
|
+
* (open 前的 document.activeElement);
|
|
7351
|
+
* - 不做完整 focus trap(两按钮场景风险可接受,DESIGN.md §8.11 已注明)。
|
|
7352
|
+
*
|
|
7353
|
+
* 安全:message 由调用方传入(渲染前已 redact 兜底,与全站一致);本组件不触碰任何凭据。
|
|
7354
|
+
* 样式:全部走 --dsw-* token(遮罩 color-mix 半透明、卡片 bg-layer-2 + border-l1),
|
|
7355
|
+
* 仅新增 dialogMask/dialogCard/dialogHeader/dialogBody 四个类(config-manager.module.css)。
|
|
7224
7356
|
*/
|
|
7225
7357
|
/**
|
|
7226
|
-
*
|
|
7227
|
-
*
|
|
7358
|
+
* 确认弹窗:遮罩 + 居中卡片 + 标题/正文/按钮区。
|
|
7359
|
+
* 自管 busy:onConfirm 返回 Promise 时置 busy 直到 resolve(reject 仍关闭 busy,错误由调用方处理)。
|
|
7228
7360
|
*/
|
|
7229
|
-
function
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7361
|
+
function ConfirmDialog({ open, title, message, confirmLabel, cancelLabel, danger, busy: busyProp, onConfirm, onCancel, children }) {
|
|
7362
|
+
const [selfBusy, setSelfBusy] = (0, react.useState)(false);
|
|
7363
|
+
const busy = busyProp === true || selfBusy;
|
|
7364
|
+
/** open 前的活动元素(关闭后还原焦点) */
|
|
7365
|
+
const prevFocus = (0, react.useRef)(null);
|
|
7366
|
+
/** 取消按钮 ref(初始焦点) */
|
|
7367
|
+
const cancelRef = (0, react.useRef)(null);
|
|
7368
|
+
(0, react.useEffect)(() => {
|
|
7369
|
+
if (open) {
|
|
7370
|
+
prevFocus.current = document.activeElement;
|
|
7371
|
+
requestAnimationFrame(() => {
|
|
7372
|
+
cancelRef.current?.focus();
|
|
7373
|
+
});
|
|
7374
|
+
return;
|
|
7375
|
+
}
|
|
7376
|
+
if (prevFocus.current !== null && prevFocus.current instanceof HTMLElement) {
|
|
7377
|
+
prevFocus.current.focus();
|
|
7378
|
+
prevFocus.current = null;
|
|
7379
|
+
}
|
|
7380
|
+
}, [open]);
|
|
7381
|
+
(0, react.useEffect)(() => {
|
|
7382
|
+
if (!open || busy) return;
|
|
7383
|
+
const onKey = (e) => {
|
|
7384
|
+
if (e.key === "Escape") onCancel();
|
|
7385
|
+
};
|
|
7386
|
+
window.addEventListener("keydown", onKey);
|
|
7387
|
+
return () => {
|
|
7388
|
+
window.removeEventListener("keydown", onKey);
|
|
7389
|
+
};
|
|
7390
|
+
}, [
|
|
7391
|
+
open,
|
|
7392
|
+
busy,
|
|
7393
|
+
onCancel
|
|
7394
|
+
]);
|
|
7395
|
+
if (!open) return null;
|
|
7396
|
+
const handleConfirm = () => {
|
|
7397
|
+
if (busy) return;
|
|
7398
|
+
const result = onConfirm();
|
|
7399
|
+
if (result instanceof Promise) {
|
|
7400
|
+
setSelfBusy(true);
|
|
7401
|
+
result.finally(() => {
|
|
7402
|
+
setSelfBusy(false);
|
|
7403
|
+
});
|
|
7404
|
+
}
|
|
7238
7405
|
};
|
|
7239
|
-
return
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7406
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7407
|
+
className: config_manager_module_css_default.dialogMask,
|
|
7408
|
+
onMouseDown: (e) => {
|
|
7409
|
+
if (e.target === e.currentTarget && !busy) onCancel();
|
|
7410
|
+
},
|
|
7411
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7412
|
+
className: config_manager_module_css_default.dialogCard,
|
|
7413
|
+
role: "dialog",
|
|
7414
|
+
"aria-modal": "true",
|
|
7415
|
+
"aria-label": title,
|
|
7416
|
+
children: [
|
|
7417
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7418
|
+
className: config_manager_module_css_default.dialogHeader,
|
|
7419
|
+
children: title
|
|
7420
|
+
}),
|
|
7421
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7422
|
+
className: config_manager_module_css_default.dialogBody,
|
|
7423
|
+
children: [message !== void 0 && message !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: message }), children]
|
|
7424
|
+
}),
|
|
7425
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7426
|
+
className: config_manager_module_css_default.actionRow,
|
|
7427
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
7428
|
+
variant: danger === true ? "danger" : "primary",
|
|
7429
|
+
disabled: busy,
|
|
7430
|
+
onClick: () => {
|
|
7431
|
+
handleConfirm();
|
|
7432
|
+
},
|
|
7433
|
+
children: busy ? "…" : confirmLabel ?? ""
|
|
7434
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7435
|
+
ref: cancelRef,
|
|
7436
|
+
type: "button",
|
|
7437
|
+
className: config_manager_module_css_default.ghostButton,
|
|
7438
|
+
disabled: busy,
|
|
7439
|
+
onClick: onCancel,
|
|
7440
|
+
children: cancelLabel ?? ""
|
|
7441
|
+
})]
|
|
7442
|
+
})
|
|
7443
|
+
]
|
|
7444
|
+
})
|
|
7445
|
+
});
|
|
7446
|
+
}
|
|
7447
|
+
//#endregion
|
|
7448
|
+
//#region src/client/market/disclaimer.ts
|
|
7449
|
+
/** localStorage key 前缀(按 key 隔离三个操作) */
|
|
7450
|
+
const DISCLAIMER_STORAGE_PREFIX = "dsh-cm-market.disclaimer.";
|
|
7451
|
+
/** 由操作 key 生成 localStorage key。 */
|
|
7452
|
+
function disclaimerStorageKey(key) {
|
|
7453
|
+
return `${DISCLAIMER_STORAGE_PREFIX}${key}`;
|
|
7454
|
+
}
|
|
7455
|
+
/** 读取「不再提示」状态(true = 已勾选,该操作以后不再弹免责;任何异常 → false)。 */
|
|
7456
|
+
function readDisclaimerDismissed(key, storage) {
|
|
7457
|
+
try {
|
|
7458
|
+
return storage.getItem(disclaimerStorageKey(key)) === "1";
|
|
7459
|
+
} catch {
|
|
7460
|
+
return false;
|
|
7461
|
+
}
|
|
7462
|
+
}
|
|
7463
|
+
/** 写入「不再提示」状态(勾选后调用;存储不可用时静默忽略)。 */
|
|
7464
|
+
function writeDisclaimerDismissed(key, storage) {
|
|
7465
|
+
try {
|
|
7466
|
+
storage.setItem(disclaimerStorageKey(key), "1");
|
|
7467
|
+
} catch {}
|
|
7468
|
+
}
|
|
7469
|
+
//#endregion
|
|
7470
|
+
//#region src/client/market/my-configs-view.ts
|
|
7471
|
+
/**
|
|
7472
|
+
* 「我的配置」区块的客户端纯渲染装配层(m-my-configs-view,node 可测)。
|
|
7473
|
+
*
|
|
7474
|
+
* 设计纪律(docs/design/2026-08-20-my-configs-design.md §4.5 / §4.6):
|
|
7475
|
+
* - 全部无副作用纯函数,React 壳(MyConfigsView)只装配,不承载业务逻辑;
|
|
7476
|
+
* - 输入数据一律由调用方(组件 / api 层)提供 —— 本文件不发起任何请求,不持有凭据;
|
|
7477
|
+
* - 录入最小化(§1.2):表单仅 name(预填 zip 文件名,可改)/ description(可选)/
|
|
7478
|
+
* categories(可选);id / author / version / updatedAt 均为系统自动生成,
|
|
7479
|
+
* 界面以「系统自动」徽章展示(MY_CONFIG_AUTO_FIELDS);
|
|
7480
|
+
* - 收录状态三态(§4.5):未收录(本地独有)| PR 待审核(带 PR 链接)| 已收录
|
|
7481
|
+
* (官方 dsh-config-market/index.json 含该 id);已收录 > PR 待审核 > 未收录
|
|
7482
|
+
* (官方已收录时即使存在 open PR 也以收录为准——PR 已合并后不应再显示待审核);
|
|
7483
|
+
* - open PR 匹配按固定分支 `dsh-market-sync/<itemId>`(§2.4 自动 PR 分支约定);
|
|
7484
|
+
* - 文案走 src/ui/i18n.ts 的 UiT('myConfigs.*' 键,zh 源 / en 镜像),不硬编码中文。
|
|
7485
|
+
*
|
|
7486
|
+
* 安全硬约束:本层只做展示推导,不接触 token / 凭据;PR URL 由调用方提供,
|
|
7487
|
+
* 渲染前仍过 redact() 兜底(与全站一致)。
|
|
7488
|
+
*/
|
|
7489
|
+
/**
|
|
7490
|
+
* 登录状态推导(纯函数):loading 优先;authError 非空(401 等)→ token 失效;
|
|
7491
|
+
* 否则按 status.loggedIn 区分已登录 / 未登录。输入由调用方提供。
|
|
7492
|
+
*/
|
|
7493
|
+
function deriveLoginState(input) {
|
|
7494
|
+
if (input.loading) return { kind: "loading" };
|
|
7495
|
+
if (input.authFailed) return { kind: "token-invalid" };
|
|
7496
|
+
const s = input.status;
|
|
7497
|
+
if (s !== null && s.loggedIn) return {
|
|
7498
|
+
kind: "logged-in",
|
|
7499
|
+
login: s.login ?? "",
|
|
7500
|
+
repoUrl: s.repoUrl ?? "",
|
|
7501
|
+
repoExists: s.repoExists ?? false
|
|
7502
|
+
};
|
|
7503
|
+
return { kind: "logged-out" };
|
|
7504
|
+
}
|
|
7505
|
+
/** 空表单初值(React 壳 useState 初始 + 测试用)。 */
|
|
7506
|
+
const EMPTY_MY_CONFIG_FORM = {
|
|
7507
|
+
name: "",
|
|
7508
|
+
description: "",
|
|
7509
|
+
categories: "",
|
|
7510
|
+
id: ""
|
|
7511
|
+
};
|
|
7512
|
+
/** 表单校验:名称必填(trim 后非空)。描述/类别可选。 */
|
|
7513
|
+
function validateMyConfigForm(form, t = zhUiT) {
|
|
7514
|
+
return { name: form.name.trim() === "" ? t("myConfigs.form.errorName") : null };
|
|
7250
7515
|
}
|
|
7251
7516
|
/** 表单是否全部合法(上传按钮可用性)。 */
|
|
7252
7517
|
function myConfigFormValid(errors) {
|
|
@@ -7256,6 +7521,89 @@ function myConfigFormValid(errors) {
|
|
|
7256
7521
|
function parseCategories(csv) {
|
|
7257
7522
|
return csv.split(",").map((c) => c.trim()).filter((c) => c !== "");
|
|
7258
7523
|
}
|
|
7524
|
+
/** 向导初始状态常量(initialWizard('upload') 语义;调用方应经 initialWizard 获取新对象)。 */
|
|
7525
|
+
const EMPTY_MY_WIZARD = {
|
|
7526
|
+
mode: "upload",
|
|
7527
|
+
step: "select",
|
|
7528
|
+
zipPath: null,
|
|
7529
|
+
fileName: null,
|
|
7530
|
+
validating: false,
|
|
7531
|
+
validated: false,
|
|
7532
|
+
validationError: null,
|
|
7533
|
+
form: { ...EMPTY_MY_CONFIG_FORM },
|
|
7534
|
+
formErrors: { name: null },
|
|
7535
|
+
running: false,
|
|
7536
|
+
result: null,
|
|
7537
|
+
error: null
|
|
7538
|
+
};
|
|
7539
|
+
/** 全量状态 → 持久化切片(忽略 validating/running/formErrors;form 浅拷贝,result 直接引用纯 JSON)。 */
|
|
7540
|
+
function toMyWizardSlice(w) {
|
|
7541
|
+
return {
|
|
7542
|
+
mode: w.mode,
|
|
7543
|
+
step: w.step,
|
|
7544
|
+
zipPath: w.zipPath,
|
|
7545
|
+
fileName: w.fileName,
|
|
7546
|
+
validated: w.validated,
|
|
7547
|
+
validationError: w.validationError,
|
|
7548
|
+
form: { ...w.form },
|
|
7549
|
+
result: w.result,
|
|
7550
|
+
error: w.error
|
|
7551
|
+
};
|
|
7552
|
+
}
|
|
7553
|
+
/**
|
|
7554
|
+
* 持久化切片 → 全量状态(null → 全新向导)。瞬态字段归零(validating/running 恒 false),
|
|
7555
|
+
* formErrors 按 form 经 validateMyConfigForm 重算;form 拷贝新对象(不共享切片引用)。
|
|
7556
|
+
*/
|
|
7557
|
+
function restoreMyWizard(slice) {
|
|
7558
|
+
if (slice === null) return {
|
|
7559
|
+
...EMPTY_MY_WIZARD,
|
|
7560
|
+
form: { ...EMPTY_MY_CONFIG_FORM }
|
|
7561
|
+
};
|
|
7562
|
+
return {
|
|
7563
|
+
mode: slice.mode,
|
|
7564
|
+
step: slice.step,
|
|
7565
|
+
zipPath: slice.zipPath,
|
|
7566
|
+
fileName: slice.fileName,
|
|
7567
|
+
validating: false,
|
|
7568
|
+
validated: slice.validated,
|
|
7569
|
+
validationError: slice.validationError,
|
|
7570
|
+
form: { ...slice.form },
|
|
7571
|
+
formErrors: validateMyConfigForm(slice.form),
|
|
7572
|
+
running: false,
|
|
7573
|
+
result: slice.result,
|
|
7574
|
+
error: slice.error
|
|
7575
|
+
};
|
|
7576
|
+
}
|
|
7577
|
+
/** 指定模式的向导初始状态(form 全新空表;mode/step 之外同 EMPTY_MY_WIZARD)。 */
|
|
7578
|
+
function initialWizard(mode) {
|
|
7579
|
+
return {
|
|
7580
|
+
...EMPTY_MY_WIZARD,
|
|
7581
|
+
mode,
|
|
7582
|
+
form: { ...EMPTY_MY_CONFIG_FORM }
|
|
7583
|
+
};
|
|
7584
|
+
}
|
|
7585
|
+
/** 全量状态 → 持久化切片(忽略 importing;detail/approvals/importResult 直接引用纯 JSON/布尔表)。 */
|
|
7586
|
+
function toMyInstallSlice(s) {
|
|
7587
|
+
return {
|
|
7588
|
+
itemId: s.itemId,
|
|
7589
|
+
detail: s.detail,
|
|
7590
|
+
approvals: s.approvals,
|
|
7591
|
+
importResult: s.importResult,
|
|
7592
|
+
error: s.error
|
|
7593
|
+
};
|
|
7594
|
+
}
|
|
7595
|
+
/** 持久化切片 → 全量状态(null → 无装回本地会话;importing 恢复后恒 false)。 */
|
|
7596
|
+
function restoreMyInstall(slice) {
|
|
7597
|
+
if (slice === null) return null;
|
|
7598
|
+
return {
|
|
7599
|
+
itemId: slice.itemId,
|
|
7600
|
+
detail: slice.detail,
|
|
7601
|
+
approvals: slice.approvals,
|
|
7602
|
+
importing: false,
|
|
7603
|
+
importResult: slice.importResult,
|
|
7604
|
+
error: slice.error
|
|
7605
|
+
};
|
|
7606
|
+
}
|
|
7259
7607
|
/** 系统自动字段徽章列表(id/作者/版本/更新时间 → 「系统自动」徽章)。 */
|
|
7260
7608
|
function autoFieldBadges(t = zhUiT) {
|
|
7261
7609
|
const autoText = t("myConfigs.autoField");
|
|
@@ -7348,12 +7696,6 @@ function summarizeMyItems(views) {
|
|
|
7348
7696
|
}
|
|
7349
7697
|
//#endregion
|
|
7350
7698
|
//#region src/market/view.ts
|
|
7351
|
-
/** 市场状态行文案(status 区块顶部一行)。count<=0 → 未添加提示 */
|
|
7352
|
-
function marketStatusText(config, t) {
|
|
7353
|
-
const count = Array.isArray(config) ? config.length : config.count;
|
|
7354
|
-
if (count <= 0) return t("market.statusUnconfigured");
|
|
7355
|
-
return t("market.statusConfigured", { count });
|
|
7356
|
-
}
|
|
7357
7699
|
/** 列表摘要:总条目数 + 缓存徽章计数(供 UI 顶部小结)。无副作用。 */
|
|
7358
7700
|
function marketListSummary(items, _t) {
|
|
7359
7701
|
const fresh = items.filter((i) => i.cacheState === "fresh").length;
|
|
@@ -7614,23 +7956,14 @@ const initialGithubFlow = {
|
|
|
7614
7956
|
interval: 5,
|
|
7615
7957
|
error: null
|
|
7616
7958
|
};
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
validationError: null,
|
|
7626
|
-
form: { ...EMPTY_MY_CONFIG_FORM },
|
|
7627
|
-
formErrors: { name: null },
|
|
7628
|
-
running: false,
|
|
7629
|
-
result: null,
|
|
7630
|
-
error: null
|
|
7631
|
-
};
|
|
7632
|
-
}
|
|
7633
|
-
function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsError, onMyItemsChange, onBack }) {
|
|
7959
|
+
/**
|
|
7960
|
+
* 上传/更新向导状态(全量模型在 my-configs-view.ts 的 MyWizardState;本组件持有的是
|
|
7961
|
+
* 持久化切片 myWizard(受控 props),经 restoreMyWizard 恢复全量、toMyWizardSlice 上抛镜像。
|
|
7962
|
+
* 瞬态(validating/running/formErrors)由 restore 重建,切 tab/刷新恢复后为初始态。
|
|
7963
|
+
* 装回本地状态(MyInstallState)同模式:持久化切片 myInstall(受控 props),
|
|
7964
|
+
* 经 restoreMyInstall 恢复全量(importing 瞬态归零)、toMyInstallSlice 上抛镜像。
|
|
7965
|
+
*/
|
|
7966
|
+
function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsError, onMyItemsChange, myWizard, onMyWizardChange, myInstall, onMyInstallChange, myConfirmDeleteId, onMyConfirmDeleteChange }) {
|
|
7634
7967
|
const uiT = meApi.t;
|
|
7635
7968
|
const [status, setStatus] = (0, react.useState)(null);
|
|
7636
7969
|
const [statusLoading, setStatusLoading] = (0, react.useState)(true);
|
|
@@ -7638,9 +7971,134 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
7638
7971
|
const [github, setGithub] = (0, react.useState)(initialGithubFlow);
|
|
7639
7972
|
const githubPollTimer = (0, react.useRef)(null);
|
|
7640
7973
|
const [listLoading, setListLoading] = (0, react.useState)(false);
|
|
7641
|
-
const [wizard, setWizard] = (0, react.useState)(() =>
|
|
7642
|
-
|
|
7974
|
+
const [wizard, setWizard] = (0, react.useState)(() => restoreMyWizard(myWizard));
|
|
7975
|
+
/** 最近一次 wizard 全量(commitWizard 读最新值,避免闭包过期) */
|
|
7976
|
+
const wizardRef = (0, react.useRef)(wizard);
|
|
7977
|
+
/** 收录/下架任务状态(结果卡轮询 /me/listing 的实时结果) */
|
|
7978
|
+
const [listingStatus, setListingStatus] = (0, react.useState)(null);
|
|
7979
|
+
/** 收录/下架任务轮询定时器 */
|
|
7980
|
+
const listingPollTimer = (0, react.useRef)(null);
|
|
7981
|
+
/** 删除确认弹窗目标条目 id(受控:MarketPanel 经 runStore 持有,切 tab/刷新不丢;null = 无确认中的删除) */
|
|
7982
|
+
const confirmDeleteId = myConfirmDeleteId;
|
|
7983
|
+
/** 正在删除的条目 id(行级 spinner + 防重复点击) */
|
|
7984
|
+
const [deletingId, setDeletingId] = (0, react.useState)(null);
|
|
7985
|
+
/** 装回本地状态(受控:切片来自 runStore;瞬态 importing 本地重建) */
|
|
7986
|
+
const [install, setInstall] = (0, react.useState)(() => restoreMyInstall(myInstall));
|
|
7987
|
+
/** 最近一次 install 全量(commitInstall 读最新值,避免闭包过期) */
|
|
7988
|
+
const installRef = (0, react.useRef)(install);
|
|
7643
7989
|
const fileInput = (0, react.useRef)(null);
|
|
7990
|
+
/** 上传/更新向导弹窗开关(瞬态 UI,不持久化:切 tab 弹窗关闭,数据仍在 runStore) */
|
|
7991
|
+
const [uploadOpen, setUploadOpen] = (0, react.useState)(false);
|
|
7992
|
+
/** 装回本地弹窗开关(同上) */
|
|
7993
|
+
const [installOpen, setInstallOpen] = (0, react.useState)(false);
|
|
7994
|
+
/** 当前展示的免责弹窗操作(null = 无;upload/download/install 三操作分开记「不再提示」) */
|
|
7995
|
+
const [disclaimerKey, setDisclaimerKey] = (0, react.useState)(null);
|
|
7996
|
+
/** 免责弹窗「不再提示」勾选(每次打开重置) */
|
|
7997
|
+
const [dontAsk, setDontAsk] = (0, react.useState)(false);
|
|
7998
|
+
/** localStorage(浏览器环境;免责「不再提示」跨会话持久化) */
|
|
7999
|
+
const storage = window.localStorage;
|
|
8000
|
+
/** 打开上传/更新弹窗(更新模式表单已预填):未勾「不再提示」→ 先弹免责,确认后开弹窗 */
|
|
8001
|
+
const openUpload = () => {
|
|
8002
|
+
if (readDisclaimerDismissed("upload", storage)) {
|
|
8003
|
+
setUploadOpen(true);
|
|
8004
|
+
return;
|
|
8005
|
+
}
|
|
8006
|
+
setDontAsk(false);
|
|
8007
|
+
setDisclaimerKey("upload");
|
|
8008
|
+
};
|
|
8009
|
+
/** 待装回本地的目标条目(免责确认后取用;避免免责流程中闭包过期) */
|
|
8010
|
+
const pendingInstallEntry = (0, react.useRef)(null);
|
|
8011
|
+
/** 打开装回本地弹窗:未勾「不再提示」→ 先弹免责,确认后开弹窗并启动下载 */
|
|
8012
|
+
const openInstall = (entry) => {
|
|
8013
|
+
pendingInstallEntry.current = entry;
|
|
8014
|
+
if (readDisclaimerDismissed("install", storage)) {
|
|
8015
|
+
setInstallOpen(true);
|
|
8016
|
+
runDownload(entry);
|
|
8017
|
+
return;
|
|
8018
|
+
}
|
|
8019
|
+
setDontAsk(false);
|
|
8020
|
+
setDisclaimerKey("install");
|
|
8021
|
+
};
|
|
8022
|
+
/** 关闭上传/更新弹窗:重置向导为初始态(弹窗即会话,关闭即放弃本次操作;
|
|
8023
|
+
* 更新模式也切回「一键上传」入口,避免入口按钮残留 update 态) */
|
|
8024
|
+
const closeUpload = () => {
|
|
8025
|
+
setUploadOpen(false);
|
|
8026
|
+
commitWizard(initialWizard("upload"));
|
|
8027
|
+
setListingStatus(null);
|
|
8028
|
+
};
|
|
8029
|
+
/** 取消更新:放弃本次更新,向导回到默认「一键上传」初始态(清空预填/暂存/校验态),弹窗保持打开 */
|
|
8030
|
+
const cancelUpdate = () => {
|
|
8031
|
+
commitWizard(initialWizard("upload"));
|
|
8032
|
+
setListingStatus(null);
|
|
8033
|
+
};
|
|
8034
|
+
/** 关闭装回本地弹窗:清 install 会话 */
|
|
8035
|
+
const closeInstall = () => {
|
|
8036
|
+
setInstallOpen(false);
|
|
8037
|
+
commitInstall(null);
|
|
8038
|
+
};
|
|
8039
|
+
/** 免责弹窗确认:勾选则记录「不再提示」→ 关闭免责 → 打开对应操作弹窗 */
|
|
8040
|
+
const confirmDisclaimer = () => {
|
|
8041
|
+
const key = disclaimerKey;
|
|
8042
|
+
if (key === null) return;
|
|
8043
|
+
if (dontAsk) writeDisclaimerDismissed(key, storage);
|
|
8044
|
+
setDisclaimerKey(null);
|
|
8045
|
+
if (key === "upload") setUploadOpen(true);
|
|
8046
|
+
else if (key === "install") {
|
|
8047
|
+
const entry = pendingInstallEntry.current;
|
|
8048
|
+
setInstallOpen(true);
|
|
8049
|
+
if (entry !== null && entry !== void 0) runDownload(entry);
|
|
8050
|
+
}
|
|
8051
|
+
};
|
|
8052
|
+
/** 取消免责弹窗:关闭,不打开操作弹窗;若向导处于 update 残留态则重置为上传初始态 */
|
|
8053
|
+
const cancelDisclaimer = () => {
|
|
8054
|
+
setDisclaimerKey(null);
|
|
8055
|
+
if (disclaimerKey === "upload" && wizardRef.current.mode === "update") {
|
|
8056
|
+
commitWizard(initialWizard("upload"));
|
|
8057
|
+
setListingStatus(null);
|
|
8058
|
+
}
|
|
8059
|
+
};
|
|
8060
|
+
/** 免责弹窗文案(MyConfigsView 只触发 upload / install 两种;default 兜底返回空串防误显) */
|
|
8061
|
+
const disclaimerText = () => {
|
|
8062
|
+
switch (disclaimerKey) {
|
|
8063
|
+
case "upload": return t("disclaimer.upload.text");
|
|
8064
|
+
case "install": return t("disclaimer.install.text");
|
|
8065
|
+
default: return "";
|
|
8066
|
+
}
|
|
8067
|
+
};
|
|
8068
|
+
/**
|
|
8069
|
+
* 向导状态统一提交:更新 ref → setState → **总是**镜像切片上抛(MarketPanel 落 runStore)。
|
|
8070
|
+
* 镜像不依赖 effect flush:异步回调在组件已卸载(切走 tab)时也能落库,切回恢复。
|
|
8071
|
+
* 镜像上抛包 try/catch:镜像失败(store 异常)绝不影响本地 UI 更新(防「点击无反应」)。
|
|
8072
|
+
*/
|
|
8073
|
+
const commitWizard = (next) => {
|
|
8074
|
+
wizardRef.current = next;
|
|
8075
|
+
setWizard(next);
|
|
8076
|
+
try {
|
|
8077
|
+
onMyWizardChange(toMyWizardSlice(next));
|
|
8078
|
+
} catch {}
|
|
8079
|
+
};
|
|
8080
|
+
const patchWizard = (p) => commitWizard({
|
|
8081
|
+
...wizardRef.current,
|
|
8082
|
+
...p
|
|
8083
|
+
});
|
|
8084
|
+
/**
|
|
8085
|
+
* 装回本地状态统一提交:更新 ref → setState → **总是**镜像切片上抛(MarketPanel 落 runStore)。
|
|
8086
|
+
* 镜像不依赖 effect flush:异步回调在组件已卸载(切走 tab)时也能落库,切回恢复。
|
|
8087
|
+
*/
|
|
8088
|
+
const commitInstall = (next) => {
|
|
8089
|
+
installRef.current = next;
|
|
8090
|
+
setInstall(next);
|
|
8091
|
+
try {
|
|
8092
|
+
onMyInstallChange(next === null ? null : toMyInstallSlice(next));
|
|
8093
|
+
} catch {}
|
|
8094
|
+
};
|
|
8095
|
+
const patchInstall = (p) => {
|
|
8096
|
+
if (installRef.current === null) return;
|
|
8097
|
+
commitInstall({
|
|
8098
|
+
...installRef.current,
|
|
8099
|
+
...p
|
|
8100
|
+
});
|
|
8101
|
+
};
|
|
7644
8102
|
/** 读取登录态(挂载 / 登录成功 / 状态刷新),返回 status 供后续判断 */
|
|
7645
8103
|
const loadStatus = async () => {
|
|
7646
8104
|
setStatusLoading(true);
|
|
@@ -7753,138 +8211,222 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
7753
8211
|
await syncApi.githubCancel(flowId);
|
|
7754
8212
|
} catch {}
|
|
7755
8213
|
};
|
|
7756
|
-
/**
|
|
8214
|
+
/** 选 zip → upload 受控临时区;upload 模式预填 name 为 zip 文件名(可改);
|
|
8215
|
+
* update 模式(更新直达表单页)留在 form 步骤并自动跑校验 */
|
|
7757
8216
|
const onPickFile = async (file) => {
|
|
7758
8217
|
if (file === void 0) return;
|
|
7759
|
-
|
|
7760
|
-
...w,
|
|
8218
|
+
patchWizard({
|
|
7761
8219
|
fileName: file.name,
|
|
7762
|
-
error: null
|
|
7763
|
-
|
|
8220
|
+
error: null,
|
|
8221
|
+
validationError: null
|
|
8222
|
+
});
|
|
7764
8223
|
try {
|
|
7765
8224
|
const uploaded = await importApi.upload(file);
|
|
7766
|
-
|
|
7767
|
-
...w,
|
|
8225
|
+
const base = {
|
|
7768
8226
|
zipPath: uploaded.zipPath,
|
|
8227
|
+
fileName: file.name
|
|
8228
|
+
};
|
|
8229
|
+
if (wizardRef.current.mode === "update") {
|
|
8230
|
+
patchWizard({
|
|
8231
|
+
...base,
|
|
8232
|
+
validated: false
|
|
8233
|
+
});
|
|
8234
|
+
await runValidateWith(uploaded.zipPath);
|
|
8235
|
+
} else patchWizard({
|
|
8236
|
+
...base,
|
|
7769
8237
|
step: "validate",
|
|
7770
|
-
form:
|
|
7771
|
-
...
|
|
8238
|
+
form: {
|
|
8239
|
+
...wizardRef.current.form,
|
|
7772
8240
|
name: file.name.replace(/\.zip$/i, "")
|
|
7773
|
-
}
|
|
7774
|
-
})
|
|
8241
|
+
}
|
|
8242
|
+
});
|
|
7775
8243
|
} catch (err) {
|
|
7776
|
-
|
|
7777
|
-
...w,
|
|
7778
|
-
error: err instanceof Error ? err.message : String(err)
|
|
7779
|
-
}));
|
|
8244
|
+
patchWizard({ error: err instanceof Error ? err.message : String(err) });
|
|
7780
8245
|
}
|
|
7781
8246
|
};
|
|
7782
8247
|
/** 步骤 2:analyzeImport dry-run(零写入)—— 无密钥 + 内容合法才放行;通过后进表单 */
|
|
7783
8248
|
const runValidate = async () => {
|
|
7784
8249
|
if (wizard.zipPath === null) return;
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
}));
|
|
8250
|
+
await runValidateWith(wizard.zipPath);
|
|
8251
|
+
};
|
|
8252
|
+
/** 校验指定 zipPath(update 模式选新 zip 后自动调用;任何异常都落到 validationError 展示,不静默) */
|
|
8253
|
+
const runValidateWith = async (zipPath) => {
|
|
7790
8254
|
try {
|
|
7791
|
-
|
|
7792
|
-
|
|
8255
|
+
patchWizard({
|
|
8256
|
+
validating: true,
|
|
8257
|
+
validationError: null
|
|
8258
|
+
});
|
|
8259
|
+
} catch (err) {
|
|
8260
|
+
setWizard((w) => ({
|
|
7793
8261
|
...w,
|
|
8262
|
+
validationError: err instanceof Error ? err.message : String(err)
|
|
8263
|
+
}));
|
|
8264
|
+
return;
|
|
8265
|
+
}
|
|
8266
|
+
try {
|
|
8267
|
+
const analysis = await importApi.analyzeImport(zipPath);
|
|
8268
|
+
if (analysis.secretCount > 0) patchWizard({
|
|
7794
8269
|
validating: false,
|
|
7795
8270
|
validated: false,
|
|
7796
8271
|
validationError: t("myconfigs.upload.validateSecrets")
|
|
7797
|
-
})
|
|
7798
|
-
else if (!analysis.valid)
|
|
7799
|
-
...w,
|
|
8272
|
+
});
|
|
8273
|
+
else if (!analysis.valid) patchWizard({
|
|
7800
8274
|
validating: false,
|
|
7801
8275
|
validated: false,
|
|
7802
8276
|
validationError: t("myconfigs.upload.validateInvalid")
|
|
7803
|
-
})
|
|
7804
|
-
else
|
|
7805
|
-
...w,
|
|
8277
|
+
});
|
|
8278
|
+
else patchWizard({
|
|
7806
8279
|
validating: false,
|
|
7807
8280
|
validated: true,
|
|
8281
|
+
validationError: null,
|
|
7808
8282
|
step: "form"
|
|
7809
|
-
})
|
|
8283
|
+
});
|
|
7810
8284
|
} catch (err) {
|
|
7811
|
-
|
|
7812
|
-
...w,
|
|
8285
|
+
patchWizard({
|
|
7813
8286
|
validating: false,
|
|
7814
8287
|
validated: false,
|
|
7815
8288
|
validationError: err instanceof Error ? err.message : String(err)
|
|
7816
|
-
})
|
|
8289
|
+
});
|
|
7817
8290
|
}
|
|
7818
8291
|
};
|
|
7819
8292
|
/** 表单字段更新 + 实时校验(pure 模型) */
|
|
7820
8293
|
const onFormField = (field, value) => {
|
|
7821
8294
|
const next = {
|
|
7822
|
-
...
|
|
8295
|
+
...wizardRef.current.form,
|
|
7823
8296
|
[field]: value
|
|
7824
8297
|
};
|
|
7825
|
-
|
|
7826
|
-
...w,
|
|
8298
|
+
patchWizard({
|
|
7827
8299
|
form: next,
|
|
7828
8300
|
formErrors: validateMyConfigForm(next, uiT)
|
|
7829
|
-
})
|
|
8301
|
+
});
|
|
7830
8302
|
};
|
|
7831
8303
|
/** 「一键上传 / 一键更新」→ meUpload / meUpdate */
|
|
7832
8304
|
const runUpload = async () => {
|
|
7833
|
-
|
|
7834
|
-
const
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
}));
|
|
8305
|
+
const w = wizardRef.current;
|
|
8306
|
+
const zipPath = w.zipPath;
|
|
8307
|
+
if (zipPath === null) return;
|
|
8308
|
+
const errs = validateMyConfigForm(w.form, uiT);
|
|
8309
|
+
patchWizard({ formErrors: errs });
|
|
7839
8310
|
if (!myConfigFormValid(errs)) return;
|
|
7840
|
-
const categories = parseCategories(
|
|
8311
|
+
const categories = parseCategories(w.form.categories);
|
|
7841
8312
|
const form = {
|
|
7842
|
-
name:
|
|
7843
|
-
...
|
|
8313
|
+
name: w.form.name.trim(),
|
|
8314
|
+
...w.mode === "update" && w.form.id !== "" ? { id: w.form.id } : {},
|
|
8315
|
+
...w.form.description.trim() !== "" ? { description: w.form.description.trim() } : {},
|
|
7844
8316
|
...categories.length > 0 ? { categories } : {}
|
|
7845
8317
|
};
|
|
7846
|
-
|
|
7847
|
-
...w,
|
|
8318
|
+
patchWizard({
|
|
7848
8319
|
running: true,
|
|
7849
8320
|
error: null,
|
|
7850
8321
|
result: null
|
|
7851
|
-
})
|
|
8322
|
+
});
|
|
7852
8323
|
try {
|
|
7853
|
-
const result =
|
|
7854
|
-
zipPath
|
|
8324
|
+
const result = w.mode === "update" ? await meApi.meUpdate({
|
|
8325
|
+
zipPath,
|
|
7855
8326
|
form
|
|
7856
8327
|
}) : await meApi.meUpload({
|
|
7857
|
-
zipPath
|
|
8328
|
+
zipPath,
|
|
7858
8329
|
form
|
|
7859
8330
|
});
|
|
7860
|
-
|
|
7861
|
-
...
|
|
8331
|
+
commitWizard({
|
|
8332
|
+
...wizardRef.current,
|
|
7862
8333
|
running: false,
|
|
7863
8334
|
result
|
|
7864
|
-
})
|
|
8335
|
+
});
|
|
8336
|
+
setListingStatus(null);
|
|
8337
|
+
if (result.ok && result.listing === "pending") startListingPoll(result.itemId);
|
|
7865
8338
|
loadItems({ silent: true });
|
|
7866
8339
|
} catch (err) {
|
|
7867
|
-
|
|
7868
|
-
...w,
|
|
8340
|
+
patchWizard({
|
|
7869
8341
|
running: false,
|
|
7870
8342
|
error: err instanceof Error ? err.message : String(err)
|
|
7871
|
-
})
|
|
8343
|
+
});
|
|
7872
8344
|
}
|
|
7873
8345
|
};
|
|
7874
|
-
/** 行操作:更新 →
|
|
8346
|
+
/** 行操作:更新 → 打开「更新配置」表单页(step='form',预填条目信息;表单内选新 zip 自动校验) */
|
|
7875
8347
|
const startUpdate = (entry) => {
|
|
7876
|
-
|
|
8348
|
+
commitWizard({
|
|
7877
8349
|
...initialWizard("update"),
|
|
8350
|
+
step: "form",
|
|
7878
8351
|
form: {
|
|
8352
|
+
id: entry.id,
|
|
7879
8353
|
name: entry.name,
|
|
7880
8354
|
description: entry.description ?? "",
|
|
7881
8355
|
categories: (entry.categories ?? []).join(", ")
|
|
7882
8356
|
}
|
|
7883
8357
|
});
|
|
8358
|
+
setListingStatus(null);
|
|
8359
|
+
};
|
|
8360
|
+
/** 轮询 /me/listing 直到任务终态(done/failed/null);间隔 3s、最多 40 次(≈2 分钟),
|
|
8361
|
+
* 后台 fork 更久时超时停止,用户可稍后手动刷新列表/点「重新收录」 */
|
|
8362
|
+
const startListingPoll = (itemId) => {
|
|
8363
|
+
if (listingPollTimer.current !== null) clearTimeout(listingPollTimer.current);
|
|
8364
|
+
let count = 0;
|
|
8365
|
+
const tick = () => {
|
|
8366
|
+
(async () => {
|
|
8367
|
+
try {
|
|
8368
|
+
const s = await meApi.meListing(itemId);
|
|
8369
|
+
if (s === null) {
|
|
8370
|
+
setListingStatus({
|
|
8371
|
+
itemId,
|
|
8372
|
+
listing: "done",
|
|
8373
|
+
prNumber: null,
|
|
8374
|
+
prUrl: null
|
|
8375
|
+
});
|
|
8376
|
+
return;
|
|
8377
|
+
}
|
|
8378
|
+
setListingStatus(s);
|
|
8379
|
+
if (s.listing !== "pending") return;
|
|
8380
|
+
} catch {}
|
|
8381
|
+
count += 1;
|
|
8382
|
+
if (count >= 40) {
|
|
8383
|
+
listingPollTimer.current = null;
|
|
8384
|
+
return;
|
|
8385
|
+
}
|
|
8386
|
+
listingPollTimer.current = setTimeout(tick, 3e3);
|
|
8387
|
+
})();
|
|
8388
|
+
};
|
|
8389
|
+
tick();
|
|
8390
|
+
};
|
|
8391
|
+
/** 挂载恢复:若持久化的向导结果仍是「收录处理中」(pending),继续轮询(仿 resume 模式,避免刷新后永久 pending 卡死) */
|
|
8392
|
+
(0, react.useEffect)(() => {
|
|
8393
|
+
const w = wizardRef.current;
|
|
8394
|
+
if (w.result !== null && w.result.ok && w.result.listing === "pending") startListingPoll(w.result.itemId);
|
|
8395
|
+
return () => {
|
|
8396
|
+
if (listingPollTimer.current !== null) clearTimeout(listingPollTimer.current);
|
|
8397
|
+
};
|
|
8398
|
+
}, []);
|
|
8399
|
+
/** 重新提交收录(收录失败 / 进程重启丢失后的一键重试)→ 重新轮询状态 */
|
|
8400
|
+
const runRelist = async (itemId) => {
|
|
8401
|
+
try {
|
|
8402
|
+
const s = await meApi.meRelist(itemId);
|
|
8403
|
+
setListingStatus(s);
|
|
8404
|
+
startListingPoll(itemId);
|
|
8405
|
+
} catch (err) {
|
|
8406
|
+
patchWizard({ error: err instanceof Error ? err.message : String(err) });
|
|
8407
|
+
}
|
|
8408
|
+
};
|
|
8409
|
+
/** 删除:调 /me/delete(同步删本地索引+文件;已收录自动后台提下架 PR)→ 刷新列表 */
|
|
8410
|
+
const runDelete = async (entry) => {
|
|
8411
|
+
if (deletingId !== null) return;
|
|
8412
|
+
setDeletingId(entry.id);
|
|
8413
|
+
onMyConfirmDeleteChange(null);
|
|
8414
|
+
try {
|
|
8415
|
+
const result = await meApi.meDelete(entry.id);
|
|
8416
|
+
if (result.ok) {
|
|
8417
|
+
if (result.delisted) patchWizard({ error: t("myconfigs.delete.delistStarted") });
|
|
8418
|
+
else if (result.prNumber !== null) patchWizard({ error: t("myconfigs.delete.prClosed") });
|
|
8419
|
+
loadItems({ silent: true });
|
|
8420
|
+
} else patchWizard({ error: result.error ?? t("common.unknownError") });
|
|
8421
|
+
} catch (err) {
|
|
8422
|
+
patchWizard({ error: err instanceof Error ? err.message : String(err) });
|
|
8423
|
+
} finally {
|
|
8424
|
+
setDeletingId(null);
|
|
8425
|
+
}
|
|
7884
8426
|
};
|
|
7885
8427
|
/** 装回本地(复用市场下载 + 逐分区批准链路;条目内容在用户自己的公开仓库,必须带 repo 来源) */
|
|
7886
8428
|
const runDownload = async (entry) => {
|
|
7887
|
-
|
|
8429
|
+
commitInstall({
|
|
7888
8430
|
itemId: entry.id,
|
|
7889
8431
|
detail: null,
|
|
7890
8432
|
approvals: {},
|
|
@@ -7894,49 +8436,40 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
7894
8436
|
});
|
|
7895
8437
|
try {
|
|
7896
8438
|
const detail = await api.download(entry.id, entry.repoUrl);
|
|
7897
|
-
|
|
7898
|
-
...
|
|
8439
|
+
if (installRef.current !== null) commitInstall({
|
|
8440
|
+
...installRef.current,
|
|
7899
8441
|
detail,
|
|
7900
8442
|
approvals: defaultApprovals(detail.plan)
|
|
7901
|
-
}
|
|
8443
|
+
});
|
|
7902
8444
|
} catch (err) {
|
|
7903
|
-
|
|
7904
|
-
...i,
|
|
7905
|
-
error: err instanceof Error ? err.message : String(err)
|
|
7906
|
-
} : i);
|
|
8445
|
+
if (installRef.current !== null) patchInstall({ error: err instanceof Error ? err.message : String(err) });
|
|
7907
8446
|
}
|
|
7908
8447
|
};
|
|
7909
8448
|
const runImport = async () => {
|
|
7910
8449
|
if (install === null || install.detail === null) return;
|
|
7911
8450
|
const approvedPlan = buildApprovedPlan(install.detail.plan, install.approvals);
|
|
7912
8451
|
if (approvedPlan.items.length === 0) {
|
|
7913
|
-
|
|
7914
|
-
...i,
|
|
7915
|
-
error: t("detail.noApproval")
|
|
7916
|
-
} : i);
|
|
8452
|
+
patchInstall({ error: t("detail.noApproval") });
|
|
7917
8453
|
return;
|
|
7918
8454
|
}
|
|
7919
|
-
|
|
7920
|
-
...i,
|
|
8455
|
+
patchInstall({
|
|
7921
8456
|
importing: true,
|
|
7922
8457
|
error: null
|
|
7923
|
-
}
|
|
8458
|
+
});
|
|
7924
8459
|
try {
|
|
7925
8460
|
const executed = await importApi.executeImportPlan(install.detail.zipPath, approvedPlan, {
|
|
7926
8461
|
confirm: true,
|
|
7927
8462
|
rollbackOnError: true
|
|
7928
8463
|
});
|
|
7929
|
-
|
|
7930
|
-
...i,
|
|
8464
|
+
patchInstall({
|
|
7931
8465
|
importing: false,
|
|
7932
8466
|
importResult: executed
|
|
7933
|
-
}
|
|
8467
|
+
});
|
|
7934
8468
|
} catch (err) {
|
|
7935
|
-
|
|
7936
|
-
...i,
|
|
8469
|
+
patchInstall({
|
|
7937
8470
|
importing: false,
|
|
7938
8471
|
error: err instanceof Error ? err.message : String(err)
|
|
7939
|
-
}
|
|
8472
|
+
});
|
|
7940
8473
|
}
|
|
7941
8474
|
};
|
|
7942
8475
|
/** 登录视图(loading / logged-out / logged-in / token-invalid) */
|
|
@@ -8061,199 +8594,305 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
8061
8594
|
};
|
|
8062
8595
|
/** 上传 / 更新向导卡片(选 zip → 校验 → 表单 → 结果) */
|
|
8063
8596
|
const renderWizard = () => {
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
children: t("myconfigs.upload.
|
|
8101
|
-
})
|
|
8102
|
-
})
|
|
8103
|
-
] }),
|
|
8104
|
-
wizard.step === "validate" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8105
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8106
|
-
className: config_manager_module_css_default.hint,
|
|
8107
|
-
children: t("myconfigs.upload.selectHint")
|
|
8108
|
-
}),
|
|
8109
|
-
wizard.fileName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8110
|
-
className: config_manager_module_css_default.statRow,
|
|
8111
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8112
|
-
kind: "info",
|
|
8113
|
-
children: t("myconfigs.upload.selected", { name: wizard.fileName })
|
|
8114
|
-
})
|
|
8115
|
-
}),
|
|
8116
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8117
|
-
className: config_manager_module_css_default.actionRow,
|
|
8118
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8119
|
-
variant: "primary",
|
|
8120
|
-
disabled: wizard.zipPath === null || wizard.validating,
|
|
8121
|
-
onClick: () => {
|
|
8122
|
-
runValidate();
|
|
8123
|
-
},
|
|
8124
|
-
children: wizard.validating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("myconfigs.upload.validating") }) : t("myconfigs.upload.validate")
|
|
8125
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8126
|
-
disabled: wizard.validating,
|
|
8127
|
-
onClick: reset,
|
|
8128
|
-
children: t("myconfigs.upload.reselect")
|
|
8129
|
-
})]
|
|
8130
|
-
}),
|
|
8131
|
-
wizard.validationError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8132
|
-
kind: "error",
|
|
8133
|
-
children: redact(wizard.validationError)
|
|
8134
|
-
})
|
|
8135
|
-
] }),
|
|
8136
|
-
wizard.step === "form" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8137
|
-
wizard.validated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8138
|
-
className: config_manager_module_css_default.statRow,
|
|
8139
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8140
|
-
kind: "ok",
|
|
8141
|
-
children: t("myconfigs.upload.validateOk")
|
|
8142
|
-
})
|
|
8143
|
-
}),
|
|
8144
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Field, {
|
|
8145
|
-
label: t("myconfigs.upload.form.name"),
|
|
8146
|
-
hint: t("myconfigs.upload.form.nameHint"),
|
|
8147
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8148
|
-
className: config_manager_module_css_default.input,
|
|
8149
|
-
value: wizard.form.name,
|
|
8150
|
-
onChange: (e) => {
|
|
8151
|
-
onFormField("name", e.target.value);
|
|
8152
|
-
}
|
|
8153
|
-
}), wizard.formErrors.name !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8154
|
-
className: config_manager_module_css_default.formError,
|
|
8155
|
-
children: redact(wizard.formErrors.name)
|
|
8156
|
-
})]
|
|
8157
|
-
}),
|
|
8158
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
8159
|
-
label: t("myconfigs.upload.form.description"),
|
|
8160
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
8161
|
-
className: config_manager_module_css_default.input,
|
|
8162
|
-
value: wizard.form.description,
|
|
8163
|
-
onChange: (e) => {
|
|
8164
|
-
onFormField("description", e.target.value);
|
|
8165
|
-
}
|
|
8166
|
-
})
|
|
8167
|
-
}),
|
|
8168
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
8169
|
-
label: t("myconfigs.upload.form.categories"),
|
|
8170
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8171
|
-
className: config_manager_module_css_default.input,
|
|
8172
|
-
value: wizard.form.categories,
|
|
8173
|
-
onChange: (e) => {
|
|
8174
|
-
onFormField("categories", e.target.value);
|
|
8175
|
-
}
|
|
8176
|
-
})
|
|
8177
|
-
}),
|
|
8178
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8179
|
-
className: config_manager_module_css_default.hint,
|
|
8180
|
-
children: t("myconfigs.upload.form.autoHint")
|
|
8181
|
-
}),
|
|
8182
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8183
|
-
className: config_manager_module_css_default.statRow,
|
|
8184
|
-
children: autoBadges.map((b) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Badge, {
|
|
8185
|
-
kind: "info",
|
|
8186
|
-
children: [
|
|
8187
|
-
b.label,
|
|
8188
|
-
":",
|
|
8189
|
-
b.autoText
|
|
8190
|
-
]
|
|
8191
|
-
}, b.field))
|
|
8192
|
-
}),
|
|
8193
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8194
|
-
className: config_manager_module_css_default.actionRow,
|
|
8195
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8196
|
-
variant: "primary",
|
|
8197
|
-
disabled: wizard.validated !== true || wizard.running || !myConfigFormValid(wizard.formErrors),
|
|
8198
|
-
onClick: () => {
|
|
8199
|
-
runUpload();
|
|
8200
|
-
},
|
|
8201
|
-
children: wizard.running ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: wizard.mode === "update" ? t("myconfigs.update.running") : t("myconfigs.upload.running") }) : wizard.mode === "update" ? t("myconfigs.update.run") : t("myconfigs.upload.run")
|
|
8202
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8203
|
-
disabled: wizard.running,
|
|
8204
|
-
onClick: reset,
|
|
8205
|
-
children: t("myconfigs.upload.reselect")
|
|
8206
|
-
})]
|
|
8207
|
-
})
|
|
8208
|
-
] }),
|
|
8209
|
-
wizard.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8210
|
-
kind: "error",
|
|
8211
|
-
children: redact(wizard.error)
|
|
8212
|
-
}),
|
|
8213
|
-
wizard.result !== null && (wizard.result.ok ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8214
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8215
|
-
className: config_manager_module_css_default.groupLabel,
|
|
8216
|
-
children: t("myconfigs.result.title")
|
|
8217
|
-
}),
|
|
8218
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8219
|
-
className: config_manager_module_css_default.statRow,
|
|
8220
|
-
children: [
|
|
8221
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8222
|
-
kind: "ok",
|
|
8223
|
-
children: t("myconfigs.result.version", { version: wizard.result.version })
|
|
8224
|
-
}),
|
|
8225
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8226
|
-
kind: "info",
|
|
8227
|
-
children: t("myconfigs.result.sha256", { hash: wizard.result.sha256 })
|
|
8228
|
-
}),
|
|
8229
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8597
|
+
/** PR 链接(优先实时任务状态;收录完成后由轮询补上,或直接取同步结果) */
|
|
8598
|
+
const prLink = (() => {
|
|
8599
|
+
const live = listingStatus;
|
|
8600
|
+
const url = live !== null && live.prUrl !== null && live.prUrl !== "" ? live.prUrl : wizardRef.current.result?.prUrl ?? null;
|
|
8601
|
+
if (url === null || url === "") return null;
|
|
8602
|
+
const number = live !== null && live.prNumber !== null ? live.prNumber : wizardRef.current.result?.prNumber;
|
|
8603
|
+
return {
|
|
8604
|
+
url,
|
|
8605
|
+
label: number !== null && number !== void 0 ? t("myconfigs.result.pr", { number: String(number) }) : t("myconfigs.result.openPr")
|
|
8606
|
+
};
|
|
8607
|
+
})();
|
|
8608
|
+
/** 重置:update 模式轻量重置(只清 zip/校验,**保留预填表单**);upload 模式完全重置 */
|
|
8609
|
+
const reset = () => {
|
|
8610
|
+
const w = wizardRef.current;
|
|
8611
|
+
if (w.mode === "update") commitWizard({
|
|
8612
|
+
...initialWizard("update"),
|
|
8613
|
+
step: "form",
|
|
8614
|
+
form: { ...w.form }
|
|
8615
|
+
});
|
|
8616
|
+
else commitWizard(initialWizard("upload"));
|
|
8617
|
+
setListingStatus(null);
|
|
8618
|
+
};
|
|
8619
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8620
|
+
className: config_manager_module_css_default.dialogMask,
|
|
8621
|
+
onMouseDown: (e) => {
|
|
8622
|
+
if (e.target === e.currentTarget && !wizard.running && !wizard.validating) closeUpload();
|
|
8623
|
+
},
|
|
8624
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8625
|
+
className: `${config_manager_module_css_default.dialogCard} ${config_manager_module_css_default.dialogWide}`,
|
|
8626
|
+
role: "dialog",
|
|
8627
|
+
"aria-modal": "true",
|
|
8628
|
+
"aria-label": wizard.mode === "update" ? t("myconfigs.update.title") : t("myconfigs.upload.title"),
|
|
8629
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8630
|
+
className: config_manager_module_css_default.dialogHeaderRow,
|
|
8631
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8632
|
+
className: config_manager_module_css_default.dialogHeader,
|
|
8633
|
+
children: [wizard.mode === "update" ? t("myconfigs.update.title") : t("myconfigs.upload.title"), wizard.mode === "update" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8230
8634
|
kind: "info",
|
|
8231
|
-
children: t("myconfigs.
|
|
8232
|
-
})
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8635
|
+
children: t("myconfigs.update.hint")
|
|
8636
|
+
})]
|
|
8637
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8638
|
+
type: "button",
|
|
8639
|
+
className: config_manager_module_css_default.dialogClose,
|
|
8640
|
+
"aria-label": t("common.close"),
|
|
8641
|
+
disabled: wizard.running || wizard.validating,
|
|
8642
|
+
onClick: closeUpload,
|
|
8643
|
+
children: "×"
|
|
8644
|
+
})]
|
|
8645
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8646
|
+
className: config_manager_module_css_default.dialogBodyScroll,
|
|
8237
8647
|
children: [
|
|
8238
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8648
|
+
wizard.step === "select" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8650
|
+
className: config_manager_module_css_default.hint,
|
|
8651
|
+
children: t("myconfigs.upload.selectHint")
|
|
8652
|
+
}),
|
|
8653
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8654
|
+
ref: fileInput,
|
|
8655
|
+
type: "file",
|
|
8656
|
+
accept: ".zip,application/zip",
|
|
8657
|
+
className: config_manager_module_css_default.hiddenFile,
|
|
8658
|
+
onChange: (e) => {
|
|
8659
|
+
const picked = e.target.files?.[0];
|
|
8660
|
+
e.target.value = "";
|
|
8661
|
+
onPickFile(picked);
|
|
8662
|
+
}
|
|
8663
|
+
}),
|
|
8664
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8665
|
+
className: config_manager_module_css_default.actionRow,
|
|
8666
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8667
|
+
variant: "primary",
|
|
8668
|
+
disabled: wizard.running,
|
|
8669
|
+
onClick: () => {
|
|
8670
|
+
fileInput.current?.click();
|
|
8671
|
+
},
|
|
8672
|
+
children: t("myconfigs.upload.select")
|
|
8673
|
+
})
|
|
8674
|
+
})
|
|
8675
|
+
] }),
|
|
8676
|
+
wizard.step === "validate" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8677
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8678
|
+
className: config_manager_module_css_default.hint,
|
|
8679
|
+
children: t("myconfigs.upload.selectHint")
|
|
8680
|
+
}),
|
|
8681
|
+
wizard.fileName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8682
|
+
className: config_manager_module_css_default.statRow,
|
|
8683
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8684
|
+
kind: "info",
|
|
8685
|
+
children: t("myconfigs.upload.selected", { name: wizard.fileName })
|
|
8686
|
+
})
|
|
8687
|
+
}),
|
|
8688
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8689
|
+
className: config_manager_module_css_default.actionRow,
|
|
8690
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8691
|
+
variant: "primary",
|
|
8692
|
+
disabled: wizard.zipPath === null || wizard.validating,
|
|
8693
|
+
onClick: () => {
|
|
8694
|
+
runValidate();
|
|
8695
|
+
},
|
|
8696
|
+
children: wizard.validating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("myconfigs.upload.validating") }) : t("myconfigs.upload.validate")
|
|
8697
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8698
|
+
disabled: wizard.validating,
|
|
8699
|
+
onClick: reset,
|
|
8700
|
+
children: t("myconfigs.upload.reselect")
|
|
8701
|
+
})]
|
|
8702
|
+
}),
|
|
8703
|
+
wizard.validationError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8704
|
+
kind: "error",
|
|
8705
|
+
children: redact(wizard.validationError)
|
|
8706
|
+
})
|
|
8707
|
+
] }),
|
|
8708
|
+
wizard.step === "form" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8709
|
+
wizard.mode === "update" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8711
|
+
className: config_manager_module_css_default.hint,
|
|
8712
|
+
children: t("myconfigs.update.zipHint")
|
|
8713
|
+
}),
|
|
8714
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8715
|
+
ref: fileInput,
|
|
8716
|
+
type: "file",
|
|
8717
|
+
accept: ".zip,application/zip",
|
|
8718
|
+
className: config_manager_module_css_default.hiddenFile,
|
|
8719
|
+
onChange: (e) => {
|
|
8720
|
+
const picked = e.target.files?.[0];
|
|
8721
|
+
e.target.value = "";
|
|
8722
|
+
onPickFile(picked);
|
|
8723
|
+
}
|
|
8724
|
+
}),
|
|
8725
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8726
|
+
className: config_manager_module_css_default.actionRow,
|
|
8727
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8728
|
+
variant: "primary",
|
|
8729
|
+
disabled: wizard.validating || wizard.running,
|
|
8730
|
+
onClick: () => {
|
|
8731
|
+
fileInput.current?.click();
|
|
8732
|
+
},
|
|
8733
|
+
children: wizard.fileName !== null && wizard.zipPath !== null ? t("myconfigs.upload.selected", { name: wizard.fileName }) : t("myconfigs.update.selectZip")
|
|
8734
|
+
}), wizard.zipPath !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8735
|
+
disabled: wizard.validating || wizard.running,
|
|
8736
|
+
onClick: reset,
|
|
8737
|
+
children: t("myconfigs.upload.reselect")
|
|
8738
|
+
})]
|
|
8739
|
+
}),
|
|
8740
|
+
wizard.validationError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8741
|
+
kind: "error",
|
|
8742
|
+
children: redact(wizard.validationError)
|
|
8743
|
+
})
|
|
8744
|
+
] }),
|
|
8745
|
+
wizard.validated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8746
|
+
className: config_manager_module_css_default.statRow,
|
|
8747
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8748
|
+
kind: "ok",
|
|
8749
|
+
children: t("myconfigs.upload.validateOk")
|
|
8750
|
+
})
|
|
8751
|
+
}),
|
|
8752
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Field, {
|
|
8753
|
+
label: t("myconfigs.upload.form.name"),
|
|
8754
|
+
hint: t("myconfigs.upload.form.nameHint"),
|
|
8755
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8756
|
+
className: config_manager_module_css_default.input,
|
|
8757
|
+
value: wizard.form.name,
|
|
8758
|
+
onChange: (e) => {
|
|
8759
|
+
onFormField("name", e.target.value);
|
|
8760
|
+
}
|
|
8761
|
+
}), wizard.formErrors.name !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8762
|
+
className: config_manager_module_css_default.formError,
|
|
8763
|
+
children: redact(wizard.formErrors.name)
|
|
8764
|
+
})]
|
|
8765
|
+
}),
|
|
8766
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
8767
|
+
label: t("myconfigs.upload.form.description"),
|
|
8768
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
8769
|
+
className: config_manager_module_css_default.input,
|
|
8770
|
+
value: wizard.form.description,
|
|
8771
|
+
onChange: (e) => {
|
|
8772
|
+
onFormField("description", e.target.value);
|
|
8773
|
+
}
|
|
8774
|
+
})
|
|
8775
|
+
}),
|
|
8776
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
8777
|
+
label: t("myconfigs.upload.form.categories"),
|
|
8778
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8779
|
+
className: config_manager_module_css_default.input,
|
|
8780
|
+
value: wizard.form.categories,
|
|
8781
|
+
onChange: (e) => {
|
|
8782
|
+
onFormField("categories", e.target.value);
|
|
8783
|
+
}
|
|
8784
|
+
})
|
|
8785
|
+
}),
|
|
8786
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8787
|
+
className: config_manager_module_css_default.hint,
|
|
8788
|
+
children: t("myconfigs.upload.form.autoHint")
|
|
8789
|
+
}),
|
|
8790
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8791
|
+
className: config_manager_module_css_default.statRow,
|
|
8792
|
+
children: autoBadges.map((b) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Badge, {
|
|
8793
|
+
kind: "info",
|
|
8794
|
+
children: [
|
|
8795
|
+
b.label,
|
|
8796
|
+
":",
|
|
8797
|
+
b.autoText
|
|
8798
|
+
]
|
|
8799
|
+
}, b.field))
|
|
8800
|
+
}),
|
|
8801
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8802
|
+
className: config_manager_module_css_default.actionRow,
|
|
8803
|
+
children: [
|
|
8804
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8805
|
+
variant: "primary",
|
|
8806
|
+
disabled: wizard.validated !== true || wizard.running || wizard.zipPath === null || !myConfigFormValid(wizard.formErrors),
|
|
8807
|
+
onClick: () => {
|
|
8808
|
+
runUpload();
|
|
8809
|
+
},
|
|
8810
|
+
children: wizard.running ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: wizard.mode === "update" ? t("myconfigs.update.running") : t("myconfigs.upload.running") }) : wizard.mode === "update" ? t("myconfigs.update.run") : t("myconfigs.upload.run")
|
|
8811
|
+
}),
|
|
8812
|
+
wizard.mode === "update" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8813
|
+
disabled: wizard.running || wizard.validating,
|
|
8814
|
+
onClick: cancelUpdate,
|
|
8815
|
+
children: t("common.cancel")
|
|
8816
|
+
}),
|
|
8817
|
+
wizard.mode === "upload" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8818
|
+
disabled: wizard.running,
|
|
8819
|
+
onClick: reset,
|
|
8820
|
+
children: t("myconfigs.upload.reselect")
|
|
8821
|
+
})
|
|
8822
|
+
]
|
|
8823
|
+
})
|
|
8824
|
+
] }),
|
|
8825
|
+
wizard.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8826
|
+
kind: "error",
|
|
8827
|
+
children: redact(wizard.error)
|
|
8245
8828
|
}),
|
|
8246
|
-
wizard.result
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8829
|
+
wizard.result !== null && (wizard.result.ok ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8830
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8831
|
+
className: config_manager_module_css_default.groupLabel,
|
|
8832
|
+
children: t("myconfigs.result.title")
|
|
8833
|
+
}),
|
|
8834
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8835
|
+
className: config_manager_module_css_default.statRow,
|
|
8836
|
+
children: [
|
|
8837
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8838
|
+
kind: "ok",
|
|
8839
|
+
children: t("myconfigs.result.version", { version: wizard.result.version })
|
|
8840
|
+
}),
|
|
8841
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8842
|
+
kind: "info",
|
|
8843
|
+
children: t("myconfigs.result.sha256", { hash: wizard.result.sha256 })
|
|
8844
|
+
}),
|
|
8845
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8846
|
+
kind: "info",
|
|
8847
|
+
children: t("myconfigs.result.sections", { sections: wizard.result.sections.join(", ") })
|
|
8848
|
+
})
|
|
8849
|
+
]
|
|
8850
|
+
}),
|
|
8851
|
+
wizard.result.listing === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8852
|
+
className: config_manager_module_css_default.statRow,
|
|
8853
|
+
children: listingStatus !== null && listingStatus.listing === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8854
|
+
kind: "error",
|
|
8855
|
+
children: t("myconfigs.result.listingFailed")
|
|
8856
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8857
|
+
variant: "danger",
|
|
8858
|
+
onClick: () => {
|
|
8859
|
+
runRelist(wizard.result.itemId);
|
|
8860
|
+
},
|
|
8861
|
+
children: t("myconfigs.result.relist")
|
|
8862
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8863
|
+
kind: "info",
|
|
8864
|
+
children: t("myconfigs.result.listingPending")
|
|
8865
|
+
})
|
|
8866
|
+
}),
|
|
8867
|
+
listingStatus !== null && listingStatus.listing === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8868
|
+
kind: "error",
|
|
8869
|
+
children: redact(listingStatus.error ?? t("common.unknownError"))
|
|
8870
|
+
}),
|
|
8871
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8872
|
+
className: config_manager_module_css_default.actionRow,
|
|
8873
|
+
children: [
|
|
8874
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8875
|
+
kind: "info",
|
|
8876
|
+
children: t("myconfigs.result.repo")
|
|
8877
|
+
}),
|
|
8878
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8879
|
+
href: wizard.result.repoUrl,
|
|
8880
|
+
children: t("myconfigs.result.openRepo")
|
|
8881
|
+
}),
|
|
8882
|
+
prLink !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8883
|
+
href: prLink.url,
|
|
8884
|
+
children: prLink.label
|
|
8885
|
+
})
|
|
8886
|
+
]
|
|
8887
|
+
})
|
|
8888
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8889
|
+
kind: "error",
|
|
8890
|
+
children: redact(wizard.result.error ?? ((wizard.result.warnings ?? []).join(" · ") || t("common.unknownError")))
|
|
8891
|
+
}))
|
|
8250
8892
|
]
|
|
8251
|
-
})
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
children: redact(wizard.result.error ?? ((wizard.result.warnings ?? []).join(" · ") || t("common.unknownError")))
|
|
8255
|
-
}))
|
|
8256
|
-
] });
|
|
8893
|
+
})]
|
|
8894
|
+
})
|
|
8895
|
+
});
|
|
8257
8896
|
};
|
|
8258
8897
|
/** 已上传列表(条目卡片 + 状态徽章 + 行操作) */
|
|
8259
8898
|
const renderList = () => {
|
|
@@ -8338,13 +8977,14 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
8338
8977
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8339
8978
|
onClick: () => {
|
|
8340
8979
|
startUpdate(entry);
|
|
8980
|
+
openUpload();
|
|
8341
8981
|
},
|
|
8342
8982
|
children: t("myconfigs.item.update")
|
|
8343
8983
|
}),
|
|
8344
8984
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8345
8985
|
disabled: install !== null && install.itemId === view.id && install.detail === null,
|
|
8346
8986
|
onClick: () => {
|
|
8347
|
-
|
|
8987
|
+
openInstall(entry);
|
|
8348
8988
|
},
|
|
8349
8989
|
children: t("myconfigs.item.install")
|
|
8350
8990
|
}),
|
|
@@ -8355,6 +8995,14 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
8355
8995
|
badge.kind === "warn" && badge.prUrl !== void 0 && badge.prUrl !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8356
8996
|
href: badge.prUrl,
|
|
8357
8997
|
children: t("myconfigs.item.openPr")
|
|
8998
|
+
}),
|
|
8999
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9000
|
+
variant: "danger",
|
|
9001
|
+
disabled: deletingId !== null,
|
|
9002
|
+
onClick: () => {
|
|
9003
|
+
onMyConfirmDeleteChange(view.id);
|
|
9004
|
+
},
|
|
9005
|
+
children: t("myconfigs.delete.run")
|
|
8358
9006
|
})
|
|
8359
9007
|
]
|
|
8360
9008
|
})]
|
|
@@ -8369,114 +9017,127 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
8369
9017
|
const approvalList = detail !== null ? approvalRows(detail.plan, install.approvals) : [];
|
|
8370
9018
|
const approvalSummary = detail !== null ? approvedAdapterSummary(detail.plan, install.approvals) : null;
|
|
8371
9019
|
const detailView = detail !== null ? marketDetailView(detail, detail.repo ?? entryRepoUrl(install.itemId), true, uiT) : null;
|
|
8372
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8399
|
-
kind: "warn",
|
|
8400
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("detail.needReview") })
|
|
8401
|
-
}),
|
|
8402
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8403
|
-
className: config_manager_module_css_default.statRow,
|
|
8404
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8405
|
-
kind: detailView.badge.valid ? "ok" : "error",
|
|
8406
|
-
children: detailView.badge.statusText
|
|
8407
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8408
|
-
kind: "info",
|
|
8409
|
-
children: detailView.badge.sectionsText
|
|
9020
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9021
|
+
className: config_manager_module_css_default.dialogMask,
|
|
9022
|
+
onMouseDown: (e) => {
|
|
9023
|
+
if (e.target === e.currentTarget && !install.importing) closeInstall();
|
|
9024
|
+
},
|
|
9025
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9026
|
+
className: `${config_manager_module_css_default.dialogCard} ${config_manager_module_css_default.dialogWide}`,
|
|
9027
|
+
role: "dialog",
|
|
9028
|
+
"aria-modal": "true",
|
|
9029
|
+
"aria-label": t("detail.title"),
|
|
9030
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9031
|
+
className: config_manager_module_css_default.dialogHeaderRow,
|
|
9032
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9033
|
+
className: config_manager_module_css_default.dialogHeader,
|
|
9034
|
+
children: [
|
|
9035
|
+
t("detail.title"),
|
|
9036
|
+
":",
|
|
9037
|
+
install.itemId
|
|
9038
|
+
]
|
|
9039
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9040
|
+
type: "button",
|
|
9041
|
+
className: config_manager_module_css_default.dialogClose,
|
|
9042
|
+
"aria-label": t("common.close"),
|
|
9043
|
+
disabled: install.importing,
|
|
9044
|
+
onClick: closeInstall,
|
|
9045
|
+
children: "×"
|
|
8410
9046
|
})]
|
|
8411
|
-
}),
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
}
|
|
8433
|
-
|
|
8434
|
-
|
|
9047
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9048
|
+
className: config_manager_module_css_default.dialogBodyScroll,
|
|
9049
|
+
children: [
|
|
9050
|
+
install.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9051
|
+
kind: "error",
|
|
9052
|
+
children: redact(install.error)
|
|
9053
|
+
}),
|
|
9054
|
+
detail === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9055
|
+
className: config_manager_module_css_default.statRow,
|
|
9056
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("list.loading") })
|
|
9057
|
+
}),
|
|
9058
|
+
detail !== null && detailView !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
9059
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9060
|
+
kind: "warn",
|
|
9061
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("detail.needReview") })
|
|
9062
|
+
}),
|
|
9063
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9064
|
+
className: config_manager_module_css_default.statRow,
|
|
9065
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9066
|
+
kind: detailView.badge.valid ? "ok" : "error",
|
|
9067
|
+
children: detailView.badge.statusText
|
|
9068
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9069
|
+
kind: "info",
|
|
9070
|
+
children: detailView.badge.sectionsText
|
|
9071
|
+
})]
|
|
9072
|
+
}),
|
|
9073
|
+
approvalList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8435
9074
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8436
|
-
className: config_manager_module_css_default.
|
|
8437
|
-
children:
|
|
9075
|
+
className: config_manager_module_css_default.groupLabel,
|
|
9076
|
+
children: t("detail.approval.title")
|
|
8438
9077
|
}),
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
children: row.highRisk ? t("detail.approval.requiresApproval") : t("detail.approval.safe")
|
|
9078
|
+
approvalSummary !== null && approvalSummary.highRiskTotal > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9079
|
+
kind: "warn",
|
|
9080
|
+
children: t("detail.approval.highRiskHint")
|
|
8443
9081
|
}),
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
9082
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9083
|
+
className: config_manager_module_css_default.conflictList,
|
|
9084
|
+
children: approvalList.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Checkbox, {
|
|
9085
|
+
checked: row.approved,
|
|
9086
|
+
onChange: (checked) => {
|
|
9087
|
+
if (installRef.current !== null) patchInstall({ approvals: {
|
|
9088
|
+
...installRef.current.approvals,
|
|
9089
|
+
[row.adapter]: checked
|
|
9090
|
+
} });
|
|
9091
|
+
},
|
|
9092
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
9093
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9094
|
+
className: config_manager_module_css_default.conflictId,
|
|
9095
|
+
children: row.adapter
|
|
9096
|
+
}),
|
|
9097
|
+
" ",
|
|
9098
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9099
|
+
kind: row.highRisk ? "warn" : "info",
|
|
9100
|
+
children: row.highRisk ? t("detail.approval.requiresApproval") : t("detail.approval.safe")
|
|
9101
|
+
}),
|
|
9102
|
+
" ",
|
|
9103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9104
|
+
kind: "info",
|
|
9105
|
+
children: row.label
|
|
9106
|
+
})
|
|
9107
|
+
] })
|
|
9108
|
+
}, row.adapter))
|
|
9109
|
+
}),
|
|
9110
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9111
|
+
className: config_manager_module_css_default.statRow,
|
|
9112
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9113
|
+
kind: approvalSummary !== null && approvalSummary.canImport ? "ok" : "warn",
|
|
9114
|
+
children: approvalSummary !== null ? t("detail.approval.count", {
|
|
9115
|
+
selected: String(approvalSummary.selected),
|
|
9116
|
+
total: String(approvalSummary.total)
|
|
9117
|
+
}) : ""
|
|
9118
|
+
})
|
|
8448
9119
|
})
|
|
8449
|
-
] })
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
9120
|
+
] }),
|
|
9121
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9122
|
+
className: config_manager_module_css_default.actionRow,
|
|
9123
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9124
|
+
variant: "primary",
|
|
9125
|
+
disabled: install.importing || approvalSummary !== null && !approvalSummary.canImport,
|
|
9126
|
+
onClick: () => {
|
|
9127
|
+
runImport();
|
|
9128
|
+
},
|
|
9129
|
+
children: install.importing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") }) : t("detail.import")
|
|
9130
|
+
})
|
|
9131
|
+
})
|
|
9132
|
+
] }),
|
|
9133
|
+
install.importResult !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Banner, {
|
|
9134
|
+
kind: install.importResult.ok ? "ok" : "error",
|
|
9135
|
+
children: [install.importResult.ok ? `导入完成:${install.importResult.executed.filter((e) => e.status === "ok").length} 项写入` : `导入失败(${install.importResult.executed.filter((e) => e.status === "failed").length} 项失败)`, install.importResult.needsRestart && " · 部分改动需重启 DSH 后生效"]
|
|
8460
9136
|
})
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8464
|
-
className: config_manager_module_css_default.actionRow,
|
|
8465
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8466
|
-
variant: "primary",
|
|
8467
|
-
disabled: install.importing || approvalSummary !== null && !approvalSummary.canImport,
|
|
8468
|
-
onClick: () => {
|
|
8469
|
-
runImport();
|
|
8470
|
-
},
|
|
8471
|
-
children: install.importing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") }) : t("detail.import")
|
|
8472
|
-
})
|
|
8473
|
-
})
|
|
8474
|
-
] }),
|
|
8475
|
-
install.importResult !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Banner, {
|
|
8476
|
-
kind: install.importResult.ok ? "ok" : "error",
|
|
8477
|
-
children: [install.importResult.ok ? `导入完成:${install.importResult.executed.filter((e) => e.status === "ok").length} 项写入` : `导入失败(${install.importResult.executed.filter((e) => e.status === "failed").length} 项失败)`, install.importResult.needsRestart && " · 部分改动需重启 DSH 后生效"]
|
|
9137
|
+
]
|
|
9138
|
+
})]
|
|
8478
9139
|
})
|
|
8479
|
-
|
|
9140
|
+
});
|
|
8480
9141
|
};
|
|
8481
9142
|
/** 装回本地详情展示用的仓库 URL(供应链警示来源行;取条目 repoUrl 兜底固定目标仓库) */
|
|
8482
9143
|
function entryRepoUrl(itemId) {
|
|
@@ -8485,23 +9146,65 @@ function MyConfigsView({ meApi, api, importApi, syncApi, t, myItems, myItemsErro
|
|
|
8485
9146
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8486
9147
|
className: config_manager_module_css_default.viewBody,
|
|
8487
9148
|
children: [
|
|
8488
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8489
|
-
className: config_manager_module_css_default.actionRow,
|
|
8490
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8491
|
-
onClick: onBack,
|
|
8492
|
-
children: t("myconfigs.back")
|
|
8493
|
-
})
|
|
8494
|
-
}),
|
|
8495
9149
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionTitle, {
|
|
8496
9150
|
title: t("myconfigs.tab.myconfigs"),
|
|
8497
9151
|
subtitle: t("myconfigs.login.hint")
|
|
8498
9152
|
}),
|
|
8499
9153
|
renderLoginCard(),
|
|
8500
9154
|
loginView.kind === "logged-in" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8501
|
-
|
|
9155
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9156
|
+
className: config_manager_module_css_default.actionRow,
|
|
9157
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9158
|
+
className: config_manager_module_css_default.groupLabel,
|
|
9159
|
+
children: t("myconfigs.upload.title")
|
|
9160
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9161
|
+
variant: "primary",
|
|
9162
|
+
onClick: openUpload,
|
|
9163
|
+
children: t("myconfigs.upload.run")
|
|
9164
|
+
})]
|
|
9165
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9166
|
+
className: config_manager_module_css_default.hint,
|
|
9167
|
+
children: t("myconfigs.upload.selectHint")
|
|
9168
|
+
})] }),
|
|
8502
9169
|
renderList(),
|
|
8503
|
-
|
|
8504
|
-
|
|
9170
|
+
uploadOpen && renderWizard(),
|
|
9171
|
+
installOpen && renderInstall()
|
|
9172
|
+
] }),
|
|
9173
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmDialog, {
|
|
9174
|
+
open: disclaimerKey !== null,
|
|
9175
|
+
title: t("disclaimer.title"),
|
|
9176
|
+
message: disclaimerText(),
|
|
9177
|
+
confirmLabel: t("disclaimer.confirm"),
|
|
9178
|
+
cancelLabel: t("common.cancel"),
|
|
9179
|
+
onConfirm: confirmDisclaimer,
|
|
9180
|
+
onCancel: cancelDisclaimer,
|
|
9181
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9182
|
+
className: config_manager_module_css_default.checkboxRow,
|
|
9183
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9184
|
+
type: "checkbox",
|
|
9185
|
+
checked: dontAsk,
|
|
9186
|
+
onChange: (e) => {
|
|
9187
|
+
setDontAsk(e.target.checked);
|
|
9188
|
+
}
|
|
9189
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("disclaimer.dontAsk") })]
|
|
9190
|
+
})
|
|
9191
|
+
}),
|
|
9192
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmDialog, {
|
|
9193
|
+
open: confirmDeleteId !== null,
|
|
9194
|
+
title: t("myconfigs.delete.confirmTitle"),
|
|
9195
|
+
message: t("myconfigs.delete.confirmText"),
|
|
9196
|
+
confirmLabel: t("myconfigs.delete.confirm"),
|
|
9197
|
+
cancelLabel: t("common.cancel"),
|
|
9198
|
+
danger: true,
|
|
9199
|
+
busy: deletingId !== null,
|
|
9200
|
+
onConfirm: async () => {
|
|
9201
|
+
const entry = (myItems ?? []).find((it) => it.id === confirmDeleteId);
|
|
9202
|
+
if (entry !== void 0) await runDelete(entry);
|
|
9203
|
+
},
|
|
9204
|
+
onCancel: () => {
|
|
9205
|
+
onMyConfirmDeleteChange(null);
|
|
9206
|
+
}
|
|
9207
|
+
})
|
|
8505
9208
|
]
|
|
8506
9209
|
});
|
|
8507
9210
|
}
|
|
@@ -8531,9 +9234,11 @@ const initial$1 = {
|
|
|
8531
9234
|
subView: "browse",
|
|
8532
9235
|
myItems: null,
|
|
8533
9236
|
myItemsError: null,
|
|
9237
|
+
myWizard: null,
|
|
9238
|
+
myInstall: null,
|
|
9239
|
+
myConfirmDeleteId: null,
|
|
8534
9240
|
loading: true,
|
|
8535
9241
|
loadError: null,
|
|
8536
|
-
market: null,
|
|
8537
9242
|
refreshing: false,
|
|
8538
9243
|
browsing: false,
|
|
8539
9244
|
items: [],
|
|
@@ -8558,6 +9263,9 @@ function initFromStore() {
|
|
|
8558
9263
|
subView: s.subView,
|
|
8559
9264
|
myItems: s.myItems,
|
|
8560
9265
|
myItemsError: s.myItemsError,
|
|
9266
|
+
myWizard: s.myWizard,
|
|
9267
|
+
myInstall: s.myInstall,
|
|
9268
|
+
myConfirmDeleteId: s.myConfirmDeleteId,
|
|
8561
9269
|
search: s.search,
|
|
8562
9270
|
category: s.category,
|
|
8563
9271
|
items: s.items,
|
|
@@ -8589,15 +9297,54 @@ function MarketPanel({ api, myConfigsApi, importApi, syncApi, t }) {
|
|
|
8589
9297
|
...stateRef.current,
|
|
8590
9298
|
...p
|
|
8591
9299
|
});
|
|
9300
|
+
/** 下载详情弹窗开关(瞬态 UI,不持久化) */
|
|
9301
|
+
const [downloadOpen, setDownloadOpen] = (0, react.useState)(false);
|
|
9302
|
+
/** 当前展示的免责弹窗操作(null = 无) */
|
|
9303
|
+
const [disclaimerKey, setDisclaimerKey] = (0, react.useState)(null);
|
|
9304
|
+
/** 免责弹窗「不再提示」勾选(每次打开重置) */
|
|
9305
|
+
const [dontAsk, setDontAsk] = (0, react.useState)(false);
|
|
9306
|
+
/** localStorage(浏览器环境;免责「不再提示」跨会话持久化) */
|
|
9307
|
+
const storage = window.localStorage;
|
|
9308
|
+
/** 待下载条目(免责确认后取用;避免免责流程中闭包过期) */
|
|
9309
|
+
const pendingDownloadItem = (0, react.useRef)(null);
|
|
9310
|
+
/** 点条目「查看详情」:未勾「不再提示」→ 先弹免责,确认后下载并打开详情弹窗 */
|
|
9311
|
+
const openDownload = (item) => {
|
|
9312
|
+
pendingDownloadItem.current = item;
|
|
9313
|
+
if (readDisclaimerDismissed("download", storage)) {
|
|
9314
|
+
setDownloadOpen(true);
|
|
9315
|
+
runDownload(item);
|
|
9316
|
+
return;
|
|
9317
|
+
}
|
|
9318
|
+
setDontAsk(false);
|
|
9319
|
+
setDisclaimerKey("download");
|
|
9320
|
+
};
|
|
9321
|
+
/** 免责弹窗确认:勾选则记录「不再提示」→ 关闭免责 → 打开下载详情弹窗并启动下载 */
|
|
9322
|
+
const confirmDownloadDisclaimer = () => {
|
|
9323
|
+
if (disclaimerKey !== "download") return;
|
|
9324
|
+
if (dontAsk) writeDisclaimerDismissed("download", storage);
|
|
9325
|
+
setDisclaimerKey(null);
|
|
9326
|
+
const item = pendingDownloadItem.current;
|
|
9327
|
+
setDownloadOpen(true);
|
|
9328
|
+
if (item !== null) runDownload(item);
|
|
9329
|
+
};
|
|
9330
|
+
/** 关闭下载详情弹窗:清 detail(弹窗即会话,关闭即放弃) */
|
|
9331
|
+
const closeDownload = () => {
|
|
9332
|
+
setDownloadOpen(false);
|
|
9333
|
+
patch({
|
|
9334
|
+
detail: null,
|
|
9335
|
+
importResult: null,
|
|
9336
|
+
error: null,
|
|
9337
|
+
approvals: {}
|
|
9338
|
+
});
|
|
9339
|
+
};
|
|
8592
9340
|
/** 卸载时置挂载守卫 + 最后镜像一次(防止「最后一次改动后立即切 tab」时丢状态)。 */
|
|
8593
9341
|
(0, react.useEffect)(() => () => {
|
|
8594
9342
|
mountedRef.current = false;
|
|
8595
9343
|
runStore.patch({ market: toMarketStoreSlice(stateRef.current) });
|
|
8596
9344
|
}, []);
|
|
8597
|
-
/** 内置市场 URL(单一权威;来自 Host
|
|
9345
|
+
/** 内置市场 URL(单一权威;来自 Host 内置常量;用于条目来源判定与详情供应链警示) */
|
|
8598
9346
|
const marketUrl = BUILTIN_MARKET_URL;
|
|
8599
|
-
|
|
8600
|
-
/** 挂载时读取内置市场状态 */
|
|
9347
|
+
/** 挂载时读取内置市场状态;返回响应供「首次打开自动更新」判据(bootAutoRefreshed) */
|
|
8601
9348
|
const loadStatus = (0, react.useCallback)(async () => {
|
|
8602
9349
|
patch({
|
|
8603
9350
|
loading: true,
|
|
@@ -8605,19 +9352,30 @@ function MarketPanel({ api, myConfigsApi, importApi, syncApi, t }) {
|
|
|
8605
9352
|
});
|
|
8606
9353
|
try {
|
|
8607
9354
|
const info = await api.status();
|
|
8608
|
-
patch({
|
|
8609
|
-
|
|
8610
|
-
market: info.markets[0] ?? null
|
|
8611
|
-
});
|
|
9355
|
+
patch({ loading: false });
|
|
9356
|
+
return info;
|
|
8612
9357
|
} catch (err) {
|
|
8613
9358
|
patch({
|
|
8614
9359
|
loading: false,
|
|
8615
9360
|
loadError: err instanceof Error ? err.message : String(err)
|
|
8616
9361
|
});
|
|
9362
|
+
return null;
|
|
8617
9363
|
}
|
|
8618
9364
|
}, [api]);
|
|
9365
|
+
/**
|
|
9366
|
+
* 启动后首次打开市场页 → 自动拉取一次最新 index(需求:dsh 启动后第一次打开市场页面自动更新一次市场)。
|
|
9367
|
+
* 判据是 Host 侧进程内存标记 bootAutoRefreshed(dsh 重启后归零;refresh 成功后置位),
|
|
9368
|
+
* 因此「每次打开都刷新」/「刷新失败后下次打开重试」都自然成立;无需客户端持久化。
|
|
9369
|
+
* bootAutoChecked 同步置位防 StrictMode 双执行/竞态重复触发(同一组件实例只自动刷一次)。
|
|
9370
|
+
*/
|
|
9371
|
+
const bootAutoChecked = (0, react.useRef)(false);
|
|
8619
9372
|
(0, react.useEffect)(() => {
|
|
8620
|
-
|
|
9373
|
+
if (bootAutoChecked.current) return;
|
|
9374
|
+
bootAutoChecked.current = true;
|
|
9375
|
+
(async () => {
|
|
9376
|
+
const info = await loadStatus();
|
|
9377
|
+
if (info !== null && info.bootAutoRefreshed !== true) await runRefresh();
|
|
9378
|
+
})();
|
|
8621
9379
|
}, []);
|
|
8622
9380
|
/** 拉取内置市场最新 index.json → 重新浏览(缓存状态由 Host 合并) */
|
|
8623
9381
|
const runRefresh = async () => {
|
|
@@ -8714,7 +9472,6 @@ function MarketPanel({ api, myConfigsApi, importApi, syncApi, t }) {
|
|
|
8714
9472
|
});
|
|
8715
9473
|
}
|
|
8716
9474
|
};
|
|
8717
|
-
const statusText = marketStatusText({ count: 1 }, uiT);
|
|
8718
9475
|
const filtered = filterMarketItems(state.items, state.search, state.category);
|
|
8719
9476
|
const summary = marketListSummary(state.items, uiT);
|
|
8720
9477
|
const categories = collectCategories(state.items);
|
|
@@ -8766,210 +9523,203 @@ function MarketPanel({ api, myConfigsApi, importApi, syncApi, t }) {
|
|
|
8766
9523
|
myItemsError: error
|
|
8767
9524
|
});
|
|
8768
9525
|
},
|
|
8769
|
-
|
|
8770
|
-
|
|
9526
|
+
myWizard: state.myWizard,
|
|
9527
|
+
onMyWizardChange: (wizard) => {
|
|
9528
|
+
patch({ myWizard: wizard });
|
|
9529
|
+
},
|
|
9530
|
+
myInstall: state.myInstall,
|
|
9531
|
+
onMyInstallChange: (install) => {
|
|
9532
|
+
patch({ myInstall: install });
|
|
9533
|
+
},
|
|
9534
|
+
myConfirmDeleteId: state.myConfirmDeleteId,
|
|
9535
|
+
onMyConfirmDeleteChange: (id) => {
|
|
9536
|
+
patch({ myConfirmDeleteId: id });
|
|
8771
9537
|
}
|
|
8772
9538
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8773
9539
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionTitle, {
|
|
8774
9540
|
title: t("section.label"),
|
|
8775
9541
|
subtitle: t("section.description")
|
|
8776
9542
|
}),
|
|
8777
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
}),
|
|
8798
|
-
!official && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8799
|
-
kind: "warn",
|
|
8800
|
-
children: t("config.custom")
|
|
8801
|
-
})
|
|
8802
|
-
]
|
|
8803
|
-
}),
|
|
8804
|
-
state.market !== null && (state.market.name || state.market.itemCount !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8805
|
-
className: config_manager_module_css_default.statRow,
|
|
8806
|
-
children: [state.market.name !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8807
|
-
kind: "info",
|
|
8808
|
-
children: state.market.name
|
|
8809
|
-
}), state.market.itemCount !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8810
|
-
kind: "info",
|
|
8811
|
-
children: t("list.count", { count: String(state.market.itemCount) })
|
|
8812
|
-
})]
|
|
8813
|
-
}),
|
|
8814
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8815
|
-
className: config_manager_module_css_default.actionRow,
|
|
8816
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8817
|
-
variant: "primary",
|
|
8818
|
-
disabled: state.refreshing || state.importing,
|
|
8819
|
-
onClick: () => {
|
|
8820
|
-
runRefresh();
|
|
8821
|
-
},
|
|
8822
|
-
children: state.refreshing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("config.refreshing") }) : t("config.refresh")
|
|
8823
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8824
|
-
disabled: state.browsing,
|
|
8825
|
-
onClick: () => {
|
|
8826
|
-
runBrowse();
|
|
8827
|
-
},
|
|
8828
|
-
children: state.browsing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("list.loading") }) : t("list.browse")
|
|
8829
|
-
})]
|
|
8830
|
-
}),
|
|
8831
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8832
|
-
className: config_manager_module_css_default.statRow,
|
|
8833
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8834
|
-
kind: state.loadError !== null ? "error" : "ok",
|
|
8835
|
-
children: statusText
|
|
8836
|
-
})
|
|
8837
|
-
})
|
|
8838
|
-
] }),
|
|
9543
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9544
|
+
className: config_manager_module_css_default.groupLabel,
|
|
9545
|
+
children: t("config.title")
|
|
9546
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9547
|
+
className: config_manager_module_css_default.actionRow,
|
|
9548
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9549
|
+
variant: "primary",
|
|
9550
|
+
disabled: state.refreshing || state.importing,
|
|
9551
|
+
onClick: () => {
|
|
9552
|
+
runRefresh();
|
|
9553
|
+
},
|
|
9554
|
+
children: state.refreshing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("config.refreshing") }) : t("config.refresh")
|
|
9555
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9556
|
+
disabled: state.browsing,
|
|
9557
|
+
onClick: () => {
|
|
9558
|
+
runBrowse();
|
|
9559
|
+
},
|
|
9560
|
+
children: state.browsing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("list.loading") }) : t("list.browse")
|
|
9561
|
+
})]
|
|
9562
|
+
})] }),
|
|
8839
9563
|
state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8840
9564
|
kind: "error",
|
|
8841
9565
|
children: state.error
|
|
8842
9566
|
}),
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
9567
|
+
downloadOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9568
|
+
className: config_manager_module_css_default.dialogMask,
|
|
9569
|
+
onMouseDown: (e) => {
|
|
9570
|
+
if (e.target === e.currentTarget && !state.importing) closeDownload();
|
|
9571
|
+
},
|
|
9572
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9573
|
+
className: `${config_manager_module_css_default.dialogCard} ${config_manager_module_css_default.dialogWide}`,
|
|
9574
|
+
role: "dialog",
|
|
9575
|
+
"aria-modal": "true",
|
|
9576
|
+
"aria-label": t("detail.title"),
|
|
9577
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9578
|
+
className: config_manager_module_css_default.dialogHeaderRow,
|
|
9579
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9580
|
+
className: config_manager_module_css_default.dialogHeader,
|
|
9581
|
+
children: [
|
|
9582
|
+
t("detail.title"),
|
|
9583
|
+
":",
|
|
9584
|
+
state.detail !== null ? state.detail.name : state.downloadingId ?? ""
|
|
9585
|
+
]
|
|
9586
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9587
|
+
type: "button",
|
|
9588
|
+
className: config_manager_module_css_default.dialogClose,
|
|
9589
|
+
"aria-label": t("common.close"),
|
|
9590
|
+
disabled: state.importing,
|
|
9591
|
+
onClick: closeDownload,
|
|
9592
|
+
children: "×"
|
|
9593
|
+
})]
|
|
9594
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9595
|
+
className: config_manager_module_css_default.dialogBodyScroll,
|
|
8848
9596
|
children: [
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
kind: "warn",
|
|
8862
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("detail.needReview") })
|
|
8863
|
-
}),
|
|
8864
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8865
|
-
className: config_manager_module_css_default.warnList,
|
|
8866
|
-
children: detailView.warnings.map((w, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
8867
|
-
style: { color: w.kind === "warn" ? "var(--dsw-alias-state-warn-primary)" : void 0 },
|
|
8868
|
-
children: w.text
|
|
8869
|
-
}, i))
|
|
8870
|
-
}),
|
|
8871
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8872
|
-
className: config_manager_module_css_default.statRow,
|
|
8873
|
-
children: [
|
|
8874
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8875
|
-
kind: detailView.badge.statusKind === "ok" ? "ok" : "error",
|
|
8876
|
-
children: detailView.badge.statusText
|
|
8877
|
-
}),
|
|
8878
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8879
|
-
kind: "info",
|
|
8880
|
-
children: detailView.badge.sectionsText
|
|
8881
|
-
}),
|
|
8882
|
-
state.detail.version !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8883
|
-
kind: "info",
|
|
8884
|
-
children: t("detail.version", { version: state.detail.version })
|
|
8885
|
-
})
|
|
8886
|
-
]
|
|
8887
|
-
}),
|
|
8888
|
-
detailView.errors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8889
|
-
className: config_manager_module_css_default.fieldLabel,
|
|
8890
|
-
children: t("detail.errors")
|
|
8891
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8892
|
-
className: config_manager_module_css_default.reportScroll,
|
|
8893
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
8894
|
-
className: config_manager_module_css_default.warnList,
|
|
8895
|
-
children: detailView.errors.map((e, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: e }, i))
|
|
8896
|
-
})
|
|
8897
|
-
})] }),
|
|
8898
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8899
|
-
kind: "info",
|
|
8900
|
-
children: t("detail.previewHint")
|
|
8901
|
-
}),
|
|
8902
|
-
detailView.canImport && approvalList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
8903
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8904
|
-
className: config_manager_module_css_default.groupLabel,
|
|
8905
|
-
children: t("detail.approval.title")
|
|
8906
|
-
}),
|
|
8907
|
-
approvalSummary !== null && approvalSummary.highRiskTotal > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8908
|
-
kind: "warn",
|
|
8909
|
-
children: t("detail.approval.highRiskHint")
|
|
8910
|
-
}),
|
|
8911
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8912
|
-
className: config_manager_module_css_default.conflictList,
|
|
8913
|
-
children: approvalList.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
8914
|
-
className: config_manager_module_css_default.checkboxRow,
|
|
8915
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8916
|
-
type: "checkbox",
|
|
8917
|
-
checked: row.approved,
|
|
8918
|
-
onChange: (e) => {
|
|
8919
|
-
patch({ approvals: {
|
|
8920
|
-
...state.approvals,
|
|
8921
|
-
[row.adapter]: e.target.checked
|
|
8922
|
-
} });
|
|
8923
|
-
}
|
|
8924
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
8925
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8926
|
-
className: config_manager_module_css_default.conflictId,
|
|
8927
|
-
children: row.adapter
|
|
9597
|
+
state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9598
|
+
kind: "error",
|
|
9599
|
+
children: redact(state.error)
|
|
9600
|
+
}),
|
|
9601
|
+
state.detail === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9602
|
+
className: config_manager_module_css_default.statRow,
|
|
9603
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") })
|
|
9604
|
+
}),
|
|
9605
|
+
state.detail !== null && detailView !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9606
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9607
|
+
kind: "warn",
|
|
9608
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("detail.needReview") })
|
|
8928
9609
|
}),
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
9610
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9611
|
+
className: config_manager_module_css_default.warnList,
|
|
9612
|
+
children: detailView.warnings.map((w, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
9613
|
+
style: { color: w.kind === "warn" ? "var(--dsw-alias-state-warn-primary)" : void 0 },
|
|
9614
|
+
children: w.text
|
|
9615
|
+
}, i))
|
|
8933
9616
|
}),
|
|
8934
|
-
|
|
8935
|
-
|
|
9617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9618
|
+
className: config_manager_module_css_default.statRow,
|
|
9619
|
+
children: [
|
|
9620
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9621
|
+
kind: detailView.badge.statusKind === "ok" ? "ok" : "error",
|
|
9622
|
+
children: detailView.badge.statusText
|
|
9623
|
+
}),
|
|
9624
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9625
|
+
kind: "info",
|
|
9626
|
+
children: detailView.badge.sectionsText
|
|
9627
|
+
}),
|
|
9628
|
+
state.detail.version !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9629
|
+
kind: "info",
|
|
9630
|
+
children: t("detail.version", { version: state.detail.version })
|
|
9631
|
+
})
|
|
9632
|
+
]
|
|
9633
|
+
}),
|
|
9634
|
+
detailView.errors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9635
|
+
className: config_manager_module_css_default.fieldLabel,
|
|
9636
|
+
children: t("detail.errors")
|
|
9637
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9638
|
+
className: config_manager_module_css_default.reportScroll,
|
|
9639
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
9640
|
+
className: config_manager_module_css_default.warnList,
|
|
9641
|
+
children: detailView.errors.map((e, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: e }, i))
|
|
9642
|
+
})
|
|
9643
|
+
})] }),
|
|
9644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8936
9645
|
kind: "info",
|
|
8937
|
-
children:
|
|
9646
|
+
children: t("detail.previewHint")
|
|
9647
|
+
}),
|
|
9648
|
+
detailView.canImport && approvalList.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
9649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9650
|
+
className: config_manager_module_css_default.groupLabel,
|
|
9651
|
+
children: t("detail.approval.title")
|
|
9652
|
+
}),
|
|
9653
|
+
approvalSummary !== null && approvalSummary.highRiskTotal > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9654
|
+
kind: "warn",
|
|
9655
|
+
children: t("detail.approval.highRiskHint")
|
|
9656
|
+
}),
|
|
9657
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9658
|
+
className: config_manager_module_css_default.conflictList,
|
|
9659
|
+
children: approvalList.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9660
|
+
className: config_manager_module_css_default.checkboxRow,
|
|
9661
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9662
|
+
type: "checkbox",
|
|
9663
|
+
checked: row.approved,
|
|
9664
|
+
onChange: (e) => {
|
|
9665
|
+
patch({ approvals: {
|
|
9666
|
+
...state.approvals,
|
|
9667
|
+
[row.adapter]: e.target.checked
|
|
9668
|
+
} });
|
|
9669
|
+
}
|
|
9670
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
9671
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9672
|
+
className: config_manager_module_css_default.conflictId,
|
|
9673
|
+
children: row.adapter
|
|
9674
|
+
}),
|
|
9675
|
+
" ",
|
|
9676
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9677
|
+
kind: row.highRisk ? "warn" : "info",
|
|
9678
|
+
children: row.highRisk ? t("detail.approval.requiresApproval") : t("detail.approval.safe")
|
|
9679
|
+
}),
|
|
9680
|
+
" ",
|
|
9681
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9682
|
+
kind: "info",
|
|
9683
|
+
children: row.label
|
|
9684
|
+
})
|
|
9685
|
+
] })]
|
|
9686
|
+
}, row.adapter))
|
|
9687
|
+
}),
|
|
9688
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9689
|
+
className: config_manager_module_css_default.statRow,
|
|
9690
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
9691
|
+
kind: approvalSummary !== null && approvalSummary.canImport ? "ok" : "warn",
|
|
9692
|
+
children: approvalSummary !== null ? t("detail.approval.count", {
|
|
9693
|
+
selected: String(approvalSummary.selected),
|
|
9694
|
+
total: String(approvalSummary.total)
|
|
9695
|
+
}) : ""
|
|
9696
|
+
})
|
|
9697
|
+
})
|
|
9698
|
+
] }),
|
|
9699
|
+
detailView.canImport ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9700
|
+
className: config_manager_module_css_default.actionRow,
|
|
9701
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9702
|
+
variant: "primary",
|
|
9703
|
+
disabled: state.importing || approvalSummary !== null && !approvalSummary.canImport,
|
|
9704
|
+
onClick: () => {
|
|
9705
|
+
runImport();
|
|
9706
|
+
},
|
|
9707
|
+
children: state.importing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") }) : t("detail.import")
|
|
9708
|
+
})
|
|
9709
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
9710
|
+
kind: "error",
|
|
9711
|
+
children: t("detail.emptySections")
|
|
9712
|
+
}),
|
|
9713
|
+
state.importResult !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Banner, {
|
|
9714
|
+
kind: state.importResult.ok ? "ok" : "error",
|
|
9715
|
+
children: [state.importResult.ok ? `导入完成:${state.importResult.executed.filter((e) => e.status === "ok").length} 项写入` : `导入失败(${state.importResult.executed.filter((e) => e.status === "failed").length} 项失败)`, state.importResult.needsRestart && " · 部分改动需重启 DSH 后生效"]
|
|
8938
9716
|
})
|
|
8939
|
-
] })
|
|
8940
|
-
|
|
8941
|
-
})
|
|
8942
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8943
|
-
className: config_manager_module_css_default.statRow,
|
|
8944
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
8945
|
-
kind: approvalSummary !== null && approvalSummary.canImport ? "ok" : "warn",
|
|
8946
|
-
children: approvalSummary !== null ? t("detail.approval.count", {
|
|
8947
|
-
selected: String(approvalSummary.selected),
|
|
8948
|
-
total: String(approvalSummary.total)
|
|
8949
|
-
}) : ""
|
|
8950
|
-
})
|
|
8951
|
-
})
|
|
8952
|
-
] }),
|
|
8953
|
-
detailView.canImport ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8954
|
-
className: config_manager_module_css_default.actionRow,
|
|
8955
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
8956
|
-
variant: "primary",
|
|
8957
|
-
disabled: state.importing || approvalSummary !== null && !approvalSummary.canImport,
|
|
8958
|
-
onClick: () => {
|
|
8959
|
-
runImport();
|
|
8960
|
-
},
|
|
8961
|
-
children: state.importing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") }) : t("detail.import")
|
|
8962
|
-
})
|
|
8963
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Banner, {
|
|
8964
|
-
kind: "error",
|
|
8965
|
-
children: t("detail.emptySections")
|
|
8966
|
-
}),
|
|
8967
|
-
state.importResult !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Banner, {
|
|
8968
|
-
kind: state.importResult.ok ? "ok" : "error",
|
|
8969
|
-
children: [state.importResult.ok ? `导入完成:${state.importResult.executed.filter((e) => e.status === "ok").length} 项写入` : `导入失败(${state.importResult.executed.filter((e) => e.status === "failed").length} 项失败)`, state.importResult.needsRestart && " · 部分改动需重启 DSH 后生效"]
|
|
9717
|
+
] })
|
|
9718
|
+
]
|
|
9719
|
+
})]
|
|
8970
9720
|
})
|
|
8971
|
-
|
|
8972
|
-
|
|
9721
|
+
}),
|
|
9722
|
+
!downloadOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, { children: [
|
|
8973
9723
|
state.loadError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Empty, { children: t("list.empty") }),
|
|
8974
9724
|
state.loadError === null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8975
9725
|
className: config_manager_module_css_default.statRow,
|
|
@@ -9060,14 +9810,35 @@ function MarketPanel({ api, myConfigsApi, importApi, syncApi, t }) {
|
|
|
9060
9810
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9061
9811
|
disabled: state.downloadingId === it.id,
|
|
9062
9812
|
onClick: () => {
|
|
9063
|
-
|
|
9813
|
+
openDownload(it);
|
|
9064
9814
|
},
|
|
9065
9815
|
children: state.downloadingId === it.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Spinner, { label: t("common.loading") }) : t("list.download")
|
|
9066
9816
|
})]
|
|
9067
9817
|
}, it.id);
|
|
9068
9818
|
})
|
|
9069
9819
|
})
|
|
9070
|
-
] })
|
|
9820
|
+
] }),
|
|
9821
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmDialog, {
|
|
9822
|
+
open: disclaimerKey === "download",
|
|
9823
|
+
title: t("disclaimer.title"),
|
|
9824
|
+
message: t("disclaimer.download.text"),
|
|
9825
|
+
confirmLabel: t("disclaimer.confirm"),
|
|
9826
|
+
cancelLabel: t("common.cancel"),
|
|
9827
|
+
onConfirm: confirmDownloadDisclaimer,
|
|
9828
|
+
onCancel: () => {
|
|
9829
|
+
setDisclaimerKey(null);
|
|
9830
|
+
},
|
|
9831
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9832
|
+
className: config_manager_module_css_default.checkboxRow,
|
|
9833
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9834
|
+
type: "checkbox",
|
|
9835
|
+
checked: dontAsk,
|
|
9836
|
+
onChange: (e) => {
|
|
9837
|
+
setDontAsk(e.target.checked);
|
|
9838
|
+
}
|
|
9839
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("disclaimer.dontAsk") })]
|
|
9840
|
+
})
|
|
9841
|
+
})
|
|
9071
9842
|
] })]
|
|
9072
9843
|
});
|
|
9073
9844
|
}
|
|
@@ -9717,10 +10488,14 @@ const zh$1 = {
|
|
|
9717
10488
|
"config.saving": "保存中…",
|
|
9718
10489
|
"config.saveHint": "表单改动会自动保存(密码/token 安全写入 DSH credentials,不会写入同步文件或日志);也可点击按钮立即保存。",
|
|
9719
10490
|
"channel.title": "同步通道",
|
|
9720
|
-
"channel.hint": "选择远程同步通道:Git 私有仓库或 WebDAV 服务器。",
|
|
9721
10491
|
"channel.git": "Git 私有仓库",
|
|
9722
10492
|
"channel.webdav": "WebDAV 服务器",
|
|
9723
10493
|
"channel.perChannelHint": "GitHub 与 WebDAV 通道的自动同步、同步模式、加密与远端快照各自独立配置。",
|
|
10494
|
+
"channel.open": "配置同步通道",
|
|
10495
|
+
"channel.openHint": "远程同步通过「同步通道」进行:Git 私有仓库或 WebDAV 服务器。点击按钮在弹窗中配置或修改。",
|
|
10496
|
+
"channel.configured": "已配置",
|
|
10497
|
+
"channel.notConfigured": "未配置",
|
|
10498
|
+
"channel.currentUrl": "当前地址",
|
|
9724
10499
|
"webdav.title": "WebDAV 配置",
|
|
9725
10500
|
"webdav.url": "服务器地址",
|
|
9726
10501
|
"webdav.urlHint": "WebDAV 服务器根地址(https://…)。同步快照与索引存放于该地址的 snapshots/ 子目录下。请勿在地址中包含用户名/密码。",
|
|
@@ -9736,6 +10511,7 @@ const zh$1 = {
|
|
|
9736
10511
|
"github.login": "使用 GitHub 登录",
|
|
9737
10512
|
"github.retry": "重新登录",
|
|
9738
10513
|
"github.cancel": "取消",
|
|
10514
|
+
"github.tokenInvalid": "GitHub 登录已失效,请重新登录。",
|
|
9739
10515
|
"github.userCode": "一次性授权代码",
|
|
9740
10516
|
"github.openAuth": "打开 GitHub 授权页面",
|
|
9741
10517
|
"github.clientIdHint": "需要插件配置 githubClientId(GitHub OAuth App 的 client_id)才能使用 GitHub 登录。",
|
|
@@ -9880,10 +10656,14 @@ const en$1 = {
|
|
|
9880
10656
|
"config.saving": "Saving…",
|
|
9881
10657
|
"config.saveHint": "Form changes are saved automatically (password/token written securely into DSH credentials, never into sync files or logs); you can also save explicitly with the button.",
|
|
9882
10658
|
"channel.title": "Sync Channel",
|
|
9883
|
-
"channel.hint": "Choose the remote sync channel: Git private repository or WebDAV server.",
|
|
9884
10659
|
"channel.git": "Git private repo",
|
|
9885
10660
|
"channel.webdav": "WebDAV server",
|
|
9886
10661
|
"channel.perChannelHint": "Auto sync, sync mode, encryption and remote snapshots are configured independently for GitHub and WebDAV channels.",
|
|
10662
|
+
"channel.open": "Configure sync channel",
|
|
10663
|
+
"channel.openHint": "Remote sync runs through a sync channel: a private Git repository or a WebDAV server. Click the button to configure or change it in the dialog.",
|
|
10664
|
+
"channel.configured": "Configured",
|
|
10665
|
+
"channel.notConfigured": "Not configured",
|
|
10666
|
+
"channel.currentUrl": "Current URL",
|
|
9887
10667
|
"webdav.title": "WebDAV Configuration",
|
|
9888
10668
|
"webdav.url": "Server URL",
|
|
9889
10669
|
"webdav.urlHint": "WebDAV server root URL (https://…). Sync snapshots and the index are stored under a snapshots/ subdirectory of that URL. Do not include a username/password in the URL.",
|
|
@@ -9899,6 +10679,7 @@ const en$1 = {
|
|
|
9899
10679
|
"github.login": "Sign in with GitHub",
|
|
9900
10680
|
"github.retry": "Sign in again",
|
|
9901
10681
|
"github.cancel": "Cancel",
|
|
10682
|
+
"github.tokenInvalid": "GitHub sign-in is no longer valid — please sign in again.",
|
|
9902
10683
|
"github.userCode": "One-time code",
|
|
9903
10684
|
"github.openAuth": "Open GitHub authorization page",
|
|
9904
10685
|
"github.clientIdHint": "Requires the githubClientId plugin config (the client_id of your GitHub OAuth App).",
|
|
@@ -10121,7 +10902,10 @@ const MY_CONFIGS_API = {
|
|
|
10121
10902
|
status: "/api/dsh-config-manager/me/status",
|
|
10122
10903
|
upload: "/api/dsh-config-manager/me/upload",
|
|
10123
10904
|
items: "/api/dsh-config-manager/me/items",
|
|
10124
|
-
update: "/api/dsh-config-manager/me/update"
|
|
10905
|
+
update: "/api/dsh-config-manager/me/update",
|
|
10906
|
+
listing: "/api/dsh-config-manager/me/listing",
|
|
10907
|
+
relist: "/api/dsh-config-manager/me/relist",
|
|
10908
|
+
delete: "/api/dsh-config-manager/me/delete"
|
|
10125
10909
|
};
|
|
10126
10910
|
/** 「我的配置」请求超时(ms):上传/更新含 git clone/push/fork/PR,与 market/sync 对齐量级 */
|
|
10127
10911
|
const MY_CONFIGS_TIMEOUT_MS = 300 * 1e3;
|
|
@@ -10181,6 +10965,18 @@ var MyConfigsApi = class {
|
|
|
10181
10965
|
async meUpdate(payload) {
|
|
10182
10966
|
return postJson(MY_CONFIGS_API.update, payload, this.t);
|
|
10183
10967
|
}
|
|
10968
|
+
/** 查询收录/下架任务状态(结果卡轮询;任务表未命中时 Host 回退 GitHub 实况推导;无任务无实况 → null) */
|
|
10969
|
+
async meListing(itemId) {
|
|
10970
|
+
return postJson(MY_CONFIGS_API.listing, { itemId }, this.t);
|
|
10971
|
+
}
|
|
10972
|
+
/** 重新提交收录(失败/重启丢失后重试;幂等复用已存在 fork/open PR) */
|
|
10973
|
+
async meRelist(itemId) {
|
|
10974
|
+
return postJson(MY_CONFIGS_API.relist, { itemId }, this.t);
|
|
10975
|
+
}
|
|
10976
|
+
/** 删除条目(同步删本地索引+文件;已收录自动后台提下架 PR;待审核自动关闭收录 PR) */
|
|
10977
|
+
async meDelete(itemId) {
|
|
10978
|
+
return postJson(MY_CONFIGS_API.delete, { itemId }, this.t);
|
|
10979
|
+
}
|
|
10184
10980
|
};
|
|
10185
10981
|
//#endregion
|
|
10186
10982
|
//#region src/client/market/market-locales.ts
|
|
@@ -10199,14 +10995,8 @@ const zh = {
|
|
|
10199
10995
|
"section.label": "配置市场",
|
|
10200
10996
|
"section.description": "浏览并下载社区共享的配置(公开 Git 仓库;下载内容一律视为不可信,导入前必经校验与确认)",
|
|
10201
10997
|
"config.title": "市场仓库",
|
|
10202
|
-
"config.builtinHint": "内置官方市场,只读、不可编辑(由创建者维护的公开 Git 仓库)。",
|
|
10203
|
-
"config.official": "内置官方市场",
|
|
10204
|
-
"config.custom": "自定义市场地址",
|
|
10205
|
-
"config.repoUrlHint": "内置公开 Git 仓库地址。市场只读拉取(绝不推送)。",
|
|
10206
10998
|
"config.refresh": "拉取最新",
|
|
10207
10999
|
"config.refreshing": "拉取中…",
|
|
10208
|
-
"config.addedAt": "更新于:{time}",
|
|
10209
|
-
"config.itemCount": "{count} 个条目",
|
|
10210
11000
|
"list.empty": "内置市场尚未加载。请先「拉取最新」。",
|
|
10211
11001
|
"list.browse": "浏览",
|
|
10212
11002
|
"list.loading": "正在读取市场…",
|
|
@@ -10273,6 +11063,8 @@ const zh = {
|
|
|
10273
11063
|
"myconfigs.update.hint": "版本将自动 +1,已预填原条目信息(名称可改)。",
|
|
10274
11064
|
"myconfigs.update.run": "一键更新",
|
|
10275
11065
|
"myconfigs.update.running": "更新中…",
|
|
11066
|
+
"myconfigs.update.zipHint": "更新需要新的配置包:选择新 zip 后自动校验,通过后即可一键更新。",
|
|
11067
|
+
"myconfigs.update.selectZip": "选择新 ZIP…",
|
|
10276
11068
|
"myconfigs.result.title": "上传/更新完成",
|
|
10277
11069
|
"myconfigs.result.version": "版本 {version}",
|
|
10278
11070
|
"myconfigs.result.sha256": "SHA-256:{hash}",
|
|
@@ -10281,6 +11073,9 @@ const zh = {
|
|
|
10281
11073
|
"myconfigs.result.openRepo": "打开仓库",
|
|
10282
11074
|
"myconfigs.result.pr": "收录 PR #{number}",
|
|
10283
11075
|
"myconfigs.result.openPr": "查看 PR",
|
|
11076
|
+
"myconfigs.result.listingPending": "已上传 ✓ 正在后台提交收录(fork + 收录 PR),稍后列表状态自动更新",
|
|
11077
|
+
"myconfigs.result.listingFailed": "收录失败",
|
|
11078
|
+
"myconfigs.result.relist": "重新提交收录",
|
|
10284
11079
|
"myconfigs.list.title": "已上传",
|
|
10285
11080
|
"myconfigs.list.empty": "尚未上传任何配置",
|
|
10286
11081
|
"myconfigs.list.loading": "正在读取…",
|
|
@@ -10290,6 +11085,18 @@ const zh = {
|
|
|
10290
11085
|
"myconfigs.item.update": "更新",
|
|
10291
11086
|
"myconfigs.item.install": "装回本地",
|
|
10292
11087
|
"myconfigs.item.openPr": "查看收录 PR",
|
|
11088
|
+
"myconfigs.delete.run": "删除",
|
|
11089
|
+
"myconfigs.delete.confirm": "确认删除",
|
|
11090
|
+
"myconfigs.delete.confirmTitle": "删除条目",
|
|
11091
|
+
"myconfigs.delete.confirmText": "确认删除?该操作会从配置仓库永久删除该条目的索引与文件(不可恢复)",
|
|
11092
|
+
"myconfigs.delete.delistStarted": "已删除本地条目,并自动提交「下架 PR」(官方市场移除需人工合并,期间市场可能仍显示该条目)",
|
|
11093
|
+
"myconfigs.delete.prClosed": "已删除本地条目,并关闭该条目的待审核收录 PR",
|
|
11094
|
+
"disclaimer.title": "免责声明",
|
|
11095
|
+
"disclaimer.upload.text": "你即将把配置上传到你的公开仓库(<login>/dsh-configs)并提交官方市场收录申请。\n\n上传后内容将对所有人公开可见,且需经过人工审核才能进入官方市场。请确保:\n· 内容不包含任何真实密钥 / 凭据(环境变量引用如 $VAR 是安全的);\n· 内容不包含个人隐私或本地环境信息;\n· 你有权分享这些配置。",
|
|
11096
|
+
"disclaimer.download.text": "你即将从公共网络市场下载配置并导入本地。\n\n下载内容属于不可信输入:未经官方审核、可能包含风险(安装插件 / 写入文件 / 修改设置)。\n· 导入前会逐项展示并校验,高风险分区默认不导入、需逐项批准;\n· 导入会先自动创建快照,失败可回滚;\n· 请核对来源与内容后再确认导入。",
|
|
11097
|
+
"disclaimer.install.text": "你即将把配置从你的公开仓库装回本地。\n\n该内容属于你此前上传的配置,但同样会经过安全校验与逐分区批准:\n· 高风险分区默认不导入、需逐项批准;\n· 导入前自动创建快照,失败可回滚。",
|
|
11098
|
+
"disclaimer.confirm": "我已了解,继续",
|
|
11099
|
+
"disclaimer.dontAsk": "不再提示(该操作以后不再显示免责声明)",
|
|
10293
11100
|
"myconfigs.error.loadStatus": "登录状态读取失败",
|
|
10294
11101
|
"myconfigs.error.loadItems": "已上传列表读取失败",
|
|
10295
11102
|
"common.cancel": "取消",
|
|
@@ -10302,14 +11109,8 @@ const en = {
|
|
|
10302
11109
|
"section.label": "Config Marketplace",
|
|
10303
11110
|
"section.description": "Browse and download community-shared configs (public Git repos; downloaded content is always untrusted — validated and confirmed before import)",
|
|
10304
11111
|
"config.title": "Market Repository",
|
|
10305
|
-
"config.builtinHint": "Built-in official market — read-only and not editable (a public Git repo maintained by the creator).",
|
|
10306
|
-
"config.official": "Built-in official market",
|
|
10307
|
-
"config.custom": "Custom market URL",
|
|
10308
|
-
"config.repoUrlHint": "Built-in public Git repository URL. Markets are read-only (never pushed).",
|
|
10309
11112
|
"config.refresh": "Refresh",
|
|
10310
11113
|
"config.refreshing": "Refreshing…",
|
|
10311
|
-
"config.addedAt": "Updated: {time}",
|
|
10312
|
-
"config.itemCount": "{count} item(s)",
|
|
10313
11114
|
"list.empty": "The built-in market has not loaded yet. Click \"Refresh\" first.",
|
|
10314
11115
|
"list.browse": "Browse",
|
|
10315
11116
|
"list.loading": "Reading market…",
|
|
@@ -10376,6 +11177,8 @@ const en = {
|
|
|
10376
11177
|
"myconfigs.update.hint": "The version will be bumped automatically (+1); item info is prefilled (name editable).",
|
|
10377
11178
|
"myconfigs.update.run": "Update",
|
|
10378
11179
|
"myconfigs.update.running": "Updating…",
|
|
11180
|
+
"myconfigs.update.zipHint": "Updating needs a new config zip: pick one and it will be validated automatically, then you can update.",
|
|
11181
|
+
"myconfigs.update.selectZip": "Choose new ZIP…",
|
|
10379
11182
|
"myconfigs.result.title": "Upload/update complete",
|
|
10380
11183
|
"myconfigs.result.version": "version {version}",
|
|
10381
11184
|
"myconfigs.result.sha256": "SHA-256: {hash}",
|
|
@@ -10384,6 +11187,9 @@ const en = {
|
|
|
10384
11187
|
"myconfigs.result.openRepo": "Open repo",
|
|
10385
11188
|
"myconfigs.result.pr": "Listing PR #{number}",
|
|
10386
11189
|
"myconfigs.result.openPr": "View PR",
|
|
11190
|
+
"myconfigs.result.listingPending": "Uploaded ✓ submitting listing in the background (fork + PR) — list status will update shortly",
|
|
11191
|
+
"myconfigs.result.listingFailed": "Listing failed",
|
|
11192
|
+
"myconfigs.result.relist": "Resubmit listing",
|
|
10387
11193
|
"myconfigs.list.title": "Uploaded",
|
|
10388
11194
|
"myconfigs.list.empty": "No configs uploaded yet",
|
|
10389
11195
|
"myconfigs.list.loading": "Loading…",
|
|
@@ -10393,6 +11199,18 @@ const en = {
|
|
|
10393
11199
|
"myconfigs.item.update": "Update",
|
|
10394
11200
|
"myconfigs.item.install": "Install locally",
|
|
10395
11201
|
"myconfigs.item.openPr": "View listing PR",
|
|
11202
|
+
"myconfigs.delete.run": "Delete",
|
|
11203
|
+
"myconfigs.delete.confirm": "Confirm delete",
|
|
11204
|
+
"myconfigs.delete.confirmTitle": "Delete item",
|
|
11205
|
+
"myconfigs.delete.confirmText": "Delete? This permanently removes the item index and files from your config repo (not recoverable)",
|
|
11206
|
+
"myconfigs.delete.delistStarted": "Local item deleted; a \"delist PR\" has been submitted (removal from the official market needs human merge; the item may still appear in the market meanwhile)",
|
|
11207
|
+
"myconfigs.delete.prClosed": "Local item deleted; its pending listing PR has been closed",
|
|
11208
|
+
"disclaimer.title": "Disclaimer",
|
|
11209
|
+
"disclaimer.upload.text": "You are about to upload configs to your public repo (<login>/dsh-configs) and submit a listing request to the official market.\n\nUploaded content becomes publicly visible and requires human review before entering the official market. Please ensure:\n· No real secrets / credentials are included (env-var references like $VAR are safe);\n· No personal privacy or local environment info is included;\n· You have the right to share these configs.",
|
|
11210
|
+
"disclaimer.download.text": "You are about to download configs from a public network market and import them locally.\n\nDownloaded content is untrusted input: not officially reviewed and may carry risks (installing plugins / writing files / changing settings).\n· Everything is validated and shown before import; high-risk sections are not imported by default and require individual approval;\n· A snapshot is auto-created before import and rollback is available on failure;\n· Please verify the source and content before confirming the import.",
|
|
11211
|
+
"disclaimer.install.text": "You are about to reinstall configs from your public repo to this machine.\n\nThis is content you uploaded before, but it still goes through the same validation and per-section approval:\n· High-risk sections are not imported by default and require individual approval;\n· A snapshot is auto-created before import and rollback is available on failure.",
|
|
11212
|
+
"disclaimer.confirm": "I understand, continue",
|
|
11213
|
+
"disclaimer.dontAsk": "Don't ask again (no more disclaimers for this action)",
|
|
10396
11214
|
"myconfigs.error.loadStatus": "Failed to read sign-in status",
|
|
10397
11215
|
"myconfigs.error.loadItems": "Failed to read uploaded items",
|
|
10398
11216
|
"common.cancel": "Cancel",
|