Files
orca/mobile/src/session/MobileDiffReviewRouteScreen.tsx
T
Neil aa07d5891a fix(mobile): break the transport and terminal-document import cycles, and gate cycles after mobile's install (#30290)
* fix(mobile): break the transport and terminal-document import cycles and gate them after mobile's install

client-context re-exported the host-client hooks, which import client-context back: the re-export
barrel is gone and importers (and their test mocks) name host-client-hooks directly. In the terminal
document, the cell-metric getters move to a leaf cell-metrics module and select-mode entry/exit to
selection-mode, so fit, transform, overlay and range no longer import each other. pr.yml lints imports
before mobile's install, when mobile's tsconfig can't load, so Mobile verify now runs the same import
rules over mobile after its install with zero warnings allowed.

* fix(mobile): the browser-pane render harness imports useHostClient from host-client-hooks

Its route source is a template string, so no typecheck saw the removed client-context re-export; the mobile web bundle check did.

* fix(ci): the e2e typecheck ratchet counts the same with or without mobile's install

Specs reach mobile/src/transport, whose expo-crypto and async-storage imports resolve only after mobile's install and then load React Native's globals (numeric timers, a required NODE_ENV), adding errors in unrelated specs. An empty stub pins both, so the static job reads 232 either way.
2026-10-18 04:00:24 -07:00

67 lines
2.8 KiB
TypeScript

import { useCallback, useMemo } from 'react'
import { useLocalSearchParams } from 'expo-router'
import { MobileDiffReviewScreenView } from '../components/MobileDiffReviewScreenView'
import { firstReviewParam, normalizeReviewFilterParam } from './mobile-diff-review-screen-model'
import { normalizeReviewAreaParam } from './mobile-diff-review-positioning'
import { useMobileDiffReviewController } from './use-mobile-diff-review-controller'
import { useForceReconnect } from '../transport/host-client-hooks'
import { useWorkspaceClient } from '../transport/use-workspace-client'
import { useHostProtocolGates } from '../components/host-protocol-gates-context'
import { useWorkspaceRouteHandoff } from '../navigation/workspace-route-handoff'
/**
* The review screen as a component rather than a route module: the page's route file mounts it, and
* the native route file, which mounts the shell, cannot be imported by the page. It reads its own
* params.
*/
export function MobileDiffReviewRouteScreen() {
const params = useLocalSearchParams<{
hostId?: string | string[]
worktreeId?: string | string[]
name?: string | string[]
scope?: string | string[]
file?: string | string[]
area?: string | string[]
}>()
const hostId = firstReviewParam(params.hostId)
const worktreeId = firstReviewParam(params.worktreeId)
const name = firstReviewParam(params.name)
const initialFilter = normalizeReviewFilterParam(firstReviewParam(params.scope))
const initialFile = firstReviewParam(params.file)
const initialArea = normalizeReviewAreaParam(firstReviewParam(params.area))
const initialTarget = useMemo(
() => (initialFile && initialArea ? { filePath: initialFile, area: initialArea } : null),
[initialArea, initialFile]
)
// Not `useRouter`: inside the shell's page the session screen is native, so that replace has to
// be handed back to the app rather than posted into a document that does not render it.
const router = useWorkspaceRouteHandoff()
const { client, state: connState } = useWorkspaceClient(hostId)
const forceReconnect = useForceReconnect()
const openSession = useCallback(() => {
const query = name ? `?${new URLSearchParams({ name }).toString()}` : ''
router.replace(
`/h/${encodeURIComponent(hostId)}/session/${encodeURIComponent(worktreeId)}${query}`
)
}, [hostId, name, router, worktreeId])
const { hostCapabilities, statusPending, statusReadable } = useHostProtocolGates()
const controller = useMobileDiffReviewController({
client,
connState,
hostCapabilities,
hostStatusPending: statusPending,
hostStatusReadable: statusReadable,
hostId,
worktreeId,
name,
initialFilter,
initialTarget,
onOpenSession: openSession,
onReconnect: forceReconnect
})
return <MobileDiffReviewScreenView controller={controller} onBack={() => router.back()} />
}