Polish desktop settings update/local-daemon sections
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { HostProfile } from '@/contexts/daemon-registry-context'
|
||||
|
||||
async function loadModuleForPlatform(platform: 'web' | 'ios' | 'android') {
|
||||
vi.resetModules()
|
||||
@@ -7,47 +6,6 @@ async function loadModuleForPlatform(platform: 'web' | 'ios' | 'android') {
|
||||
return import('./desktop-updates')
|
||||
}
|
||||
|
||||
function createHost(input: {
|
||||
serverId: string
|
||||
endpoint: string
|
||||
type?: 'direct' | 'relay'
|
||||
}): HostProfile {
|
||||
const now = new Date(0).toISOString()
|
||||
|
||||
if (input.type === 'relay') {
|
||||
return {
|
||||
serverId: input.serverId,
|
||||
label: input.serverId,
|
||||
connections: [
|
||||
{
|
||||
id: `${input.serverId}-relay`,
|
||||
type: 'relay',
|
||||
relayEndpoint: input.endpoint,
|
||||
daemonPublicKeyB64: 'test-key',
|
||||
},
|
||||
],
|
||||
preferredConnectionId: `${input.serverId}-relay`,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
serverId: input.serverId,
|
||||
label: input.serverId,
|
||||
connections: [
|
||||
{
|
||||
id: `${input.serverId}-direct`,
|
||||
type: 'direct',
|
||||
endpoint: input.endpoint,
|
||||
},
|
||||
],
|
||||
preferredConnectionId: `${input.serverId}-direct`,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
}
|
||||
|
||||
describe('desktop-updates helpers', () => {
|
||||
afterEach(() => {
|
||||
vi.doUnmock('react-native')
|
||||
@@ -79,20 +37,47 @@ describe('desktop-updates helpers', () => {
|
||||
expect(formatVersionWithPrefix(null)).toBe('\u2014')
|
||||
})
|
||||
|
||||
it('prefers localhost direct host when selecting local daemon', async () => {
|
||||
const { findLikelyLocalDaemonHost } = await loadModuleForPlatform('web')
|
||||
const remote = createHost({ serverId: 'remote', endpoint: '10.0.0.2:6767' })
|
||||
const local = createHost({ serverId: 'local', endpoint: 'localhost:6767' })
|
||||
it('parses valid local daemon version result', async () => {
|
||||
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
|
||||
|
||||
expect(findLikelyLocalDaemonHost([remote, local])?.serverId).toBe('local')
|
||||
expect(parseLocalDaemonVersionResult({ version: '0.1.15', error: null })).toEqual({
|
||||
version: '0.1.15',
|
||||
error: null,
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back to first host when no localhost endpoint exists', async () => {
|
||||
const { findLikelyLocalDaemonHost } = await loadModuleForPlatform('web')
|
||||
const relay = createHost({ serverId: 'relay', endpoint: 'relay.paseo.sh:443', type: 'relay' })
|
||||
const remote = createHost({ serverId: 'remote', endpoint: '10.0.0.2:6767' })
|
||||
it('parses local daemon version error result', async () => {
|
||||
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
|
||||
|
||||
expect(findLikelyLocalDaemonHost([relay, remote])?.serverId).toBe('relay')
|
||||
expect(
|
||||
parseLocalDaemonVersionResult({ version: null, error: 'paseo command not found in PATH' })
|
||||
).toEqual({
|
||||
version: null,
|
||||
error: 'paseo command not found in PATH',
|
||||
})
|
||||
})
|
||||
|
||||
it('parses unexpected local daemon version result', async () => {
|
||||
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
|
||||
|
||||
expect(parseLocalDaemonVersionResult(null)).toEqual({
|
||||
version: null,
|
||||
error: 'Unexpected response from version check.',
|
||||
})
|
||||
|
||||
expect(parseLocalDaemonVersionResult('not an object')).toEqual({
|
||||
version: null,
|
||||
error: 'Unexpected response from version check.',
|
||||
})
|
||||
})
|
||||
|
||||
it('trims whitespace in parsed version', async () => {
|
||||
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
|
||||
|
||||
expect(parseLocalDaemonVersionResult({ version: ' 0.1.15 ', error: null })).toEqual({
|
||||
version: '0.1.15',
|
||||
error: null,
|
||||
})
|
||||
})
|
||||
|
||||
it('builds copyable daemon update diagnostics', async () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Platform } from 'react-native'
|
||||
import type { HostProfile } from '@/contexts/daemon-registry-context'
|
||||
import { getTauri } from '@/utils/tauri'
|
||||
import { invokeDesktopCommand } from '@/desktop/tauri/invoke-desktop-command'
|
||||
|
||||
@@ -23,6 +22,11 @@ export interface LocalDaemonUpdateResult {
|
||||
stderr: string
|
||||
}
|
||||
|
||||
export interface LocalDaemonVersionResult {
|
||||
version: string | null
|
||||
error: string | null
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
@@ -44,24 +48,26 @@ function toNumberOr(defaultValue: number, value: unknown): number {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value : defaultValue
|
||||
}
|
||||
|
||||
function isLikelyLocalDirectEndpoint(endpoint: string): boolean {
|
||||
const normalized = endpoint.trim().toLowerCase()
|
||||
return (
|
||||
normalized === 'localhost' ||
|
||||
normalized.startsWith('localhost:') ||
|
||||
normalized === '127.0.0.1' ||
|
||||
normalized.startsWith('127.0.0.1:') ||
|
||||
normalized === '::1' ||
|
||||
normalized.startsWith('::1:') ||
|
||||
normalized === '[::1]' ||
|
||||
normalized.startsWith('[::1]:')
|
||||
)
|
||||
}
|
||||
|
||||
export function shouldShowDesktopUpdateSection(): boolean {
|
||||
return Platform.OS === 'web' && getTauri() !== null
|
||||
}
|
||||
|
||||
export function parseLocalDaemonVersionResult(raw: unknown): LocalDaemonVersionResult {
|
||||
if (!isRecord(raw)) {
|
||||
return { version: null, error: 'Unexpected response from version check.' }
|
||||
}
|
||||
|
||||
return {
|
||||
version: toStringOrNull(raw.version),
|
||||
error: toStringOrNull(raw.error),
|
||||
}
|
||||
}
|
||||
|
||||
export async function getLocalDaemonVersion(): Promise<LocalDaemonVersionResult> {
|
||||
const result = await invokeDesktopCommand<unknown>('get_local_daemon_version')
|
||||
return parseLocalDaemonVersionResult(result)
|
||||
}
|
||||
|
||||
export async function checkDesktopAppUpdate(): Promise<DesktopAppUpdateCheckResult> {
|
||||
const result = await invokeDesktopCommand<unknown>('check_app_update')
|
||||
if (!isRecord(result)) {
|
||||
@@ -135,27 +141,6 @@ export function formatVersionWithPrefix(version: string | null | undefined): str
|
||||
return value.startsWith('v') ? value : `v${value}`
|
||||
}
|
||||
|
||||
export function findLikelyLocalDaemonHost(daemons: HostProfile[]): HostProfile | null {
|
||||
if (daemons.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const localhostDaemon = daemons.find((daemon) => isLikelyLocalHost(daemon))
|
||||
|
||||
return localhostDaemon ?? daemons[0] ?? null
|
||||
}
|
||||
|
||||
export function isLikelyLocalHost(host: HostProfile | null | undefined): boolean {
|
||||
if (!host) {
|
||||
return false
|
||||
}
|
||||
|
||||
return host.connections.some(
|
||||
(connection) =>
|
||||
connection.type === 'direct' && isLikelyLocalDirectEndpoint(connection.endpoint)
|
||||
)
|
||||
}
|
||||
|
||||
export function buildDaemonUpdateDiagnostics(result: LocalDaemonUpdateResult): string {
|
||||
const stdout = result.stdout.length > 0 ? result.stdout : '(empty)'
|
||||
const stderr = result.stderr.length > 0 ? result.stderr : '(empty)'
|
||||
|
||||
Reference in New Issue
Block a user