feat(web): add file tree manual refresh + 5s polling + focus refetch
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { ChevronRight, FileCode2, Folder } from "lucide-react";
|
import { useQueryClient, useIsFetching } from "@tanstack/react-query";
|
||||||
|
import { ChevronRight, FileCode2, Folder, RefreshCw } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
@@ -131,6 +132,9 @@ function EmptyState({ children }: { children: ReactNode }) {
|
|||||||
export function FileExplorerPanel({ workspaceId }: FileExplorerPanelProps) {
|
export function FileExplorerPanel({ workspaceId }: FileExplorerPanelProps) {
|
||||||
const setActiveFilePath = useWorkspaceUiStore((s) => s.setActiveFilePath);
|
const setActiveFilePath = useWorkspaceUiStore((s) => s.setActiveFilePath);
|
||||||
const setSelectedPath = useFileTreeStore((s) => s.setSelectedPath);
|
const setSelectedPath = useFileTreeStore((s) => s.setSelectedPath);
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const filesQueryKey = ["workspaces", workspaceId ?? "", "files"] as const;
|
||||||
|
const isFetchingFiles = useIsFetching({ queryKey: filesQueryKey }) > 0;
|
||||||
const { data, isLoading, error } = useFileList(workspaceId, ".");
|
const { data, isLoading, error } = useFileList(workspaceId, ".");
|
||||||
|
|
||||||
const onSelectFile = (path: string) => {
|
const onSelectFile = (path: string) => {
|
||||||
@@ -138,12 +142,33 @@ export function FileExplorerPanel({ workspaceId }: FileExplorerPanelProps) {
|
|||||||
setActiveFilePath(path);
|
setActiveFilePath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const refreshAll = () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: filesQueryKey });
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = (
|
||||||
|
<div className="flex h-9 shrink-0 items-center justify-between border-b border-sidebar-border px-3 text-[11px] font-semibold uppercase text-muted-foreground">
|
||||||
|
<span>Explorer</span>
|
||||||
|
{workspaceId && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={refreshAll}
|
||||||
|
aria-label="refresh file tree"
|
||||||
|
className="inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
|
||||||
|
>
|
||||||
|
<RefreshCw
|
||||||
|
className={cn("size-3", isFetchingFiles && "animate-spin")}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
if (!workspaceId) {
|
if (!workspaceId) {
|
||||||
return (
|
return (
|
||||||
<aside className="flex h-full min-h-0 flex-col bg-sidebar text-sidebar-foreground">
|
<aside className="flex h-full min-h-0 flex-col bg-sidebar text-sidebar-foreground">
|
||||||
<div className="flex h-9 shrink-0 items-center border-b border-sidebar-border px-3 text-[11px] font-semibold uppercase text-muted-foreground">
|
{header}
|
||||||
Explorer
|
|
||||||
</div>
|
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<p>No workspace selected</p>
|
<p>No workspace selected</p>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
@@ -153,9 +178,7 @@ export function FileExplorerPanel({ workspaceId }: FileExplorerPanelProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="flex h-full min-h-0 flex-col bg-sidebar text-sidebar-foreground">
|
<aside className="flex h-full min-h-0 flex-col bg-sidebar text-sidebar-foreground">
|
||||||
<div className="flex h-9 shrink-0 items-center border-b border-sidebar-border px-3 text-[11px] font-semibold uppercase text-muted-foreground">
|
{header}
|
||||||
Explorer
|
|
||||||
</div>
|
|
||||||
<ScrollArea className="min-h-0 flex-1">
|
<ScrollArea className="min-h-0 flex-1">
|
||||||
<nav className="py-2" aria-label="Workspace files">
|
<nav className="py-2" aria-label="Workspace files">
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ export function useFileList(
|
|||||||
queryKey: fileListQueryKey(workspaceId ?? "", queryPath),
|
queryKey: fileListQueryKey(workspaceId ?? "", queryPath),
|
||||||
queryFn: () => fetchFileList(workspaceId!, queryPath),
|
queryFn: () => fetchFileList(workspaceId!, queryPath),
|
||||||
enabled: !!workspaceId && enabled,
|
enabled: !!workspaceId && enabled,
|
||||||
|
refetchInterval: 5_000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user