diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index ea59138..297f47f 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -51,27 +51,39 @@ export interface GitCommit { files_changed: number; } -export async function getGitLog(): Promise { +const projQuery = (project?: string | null) => + project ? `&project=${encodeURIComponent(project)}` : ""; + +export async function getGitLog(project?: string | null): Promise { try { - const res = await fetch("/api/git/log"); + const res = await fetch(`/api/git/log?limit=40${projQuery(project)}`); return (await res.json()).commits; } catch { return []; } } -export async function getGitDiff(hash?: string): Promise { - const url = hash ? `/api/git/diff?hash=${encodeURIComponent(hash)}` : "/api/git/diff"; - const res = await fetch(url); +export async function getGitDiff( + hash?: string, + project?: string | null +): Promise { + const params = new URLSearchParams(); + if (hash) params.set("hash", hash); + if (project) params.set("project", project); + const qs = params.toString(); + const res = await fetch(`/api/git/diff${qs ? `?${qs}` : ""}`); if (!res.ok) return ""; return (await res.json()).diff; } -export async function revertCommit(hash: string): Promise<{ message: string }> { +export async function revertCommit( + hash: string, + project?: string | null +): Promise<{ message: string }> { const res = await fetch("/api/git/revert", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ hash }), + body: JSON.stringify({ hash, project: project ?? null }), }); if (!res.ok) throw await apiError(res, "revert impossible"); return res.json(); @@ -214,6 +226,7 @@ export interface Session { id: string; title: string; model?: string; + project?: string | null; created_at: number; updated_at: number; message_count?: number; @@ -400,29 +413,39 @@ export interface FileNode { children?: FileNode[]; } -export async function listFiles(): Promise { - const res = await fetch("/api/files"); +export async function listFiles(project?: string | null): Promise { + const query = project ? `?project=${encodeURIComponent(project)}` : ""; + const res = await fetch(`/api/files${query}`); return (await res.json()).tree; } -export async function fileContent(path: string): Promise { - const res = await fetch(`/api/files/content?path=${encodeURIComponent(path)}`); +export async function fileContent( + path: string, + project?: string | null +): Promise { + const res = await fetch( + `/api/files/content?path=${encodeURIComponent(path)}${projQuery(project)}` + ); if (!res.ok) return ""; return (await res.json()).content; } -export async function deleteFile(path: string): Promise { - const res = await fetch(`/api/files?path=${encodeURIComponent(path)}`, { - method: "DELETE", - }); +export async function deleteFile( + path: string, + project?: string | null +): Promise { + const res = await fetch( + `/api/files?path=${encodeURIComponent(path)}${projQuery(project)}`, + { method: "DELETE" } + ); if (!res.ok) { throw await apiError(res, `suppression impossible (${res.status})`); } } -export function downloadFile(path: string): void { +export function downloadFile(path: string, project?: string | null): void { const link = document.createElement("a"); - link.href = `/api/files/download?path=${encodeURIComponent(path)}`; + link.href = `/api/files/download?path=${encodeURIComponent(path)}${projQuery(project)}`; link.download = path.split(/[\\/]/).pop() ?? "fichier"; document.body.appendChild(link); link.click(); @@ -473,15 +496,51 @@ export async function listSessions(): Promise { return (await res.json()).sessions; } -export async function createSession(model?: string): Promise { +export async function createSession( + model?: string, + project?: string | null +): Promise { const res = await fetch("/api/sessions", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ title: "Nouvelle session", model }), + body: JSON.stringify({ + title: "Nouvelle session", + model, + project: project ?? null, + }), }); return res.json(); } +export async function listProjects(): Promise<{ + projects: { name: string; files: number }[]; + root_files: number; +}> { + const res = await fetch("/api/projects"); + return res.json(); +} + +export async function createProject(name: string): Promise { + const res = await fetch("/api/projects", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name }), + }); + if (!res.ok) throw await apiError(res, "création du projet impossible"); +} + +export async function setSessionProject( + id: string, + project: string | null +): Promise { + const res = await fetch(`/api/sessions/${id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ project: project ?? "" }), + }); + if (!res.ok) throw await apiError(res, "changement de projet impossible"); +} + export async function getSession( id: string ): Promise<{ session: Session; messages: Message[] }> { diff --git a/frontend/src/panels/ActivityViews.tsx b/frontend/src/panels/ActivityViews.tsx index 665a19c..f6861e1 100644 --- a/frontend/src/panels/ActivityViews.tsx +++ b/frontend/src/panels/ActivityViews.tsx @@ -61,7 +61,7 @@ export function FilesView() { } function WorkspaceTree({ nodes, depth }: { nodes: FileNode[]; depth: number }) { - const { openPreview, previewPath, removeFile } = useStore(); + const { openPreview, previewPath, removeFile, currentProject } = useStore(); const confirmDelete = (node: FileNode) => { const msg = node.type === "dir" @@ -93,7 +93,7 @@ function WorkspaceTree({ nodes, depth }: { nodes: FileNode[]; depth: number }) { {node.type === "file" && (