fix(mobile): preserve edited reconnect profiles

This commit is contained in:
Brennan Benson
2026-08-01 13:10:10 -07:00
parent 8e00b065bd
commit 19f668cf7c
4 changed files with 34 additions and 9 deletions
+9 -3
View File
@@ -17,7 +17,10 @@ import { colors, radii, spacing, typography } from '../../../src/theme/mobile-th
import { loadHosts, updateHostNameAndEndpoint } from '../../../src/transport/host-store'
import { getHostListLoadRevision } from '../../../src/transport/host-list-load-sharing'
import { displayHostEndpoint } from '../../../src/transport/host-endpoint'
import { resolveHostEndpointEdit } from '../../../src/transport/host-endpoint-edit'
import {
hostProfileAfterEdit,
resolveHostEndpointEdit
} from '../../../src/transport/host-endpoint-edit'
import { useForceReconnect, usePrimeHosts } from '../../../src/transport/client-context'
import { showForceReconnectError } from '../../../src/transport/force-reconnect-feedback'
import type { HostProfile } from '../../../src/transport/types'
@@ -106,6 +109,7 @@ export default function EditHostScreen() {
...(willRename ? { name: nextName } : {}),
...(nextEndpoint !== undefined ? { endpoint: nextEndpoint } : {})
}
let reconnectProfile = hostProfileAfterEdit(host, updates)
savingRef.current = true
setSaving(true)
setSaveError(null)
@@ -131,11 +135,13 @@ export default function EditHostScreen() {
if (hostLoadRevision !== getHostListLoadRevision()) {
continue
}
if (!hosts.some(({ id }) => id === host.id)) {
const loadedHost = hosts.find(({ id }) => id === host.id)
if (!loadedHost) {
break
}
primeHosts(hosts, hostLoadRevision)
if (hostLoadRevision === getHostListLoadRevision()) {
reconnectProfile = loadedHost
break
}
}
@@ -151,7 +157,7 @@ export default function EditHostScreen() {
// Why: reconnect is a follow-on side effect of a save that already
// committed — its failure or a hang must not be reported as a save
// failure or block navigating back.
void forceReconnectHost(host.id).catch(showForceReconnectError)
void forceReconnectHost(host.id, reconnectProfile).catch(showForceReconnectError)
}
}
+9 -6
View File
@@ -187,7 +187,7 @@ describe('edit host handleSave', () => {
endpoint: 'ws://192.168.1.20:6768'
})
expect(dependencies.primeHosts).toHaveBeenCalledWith([savedHost], 0)
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', savedHost)
expect(dependencies.back).toHaveBeenCalledTimes(1)
act(() => renderer.unmount())
@@ -211,7 +211,7 @@ describe('edit host handleSave', () => {
endpoint: 'ws://192.168.1.20:6768'
})
expect(dependencies.primeHosts).toHaveBeenCalledWith([savedHost], 0)
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', savedHost)
expect(dependencies.back).toHaveBeenCalledTimes(1)
act(() => renderer.unmount())
@@ -264,7 +264,10 @@ describe('edit host handleSave', () => {
await pressSave(renderer)
expect(dependencies.primeHosts).not.toHaveBeenCalled()
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', {
...HOST_FIXTURE,
endpoint: 'ws://192.168.1.20:6768'
})
expect(dependencies.back).toHaveBeenCalledTimes(1)
act(() => renderer.unmount())
@@ -282,7 +285,7 @@ describe('edit host handleSave', () => {
await Promise.resolve()
})
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', savedHost)
expect(dependencies.back).toHaveBeenCalledTimes(1)
expect(dependencies.alert).toHaveBeenCalledWith('Unable to reconnect', 'connect failed')
@@ -304,7 +307,7 @@ describe('edit host handleSave', () => {
await pressSave(renderer)
expect(dependencies.primeHosts).toHaveBeenCalledWith([relayHost], 0)
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', relayHost)
act(() => renderer.unmount())
})
@@ -325,7 +328,7 @@ describe('edit host handleSave', () => {
await pressSave(renderer)
expect(dependencies.primeHosts).toHaveBeenCalledWith([editedHost], 2)
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1')
expect(dependencies.forceReconnectHost).toHaveBeenCalledWith('host-1', editedHost)
act(() => renderer.unmount())
})
@@ -80,4 +80,19 @@ describe('HostReconnectProfileCache', () => {
expect(cache.get(HOST.id, 5)).toEqual(relayHost)
})
it('keeps an explicit endpoint edit ahead of its retired lifecycle publisher', () => {
const cache = new HostReconnectProfileCache()
const initialVersion = cache.prime(HOST, 4)
const publish = cache.publisher(HOST.id, initialVersion, () => 4)
const editedHost = { ...HOST, endpoint: 'ws://127.0.0.1:2' }
cache.reconnectProfile(HOST.id, 4, editedHost)
publish({
...HOST,
endpoints: [{ id: 'direct-primary', kind: 'lan', url: HOST.endpoint }]
})
expect(cache.get(HOST.id, 4)).toEqual(editedHost)
})
})
+1
View File
@@ -416,6 +416,7 @@ const MOBILE_RPC_METHOD_ALLOWLIST = new Set([
'worktree.activate',
'worktree.create',
'worktree.forceDeleteBranch',
'worktree.list',
'worktree.prefetchCreateBase',
'worktree.ps',
'worktree.show',