feat(web): suppress browser ctrl+s and add file tree CRUD

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tao.chen
2026-07-03 17:17:55 +08:00
co-authored by Claude
parent ac87454711
commit fcb678773c
3 changed files with 292 additions and 18 deletions
+101
View File
@@ -127,6 +127,107 @@ export function useFileWrite(): UseMutationResult<
queryClient.invalidateQueries({
queryKey: fileReadQueryKey(variables.workspaceId, variables.path),
});
queryClient.invalidateQueries({
queryKey: ["workspaces", variables.workspaceId, "files"],
});
},
});
}
export interface MkdirVariables {
workspaceId: string;
path: string;
}
export function useFileMkdir(): UseMutationResult<
void,
Error,
MkdirVariables
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ workspaceId, path }) => {
const url = `/api/workspaces/${encodeURIComponent(workspaceId)}/files/mkdir`;
const res = await apiClient(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path }),
});
if (!res.ok) {
throw new Error(`Failed to create folder: ${res.status}`);
}
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: ["workspaces", variables.workspaceId, "files"],
});
},
});
}
export interface RemoveVariables {
workspaceId: string;
path: string;
}
export function useFileRemove(): UseMutationResult<
void,
Error,
RemoveVariables
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ workspaceId, path }) => {
const url =
`/api/workspaces/${encodeURIComponent(workspaceId)}/files?` +
new URLSearchParams({ path }).toString();
const res = await apiClient(url, { method: "DELETE" });
if (!res.ok) {
throw new Error(`Failed to delete file: ${res.status}`);
}
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: ["workspaces", variables.workspaceId, "files"],
});
queryClient.invalidateQueries({
queryKey: fileReadQueryKey(variables.workspaceId, variables.path),
});
},
});
}
export interface RenameVariables {
workspaceId: string;
oldPath: string;
newPath: string;
}
export function useFileRename(): UseMutationResult<
void,
Error,
RenameVariables
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ workspaceId, oldPath, newPath }) => {
const url = `/api/workspaces/${encodeURIComponent(workspaceId)}/files/rename`;
const res = await apiClient(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ oldPath, newPath }),
});
if (!res.ok) {
throw new Error(`Failed to rename file: ${res.status}`);
}
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: ["workspaces", variables.workspaceId, "files"],
});
queryClient.invalidateQueries({
queryKey: fileReadQueryKey(variables.workspaceId, variables.oldPath),
});
},
});
}