设置页第二轮:行内编辑、GEO 资源展开、恢复与导入分家
单值设置从常驻输入框改成 InlineEdit(纯文本加铅笔,Enter 或失焦提交, 失焦无效直接放弃——失焦是「我走了」,不该把人拽回来)。测速地址加恢复 默认按钮;内核参数逐项提交,不再攒一个保存按钮。 资源一节按文件展开:四类 GEO 文件的大小和更新时间由服务端 stat 内核 工作目录得来(GET /api/geo;文件名和大小写不敏感匹配照 constant/ path.go:18-20,193-224),下载地址可改(geox-url,config.go:363-368, 默认值 578-583)。行内的更新按钮仍是全量更新——内核只有这一个口子, 没变化的文件靠内容哈希跳过。 上传拆成两个入口:恢复只认带 Patchbay 标记的文件,导入收任意配置; 新增恢复策略(兼容只搬接管段落 listeners/proxy-groups/rules/ proxy-providers/rule-providers,覆盖整份替换)。平时是按钮,拖着文件 进窗口时整行变成投放区。
This commit is contained in:
+32
-8
@@ -286,14 +286,29 @@ async function pruneBackups(env: Env): Promise<void> {
|
||||
await Promise.all(stale.map((name) => unlink(join(dir, name)).catch(() => {})))
|
||||
}
|
||||
|
||||
export type ImportMode = 'override' | 'compatible'
|
||||
|
||||
/**
|
||||
* 用上传的 YAML 原文整份替换当前配置。
|
||||
*
|
||||
* 解析用和读配置同一个引擎,之后走 applyConfig 完整的保护链路(自检、备份、
|
||||
* 重载、失败回退)。没有 baseRevision——整份替换本来就是覆盖语义,同还原备份。
|
||||
* 兼容模式搬运的段落:Patchbay 接管的那几个(决策记录 0003)。
|
||||
* 老式顶层端口、dns、tun 这类属于机器本身的设置不在其中——兼容恢复的语义是
|
||||
* 「把我在 Patchbay 里做的接线搬过来」,不动当前机器的底座。
|
||||
*/
|
||||
export async function importConfig(env: Env, content: string): Promise<ApplyOutcome> {
|
||||
let data: ConfigObject
|
||||
const MANAGED_KEYS = ['listeners', 'proxy-groups', 'rules', 'proxy-providers', 'rule-providers']
|
||||
|
||||
/**
|
||||
* 用上传的 YAML 替换当前配置。
|
||||
*
|
||||
* `override` 整份替换;`compatible` 只把上传文件里 Patchbay 接管的段落搬到
|
||||
* 当前配置上(上传文件里没有的段落维持当前的样子)。解析用和读配置同一个引擎,
|
||||
* 之后走 applyConfig 完整的保护链路(自检、备份、重载、失败回退)。
|
||||
* 没有 baseRevision——替换本来就是覆盖语义,同还原备份。
|
||||
*/
|
||||
export async function importConfig(
|
||||
env: Env,
|
||||
content: string,
|
||||
mode: ImportMode,
|
||||
): Promise<ApplyOutcome> {
|
||||
let uploaded: ConfigObject
|
||||
try {
|
||||
const doc = openDocument(content)
|
||||
const broken = doc.diagnostics.filter((d) => d.severity === 'error')
|
||||
@@ -306,7 +321,7 @@ export async function importConfig(env: Env, content: string): Promise<ApplyOutc
|
||||
restored: false,
|
||||
}
|
||||
}
|
||||
data = doc.data
|
||||
uploaded = doc.data
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
@@ -316,7 +331,16 @@ export async function importConfig(env: Env, content: string): Promise<ApplyOutc
|
||||
restored: false,
|
||||
}
|
||||
}
|
||||
return applyConfig(env, data)
|
||||
|
||||
if (mode === 'override') return applyConfig(env, uploaded)
|
||||
|
||||
const current = await readDocument(env)
|
||||
const merged: ConfigObject = { ...current.data }
|
||||
for (const key of MANAGED_KEYS) {
|
||||
const value = uploaded[key]
|
||||
if (value !== undefined) merged[key] = value
|
||||
}
|
||||
return applyConfig(env, merged)
|
||||
}
|
||||
|
||||
/** 把某个备份恢复成当前配置。走的是和普通改动同一条保护链路。 */
|
||||
|
||||
Reference in New Issue
Block a user