feat(git-diff): add React Query with pull-to-refresh and cleaner diff display

- Add useGitDiffQuery hook using React Query for caching and revalidation
- Add sendRpcRequest utility for promisified WebSocket RPC with requestId matching
- Add requestId to git_diff_request/response for proper request correlation
- Enable pull-to-refresh via RefreshControl in GitDiffPane
- Auto-revalidate when sidebar opens with "changes" tab active
- Clean up diff display: remove metadata noise, strip +/- prefixes
- Default both sidebars open on web platform

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2026-01-05 21:27:35 +07:00
co-authored by Claude Opus 4.5
parent 8c33df472f
commit 348242541c
9 changed files with 486 additions and 65 deletions
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useRef, useState } from "react";
import { useCallback, useMemo, useRef } from "react";
import { View, Text, Pressable, Platform } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Animated, {
@@ -13,13 +13,12 @@ import {
useExplorerSidebarStore,
MIN_EXPLORER_SIDEBAR_WIDTH,
MAX_EXPLORER_SIDEBAR_WIDTH,
type ViewMode,
} from "@/stores/explorer-sidebar-store";
import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context";
import { GitDiffPane } from "./git-diff-pane";
import { FileExplorerPane } from "./file-explorer-pane";
type ViewMode = "list" | "grid";
type ExplorerTab = "changes" | "files";
interface ExplorerSidebarProps {
@@ -30,7 +29,7 @@ interface ExplorerSidebarProps {
export function ExplorerSidebar({ serverId, agentId }: ExplorerSidebarProps) {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const { isOpen, activeTab, width, close, setActiveTab, setWidth } =
const { isOpen, activeTab, width, viewMode, close, setActiveTab, setWidth, setViewMode } =
useExplorerSidebarStore();
const {
translateX,
@@ -45,9 +44,6 @@ export function ExplorerSidebar({ serverId, agentId }: ExplorerSidebarProps) {
const isMobile =
UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
// File explorer view mode state
const [fileViewMode, setFileViewMode] = useState<ViewMode>("list");
// For resize drag, track the starting width
const startWidthRef = useRef(width);
const resizeWidth = useSharedValue(width);
@@ -174,8 +170,8 @@ export function ExplorerSidebar({ serverId, agentId }: ExplorerSidebarProps) {
onClose={handleClose}
serverId={serverId}
agentId={agentId}
fileViewMode={fileViewMode}
onFileViewModeChange={setFileViewMode}
fileViewMode={viewMode}
onFileViewModeChange={setViewMode}
isMobile={isMobile}
/>
</Animated.View>
@@ -209,8 +205,8 @@ export function ExplorerSidebar({ serverId, agentId }: ExplorerSidebarProps) {
onClose={handleClose}
serverId={serverId}
agentId={agentId}
fileViewMode={fileViewMode}
onFileViewModeChange={setFileViewMode}
fileViewMode={viewMode}
onFileViewModeChange={setViewMode}
isMobile={false}
/>
</Animated.View>