From 9760bd17dc50fd335e665cfe0ffa73178a176f2b Mon Sep 17 00:00:00 2001 From: root Date: Thu, 1 Jan 2026 03:08:35 +0800 Subject: [PATCH] fix(web): preserve machine/path selection in new session screen On web, the NewSessionScreen component could be unmounted during navigation to picker screens, causing the module-level callback handlers to be reset to empty functions. This resulted in machine and path selections being lost when returning from picker screens. Fix by using URL parameters to pass selections back from picker screens, which works reliably even when components are remounted. The callback mechanism is kept for native platforms where it works. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- sources/app/(app)/new/index.tsx | 26 ++++++++++++++++++++++++-- sources/app/(app)/new/pick/machine.tsx | 3 ++- sources/app/(app)/new/pick/path.tsx | 7 ++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sources/app/(app)/new/index.tsx b/sources/app/(app)/new/index.tsx index 141a9949b..679700845 100644 --- a/sources/app/(app)/new/index.tsx +++ b/sources/app/(app)/new/index.tsx @@ -3,7 +3,7 @@ import { View, Text, Platform, Pressable, useWindowDimensions } from 'react-nati import { Typography } from '@/constants/Typography'; import { useAllMachines, storage, useSetting } from '@/sync/storage'; import { Ionicons } from '@expo/vector-icons'; -import { useRouter, useLocalSearchParams } from 'expo-router'; +import { useRouter, useLocalSearchParams, useFocusEffect } from 'expo-router'; import { useUnistyles } from 'react-native-unistyles'; import { layout } from '@/components/layout'; import { t } from '@/text'; @@ -87,7 +87,7 @@ const updateRecentMachinePaths = ( function NewSessionScreen() { const { theme } = useUnistyles(); const router = useRouter(); - const { prompt, dataId } = useLocalSearchParams<{ prompt?: string; dataId?: string }>(); + const { prompt, dataId, selectedMachineParam, selectedPathParam } = useLocalSearchParams<{ prompt?: string; dataId?: string; selectedMachineParam?: string; selectedPathParam?: string }>(); // Try to get data from temporary store first, fallback to direct prompt parameter const tempSessionData = React.useMemo(() => { @@ -202,6 +202,28 @@ function NewSessionScreen() { }; }, []); + // Handle URL parameters from picker screens (for web compatibility) + React.useEffect(() => { + if (selectedMachineParam) { + const machine = storage.getState().machines[selectedMachineParam]; + if (machine) { + setSelectedMachineId(selectedMachineParam); + const bestPath = getRecentPathForMachine(selectedMachineParam, recentMachinePaths); + setSelectedPath(bestPath); + } + // Clear the URL parameter to prevent re-processing + router.setParams({ selectedMachineParam: undefined }); + } + }, [selectedMachineParam, recentMachinePaths]); + + React.useEffect(() => { + if (selectedPathParam) { + setSelectedPath(selectedPathParam); + // Clear the URL parameter to prevent re-processing + router.setParams({ selectedPathParam: undefined }); + } + }, [selectedPathParam]); + const handleMachineClick = React.useCallback(() => { router.push('/new/pick/machine'); }, []); diff --git a/sources/app/(app)/new/pick/machine.tsx b/sources/app/(app)/new/pick/machine.tsx index f1262bced..6fff63b11 100644 --- a/sources/app/(app)/new/pick/machine.tsx +++ b/sources/app/(app)/new/pick/machine.tsx @@ -75,7 +75,8 @@ export default function MachinePickerScreen() { const handleSelectMachine = (machineId: string) => { callbacks.onMachineSelected(machineId); - router.back(); + // Navigate back with the selected machine ID as a parameter (for web compatibility) + router.navigate({ pathname: '/new', params: { selectedMachineParam: machineId } }); }; if (machines.length === 0) { diff --git a/sources/app/(app)/new/pick/path.tsx b/sources/app/(app)/new/pick/path.tsx index a648a42f1..ae6c411cc 100644 --- a/sources/app/(app)/new/pick/path.tsx +++ b/sources/app/(app)/new/pick/path.tsx @@ -122,10 +122,11 @@ export default function PathPickerScreen() { const handleSelectPath = React.useCallback(() => { const pathToUse = customPath.trim() || machine?.metadata?.homeDir || '/home'; - // Set the selection and go back + // Set the selection via callback (for native) and navigate with params (for web compatibility) + // Also pass the machineId to preserve the machine selection callbacks.onPathSelected(pathToUse); - router.back(); - }, [customPath, router, machine]); + router.navigate({ pathname: '/new', params: { selectedPathParam: pathToUse, selectedMachineParam: params.machineId } }); + }, [customPath, router, machine, params.machineId]); if (!machine) { return (