diff --git a/src/pages/IntelligentLabNotebook.tsx b/src/pages/IntelligentLabNotebook.tsx
index 86107c7..280b0bc 100644
--- a/src/pages/IntelligentLabNotebook.tsx
+++ b/src/pages/IntelligentLabNotebook.tsx
@@ -21,6 +21,7 @@ interface Note {
id: number;
experimentId: number;
userId: number;
+ title: string;
content: string;
createdAt: string;
updatedAt: string;
@@ -68,6 +69,9 @@ export default function IntelligentLabNotebook() {
const [isExtractingInsertable, setIsExtractingInsertable] = useState(false);
const [isGeneratingSuggestions, setIsGeneratingSuggestions] = useState(false);
const [showHistory, setShowHistory] = useState(false);
+ const [isSaving, setIsSaving] = useState(false);
+ const [saveStatus, setSaveStatus] = useState<'idle' | 'saved' | 'error'>('idle');
+ const [noteTitle, setNoteTitle] = useState('');
const scrollRef = useRef(null);
const noteTextareaRef = useRef(null);
@@ -86,10 +90,23 @@ export default function IntelligentLabNotebook() {
const loadNotes = async () => {
try {
- const response = await fetch(`/api/experiments/${experimentId}/notes`);
+ const userId = localStorage.getItem('sapientlab_user_id');
+ const url = userId
+ ? `/api/experiment-notes/by-experiment/${experimentId}?user_id=${userId}`
+ : `/api/experiment-notes/by-experiment/${experimentId}`;
+ const response = await fetch(url);
if (response.ok) {
const data = await response.json();
- setNotes(Array.isArray(data) ? data : []);
+ const normalized = Array.isArray(data) ? data : [];
+ setNotes(normalized.map((n: any) => ({
+ id: n.id,
+ experimentId: n.experiment_id,
+ userId: n.user_id,
+ title: n.title ?? '',
+ content: n.content,
+ createdAt: n.created_at,
+ updatedAt: n.updated_at,
+ })));
}
} catch {
// notes endpoint not yet available
@@ -309,39 +326,88 @@ export default function IntelligentLabNotebook() {
}
};
+ const deriveTitle = (content: string): string => {
+ const firstLine = content.split('\n').find(l => l.trim()) ?? '';
+ return firstLine.substring(0, 100) || `Nota del ${new Date().toLocaleDateString()}`;
+ };
+
+ const mapNoteResponse = (n: any): Note => ({
+ id: n.id,
+ experimentId: n.experiment_id,
+ userId: n.user_id,
+ title: n.title ?? '',
+ content: n.content,
+ createdAt: n.created_at,
+ updatedAt: n.updated_at,
+ });
+
const saveNote = async (content: string): Promise => {
+ const userId = parseInt(localStorage.getItem('sapientlab_user_id') ?? '1', 10);
+ const title = noteTitle.trim() || deriveTitle(content);
+
try {
if (currentNoteId) {
- const response = await fetch(`/api/experiments/${experimentId}/notes/${currentNoteId}`, {
- method: 'PUT',
+ const response = await fetch(`/api/experiment-notes/${currentNoteId}`, {
+ method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ content }),
+ body: JSON.stringify({ title, content }),
});
if (response.ok) {
- const updated = await response.json();
- setNotes(prev =>
- prev.map(n => (n.id === currentNoteId ? { ...n, ...updated } : n))
- );
+ const updated = mapNoteResponse(await response.json());
+ setNoteTitle(updated.title);
+ setNotes(prev => prev.map(n => (n.id === currentNoteId ? updated : n)));
return currentNoteId;
}
+ const err = await response.json().catch(() => null);
+ console.error('Error al actualizar nota:', response.status, err);
+ return null;
} else {
- const response = await fetch(`/api/experiments/${experimentId}/notes`, {
+ const response = await fetch('/api/experiment-notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ content }),
+ body: JSON.stringify({
+ experiment_id: experimentId,
+ user_id: userId,
+ title,
+ content,
+ }),
});
if (response.ok) {
- const newNote = await response.json();
- setNotes([newNote, ...notes]);
+ const newNote = mapNoteResponse(await response.json());
+ setNotes(prev => [newNote, ...prev]);
setCurrentNoteId(newNote.id);
+ setNoteTitle(newNote.title);
return newNote.id;
}
+ const err = await response.json().catch(() => null);
+ console.error('Error al crear nota:', response.status, err);
+ return null;
}
} catch (error) {
console.error('Error saving note:', error);
+ return null;
}
+ };
- return currentNoteId;
+ const handleSaveNote = async () => {
+ if (!noteContent.trim() || isSaving) return;
+ setIsSaving(true);
+ setSaveStatus('idle');
+ try {
+ const savedId = await saveNote(noteContent);
+ if (savedId !== null) {
+ setSaveStatus('saved');
+ setTimeout(() => setSaveStatus('idle'), 2500);
+ } else {
+ setSaveStatus('error');
+ setTimeout(() => setSaveStatus('idle'), 3000);
+ }
+ } catch {
+ setSaveStatus('error');
+ setTimeout(() => setSaveStatus('idle'), 3000);
+ } finally {
+ setIsSaving(false);
+ }
};
const handleAnalyzeText = async () => {
@@ -529,13 +595,17 @@ ${sugg.safetyWarnings.length > 0 ? `### Advertencias de Seguridad\n${sugg.safety
const createNewNote = () => {
setNoteContent('');
+ setNoteTitle('');
setCurrentNoteId(null);
+ setSaveStatus('idle');
setMessages([messages[0]]);
};
const selectNote = (note: Note) => {
setNoteContent(note.content);
+ setNoteTitle(note.title);
setCurrentNoteId(note.id);
+ setSaveStatus('idle');
setShowHistory(false);
setMessages([messages[0]]);
};
@@ -650,7 +720,7 @@ ${sugg.safetyWarnings.length > 0 ? `### Advertencias de Seguridad\n${sugg.safety
{new Date(note.createdAt).toLocaleString()}
- {note.content.substring(0, 40)}...
+ {note.title || note.content.substring(0, 40)}
))
@@ -662,6 +732,18 @@ ${sugg.safetyWarnings.length > 0 ? `### Advertencias de Seguridad\n${sugg.safety
{/* Notepad Editor */}