feat(notes): liens internes, onglet Réseau, living blocks et consentement IA
Some checks failed
CI / Lint, Test & Build (push) Failing after 1m19s
CI / Deploy production (on server) (push) Has been skipped

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:
Antigravity
2026-05-24 14:27:29 +00:00
parent 077e665dfc
commit e2672cd2c2
323 changed files with 20670 additions and 42431 deletions

View File

@@ -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 }) }