mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 09:57:48 +00:00
feat(mobile): a commit's files open in the diff screen (#37113)
Tapping a file on the commit page now opens the shared diff screen for that file in that commit (openDiffForFile kind 'commit'), in today's Commits tab and inside the hub's Commits page.
This commit is contained in:
@@ -34,6 +34,8 @@ type Props = {
|
||||
commit: MobileGitHistoryItem
|
||||
bottomInset: number
|
||||
onBack: () => void
|
||||
// Opens a file in the shared diff screen; rows stay inert when the host offers none.
|
||||
onOpenFile?: (filePath: string) => void
|
||||
}
|
||||
|
||||
function splitPath(path: string): { name: string; dir: string } {
|
||||
@@ -57,7 +59,8 @@ export function MobileCommitDetailPage({
|
||||
worktreeId,
|
||||
commit,
|
||||
bottomInset,
|
||||
onBack
|
||||
onBack,
|
||||
onOpenFile
|
||||
}: Props) {
|
||||
useMobileColorScheme()
|
||||
const t = useMobileTranslation()
|
||||
@@ -271,19 +274,33 @@ export function MobileCommitDetailPage({
|
||||
{t('sourceControl.gitHistoryList.noFileChanges', 'No file changes')}
|
||||
</Text>
|
||||
) : (
|
||||
loadedFiles.map((file) => <CommitFileRow key={file.path} file={file} />)
|
||||
loadedFiles.map((file) => (
|
||||
<CommitFileRow key={file.path} file={file} onOpen={onOpenFile} />
|
||||
))
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function CommitFileRow({ file }: { file: MobileGitChangedFile }) {
|
||||
function CommitFileRow({
|
||||
file,
|
||||
onOpen
|
||||
}: {
|
||||
file: MobileGitChangedFile
|
||||
onOpen?: (filePath: string) => void
|
||||
}) {
|
||||
useMobileColorScheme()
|
||||
const status = file.status ?? 'modified'
|
||||
const { name, dir } = splitPath(file.path)
|
||||
return (
|
||||
<View style={styles.fileRow} accessibilityLabel={file.path}>
|
||||
<Pressable
|
||||
style={({ pressed }) => [styles.fileRow, pressed && onOpen && styles.fileRowPressed]}
|
||||
disabled={!onOpen}
|
||||
onPress={() => onOpen?.(file.path)}
|
||||
accessibilityRole={onOpen ? 'button' : undefined}
|
||||
accessibilityLabel={file.path}
|
||||
>
|
||||
<Text style={[styles.fileStatus, { color: statusColor(status) }]}>
|
||||
{STATUS_LABELS[status]}
|
||||
</Text>
|
||||
@@ -301,7 +318,7 @@ function CommitFileRow({ file }: { file: MobileGitChangedFile }) {
|
||||
) : null}
|
||||
</View>
|
||||
<CommitLineStat added={file.added ?? 0} removed={file.removed ?? 0} />
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -358,6 +375,7 @@ const styles = themedStyleSheet(() => ({
|
||||
fontFamily: typography.monoFamily,
|
||||
fontWeight: '600'
|
||||
},
|
||||
fileRowPressed: { backgroundColor: colors.bgRaised },
|
||||
fileMain: { flex: 1, minWidth: 0 },
|
||||
fileName: { color: colors.textPrimary, fontSize: typography.bodySize },
|
||||
fileNameDeleted: { textDecorationLine: 'line-through', color: colors.textMuted },
|
||||
|
||||
@@ -297,6 +297,35 @@ describe('MobileCommitsScreen', () => {
|
||||
expect(list?.props.refreshControl.props.refreshing).toBe(false)
|
||||
})
|
||||
|
||||
it("opens a commit's file in the shared diff screen against that commit", async () => {
|
||||
const openDiffForFile = vi.fn()
|
||||
const client = createFakeRpcClient()
|
||||
client.sendRequest = routedSend(() => Promise.resolve(historyResponse('expandable')))
|
||||
await act(async () => {
|
||||
renderer = create(
|
||||
createElement(MobileCommitsScreen, {
|
||||
client,
|
||||
connState: 'connected',
|
||||
worktreeId: 'wt-1',
|
||||
hostId: 'host-1',
|
||||
bottomInset: 0,
|
||||
openDiffForFile
|
||||
})
|
||||
)
|
||||
await settle()
|
||||
})
|
||||
await openFirstCommit()
|
||||
const fileRow = renderer?.root.find(
|
||||
(node) => String(node.type) === 'Pressable' && node.props.accessibilityLabel === 'src/app.ts'
|
||||
)
|
||||
await act(async () => fileRow?.props.onPress())
|
||||
expect(openDiffForFile).toHaveBeenCalledWith({
|
||||
kind: 'commit',
|
||||
filePath: 'src/app.ts',
|
||||
commitOid: 'commit-1'
|
||||
})
|
||||
})
|
||||
|
||||
it('wipes commits when the worktree identity changes', async () => {
|
||||
let historyCalls = 0
|
||||
const sendRequest = routedSend(() => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { RpcClient } from '../transport/rpc-client'
|
||||
import type { ConnectionState } from '../transport/types'
|
||||
import type { MobileGitHistoryItem } from './git-history-reply-schema'
|
||||
import { MobileCommitDetailPage } from './MobileCommitDetailPage'
|
||||
import type { MobileDiffFileTarget } from './use-mobile-source-control-openers'
|
||||
import { MobileGitHistoryList, type MobileGitHistoryListProps } from './MobileGitHistoryList'
|
||||
|
||||
type OpenCommit = (commit: MobileGitHistoryItem) => void
|
||||
@@ -17,12 +18,14 @@ type Props = Omit<MobileGitHistoryListProps, 'onOpenCommit'> & {
|
||||
embedded?: boolean
|
||||
// Set by a parent whose own commit page covers more than this list, e.g. the whole Source Control screen.
|
||||
onOpenCommit?: OpenCommit
|
||||
openDiffForFile?: (target: MobileDiffFileTarget) => void
|
||||
}
|
||||
|
||||
// The branch's commits; a commit opens over them unless the parent hosts the commit page itself.
|
||||
export const MobileCommitsScreen = memo(function MobileCommitsScreen({
|
||||
embedded = false,
|
||||
onOpenCommit,
|
||||
openDiffForFile,
|
||||
...props
|
||||
}: Props) {
|
||||
const list = (open: OpenCommit) => <MobileGitHistoryList {...props} onOpenCommit={open} />
|
||||
@@ -37,6 +40,7 @@ export const MobileCommitsScreen = memo(function MobileCommitsScreen({
|
||||
worktreeId={props.worktreeId}
|
||||
bottomInset={props.bottomInset}
|
||||
padTop={false}
|
||||
openDiffForFile={openDiffForFile}
|
||||
>
|
||||
{list}
|
||||
</MobileCommitPageHost>
|
||||
@@ -58,6 +62,7 @@ export function MobileCommitPageHost({
|
||||
worktreeId,
|
||||
bottomInset,
|
||||
padTop,
|
||||
openDiffForFile,
|
||||
children
|
||||
}: {
|
||||
client: RpcClient | null
|
||||
@@ -66,6 +71,7 @@ export function MobileCommitPageHost({
|
||||
bottomInset: number
|
||||
// The page covers a screen-top header, so it pads under the status bar unless an ancestor already did.
|
||||
padTop: boolean
|
||||
openDiffForFile?: (target: MobileDiffFileTarget) => void
|
||||
children: (openCommit: OpenCommit) => ReactNode
|
||||
}) {
|
||||
const pager = useOptionPager<'commit'>()
|
||||
@@ -97,6 +103,11 @@ export function MobileCommitPageHost({
|
||||
commit={commit}
|
||||
bottomInset={bottomInset}
|
||||
onBack={close}
|
||||
onOpenFile={
|
||||
openDiffForFile
|
||||
? (filePath) => openDiffForFile({ kind: 'commit', filePath, commitOid: commit.id })
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
) : null
|
||||
return (
|
||||
|
||||
@@ -317,6 +317,7 @@ export function MobileSourceControlPanel({
|
||||
worktreeId={worktreeId}
|
||||
bottomInset={insets.bottom}
|
||||
padTop={!embedded}
|
||||
openDiffForFile={state.openDiffForFile}
|
||||
>
|
||||
{(openCommit) => (
|
||||
<View style={styles.container}>
|
||||
|
||||
Reference in New Issue
Block a user