From 8dd8d65b42c9aa636d80029a1071331a1336b10d Mon Sep 17 00:00:00 2001 From: Xavier Date: Wed, 7 Oct 2026 09:54:06 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20int=C3=A9gration=20de=20la=20route=20API?= =?UTF-8?q?=20de=20renommage=20des=20projets=20dans=20main.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 14 +++++- backend/schemas.py | 5 +- frontend/dashboard.html | 101 +++++++++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 29 deletions(-) diff --git a/backend/main.py b/backend/main.py index b67d706..e46b880 100644 --- a/backend/main.py +++ b/backend/main.py @@ -9,7 +9,7 @@ import os from .database import engine, Base, get_db from .models import User, Project, Message from .auth import get_password_hash, generate_totp_secret, get_totp_uri, verify_password, verify_totp, create_access_token, verify_token -from .schemas import AdminCreate, LoginRequest, ProjectCreate, ProjectResponse, MessageCreate, MessageResponse +from .schemas import AdminCreate, LoginRequest, ProjectCreate, ProjectResponse, ProjectRename, MessageCreate, MessageResponse # Création des tables dans la base de données Base.metadata.create_all(bind=engine) @@ -171,6 +171,18 @@ def create_project(project: ProjectCreate, db: Session = Depends(get_db), curren db.refresh(new_project) return new_project +@app.put("/api/projects/{project_id}/rename", response_model=ProjectResponse) +def rename_project(project_id: int, project_data: ProjectRename, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): + """Renomme un projet existant.""" + project = db.query(Project).filter(Project.id == project_id, Project.user_id == current_user.id).first() + if not project: + raise HTTPException(status_code=404, detail="Projet introuvable") + + project.title = project_data.title + db.commit() + db.refresh(project) + return project + @app.put("/api/projects/{project_id}/pin", response_model=ProjectResponse) def toggle_pin_project(project_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): """Bascule le statut épinglé (is_pinned) d'un projet.""" diff --git a/backend/schemas.py b/backend/schemas.py index 7e34133..06cd645 100644 --- a/backend/schemas.py +++ b/backend/schemas.py @@ -41,4 +41,7 @@ class MessageResponse(MessageBase): project_id: int class Config: - from_attributes = True \ No newline at end of file + from_attributes = True + +class ProjectRename(BaseModel): + title: str \ No newline at end of file diff --git a/frontend/dashboard.html b/frontend/dashboard.html index bb2bd02..54d5c21 100644 --- a/frontend/dashboard.html +++ b/frontend/dashboard.html @@ -53,9 +53,10 @@ {{ project.title }} - - -
{{ activeProject.title }}
+
+ {{ activeProject.title }} + +
- +
AETHAS38 Logo

Comment puis-je vous aider aujourd'hui ?

Sélectionnez ou créez un projet pour commencer.

- +
Démarrez la conversation ci-dessous.
@@ -119,22 +124,35 @@
{{ msg.content }}
+ + +
+
+ + AETHAS38 +
+
+
+
+
+
+
- + - +

AETHAS38 peut faire des erreurs. Vérifiez toujours les informations importantes.

@@ -154,19 +172,18 @@ const activeProject = ref(null); const messages = ref([]); const isLoading = ref(false); + const isAiThinking = ref(false); const pinnedProjects = computed(() => projects.value.filter(p => p.is_pinned)); const recentProjects = computed(() => projects.value.filter(p => !p.is_pinned)); const toggleSidebar = () => { isSidebarOpen.value = !isSidebarOpen.value; }; - const autoResize = () => { const el = promptTextarea.value; if (!el) return; el.style.height = 'auto'; el.style.height = el.scrollHeight + 'px'; }; - const scrollToBottom = () => { nextTick(() => { const container = document.getElementById('chat-container'); @@ -181,7 +198,7 @@ projects.value = await response.json(); nextTick(() => lucide.createIcons()); } - } catch (error) { console.error("Erreur", error); } + } catch (error) { console.error(error); } }; const selectProject = async (project) => { @@ -194,7 +211,7 @@ scrollToBottom(); nextTick(() => lucide.createIcons()); } - } catch (error) { console.error("Erreur chargement messages", error); } + } catch (error) { console.error(error); } }; const createNewProject = async () => { @@ -210,33 +227,63 @@ projects.value.unshift(newProject); selectProject(newProject); } - } catch (error) { console.error("Erreur", error); } + } catch (error) { console.error(error); } finally { isLoading.value = false; } }; + const renameProject = async (project) => { + const newTitle = window.prompt("Nouveau nom du projet :", project.title); + if (!newTitle || newTitle.trim() === "" || newTitle === project.title) return; + + try { + const response = await fetch(`/api/projects/${project.id}/rename`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ title: newTitle.trim() }) + }); + if (response.ok) { + const updatedProject = await response.json(); + const index = projects.value.findIndex(p => p.id === project.id); + if (index !== -1) projects.value[index] = updatedProject; + if (activeProject.value && activeProject.value.id === project.id) { + activeProject.value.title = updatedProject.title; + } + } + } catch (error) { console.error("Erreur de renommage", error); } + }; + const sendMessage = async () => { if (!prompt.value.trim() || !activeProject.value) return; const userText = prompt.value.trim(); prompt.value = ""; autoResize(); - // Ajout optimiste à l'UI messages.value.push({ id: Date.now(), role: 'user', content: userText }); + isAiThinking.value = true; scrollToBottom(); nextTick(() => lucide.createIcons()); - // Sauvegarde en DB try { await fetch(`/api/projects/${activeProject.value.id}/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ role: 'user', content: userText }) }); - // Bientôt : C'est ici que nous déclencherons le workflow IA ! - } catch (error) { console.error("Erreur envoi message", error); } + + // SIMULATION TEMPORAIRE : Attente de l'IA (2 secondes) + setTimeout(() => { + isAiThinking.value = false; + scrollToBottom(); + // La prochaine étape remplacera ce setTimeout par le véritable appel au moteur IA ! + }, 2000); + + } catch (error) { + console.error("Erreur envoi message", error); + isAiThinking.value = false; + } }; - const togglePin = async (projectId) => { + const togglePin = async (projectId) => { /* ... code existant identique ... */ try { const response = await fetch(`/api/projects/${projectId}/pin`, { method: 'PUT' }); if (response.ok) { @@ -244,10 +291,10 @@ const index = projects.value.findIndex(p => p.id === projectId); if (index !== -1) projects.value[index] = updatedProject; } - } catch (error) { console.error("Erreur d'épinglage", error); } + } catch (error) { console.error(error); } }; - const deleteProject = async (projectId) => { + const deleteProject = async (projectId) => { /* ... code existant identique ... */ if (!confirm("Voulez-vous vraiment supprimer ce projet ?")) return; try { const response = await fetch(`/api/projects/${projectId}`, { method: 'DELETE' }); @@ -255,7 +302,7 @@ projects.value = projects.value.filter(p => p.id !== projectId); if (activeProject.value && activeProject.value.id === projectId) activeProject.value = null; } - } catch (error) { console.error("Erreur de suppression", error); } + } catch (error) { console.error(error); } }; onMounted(() => { @@ -265,8 +312,8 @@ return { username, isSidebarOpen, toggleSidebar, prompt, autoResize, promptTextarea, - projects, pinnedProjects, recentProjects, activeProject, messages, - createNewProject, selectProject, sendMessage, isLoading, togglePin, deleteProject + projects, pinnedProjects, recentProjects, activeProject, messages, isAiThinking, + createNewProject, selectProject, renameProject, sendMessage, isLoading, togglePin, deleteProject }; } }).mount('#app');