A deployable markdown editor that connects with your self hosted files and lets you edit in a beautiful interface
1import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
2import { reposApi } from '../api';
3
4export function useRepositories(sortBy: 'updated' | 'created' | 'name' = 'updated') {
5 return useQuery({
6 queryKey: ['repositories', sortBy],
7 queryFn: () => reposApi.listRepositories(sortBy),
8 });
9}
10
11export function useFiles(
12 owner: string,
13 repo: string,
14 path: string = '',
15 branch: string = '',
16 extensions: string[] = ['md', 'mdx']
17) {
18 return useQuery({
19 queryKey: ['files', owner, repo, path, branch, extensions],
20 queryFn: () => reposApi.listFiles(owner, repo, path, branch, extensions),
21 enabled: !!owner && !!repo,
22 // Extended cache configuration for performance
23 staleTime: 5 * 60 * 1000, // 5 min - aligns with backend cache
24 gcTime: 10 * 60 * 1000, // 10 min - keep in cache longer
25 refetchOnMount: false, // Don't refetch if data is fresh
26 refetchOnReconnect: false, // Don't refetch on reconnect
27 });
28}
29
30export function useFileContent(
31 owner: string,
32 repo: string,
33 path: string,
34 branch: string = ''
35) {
36 return useQuery({
37 queryKey: ['file-content', owner, repo, path, branch],
38 queryFn: () => reposApi.getFileContent(owner, repo, path, branch),
39 enabled: !!owner && !!repo && !!path,
40 });
41}
42
43export function useCreateFile(owner: string, repo: string) {
44 const queryClient = useQueryClient();
45
46 return useMutation({
47 mutationFn: ({ path, content, message }: { path: string; content?: string; message?: string }) =>
48 reposApi.createFile(owner, repo, path, content, message),
49 onSuccess: () => {
50 // Invalidate and refetch files query and pending changes
51 queryClient.invalidateQueries({ queryKey: ['files', owner, repo] });
52 queryClient.invalidateQueries({ queryKey: ['pending-changes', owner, repo] });
53 },
54 });
55}
56
57export function useCreateFolder(owner: string, repo: string) {
58 const queryClient = useQueryClient();
59
60 return useMutation({
61 mutationFn: ({ path, message }: { path: string; message?: string }) =>
62 reposApi.createFolder(owner, repo, path, message),
63 onSuccess: () => {
64 // Invalidate and refetch files query and pending changes
65 queryClient.invalidateQueries({ queryKey: ['files', owner, repo] });
66 queryClient.invalidateQueries({ queryKey: ['pending-changes', owner, repo] });
67 },
68 });
69}
70
71export function useRenameItem(owner: string, repo: string) {
72 const queryClient = useQueryClient();
73
74 return useMutation({
75 mutationFn: ({ oldPath, newPath, message }: { oldPath: string; newPath: string; message?: string }) =>
76 reposApi.renameItem(owner, repo, oldPath, newPath, message),
77 onSuccess: () => {
78 // Invalidate and refetch files query and pending changes
79 queryClient.invalidateQueries({ queryKey: ['files', owner, repo] });
80 queryClient.invalidateQueries({ queryKey: ['pending-changes', owner, repo] });
81 },
82 });
83}
84
85export function usePendingChanges(owner: string, repo: string) {
86 return useQuery({
87 queryKey: ['pending-changes', owner, repo],
88 queryFn: () => reposApi.getPendingChanges(owner, repo),
89 enabled: !!owner && !!repo,
90 refetchInterval: 5000, // Refetch every 5 seconds to keep in sync
91 });
92}
93
94export function useDiscardChanges(owner: string, repo: string) {
95 const queryClient = useQueryClient();
96
97 return useMutation({
98 mutationFn: () => reposApi.discardChanges(owner, repo),
99 onSuccess: () => {
100 // Invalidate and refetch all related queries
101 queryClient.invalidateQueries({ queryKey: ['pending-changes', owner, repo] });
102 queryClient.invalidateQueries({ queryKey: ['files', owner, repo] });
103 queryClient.invalidateQueries({ queryKey: ['branchStatus', owner, repo] });
104 },
105 });
106}