Fix workspace route state syncing
This commit is contained in:
@@ -1,16 +1,22 @@
|
|||||||
import { useGlobalSearchParams, usePathname } from 'expo-router'
|
import { useLocalSearchParams } from 'expo-router'
|
||||||
import { WorkspaceScreen } from '@/screens/workspace/workspace-screen'
|
import { WorkspaceScreen } from '@/screens/workspace/workspace-screen'
|
||||||
import {
|
import {
|
||||||
parseHostWorkspaceRouteFromPathname,
|
decodeWorkspaceIdFromPathSegment,
|
||||||
parseWorkspaceOpenIntent,
|
parseWorkspaceOpenIntent,
|
||||||
} from '@/utils/host-routes'
|
} from '@/utils/host-routes'
|
||||||
|
|
||||||
export default function HostWorkspaceLayout() {
|
export default function HostWorkspaceLayout() {
|
||||||
const expoPathname = usePathname()
|
const params = useLocalSearchParams<{
|
||||||
const params = useGlobalSearchParams<{ open?: string | string[] }>()
|
serverId?: string | string[]
|
||||||
const activeRoute = parseHostWorkspaceRouteFromPathname(expoPathname)
|
workspaceId?: string | string[]
|
||||||
const serverId = activeRoute?.serverId ?? ''
|
open?: string | string[]
|
||||||
const workspaceId = activeRoute?.workspaceId ?? ''
|
}>()
|
||||||
|
const serverValue = Array.isArray(params.serverId) ? params.serverId[0] : params.serverId
|
||||||
|
const workspaceValue = Array.isArray(params.workspaceId)
|
||||||
|
? params.workspaceId[0]
|
||||||
|
: params.workspaceId
|
||||||
|
const serverId = serverValue?.trim() ?? ''
|
||||||
|
const workspaceId = workspaceValue ? (decodeWorkspaceIdFromPathSegment(workspaceValue) ?? '') : ''
|
||||||
const openValue = Array.isArray(params.open) ? params.open[0] : params.open
|
const openValue = Array.isArray(params.open) ? params.open[0] : params.open
|
||||||
const openIntent = parseWorkspaceOpenIntent(openValue)
|
const openIntent = parseWorkspaceOpenIntent(openValue)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import Animated, {
|
|||||||
withRepeat,
|
withRepeat,
|
||||||
withTiming,
|
withTiming,
|
||||||
} from "react-native-reanimated";
|
} from "react-native-reanimated";
|
||||||
|
import { WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
|
||||||
import { Fonts } from "@/constants/theme";
|
import { Fonts } from "@/constants/theme";
|
||||||
import * as Clipboard from "expo-clipboard";
|
import * as Clipboard from "expo-clipboard";
|
||||||
import {
|
import {
|
||||||
@@ -581,13 +582,12 @@ export function FileExplorerPane({
|
|||||||
style={({ hovered, pressed }) => [
|
style={({ hovered, pressed }) => [
|
||||||
styles.iconButton,
|
styles.iconButton,
|
||||||
(hovered || pressed) && styles.iconButtonHovered,
|
(hovered || pressed) && styles.iconButtonHovered,
|
||||||
pressed && styles.iconButtonPressed,
|
|
||||||
]}
|
]}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel="Refresh files"
|
accessibilityLabel="Refresh files"
|
||||||
>
|
>
|
||||||
<Animated.View style={[styles.refreshIcon, refreshIconAnimatedStyle]}>
|
<Animated.View style={[styles.refreshIcon, refreshIconAnimatedStyle]}>
|
||||||
<RotateCw size={16} color={theme.colors.foregroundMuted} />
|
<RotateCw size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
||||||
@@ -875,7 +875,7 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
height: 32 + theme.spacing[2] * 2,
|
height: WORKSPACE_SECONDARY_HEADER_HEIGHT,
|
||||||
paddingHorizontal: theme.spacing[3],
|
paddingHorizontal: theme.spacing[3],
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: theme.colors.border,
|
borderBottomColor: theme.colors.border,
|
||||||
@@ -898,7 +898,7 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
},
|
},
|
||||||
sortButton: {
|
sortButton: {
|
||||||
height: 32,
|
height: 28,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -1025,8 +1025,8 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
fontWeight: theme.fontWeight.normal,
|
fontWeight: theme.fontWeight.normal,
|
||||||
},
|
},
|
||||||
iconButton: {
|
iconButton: {
|
||||||
width: 32,
|
width: 22,
|
||||||
height: 32,
|
height: 22,
|
||||||
borderRadius: theme.borderRadius.md,
|
borderRadius: theme.borderRadius.md,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -1034,10 +1034,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
iconButtonHovered: {
|
iconButtonHovered: {
|
||||||
backgroundColor: theme.colors.surface2,
|
backgroundColor: theme.colors.surface2,
|
||||||
},
|
},
|
||||||
iconButtonPressed: {
|
|
||||||
opacity: 0.8,
|
|
||||||
transform: [{ scale: 0.96 }],
|
|
||||||
},
|
|
||||||
refreshIcon: {
|
refreshIcon: {
|
||||||
width: 16,
|
width: 16,
|
||||||
height: 16,
|
height: 16,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { useCheckoutStatusQuery } from "@/hooks/use-checkout-status-query";
|
|||||||
import { useCheckoutPrStatusQuery } from "@/hooks/use-checkout-pr-status-query";
|
import { useCheckoutPrStatusQuery } from "@/hooks/use-checkout-pr-status-query";
|
||||||
import { useHorizontalScrollOptional } from "@/contexts/horizontal-scroll-context";
|
import { useHorizontalScrollOptional } from "@/contexts/horizontal-scroll-context";
|
||||||
import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context";
|
import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context";
|
||||||
|
import { WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
|
||||||
import { Fonts } from "@/constants/theme";
|
import { Fonts } from "@/constants/theme";
|
||||||
import { shouldAnchorHeaderBeforeCollapse } from "@/utils/git-diff-scroll";
|
import { shouldAnchorHeaderBeforeCollapse } from "@/utils/git-diff-scroll";
|
||||||
import {
|
import {
|
||||||
@@ -1086,11 +1087,12 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
diffStatusContainer: {
|
diffStatusContainer: {
|
||||||
paddingVertical: 1.5,
|
height: WORKSPACE_SECONDARY_HEADER_HEIGHT,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: theme.colors.border,
|
borderBottomColor: theme.colors.border,
|
||||||
},
|
},
|
||||||
diffStatusInner: {
|
diffStatusInner: {
|
||||||
|
flex: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
type ReactElement,
|
type ReactElement,
|
||||||
type MutableRefObject,
|
type MutableRefObject,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { router, usePathname } from 'expo-router'
|
import { router, useGlobalSearchParams, usePathname } from 'expo-router'
|
||||||
import { navigateToWorkspace } from '@/hooks/use-workspace-navigation'
|
import { navigateToWorkspace } from '@/hooks/use-workspace-navigation'
|
||||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from 'react-native-unistyles'
|
import { StyleSheet, UnistylesRuntime, useUnistyles } from 'react-native-unistyles'
|
||||||
import { type GestureType } from 'react-native-gesture-handler'
|
import { type GestureType } from 'react-native-gesture-handler'
|
||||||
@@ -35,8 +35,10 @@ import { projectIconQueryKey } from '@/hooks/use-project-icon-query'
|
|||||||
import {
|
import {
|
||||||
buildHostNewAgentRoute,
|
buildHostNewAgentRoute,
|
||||||
buildHostWorkspaceRoute,
|
buildHostWorkspaceRoute,
|
||||||
|
decodeWorkspaceIdFromPathSegment,
|
||||||
parseHostWorkspaceRouteFromPathname,
|
parseHostWorkspaceRouteFromPathname,
|
||||||
} from '@/utils/host-routes'
|
} from '@/utils/host-routes'
|
||||||
|
import { normalizeWorkspaceIdentity } from '@/utils/workspace-identity'
|
||||||
import {
|
import {
|
||||||
type SidebarProjectEntry,
|
type SidebarProjectEntry,
|
||||||
type SidebarWorkspaceEntry,
|
type SidebarWorkspaceEntry,
|
||||||
@@ -1210,6 +1212,10 @@ export function SidebarWorkspaceList({
|
|||||||
const isMobile = UnistylesRuntime.breakpoint === 'xs' || UnistylesRuntime.breakpoint === 'sm'
|
const isMobile = UnistylesRuntime.breakpoint === 'xs' || UnistylesRuntime.breakpoint === 'sm'
|
||||||
const isNative = Platform.OS !== 'web'
|
const isNative = Platform.OS !== 'web'
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
|
const routeParams = useGlobalSearchParams<{
|
||||||
|
serverId?: string | string[]
|
||||||
|
workspaceId?: string | string[]
|
||||||
|
}>()
|
||||||
const isTauri = getIsTauri()
|
const isTauri = getIsTauri()
|
||||||
const altDown = useKeyboardShortcutsStore((state) => state.altDown)
|
const altDown = useKeyboardShortcutsStore((state) => state.altDown)
|
||||||
const cmdOrCtrlDown = useKeyboardShortcutsStore((state) => state.cmdOrCtrlDown)
|
const cmdOrCtrlDown = useKeyboardShortcutsStore((state) => state.cmdOrCtrlDown)
|
||||||
@@ -1224,15 +1230,36 @@ export function SidebarWorkspaceList({
|
|||||||
if (!pathname) {
|
if (!pathname) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const parsed = parseHostWorkspaceRouteFromPathname(pathname)
|
if (!parseHostWorkspaceRouteFromPathname(pathname)) {
|
||||||
if (!parsed) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
serverId: parsed.serverId,
|
const serverValue = Array.isArray(routeParams.serverId)
|
||||||
workspaceId: parsed.workspaceId,
|
? routeParams.serverId[0]
|
||||||
|
: routeParams.serverId
|
||||||
|
const workspaceValue = Array.isArray(routeParams.workspaceId)
|
||||||
|
? routeParams.workspaceId[0]
|
||||||
|
: routeParams.workspaceId
|
||||||
|
const serverId = serverValue?.trim() ?? ''
|
||||||
|
const workspaceId = normalizeWorkspaceIdentity(
|
||||||
|
workspaceValue ? decodeWorkspaceIdFromPathSegment(workspaceValue) : null
|
||||||
|
)
|
||||||
|
if (!serverId || !workspaceId) {
|
||||||
|
const parsed = parseHostWorkspaceRouteFromPathname(pathname)
|
||||||
|
if (!parsed) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
serverId: parsed.serverId,
|
||||||
|
workspaceId: parsed.workspaceId,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [pathname])
|
|
||||||
|
return {
|
||||||
|
serverId,
|
||||||
|
workspaceId,
|
||||||
|
}
|
||||||
|
}, [pathname, routeParams.serverId, routeParams.workspaceId])
|
||||||
|
|
||||||
const projectIconRequests = useMemo(() => {
|
const projectIconRequests = useMemo(() => {
|
||||||
if (!serverId) {
|
if (!serverId) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const FOOTER_HEIGHT = 75;
|
|||||||
// This ensures both headers have the same visual height
|
// This ensures both headers have the same visual height
|
||||||
export const HEADER_INNER_HEIGHT = 48;
|
export const HEADER_INNER_HEIGHT = 48;
|
||||||
export const HEADER_INNER_HEIGHT_MOBILE = 56;
|
export const HEADER_INNER_HEIGHT_MOBILE = 56;
|
||||||
|
export const WORKSPACE_SECONDARY_HEADER_HEIGHT = 36;
|
||||||
export const HEADER_TOP_PADDING_MOBILE = 8;
|
export const HEADER_TOP_PADDING_MOBILE = 8;
|
||||||
|
|
||||||
// Max width for chat content (stream view, input area, new agent form)
|
// Max width for chat content (stream view, input area, new agent form)
|
||||||
|
|||||||
Reference in New Issue
Block a user