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 }}
-
-
-
+
+
+
+
@@ -71,9 +72,10 @@
{{ project.title }}
-
-
-
+
+
+
+
@@ -97,17 +99,20 @@
AETHAS38
- {{ activeProject.title }}
+
+ {{ activeProject.title }}
+
+
-
+
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 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');