Update files

This commit is contained in:
Mohamed Boudra
2026-02-06 22:41:20 +07:00
parent 2d74b5407c
commit 1a01e836bc
6 changed files with 268 additions and 318 deletions
@@ -1,187 +0,0 @@
import { useCallback, useMemo } from "react";
import { Pressable, Text, View } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { Copy, Info } from "lucide-react-native";
import * as Clipboard from "expo-clipboard";
import { AdaptiveModalSheet } from "@/components/adaptive-modal-sheet";
import { Fonts } from "@/constants/theme";
import { useToast } from "@/contexts/toast-context";
export type AgentDetailsSheetProps = {
visible: boolean;
onClose: () => void;
agentId: string;
persistenceSessionId: string | null;
};
export function AgentDetailsSheet({
visible,
onClose,
agentId,
persistenceSessionId,
}: AgentDetailsSheetProps) {
const toast = useToast();
const details = useMemo(
() => [
{
label: "Agent ID",
value: agentId,
testID: "agent-details-agent-id",
copyLabel: "agent id",
},
{
label: "Persistence session ID",
value: persistenceSessionId,
testID: "agent-details-persistence-session-id",
copyLabel: "session id",
},
],
[agentId, persistenceSessionId]
);
const handleCopy = useCallback(
async (value: string | null, label: string) => {
if (!value) return;
try {
await Clipboard.setStringAsync(value);
toast.copied(label);
} catch {
toast.error("Copy failed");
}
},
[toast]
);
return (
<AdaptiveModalSheet
title="Agent details"
visible={visible}
onClose={onClose}
testID="agent-details-sheet"
snapPoints={["45%", "70%"]}
>
{details.map((row) => (
<DetailRow
key={row.label}
label={row.label}
value={row.value}
onCopy={() => void handleCopy(row.value, row.copyLabel)}
testID={row.testID}
disabled={!row.value}
/>
))}
</AdaptiveModalSheet>
);
}
function DetailRow({
label,
value,
onCopy,
disabled,
testID,
}: {
label: string;
value: string | null;
onCopy: () => void;
disabled?: boolean;
testID: string;
}) {
const { theme } = useUnistyles();
return (
<Pressable
testID={testID}
accessibilityRole="button"
accessibilityLabel={`${label} copy`}
accessibilityHint={disabled ? "Not available" : "Copies to clipboard"}
disabled={disabled}
onPress={onCopy}
style={({ pressed }) => [
styles.row,
disabled ? styles.rowDisabled : null,
pressed && !disabled ? styles.rowPressed : null,
]}
>
<View style={styles.rowTop}>
<View style={styles.labelRow}>
<Info size={16} color={theme.colors.foregroundMuted} />
<Text style={styles.label}>{label}</Text>
</View>
<View style={styles.copyPill}>
<Copy size={14} color={theme.colors.foregroundMuted} />
<Text style={styles.copyText}>Copy</Text>
</View>
</View>
<Text
testID={`${testID}-value`}
style={[styles.value, !value ? styles.valueEmpty : null]}
numberOfLines={2}
ellipsizeMode="middle"
>
{value ?? "Not available"}
</Text>
</Pressable>
);
}
const styles = StyleSheet.create((theme) => ({
row: {
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.surface2,
backgroundColor: theme.colors.surface1,
paddingHorizontal: theme.spacing[4],
paddingVertical: theme.spacing[4],
gap: theme.spacing[3],
},
rowPressed: {
backgroundColor: theme.colors.surface2,
},
rowDisabled: {
opacity: 0.65,
},
rowTop: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
gap: theme.spacing[3],
},
labelRow: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
flex: 1,
},
label: {
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.semibold,
flex: 1,
},
copyPill: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.surface2,
},
copyText: {
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.medium,
},
value: {
color: theme.colors.foreground,
fontSize: theme.fontSize.sm,
fontFamily: Fonts.mono,
},
valueEmpty: {
color: theme.colors.foregroundMuted,
fontFamily: Fonts.sans,
},
}));
@@ -424,12 +424,20 @@ export function FileExplorerPane({ serverId, agentId }: FileExplorerPaneProps) {
<DropdownMenuContent align="end" width={220}>
<View style={styles.contextMetaBlock}>
<View style={styles.contextMetaRow}>
<Text style={styles.contextMetaLabel}>Size</Text>
<Text style={styles.contextMetaValue}>{formatFileSize({ size: entry.size })}</Text>
<Text style={styles.contextMetaLabel} numberOfLines={1}>
Size
</Text>
<Text style={styles.contextMetaValue} numberOfLines={1} ellipsizeMode="tail">
{formatFileSize({ size: entry.size })}
</Text>
</View>
<View style={styles.contextMetaRow}>
<Text style={styles.contextMetaLabel}>Modified</Text>
<Text style={styles.contextMetaValue}>{formatTimeAgo(new Date(entry.modifiedAt))}</Text>
<Text style={styles.contextMetaLabel} numberOfLines={1}>
Modified
</Text>
<Text style={styles.contextMetaValue} numberOfLines={1} ellipsizeMode="tail">
{formatTimeAgo(new Date(entry.modifiedAt))}
</Text>
</View>
</View>
<DropdownMenuSeparator />
@@ -1132,11 +1140,15 @@ const styles = StyleSheet.create((theme) => ({
contextMetaLabel: {
fontSize: theme.fontSize.sm,
color: theme.colors.foregroundMuted,
flexShrink: 0,
},
contextMetaValue: {
fontSize: theme.fontSize.sm,
color: theme.colors.foreground,
fontWeight: theme.fontWeight.medium,
flex: 1,
minWidth: 0,
textAlign: "right",
},
previewHeaderText: {
flex: 1,
+36 -3
View File
@@ -15,7 +15,19 @@ import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gest
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as Linking from "expo-linking";
import { Archive, ChevronDown, ChevronRight, GitBranch, MoreVertical, ListChevronsDownUp, ListChevronsUpDown } from "lucide-react-native";
import {
Archive,
ChevronDown,
ChevronRight,
GitBranch,
GitCommitHorizontal,
GitMerge,
ListChevronsDownUp,
ListChevronsUpDown,
MoreVertical,
RefreshCcw,
Upload,
} from "lucide-react-native";
import { useCheckoutGitActionsStore } from "@/stores/checkout-git-actions-store";
import {
useCheckoutDiffQuery,
@@ -37,6 +49,7 @@ import {
DropdownMenuTrigger,
type ActionStatus,
} from "@/components/ui/dropdown-menu";
import { GitHubIcon } from "@/components/icons/github-icon";
// =============================================================================
// Git Actions Data Structure
@@ -856,6 +869,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
successLabel: "Committed",
disabled: commitDisabled,
status: commitStatus,
icon: <GitCommitHorizontal size={16} color={theme.colors.foregroundMuted} />,
handler: handleCommit,
});
@@ -869,6 +883,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
disabled: pushDisabled,
status: pushStatus,
description: !hasRemote ? "No remote configured" : undefined,
icon: <Upload size={16} color={theme.colors.foregroundMuted} />,
handler: handlePush,
});
}
@@ -883,6 +898,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
successLabel: "View PR",
disabled: false,
status: "idle",
icon: <GitHubIcon size={16} color={theme.colors.foregroundMuted} />,
handler: () => openURLInNewTab(prUrl),
});
}
@@ -896,6 +912,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
successLabel: "PR Created",
disabled: prDisabled,
status: prCreateStatus,
icon: <GitHubIcon size={16} color={theme.colors.foregroundMuted} />,
handler: handleCreatePr,
});
}
@@ -910,6 +927,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
disabled: mergeDisabled,
status: mergeStatus,
description: hasUncommittedChanges ? "Requires clean working tree" : undefined,
icon: <GitMerge size={16} color={theme.colors.foregroundMuted} />,
handler: handleMergeBranch,
});
}
@@ -924,6 +942,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
disabled: mergeFromBaseDisabled,
status: mergeFromBaseStatus,
description: hasUncommittedChanges ? "Requires clean working tree" : undefined,
icon: <RefreshCcw size={16} color={theme.colors.foregroundMuted} />,
handler: handleMergeFromBase,
});
}
@@ -994,6 +1013,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
commitDisabled, pushDisabled, prDisabled, mergeDisabled, mergeFromBaseDisabled, archiveDisabled,
commitStatus, pushStatus, prCreateStatus, mergeStatus, mergeFromBaseStatus, archiveStatus,
handleCommit, handlePush, handleCreatePr, handleMergeBranch, handleMergeFromBase, handleArchiveWorktree,
theme.colors.foregroundMuted,
]);
// Helper to get display label based on status
@@ -1033,7 +1053,10 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
{gitActions.primary.status === "pending" ? (
<ActivityIndicator size="small" color={theme.colors.foreground} style={styles.splitButtonSpinner} />
) : (
<Text style={styles.splitButtonText}>{getActionDisplayLabel(gitActions.primary)}</Text>
<View style={styles.splitButtonContent}>
{gitActions.primary.icon}
<Text style={styles.splitButtonText}>{getActionDisplayLabel(gitActions.primary)}</Text>
</View>
)}
</Pressable>
{gitActions.secondary.length > 0 ? (
@@ -1054,6 +1077,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
{needsSeparator && index > 0 ? <DropdownMenuSeparator /> : null}
<DropdownMenuItem
testID={`changes-menu-${action.id}`}
leading={action.icon}
disabled={action.disabled}
status={action.status}
pendingLabel={action.pendingLabel}
@@ -1077,7 +1101,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
<DropdownMenuTrigger
testID="changes-overflow-menu"
hitSlop={8}
style={styles.iconButton}
style={[styles.iconButton, styles.overflowMenuButton]}
accessibilityRole="button"
accessibilityLabel="More actions"
>
@@ -1280,6 +1304,12 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foreground,
fontWeight: theme.fontWeight.medium,
},
splitButtonContent: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: theme.spacing[2],
},
splitButtonSpinner: {
height: theme.fontSize.xs * 1.5,
width: theme.fontSize.xs * 1.5,
@@ -1298,6 +1328,9 @@ const styles = StyleSheet.create((theme) => ({
justifyContent: "center",
borderRadius: theme.borderRadius.md,
},
overflowMenuButton: {
marginRight: -theme.spacing[2],
},
menuOverlay: {
flex: 1,
},
@@ -0,0 +1,14 @@
import Svg, { Path } from "react-native-svg";
interface GitHubIconProps {
size?: number;
color?: string;
}
export function GitHubIcon({ size = 16, color = "currentColor" }: GitHubIconProps) {
return (
<Svg width={size} height={size} viewBox="0 -0.5 25 25" fill={color}>
<Path d="m12.301 0h.093c2.242 0 4.34.613 6.137 1.68l-.055-.031c1.871 1.094 3.386 2.609 4.449 4.422l.031.058c1.04 1.769 1.654 3.896 1.654 6.166 0 5.406-3.483 10-8.327 11.658l-.087.026c-.063.02-.135.031-.209.031-.162 0-.312-.054-.433-.144l.002.001c-.128-.115-.208-.281-.208-.466 0-.005 0-.01 0-.014v.001q0-.048.008-1.226t.008-2.154c.007-.075.011-.161.011-.249 0-.792-.323-1.508-.844-2.025.618-.061 1.176-.163 1.718-.305l-.076.017c.573-.16 1.073-.373 1.537-.642l-.031.017c.508-.28.938-.636 1.292-1.058l.006-.007c.372-.476.663-1.036.84-1.645l.009-.035c.209-.683.329-1.468.329-2.281 0-.045 0-.091-.001-.136v.007c0-.022.001-.047.001-.072 0-1.248-.482-2.383-1.269-3.23l.003.003c.168-.44.265-.948.265-1.479 0-.649-.145-1.263-.404-1.814l.011.026c-.115-.022-.246-.035-.381-.035-.334 0-.649.078-.929.216l.012-.005c-.568.21-1.054.448-1.512.726l.038-.022-.609.384c-.922-.264-1.981-.416-3.075-.416s-2.153.152-3.157.436l.081-.02q-.256-.176-.681-.433c-.373-.214-.814-.421-1.272-.595l-.066-.022c-.293-.154-.64-.244-1.009-.244-.124 0-.246.01-.364.03l.013-.002c-.248.524-.393 1.139-.393 1.788 0 .531.097 1.04.275 1.509l-.01-.029c-.785.844-1.266 1.979-1.266 3.227 0 .025 0 .051.001.076v-.004c-.001.039-.001.084-.001.13 0 .809.12 1.591.344 2.327l-.015-.057c.189.643.476 1.202.85 1.693l-.009-.013c.354.435.782.793 1.267 1.062l.022.011c.432.252.933.465 1.46.614l.046.011c.466.125 1.024.227 1.595.284l.046.004c-.431.428-.718 1-.784 1.638l-.001.012c-.207.101-.448.183-.699.236l-.021.004c-.256.051-.549.08-.85.08-.022 0-.044 0-.066 0h.003c-.394-.008-.756-.136-1.055-.348l.006.004c-.371-.259-.671-.595-.881-.986l-.007-.015c-.198-.336-.459-.614-.768-.827l-.009-.006c-.225-.169-.49-.301-.776-.38l-.016-.004-.32-.048c-.023-.002-.05-.003-.077-.003-.14 0-.273.028-.394.077l.007-.003q-.128.072-.08.184c.039.086.087.16.145.225l-.001-.001c.061.072.13.135.205.19l.003.002.112.08c.283.148.516.354.693.603l.004.006c.191.237.359.505.494.792l.01.024.16.368c.135.402.38.738.7.981l.005.004c.3.234.662.402 1.057.478l.016.002c.33.064.714.104 1.106.112h.007c.045.002.097.002.15.002.261 0 .517-.021.767-.062l-.027.004.368-.064q0 .609.008 1.418t.008.873v.014c0 .185-.08.351-.208.466h-.001c-.119.089-.268.143-.431.143-.075 0-.147-.011-.214-.032l.005.001c-4.929-1.689-8.409-6.283-8.409-11.69 0-2.268.612-4.393 1.681-6.219l-.032.058c1.094-1.871 2.609-3.386 4.422-4.449l.058-.031c1.739-1.034 3.835-1.645 6.073-1.645h.098-.005zm-7.64 17.666q.048-.112-.112-.192-.16-.048-.208.032-.048.112.112.192.144.096.208-.032zm.497.545q.112-.08-.032-.256-.16-.144-.256-.048-.112.08.032.256.159.157.256.047zm.48.72q.144-.112 0-.304-.128-.208-.272-.096-.144.08 0 .288t.272.112zm.672.673q.128-.128-.064-.304-.192-.192-.32-.048-.144.128.064.304.192.192.32.044zm.913.4q.048-.176-.208-.256-.24-.064-.304.112t.208.24q.24.097.304-.096zm1.009.08q0-.208-.272-.176-.256 0-.256.176 0 .208.272.176.256.001.256-.175zm.929-.16q-.032-.176-.288-.144-.256.048-.224.24t.288.128.225-.224z" />
</Svg>
);
}