Files
orca/mobile/src/session/MobileSessionHeaderMoreMenu.tsx
T
NeilandKelvin Amoaba 5d61e00c6d build(mobile): upgrade to Expo SDK 58 and React Native 0.88 (#37935)
* build(mobile): upgrade to Expo SDK 58 and React Native 0.88

Expo 58 drops Zod from @expo/cli, which clears the last Zod 3 advisory
(GHSA-mrhx-c7xc-m3w5) in mobile along with its local patch and override.

- Expo 55 -> 58, React Native 0.83 -> 0.88, React 19.3, gesture-handler 3,
  webview 14, reanimated 4.7, worklets 0.13 (SDK 58 bundled versions,
  pinned below today's batch to respect minimumReleaseAge).
- Port the react-native and react-native-webview patches unchanged; drop
  expo-constants, expo-notifications, @expo/cli, expo-router, zod and
  query-string patches plus the zod/query-string/xcode>uuid overrides,
  which upstream fixed or no longer need.
- iOS minimum rises to 16.4 (Expo 58 / RN 0.88 requirement).
- Migrate to RN 0.88 strict types: instance ref types, NamedStyles,
  AppState.currentState, list header/footer nulls.
- Replace removed runtime APIs: InteractionManager -> idle callback with a
  macrotask fallback; StyleSheet.absoluteFillObject -> absoluteFill;
  FileHandle.readBytes -> readBytesSync (it became async).
- Resolve react-native/asset-registry for shared assets in Metro and alias
  the old registry path for react-native-svg in the desktop mobile-web bundle.
- Reduce the iOS scene plugin to the reconnect override; Expo 58's template
  now ships the scene delegate itself.

* fix(mobile): bridge react-native-svg web imports and libsodium runtime for RN 0.88

- Share react-native-svg web shims between the mobile-web build and its render
  checks: map the old asset-registry path to react-native-web's registry and stub
  the Android-only touch-sound TurboModule.
- Patch react-native-libsodium 1.7.0 to read the JSI runtime from the bridge proxy;
  RN 0.88 removed RCTCxxBridge.runtime.

* fix(mobile): use Expo 58's legacy promise resolver for audio permissions

* fix(mobile): skip null handles in the RPC recording timer shims for RN 0.88 types

* style(mobile): format MobilePRSidebar after rebase

* fix(mobile): name RN 0.88 text input refs for declarations; allow queued back in stack render check

- Type text input refs with an exported interface so declaration emit can name hook results
  (RN 0.88 aliases TextInputInstance to an unexported class).
- Expo Router 58 drains back() after a commit; check the interrupted push's exit from the
  frame it starts, bounded to three frames of lag.

* chore(mobile): justify the text input handle interface for React Doctor

* chore(mobile): use a nameable intersection alias for text input refs

* fix(mobile): use sync expo-file-system writes, copies and moves on Expo 58

Expo 58 made File.write/copy/move and FileHandle.writeBytes return promises.
Our callers never awaited them, so failures escaped their try/catch and the
store's tmp-then-move and PDF writes could race their close or rename.

* build(mobile): raise the page bundle budget to 10 MiB for Expo 58

Expo 58 adds about 310 KB to the page: expo-router (+258 KB, now carrying
React Navigation, net about +110 KB) and Reanimated 4.7 (+152 KB). Main had
85 KB of headroom left. 10 MiB still stays within the 10 MiB per-asset contract.

* fix(mobile): drop the window-metrics seed RN 0.88 removed from Android

RN 0.88 no longer holds window metrics: DeviceInfoModule reads the activity's
WindowMetrics on demand and setWindowDisplayMetrics is gone, so MainActivity
no longer compiled. Layout scale still comes from the screen metrics we reseed.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-11-11 23:30:02 +00:00

138 lines
4.1 KiB
TypeScript

import type { RefObject } from 'react'
import type { HostInstance } from 'react-native'
import {
Columns2,
Folder,
GitBranch,
ListChecks,
Plus,
SquareChevronRight
} from 'lucide-react-native'
import { MobileAgentSessionHistoryIcon } from '../agent-history/MobileAgentSessionHistoryIcon'
import type { ActionSheetAction } from '../components/ActionSheetModal'
import { PullDownMenu } from '../components/nav-bar/PullDownMenu'
import { colors } from '../theme/mobile-theme'
import { useMobileColorScheme } from '../theme/use-mobile-color-scheme'
import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { MobileSessionController } from './use-mobile-session-controller'
type Props = {
controller: MobileSessionController
anchorRef: RefObject<HostInstance | null>
/** A narrow sideways header also moves source control and New tab in here. */
actionsCollapsed: boolean
}
export function MobileSessionHeaderMoreMenu({ controller, anchorRef, actionsCollapsed }: Props) {
useMobileColorScheme()
const t = useMobileTranslation()
const {
isFloatingWorkspaceRoute,
showHeaderMoreActions,
setShowHeaderMoreActions,
showAgentSessionHistoryAction,
showChecksAction,
openAgentSessionHistory,
handlePanelTap,
canSplitTerminals,
terminalSplitActive,
setShowTerminalLayout,
connState,
createTabBusy,
handleOpenNewTab,
handleOpenQuickCommands
} = controller
const tabActionsDisabled = createTabBusy || connState !== 'connected'
const panels: ActionSheetAction[] = [
...(!isFloatingWorkspaceRoute
? [
{
id: 'files',
label: t('session.header.fileExplorer', 'File explorer'),
icon: Folder,
closeBeforePress: true,
onPress: () => handlePanelTap('files')
}
]
: []),
...(actionsCollapsed && !isFloatingWorkspaceRoute
? [
{
id: 'sourceControl',
label: t('session.header.sourceControl', 'Source control'),
icon: GitBranch,
closeBeforePress: true,
onPress: () => handlePanelTap('sourceControl')
}
]
: []),
...(showChecksAction
? [
{
id: 'checks',
label: t('session.headerMoreActionsSheet.checks', 'Checks'),
hint: t('session.headerMoreActionsSheet.checksHint', 'Open pull request checks'),
icon: ListChecks,
onPress: () => handlePanelTap('pr')
}
]
: []),
...(showAgentSessionHistoryAction
? [
{
id: 'agentHistory',
label: t('session.headerMoreActionsSheet.agentHistory', 'Agent History'),
hint: t(
'session.headerMoreActionsSheet.agentHistoryHint',
'Browse and resume agent sessions'
),
renderIcon: () => (
<MobileAgentSessionHistoryIcon size={17} color={colors.textPrimary} strokeWidth={2} />
),
onPress: openAgentSessionHistory
}
]
: []),
{
id: 'quickCommands',
label: t('session.header.quickCommands', 'Quick commands'),
icon: SquareChevronRight,
disabled: tabActionsDisabled,
closeBeforePress: true,
onPress: handleOpenQuickCommands
}
]
const view: ActionSheetAction[] =
canSplitTerminals || terminalSplitActive
? [
{
id: 'terminalLayout',
label: t('session.header.terminalLayout', 'Terminal layout'),
icon: Columns2,
closeBeforePress: true,
onPress: () => setShowTerminalLayout(true)
}
]
: []
const tabs: ActionSheetAction[] = actionsCollapsed
? [
{
id: 'newTab',
label: t('session.header.newTab', 'New tab'),
icon: Plus,
disabled: tabActionsDisabled,
closeBeforePress: true,
onPress: handleOpenNewTab
}
]
: []
return (
<PullDownMenu
visible={showHeaderMoreActions}
anchorRef={anchorRef}
groups={[panels, view, tabs]}
onClose={() => setShowHeaderMoreActions(false)}
/>
)
}