Hide Changes tab when not git repo and add refresh button to Files pane
- Hide Changes tab completely when isGit is false instead of just muting it - Automatically switch to Files tab if user was on Changes when it becomes hidden - Add refresh button next to sort button in Files pane header - Refresh button refreshes root directory, expanded directories, and file preview if open
This commit is contained in:
@@ -263,25 +263,33 @@ function SidebarContent({
|
|||||||
const { status } = useCheckoutStatusQuery({ serverId, cwd });
|
const { status } = useCheckoutStatusQuery({ serverId, cwd });
|
||||||
const isGit = status?.isGit ?? false;
|
const isGit = status?.isGit ?? false;
|
||||||
|
|
||||||
|
// Switch to Files tab if Changes tab is hidden and user was on it
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isGit && activeTab === "changes") {
|
||||||
|
onTabPress("files");
|
||||||
|
}
|
||||||
|
}, [isGit, activeTab, onTabPress]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.sidebarContent} pointerEvents="auto">
|
<View style={styles.sidebarContent} pointerEvents="auto">
|
||||||
{/* Header with tabs and close button */}
|
{/* Header with tabs and close button */}
|
||||||
<View style={styles.header} testID="explorer-header">
|
<View style={styles.header} testID="explorer-header">
|
||||||
<View style={styles.tabsContainer}>
|
<View style={styles.tabsContainer}>
|
||||||
<Pressable
|
{isGit && (
|
||||||
style={[styles.tab, activeTab === "changes" && styles.tabActive]}
|
<Pressable
|
||||||
onPress={() => onTabPress("changes")}
|
style={[styles.tab, activeTab === "changes" && styles.tabActive]}
|
||||||
>
|
onPress={() => onTabPress("changes")}
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.tabText,
|
|
||||||
activeTab === "changes" && styles.tabTextActive,
|
|
||||||
!isGit && styles.tabTextMuted,
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
Changes
|
<Text
|
||||||
</Text>
|
style={[
|
||||||
</Pressable>
|
styles.tabText,
|
||||||
|
activeTab === "changes" && styles.tabTextActive,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Changes
|
||||||
|
</Text>
|
||||||
|
</Pressable>
|
||||||
|
)}
|
||||||
<Pressable
|
<Pressable
|
||||||
style={[styles.tab, activeTab === "files" && styles.tabActive]}
|
style={[styles.tab, activeTab === "files" && styles.tabActive]}
|
||||||
onPress={() => onTabPress("files")}
|
onPress={() => onTabPress("files")}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
FolderOpen,
|
FolderOpen,
|
||||||
Image as ImageIcon,
|
Image as ImageIcon,
|
||||||
MoreVertical,
|
MoreVertical,
|
||||||
|
RotateCw,
|
||||||
X,
|
X,
|
||||||
} from "lucide-react-native";
|
} from "lucide-react-native";
|
||||||
import type {
|
import type {
|
||||||
@@ -263,6 +264,26 @@ export function FileExplorerPane({ serverId, agentId }: FileExplorerPaneProps) {
|
|||||||
setSortOption(SORT_OPTIONS[nextIndex].value);
|
setSortOption(SORT_OPTIONS[nextIndex].value);
|
||||||
}, [sortOption, setSortOption]);
|
}, [sortOption, setSortOption]);
|
||||||
|
|
||||||
|
const handleRefresh = useCallback(() => {
|
||||||
|
if (!agentId || !requestDirectoryListing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Refresh the root directory
|
||||||
|
requestDirectoryListing(agentId, ".", { recordHistory: false, setCurrentPath: false });
|
||||||
|
|
||||||
|
// Also refresh any expanded directories
|
||||||
|
expandedPaths.forEach((path) => {
|
||||||
|
if (path !== ".") {
|
||||||
|
requestDirectoryListing(agentId, path, { recordHistory: false, setCurrentPath: false });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Refresh the preview if a file is selected
|
||||||
|
if (selectedEntryPath && requestFilePreview) {
|
||||||
|
requestFilePreview(agentId, selectedEntryPath);
|
||||||
|
}
|
||||||
|
}, [agentId, expandedPaths, requestDirectoryListing, requestFilePreview, selectedEntryPath]);
|
||||||
|
|
||||||
const currentSortLabel = SORT_OPTIONS.find((opt) => opt.value === sortOption)?.label ?? "Name";
|
const currentSortLabel = SORT_OPTIONS.find((opt) => opt.value === sortOption)?.label ?? "Name";
|
||||||
|
|
||||||
const treeRows = useMemo(() => {
|
const treeRows = useMemo(() => {
|
||||||
@@ -603,9 +624,23 @@ export function FileExplorerPane({ serverId, agentId }: FileExplorerPaneProps) {
|
|||||||
</GestureDetector>
|
</GestureDetector>
|
||||||
<View style={styles.paneHeader} testID="files-pane-header">
|
<View style={styles.paneHeader} testID="files-pane-header">
|
||||||
<View style={styles.paneHeaderLeft} />
|
<View style={styles.paneHeaderLeft} />
|
||||||
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
<View style={styles.paneHeaderRight}>
|
||||||
<Text style={styles.sortButtonText}>{currentSortLabel}</Text>
|
<Pressable
|
||||||
</Pressable>
|
onPress={handleRefresh}
|
||||||
|
hitSlop={8}
|
||||||
|
style={({ hovered, pressed }) => [
|
||||||
|
styles.iconButton,
|
||||||
|
(hovered || pressed) && styles.iconButtonHovered,
|
||||||
|
]}
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Refresh files"
|
||||||
|
>
|
||||||
|
<RotateCw size={16} color={theme.colors.foregroundMuted} />
|
||||||
|
</Pressable>
|
||||||
|
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
||||||
|
<Text style={styles.sortButtonText}>{currentSortLabel}</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<FlatList
|
<FlatList
|
||||||
style={styles.treeList}
|
style={styles.treeList}
|
||||||
@@ -622,9 +657,23 @@ export function FileExplorerPane({ serverId, agentId }: FileExplorerPaneProps) {
|
|||||||
<View style={[styles.treePane, styles.treePaneFill]}>
|
<View style={[styles.treePane, styles.treePaneFill]}>
|
||||||
<View style={styles.paneHeader} testID="files-pane-header">
|
<View style={styles.paneHeader} testID="files-pane-header">
|
||||||
<View style={styles.paneHeaderLeft} />
|
<View style={styles.paneHeaderLeft} />
|
||||||
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
<View style={styles.paneHeaderRight}>
|
||||||
<Text style={styles.sortButtonText}>{currentSortLabel}</Text>
|
<Pressable
|
||||||
</Pressable>
|
onPress={handleRefresh}
|
||||||
|
hitSlop={8}
|
||||||
|
style={({ hovered, pressed }) => [
|
||||||
|
styles.iconButton,
|
||||||
|
(hovered || pressed) && styles.iconButtonHovered,
|
||||||
|
]}
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Refresh files"
|
||||||
|
>
|
||||||
|
<RotateCw size={16} color={theme.colors.foregroundMuted} />
|
||||||
|
</Pressable>
|
||||||
|
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
|
||||||
|
<Text style={styles.sortButtonText}>{currentSortLabel}</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<FlatList
|
<FlatList
|
||||||
style={styles.treeList}
|
style={styles.treeList}
|
||||||
@@ -1023,6 +1072,12 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
|
paneHeaderRight: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: theme.spacing[2],
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
previewHeaderRight: {
|
previewHeaderRight: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
Reference in New Issue
Block a user