From c2cae205ac9359c3c3204533fa36e58e4bbbccb3 Mon Sep 17 00:00:00 2001 From: Greg Pstrucha <875316+Gricha@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:46:46 -0800 Subject: [PATCH] Add workspace switcher dropdown in mobile navbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tap the workspace name in the detail screen header to show a dropdown with all workspaces. Select one to quickly switch between workspaces without going back to the home screen. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- mobile/src/screens/WorkspaceDetailScreen.tsx | 119 ++++++++++++++++++- 1 file changed, 116 insertions(+), 3 deletions(-) diff --git a/mobile/src/screens/WorkspaceDetailScreen.tsx b/mobile/src/screens/WorkspaceDetailScreen.tsx index 69c1631b..667a660b 100644 --- a/mobile/src/screens/WorkspaceDetailScreen.tsx +++ b/mobile/src/screens/WorkspaceDetailScreen.tsx @@ -110,6 +110,7 @@ export function WorkspaceDetailScreen({ route, navigation }: any) { const [agentFilter, setAgentFilter] = useState(undefined) const [showAgentPicker, setShowAgentPicker] = useState(false) const [showNewChatPicker, setShowNewChatPicker] = useState(false) + const [showWorkspacePicker, setShowWorkspacePicker] = useState(false) const isHost = name === HOST_WORKSPACE_NAME @@ -126,6 +127,11 @@ export function WorkspaceDetailScreen({ route, navigation }: any) { enabled: isHost, }) + const { data: allWorkspaces } = useQuery({ + queryKey: ['workspaces'], + queryFn: api.listWorkspaces, + }) + const isRunning = isHost ? true : workspace?.status === 'running' const isCreating = isHost ? false : workspace?.status === 'creating' @@ -170,10 +176,14 @@ export function WorkspaceDetailScreen({ route, navigation }: any) { navigation.goBack()} style={styles.backBtn}> ‹ - - {displayName} + setShowWorkspacePicker(!showWorkspacePicker)} + > + {displayName} - + ▼ + {isHost ? ( ) : ( @@ -259,6 +269,43 @@ export function WorkspaceDetailScreen({ route, navigation }: any) { )} + {showWorkspacePicker && ( + + setShowWorkspacePicker(false)} /> + + Switch workspace + {allWorkspaces?.map((ws) => ( + { + setShowWorkspacePicker(false) + if (ws.name !== name) { + navigation.replace('WorkspaceDetail', { name: ws.name }) + } + }} + > + + {ws.name} + {ws.name === name && ✓} + + ))} + {!isHost && ( + { + setShowWorkspacePicker(false) + navigation.replace('WorkspaceDetail', { name: HOST_WORKSPACE_NAME }) + }} + > + + Host Machine + + )} + + + )} + {isHost && ( @@ -602,4 +649,70 @@ const styles = StyleSheet.create({ fontWeight: '700', color: '#fff', }, + headerChevron: { + fontSize: 10, + color: '#8e8e93', + marginLeft: 4, + }, + workspacePickerOverlay: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: 100, + }, + workspacePickerBackdrop: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: 'rgba(0,0,0,0.5)', + }, + workspacePicker: { + position: 'absolute', + top: 60, + left: 50, + right: 50, + backgroundColor: '#2c2c2e', + borderRadius: 12, + padding: 12, + }, + workspacePickerTitle: { + fontSize: 13, + fontWeight: '600', + color: '#8e8e93', + marginBottom: 12, + textAlign: 'center', + }, + workspacePickerItem: { + flexDirection: 'row', + alignItems: 'center', + paddingVertical: 12, + paddingHorizontal: 12, + borderRadius: 8, + gap: 10, + }, + workspacePickerItemActive: { + backgroundColor: '#3c3c3e', + }, + workspacePickerItemText: { + fontSize: 16, + color: '#fff', + flex: 1, + }, + workspacePickerItemTextActive: { + fontWeight: '600', + }, + workspaceStatusDot: { + width: 8, + height: 8, + borderRadius: 4, + }, + workspaceCheckmark: { + fontSize: 14, + color: '#0a84ff', + fontWeight: '600', + }, })