Skip to content

Commit cfe9c73

Browse files
committed
Merge remote-tracking branch 'origin/benjcooley/matrix-detection-proof' into benjcooley/matrix-detection-proof
2 parents 0e3eb1e + 0383f55 commit cfe9c73

8 files changed

Lines changed: 512 additions & 30 deletions

File tree

browser_tests/fixtures/helpers/SettingsHelper.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,18 @@ export class SettingsHelper {
2020
return await window.app!.extensionManager.setting.get(id)
2121
}, settingId)) as T
2222
}
23+
24+
/**
25+
* Reads the value the server holds, which {@link getSetting} cannot: that
26+
* reports the in-memory store, where a value may have been derived at load
27+
* rather than persisted. Returns `undefined` for a setting never written.
28+
*/
29+
async getPersistedSetting<T = unknown>(
30+
settingId: string
31+
): Promise<T | undefined> {
32+
return (await this.page.evaluate(async (id) => {
33+
const persisted = await window.app!.api.getSettings()
34+
return persisted[id as keyof typeof persisted]
35+
}, settingId)) as T | undefined
36+
}
2337
}

browser_tests/tests/canvasSettings.spec.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,138 @@ test.describe('Canvas settings', { tag: '@canvas' }, () => {
188188
})
189189
})
190190

