A deployable markdown editor that connects with your self hosted files and lets you edit in a beautiful interface
1import { useState } from 'react';
2import { useQueryClient } from '@tanstack/react-query';
3import { reposApi } from '../../lib/api/repos';
4import { toast } from 'sonner';
5
6interface FileTreeHeaderProps {
7 owner: string;
8 repo: string;
9}
10
11export function FileTreeHeader({ owner, repo }: FileTreeHeaderProps) {
12 const [isRefreshing, setIsRefreshing] = useState(false);
13 const queryClient = useQueryClient();
14
15 const handleRefresh = async () => {
16 setIsRefreshing(true);
17
18 try {
19 // Invalidate backend cache
20 const result = await reposApi.invalidateCache(owner, repo);
21
22 // Invalidate React Query cache
23 await queryClient.invalidateQueries({
24 queryKey: ['files', owner, repo],
25 refetchType: 'all', // Force refetch even for inactive queries
26 });
27
28 toast.success(`Cache cleared! ${result.invalidated_count} entries invalidated.`);
29 } catch (error) {
30 console.error('Failed to refresh cache:', error);
31 toast.error('Failed to refresh cache. Please try again.');
32 } finally {
33 setIsRefreshing(false);
34 }
35 };
36
37 return (
38 <div className="p-4 border-b border-gray-200 flex items-center justify-between">
39 <div className="text-sm font-semibold text-gray-900">Files</div>
40 <button
41 onClick={handleRefresh}
42 disabled={isRefreshing}
43 className="text-xs px-3 py-1.5 rounded-md border border-gray-300 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-1.5 transition-colors"
44 title="Refresh file list (clears cache)"
45 >
46 <svg
47 className={`w-3.5 h-3.5 ${isRefreshing ? 'animate-spin' : ''}`}
48 fill="none"
49 viewBox="0 0 24 24"
50 stroke="currentColor"
51 >
52 <path
53 strokeLinecap="round"
54 strokeLinejoin="round"
55 strokeWidth={2}
56 d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
57 />
58 </svg>
59 <span>{isRefreshing ? 'Refreshing...' : 'Refresh'}</span>
60 </button>
61 </div>
62 );
63}