refactor(mobile): remove unused PR and review code (#13404)

This commit is contained in:
Neil 2026-08-09 18:30:44 -07:00 committed by GitHub
parent ced2719b26
commit 954de38507
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 12 additions and 145 deletions

View File

@ -1,52 +0,0 @@
import { Linking } from 'react-native'
import { BottomDrawer } from './BottomDrawer'
import { MobilePrComposeForm, type PrComposePrefill } from './pr-sidebar/MobilePrComposeForm'
import type { RpcClient } from '../transport/rpc-client'
type Props = {
visible: boolean
client: RpcClient | null
worktreeId: string
prefill: PrComposePrefill
// Head branch — enables the base≠head guard and the "from <branch>" hint.
head?: string | null
onClose: () => void
onCreated: (url: string, warning?: string) => void
}
// BottomDrawer wrapper around the inline compose form, for full-screen roots
// (source-control modals). The PR sidebar empty-state renders MobilePrComposeForm
// inline instead, since a BottomDrawer overlay nested in a ScrollView clips it.
export function MobilePrComposeSheet({
visible,
client,
worktreeId,
prefill,
head,
onClose,
onCreated
}: Props) {
return (
<BottomDrawer visible={visible} onClose={onClose}>
{/* Why: key on visible + prefill fields so reopening (or a new prefill)
remounts the form with fresh initial values; the previous sheet reset
its fields via an effect on the same signals. */}
<MobilePrComposeForm
key={`${visible}:${prefill.title}:${prefill.base}:${prefill.body}`}
client={client}
worktreeId={worktreeId}
prefill={prefill}
head={head}
onCancel={onClose}
onCreated={onCreated}
/>
</BottomDrawer>
)
}
export function openMobilePrUrl(url: string): void {
// Why: Linking.openURL rejects when iOS/Android can't open the URL (no app,
// bad scheme, etc.). Without a catch that surfaces as LogBox "Uncaught
// (in promise) Error: Unable to open URL…" over the PR screen.
void Linking.openURL(url).catch(() => {})
}

View File

@ -0,0 +1,6 @@
import { Linking } from 'react-native'
export function openMobilePrUrl(url: string): void {
// Prevent unhandled rejections when no app accepts the URL.
void Linking.openURL(url).catch(() => {})
}

View File

@ -38,11 +38,7 @@ type Props = {
onCreated: (url: string, warning?: string) => void
}
// PR compose form body: title/body/base/draft with AI prefill (git.generate
// PullRequestFields), submitting via createMobilePr. Renders a plain View so it
// can sit inline inside the PR sidebar's existing ScrollView (a BottomDrawer
// overlay trapped in a ScrollView clips the form). The BottomDrawer wrapper
// MobilePrComposeSheet reuses this body at full-screen roots.
// A plain View keeps the compose form usable inside the PR sidebar ScrollView.
export function MobilePrComposeForm({
client,
worktreeId,

View File

@ -7,7 +7,7 @@ import type { MobilePrTitleAction } from '../../session/use-mobile-pr-title-acti
import { prStateBadge } from './pr-checks-presentation'
import { statusColor } from './pr-sidebar-status-color'
import { canEditPRTitle } from '../../session/pr-title-edit'
import { openMobilePrUrl } from '../MobilePrComposeSheet'
import { openMobilePrUrl } from '../mobile-pr-url'
import { mobilePrSidebarStyles as styles } from './mobile-pr-sidebar-styles'
import { prCommentComposerStyles as composerStyles } from './pr-comment-composer-styles'

View File

@ -18,7 +18,7 @@ import {
runMobileHostedReviewCreateIntent
} from '../../source-control/mobile-hosted-review-create-intent-runner'
import { fetchWorktreeLinkedPR } from '../../source-control/mobile-pr-link'
import { openMobilePrUrl } from '../MobilePrComposeSheet'
import { openMobilePrUrl } from '../mobile-pr-url'
import { MobileLinkPrForm } from './MobileLinkPrForm'
import { prCreateEmptyStateStyles as styles } from './pr-create-empty-state-styles'

View File

@ -104,31 +104,6 @@ export function mergeMobileDiffReviewState(
}
}
export function markMobileDiffReviewFileOpened(
state: MobileDiffReviewState,
descriptor: MobileDiffReviewFileDescriptor,
now: number
): MobileDiffReviewState {
const previous = state.files[descriptor.key]
return {
...state,
updatedAt: now,
files: {
...state.files,
[descriptor.key]: {
key: descriptor.key,
filePath: descriptor.filePath,
oldPath: descriptor.oldPath,
scope: descriptor.scope,
reviewedAt: previous?.reviewedAt,
reviewDiffIdentity: previous?.reviewDiffIdentity,
lastOpenedAt: now,
lastSeenDiffIdentity: descriptor.diffIdentity
}
}
}
}
export function markMobileDiffReviewFileReviewed(
state: MobileDiffReviewState,
descriptor: MobileDiffReviewFileDescriptor,

View File

@ -1,5 +1,4 @@
import { useCallback } from 'react'
import type { MobileNativeChatSendOutcome } from './mobile-native-chat-send'
/** Wraps a chat card action so an accepted write also retires the route's held
* failure banner.
@ -23,15 +22,3 @@ export function useNativeChatAcceptedAction<Params extends unknown[]>(
[action, onAccepted]
)
}
/** Boolean surface for callers with no pre-pasted input: 'unknown' stays true
* (the send usually landed; the optimistic echo is already held unconfirmed). */
export function useNativeChatSentFlag(
send: (text: string, images?: string[]) => Promise<MobileNativeChatSendOutcome>
): (text: string, images?: string[]) => Promise<boolean> {
return useCallback(
async (text: string, images?: string[]): Promise<boolean> =>
(await send(text, images)) !== 'rejected',
[send]
)
}

View File

@ -1,7 +1,7 @@
import { ActionSheetModal, type ActionSheetAction } from '../components/ActionSheetModal'
import { ConfirmModal } from '../components/ConfirmModal'
import { PickerModal } from '../components/PickerModal'
import { openMobilePrUrl } from '../components/MobilePrComposeSheet'
import { openMobilePrUrl } from '../components/mobile-pr-url'
import { MobileBranchDiffPreviewDrawer } from './MobileBranchDiffPreviewDrawer'
import type { MobileSourceControlState } from './use-mobile-source-control-state'

View File

@ -18,7 +18,7 @@ import { isMobileConflictAborting } from './mobile-source-control-conflict-abort
import { useMobilePrSidebarController } from '../session/use-mobile-pr-sidebar-controller'
import { prSidebarDetailsNeedFetch } from '../session/mobile-pr-sidebar-state'
import { MobilePrViewPanelBody } from '../components/pr-sidebar/MobilePrViewPanel'
import { openMobilePrUrl } from '../components/MobilePrComposeSheet'
import { openMobilePrUrl } from '../components/mobile-pr-url'
export type MobileSourceControlPanelProps = {
hostId: string

View File

@ -2,13 +2,6 @@ import type { RpcClient } from '../transport/rpc-client'
import type { RpcSuccess } from '../transport/types'
import { mobileRepoSelectorFromWorktreeId } from './mobile-pr-create'
// Base-branch selection for the create-PR composer, mirroring the desktop
// useCreatePullRequestDialogFields flow: a default ref from repo.baseRefDefault and
// a debounced search via repo.searchRefs (both allowlisted for mobile). Result
// mapping is pure + unit-tested; the wrappers are thin sendRequest calls.
// Defensively normalize the repo.searchRefs payload (`{ refs: string[] }`) to a
// clean string[] — drops non-string / malformed entries instead of throwing.
export function mapBaseRefResults(raw: unknown): string[] {
if (raw === null || typeof raw !== 'object') {
return []
@ -20,20 +13,6 @@ export function mapBaseRefResults(raw: unknown): string[] {
return refs.filter((r): r is string => typeof r === 'string' && r.length > 0)
}
export async function fetchDefaultBaseRef(
client: Pick<RpcClient, 'sendRequest'>,
worktreeId: string
): Promise<string | null> {
const response = await client.sendRequest('repo.baseRefDefault', {
repo: mobileRepoSelectorFromWorktreeId(worktreeId)
})
if (!response.ok) {
return null
}
const result = (response as RpcSuccess).result as { defaultBaseRef?: string | null }
return typeof result?.defaultBaseRef === 'string' ? result.defaultBaseRef : null
}
export async function searchBaseRefs(
client: Pick<RpcClient, 'sendRequest'>,
worktreeId: string,

View File

@ -1,14 +1,7 @@
import type { RpcClient } from '../transport/rpc-client'
import { readMobileGitStatusResult } from '../session/mobile-diff-review-rpc'
import type { MobileGitStatusResult } from './mobile-git-status'
import { resolveMobilePrPrefill, type MobilePrPrefill } from './mobile-pr-create'
// Resolves the create-PR prefill from a git status snapshot. Split from the
// runners hook to keep that file under the line limit.
// Reads a fresh git.status after a push so the prefill reflects the just-pushed
// branch's upstream/ahead data instead of the pre-push captured status. Best-effort:
// returns the captured status on any read failure.
// Refresh after a push when possible so readiness reflects the new upstream state.
export async function readFreshGitStatus(
worktreeId: string,
fallback: MobileGitStatusResult | null,
@ -22,23 +15,6 @@ export async function readFreshGitStatus(
}
}
export async function buildOpenPrPrefill(
client: Pick<RpcClient, 'sendRequest'> | null,
worktreeId: string,
status: MobileGitStatusResult | null,
branchLabel: string
): Promise<MobilePrPrefill> {
if (!client) {
return { provider: 'github', base: 'main', title: branchLabel, body: '' }
}
const gitReadiness = getMobilePrEligibilityReadiness(status)
return resolveMobilePrPrefill(client, worktreeId, {
branch: status?.branch,
title: branchLabel,
...gitReadiness
})
}
export function getMobilePrEligibilityReadiness(status: MobileGitStatusResult | null): {
hasUncommittedChanges?: boolean
hasUpstream?: boolean