mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 10:39:32 +01:00
fix(settings): a tab-return read never undoes a pick or save made while it was out
- session-ui.js: drop the answer when the case-sync chain moved during the read; settings-ui.js calls _applyServerCaseSettings with ?. - i18n.js: zh-CN for the failed case-options save toast, case name passed through - tests: regression for the stale read, zh-CN toast row
This commit is contained in:
1 parent
bb088bcd3e
commit
607c88afd9
5 files changed
+37
-2
No files matched your search
@@ -1734,6 +1734,11 @@
|
||||
(_m, what, why) =>
|
||||
`${what === 'Run mode' ? '运行模式' : '重生预设'}已保存到本设备,但未保存到服务器:${ZH_CN[why] || why}`,
|
||||
],
|
||||
// The case-options save (session-ui.js _pushCaseSettings): the case name passes through.
|
||||
[
|
||||
/^Options for "([^"]+)" \(until the next sync\) saved on this device, not on the server: ([\s\S]+)$/,
|
||||
(_m, name, why) => `案例“${name}”的选项已保存到本设备(同步前有效),但未保存到服务器:${ZH_CN[why] || why}`,
|
||||
],
|
||||
// A dialog read off a hook-less CLI's screen (src/web/screen-blocked.ts), as the
|
||||
// notification drawer shows it. The CLI's label passes through.
|
||||
[/^(.+) is waiting for your answer in the terminal$/, (_m, cli) => `${cli} 正在终端中等待你的回答`],
|
||||
|
||||
@@ -3775,11 +3775,13 @@ Object.assign(CodemanApp.prototype, {
|
||||
if (this.loadAppSettingsFromStorage?.()?.syncCaseState !== true) return;
|
||||
const seq = (this._caseSyncRefresh = (this._caseSyncRefresh || 0) + 1);
|
||||
try {
|
||||
await this._caseSyncChain; // this device's own saves land first, so the copy read next includes them
|
||||
const chain = this._caseSyncChain;
|
||||
await chain; // this device's own saves land first, so the copy read next includes them
|
||||
const res = await fetch('/api/settings');
|
||||
if (!res.ok) return;
|
||||
const server = (await res.json())?.data ?? null;
|
||||
if (seq !== this._caseSyncRefresh || !server) return; // a newer refresh owns the answer
|
||||
if (this._caseSyncChain !== chain) return; // a save or pick made while the read was out is newer than it
|
||||
this._adoptServerCaseSyncPreference(server);
|
||||
if (server.syncCaseState !== true) return;
|
||||
this._applyServerCaseSettings(server);
|
||||
|
||||
@@ -5282,7 +5282,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
// installs that had saved `false` (agent-skill-default-migration.ts).
|
||||
if (!('agentSkillEnabled' in appSettings)) delete merged.agentSkillEnabled;
|
||||
this.saveAppSettingsToStorage(merged);
|
||||
this._applyServerCaseSettings(settings);
|
||||
this._applyServerCaseSettings?.(settings);
|
||||
|
||||
// Apply notification prefs from server if present (only if localStorage has none)
|
||||
if (notificationPreferences && this.notificationManager) {
|
||||
|
||||
@@ -526,6 +526,10 @@ describe('the new toasts in zh-CN', () => {
|
||||
'Saved on this device, not on the server: the server could not be reached',
|
||||
'已保存到本设备,但未保存到服务器:无法连接到服务器',
|
||||
],
|
||||
[
|
||||
'Options for "demo" (until the next sync) saved on this device, not on the server: HTTP 500',
|
||||
'案例“demo”的选项已保存到本设备(同步前有效),但未保存到服务器:HTTP 500',
|
||||
],
|
||||
[`Tunnel not stopped: ${TORN}`, `隧道未停止:${TORN}`],
|
||||
];
|
||||
for (const [english, chinese] of cases) {
|
||||
|
||||
@@ -262,6 +262,30 @@ describe('returning to the tab', () => {
|
||||
expect(unchanged.hidden.size).toBe(0);
|
||||
});
|
||||
|
||||
it('does not undo a pick or a case save made while its read was out', async () => {
|
||||
let release!: () => void;
|
||||
const gate = new Promise<void>((r) => (release = r));
|
||||
const { app, select, store } = makeApp({ syncCaseState: true }, async (_url, init) => {
|
||||
if (init?.method === 'PUT') return { body: { success: true, data: {} } };
|
||||
await gate; // the server read this copy before the pick and the save below reached it
|
||||
return env({
|
||||
syncCaseState: true,
|
||||
lastPickedCase: 'alpha',
|
||||
caseSettings: { beta: { agentTeams: false, opusContext1m: true } },
|
||||
});
|
||||
});
|
||||
const refresh = app._syncCaseStateFromServer();
|
||||
await settle();
|
||||
select.value = 'beta';
|
||||
await app.saveLastUsedCase('beta');
|
||||
app.saveCaseSettings('beta', entry);
|
||||
await app._caseSyncChain;
|
||||
release();
|
||||
await refresh;
|
||||
expect(select.value).toBe('beta');
|
||||
expect(JSON.parse(store.get('caseSettings_beta')!)).toEqual(entry);
|
||||
});
|
||||
|
||||
it('asks for nothing on a tab return while this device has sync off', async () => {
|
||||
const { app, select, calls } = makeApp({}, () => env({ syncCaseState: true, lastUsedCase: 'beta' }));
|
||||
await app._syncCaseStateFromServer();
|
||||
|
||||
Reference in new issue
Block a user