191+
test.describe('Comfy.Canvas.NavigationMode', () => {
192+
test('picking a preset never persists custom', async ({ comfyPage }) => {
193+
const modeWrites: unknown[] = []
194+
comfyPage.page.on('request', (request) => {
195+
if (
196+
request.method() === 'POST' &&
197+
request.url().endsWith('/api/settings/Comfy.Canvas.NavigationMode')
198+
) {
199+
modeWrites.push(request.postDataJSON())
200+
}
201+
})
202+
203+
await comfyPage.settings.setSetting(
204+
'Comfy.Canvas.NavigationMode',
205+
'standard'
206+
)
207+
await comfyPage.workflow.reloadAndWaitForApp()
208+
209+
// A preset also writes the two overrides it implies; those writes must
210+
// not read back as the user hand-picking an override.
211+
expect(modeWrites).toContain('standard')
212+
expect(modeWrites).not.toContain('custom')
213+
expect(
214+
await comfyPage.settings.getSetting('Comfy.Canvas.NavigationMode')
215+
).toBe('standard')
216+
})
217+
218+
test('picking custom leaves the overrides untouched', async ({
219+
comfyPage
220+
}) => {
221+
// Arrive on the standard pair first, so both overrides differ from their
222+
// defaults and a handler that rewrote them would be caught.
223+
await comfyPage.settings.setSetting(
224+
'Comfy.Canvas.NavigationMode',
225+
'standard'
226+
)
227+
228+
await comfyPage.settings.setSetting(
229+
'Comfy.Canvas.NavigationMode',
230+
'custom'
231+
)
232+
await comfyPage.workflow.reloadAndWaitForApp()
233+
234+
expect(
235+
await comfyPage.settings.getSetting('Comfy.Canvas.NavigationMode')
236+
).toBe('custom')
237+
expect(
238+
await comfyPage.settings.getSetting(
239+
'Comfy.Canvas.LeftMouseClickBehavior'
240+
)
241+
).toBe('select')
242+
expect(
243+
await comfyPage.settings.getSetting('Comfy.Canvas.MouseWheelScroll')
244+
).toBe('panning')
245+
})
246+
247+
// A mode stored before the overrides shipped in 1.27.4 is the only value on
248+
// record, so they load as their defaults — which describe a different mode.
249+
test.describe('stored without the override settings', () => {
250+
test.use({
251+
initialSettings: { 'Comfy.Canvas.NavigationMode': 'standard' }
252+
})
253+
254+
test('keeps the stored preset through load', async ({ comfyPage }) => {
255+
expect(
256+
await comfyPage.settings.getSetting('Comfy.Canvas.NavigationMode')
257+
).toBe('standard')
258+
})
259+
260+
// Reads the server, not the store: the migration is idempotent, so an
261+
// in-memory read passes whether or not the write ever landed.
262+
test('persists the stored preset to the overrides', async ({
263+
comfyPage
264+
}) => {
265+
expect(
266+
await comfyPage.settings.getPersistedSetting(
267+
'Comfy.Canvas.LeftMouseClickBehavior'
268+
)
269+
).toBe('select')
270+
expect(
271+
await comfyPage.settings.getPersistedSetting(
272+
'Comfy.Canvas.MouseWheelScroll'
273+
)
274+
).toBe('panning')
275+
})
276+
})
277+
278+
// Every profile that already loaded a 1.27.4+ build has the mode demoted to
279+
// 'custom' with the overrides never written. The original choice is
280+
// unrecoverable, so this pins the no-op as deliberate.
281+
test.describe('already demoted to custom', () => {
282+
test.use({
283+
initialSettings: { 'Comfy.Canvas.NavigationMode': 'custom' }
284+
})
285+
286+
test('is left as custom', async ({ comfyPage }) => {
287+
expect(
288+
await comfyPage.settings.getSetting('Comfy.Canvas.NavigationMode')
289+
).toBe('custom')
290+
})
291+
})
292+
293+
test.describe('stored with only one override', () => {
294+
test.use({
295+
initialSettings: {
296+
'Comfy.Canvas.NavigationMode': 'standard',
297+
'Comfy.Canvas.MouseWheelScroll': 'zoom'
298+
}
299+
})
300+
301+
test('fills the gap without overwriting the stored override', async ({
302+
comfyPage
303+
}) => {
304+
expect(
305+
await comfyPage.settings.getSetting(
306+
'Comfy.Canvas.LeftMouseClickBehavior'
307+
)
308+
).toBe('select')
309+
expect(
310+
await comfyPage.settings.getSetting('Comfy.Canvas.MouseWheelScroll')
311+
).toBe('zoom')
312+
313+
// select + zoom is no preset, so demoting the mode is correct here.
314+
// Overwriting the stored 'zoom' to match the mode instead would
315+
// discard a real preference, which is the bug this all started as.
316+
expect(
317+
await comfyPage.settings.getSetting('Comfy.Canvas.NavigationMode')
318+
).toBe('custom')
319+
})
320+
})
321+
})
322+
191323
test.describe('Comfy.Canvas.LeftMouseClickBehavior', () => {
192324
test('override to panning makes empty left-drag pan the canvas', async ({
193325
comfyPage
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { CANVAS_NAVIGATION_PRESETS } from '@/platform/settings/constants/canvasNavigation'
4+
import { CORE_SETTINGS } from '@/platform/settings/constants/coreSettings'
5+
import type { SettingParams } from '@/platform/settings/types'
6+
7+
const NAV = 'Comfy.Canvas.NavigationMode'
8+
const LEFT = 'Comfy.Canvas.LeftMouseClickBehavior'
9+
const WHEEL = 'Comfy.Canvas.MouseWheelScroll'
10+
11+
const settingById = (id: string) => CORE_SETTINGS.find((s) => s.id === id)
12+
13+
const resolveDefaultValue = (setting: SettingParams | undefined): unknown => {
14+
const { defaultValue } = setting ?? {}
15+
return typeof defaultValue === 'function'
16+
? (defaultValue as () => unknown)()
17+
: defaultValue
18+
}
19+
20+
const presetForMode = (mode: unknown) =>
21+
typeof mode === 'string' ? CANVAS_NAVIGATION_PRESETS[mode] : undefined
22+
23+
const overrideDefaults = () => ({
24+
[LEFT]: resolveDefaultValue(settingById(LEFT)),
25+
[WHEEL]: resolveDefaultValue(settingById(WHEEL))
26+
})
27+
28+
describe('CANVAS_NAVIGATION_PRESETS', () => {
29+
/**
30+
* The override defaults have to describe whichever Navigation Mode a fresh
31+
* profile resolves to. If they disagree, that profile loads with a mode no
32+
* preset matches and the override handlers demote it to 'custom' on first
33+
* load — the bug this pairing exists to prevent. Asserted as a relationship
34+
* rather than against fixed values so changing a default is what trips it.
35+
*/
36+
it('agrees with the default Navigation Mode', () => {
37+
const defaultMode = resolveDefaultValue(settingById(NAV))
38+
39+
expect(presetForMode(defaultMode)).toEqual(overrideDefaults())
40+
})
41+
42+
it('agrees with every install-versioned Navigation Mode default', () => {
43+
const versioned = settingById(NAV)?.defaultsByInstallVersion ?? {}
44+
45+
for (const mode of Object.values(versioned)) {
46+
expect(presetForMode(mode)).toEqual(overrideDefaults())
47+
}
48+
})
49+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Settings } from '@/schemas/apiSchema'
2+
3+
/**
4+
* The Left Mouse Click Behavior and Mouse Wheel Scroll values each Navigation
5+
* Mode preset stands for.
6+
*
7+
* `custom` is deliberately absent: it means "the overrides are whatever the
8+
* user set", so there is no pair to apply or to restore from it.
9+
*/
10+
export const CANVAS_NAVIGATION_PRESETS: Record<
11+
string,
12+
Partial<Settings> | undefined
13+
> = {
14+
standard: {
15+
'Comfy.Canvas.LeftMouseClickBehavior': 'select',
16+
'Comfy.Canvas.MouseWheelScroll': 'panning'
17+
},
18+
legacy: {
19+
'Comfy.Canvas.LeftMouseClickBehavior': 'panning',
20+
'Comfy.Canvas.MouseWheelScroll': 'zoom'
21+
}
22+
}

src/platform/settings/constants/coreSettings.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
} from '@/locales/localeConfig'
66
import { isCloud, isDesktop, isNightly } from '@/platform/distribution/types'
77
import { TOUR_SEEN_SETTING } from '@/platform/onboarding/onboardingTours'
8+
import { CANVAS_NAVIGATION_PRESETS } from '@/platform/settings/constants/canvasNavigation'
89
import { useSettingStore } from '@/platform/settings/settingStore'
910
import type { SettingParams } from '@/platform/settings/types'
1011
import type { ColorPalettes } from '@/schemas/colorPaletteSchema'
@@ -188,22 +189,11 @@ export const CORE_SETTINGS: SettingParams[] = [
188189
'1.25.0': 'legacy'
189190
},
190191
onChange: async (val: unknown, old?: unknown) => {
191-
const newValue = val as string
192-
const oldValue = old as string | undefined
193-
if (!oldValue) return
194-
const settingStore = useSettingStore()
192+
if (!old || typeof val !== 'string') return
193+
const preset = CANVAS_NAVIGATION_PRESETS[val]
194+
if (!preset) return
195195

196-
if (newValue === 'standard') {
197-
await settingStore.setMany({
198-
'Comfy.Canvas.LeftMouseClickBehavior': 'select',
199-
'Comfy.Canvas.MouseWheelScroll': 'panning'
200-
})
201-
} else if (newValue === 'legacy') {
202-
await settingStore.setMany({
203-
'Comfy.Canvas.LeftMouseClickBehavior': 'panning',
204-
'Comfy.Canvas.MouseWheelScroll': 'zoom'
205-
})
206-
}
196+
await useSettingStore().setMany(preset)
207197
}
208198
},
209199
{

0 commit comments

Comments
 (0)