feat(notes): liens internes, onglet Réseau, living blocks et consentement IA
Rend les liens entre notes visibles et persistants (sync NoteLink au save, auto-save, graphe réseau rafraîchi), ajoute living blocks, Memory Echo, recherche globale, consentement IA explicite et consolide les prototypes design en architectural-grid. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import { auth } from '@/auth'
|
||||
import { getAIProvider } from '@/lib/ai/factory'
|
||||
import { parseNote, getHashColor } from '@/lib/utils'
|
||||
import { upsertNoteEmbedding } from '@/lib/embeddings'
|
||||
import { syncNoteLinksForNote } from '@/lib/notes/sync-note-links'
|
||||
import { getSystemConfig, getConfigNumber, getConfigBoolean, SEARCH_DEFAULTS } from '@/lib/config'
|
||||
import { contextualAutoTagService } from '@/lib/ai/services/contextual-auto-tag.service'
|
||||
import { semanticSearchService } from '@/lib/ai/services/semantic-search.service'
|
||||
@@ -572,18 +573,18 @@ export async function updateNote(id: string, data: {
|
||||
|
||||
if (data.content !== undefined) {
|
||||
const noteId = id
|
||||
const content = data.content
|
||||
; (async () => {
|
||||
try {
|
||||
const provider = getAIProvider(await getSystemConfig());
|
||||
const embedding = await provider.getEmbeddings(content);
|
||||
if (embedding) {
|
||||
await upsertNoteEmbedding(noteId, embedding)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[BG] Embedding regeneration failed:', e);
|
||||
const content = data.content;
|
||||
(async () => {
|
||||
try {
|
||||
const provider = getAIProvider(await getSystemConfig());
|
||||
const embedding = await provider.getEmbeddings(content);
|
||||
if (embedding) {
|
||||
await upsertNoteEmbedding(noteId, embedding);
|
||||
}
|
||||
}).catch(e => console.error('[BG] Uncaught background error:', e))
|
||||
} catch (e) {
|
||||
console.error('[BG] Embedding regeneration failed:', e);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
if ('checkItems' in data) updateData.checkItems = data.checkItems ? JSON.stringify(data.checkItems) : null
|
||||
@@ -655,6 +656,12 @@ export async function updateNote(id: string, data: {
|
||||
console.error('[HISTORY] Failed to create snapshot after update:', snapshotError)
|
||||
}
|
||||
|
||||
if (data.content !== undefined) {
|
||||
syncNoteLinksForNote(id, session.user.id, data.content).catch(err => {
|
||||
console.error('[NoteLink] sync failed after updateNote:', err)
|
||||
})
|
||||
}
|
||||
|
||||
// Only revalidate for STRUCTURAL changes that affect the page layout/lists
|
||||
// Content edits (title, content, size, color) use optimistic UI — no refresh needed
|
||||
const structuralFields = ['isPinned', 'isArchived', 'labels', 'notebookId']
|
||||
@@ -665,19 +672,19 @@ export async function updateNote(id: string, data: {
|
||||
if (!options?.skipRevalidation) {
|
||||
try { revalidatePath(`/note/${id}`) } catch {}
|
||||
try { revalidatePath('/home') } catch {}
|
||||
}
|
||||
|
||||
if (isStructuralChange) {
|
||||
if (data.isArchived !== undefined) {
|
||||
revalidatePath('/archive')
|
||||
}
|
||||
|
||||
if (data.notebookId !== undefined && data.notebookId !== oldNotebookId) {
|
||||
if (oldNotebookId) {
|
||||
revalidatePath(`/notebook/${oldNotebookId}`)
|
||||
if (isStructuralChange) {
|
||||
if (data.isArchived !== undefined) {
|
||||
revalidatePath('/archive')
|
||||
}
|
||||
if (data.notebookId) {
|
||||
revalidatePath(`/notebook/${data.notebookId}`)
|
||||
|
||||
if (data.notebookId !== undefined && data.notebookId !== oldNotebookId) {
|
||||
if (oldNotebookId) {
|
||||
revalidatePath(`/notebook/${oldNotebookId}`)
|
||||
}
|
||||
if (data.notebookId) {
|
||||
revalidatePath(`/notebook/${data.notebookId}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,8 +702,20 @@ export async function updateNote(id: string, data: {
|
||||
}
|
||||
|
||||
// Toggle functions
|
||||
export async function togglePin(id: string, isPinned: boolean) { return updateNote(id, { isPinned }) }
|
||||
export async function toggleArchive(id: string, isArchived: boolean) { return updateNote(id, { isArchived }) }
|
||||
export async function togglePin(
|
||||
id: string,
|
||||
isPinned: boolean,
|
||||
options?: { skipRevalidation?: boolean }
|
||||
) {
|
||||
return updateNote(id, { isPinned }, options)
|
||||
}
|
||||
export async function toggleArchive(
|
||||
id: string,
|
||||
isArchived: boolean,
|
||||
options?: { skipRevalidation?: boolean }
|
||||
) {
|
||||
return updateNote(id, { isArchived }, options)
|
||||
}
|
||||
export async function updateColor(id: string, color: string) { return updateNote(id, { color }) }
|
||||
export async function updateLabels(id: string, labels: string[]) { return updateNote(id, { labels }) }
|
||||
export async function removeFusedBadge(id: string) { return updateNote(id, { autoGenerated: null, aiProvider: null }) }
|
||||
|
||||
Reference in New Issue
Block a user