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

@@ -64,7 +64,7 @@ const ComparisonModal = dynamic(() => import('./comparison-modal').then(m => ({
const FusionModal = dynamic(() => import('./fusion-modal').then(m => ({ default: m.FusionModal })), { ssr: false })
import { useConnectionsCompare } from '@/hooks/use-connections-compare'
import { useNotebooks } from '@/context/notebooks-context'
import { useRefresh } from '@/lib/use-refresh'
import { emitNoteChange } from '@/lib/note-change-sync'
import { useLanguage } from '@/lib/i18n'
import { toast } from 'sonner'
@@ -178,7 +178,6 @@ export const NoteCard = memo(function NoteCard({
}: NoteCardProps) {
const router = useRouter()
const searchParams = useSearchParams()
const { refreshNotes } = useRefresh()
const { data: session } = useSession()
const { t, language } = useLanguage()
const { notebooks, moveNoteToNotebookOptimistic, refreshLabels } = useNotebooks()
@@ -203,9 +202,9 @@ export const NoteCard = memo(function NoteCard({
const handleUpdateReminder = async (noteId: string, reminder: Date | null) => {
startTransition(async () => {
try {
await updateNote(noteId, { reminder })
await updateNote(noteId, { reminder }, { skipRevalidation: true })
setReminderDate(reminder)
refreshNotes(note?.notebookId)
emitNoteChange({ type: 'updated', note: { ...note, reminder: reminder?.toISOString() ?? null } })
if (reminder) {
toast.success(t('notes.reminderSet', { datetime: reminder.toLocaleString() }))
} else {
@@ -304,9 +303,9 @@ export const NoteCard = memo(function NoteCard({
setIsDeleting(true)
setIsHidden(true) // masquage immédiat
try {
await deleteNote(note.id)
await deleteNote(note.id, { skipRevalidation: true })
await refreshLabels()
refreshNotes(note?.notebookId) // met à jour la liste et le compteur du carnet
emitNoteChange({ type: 'deleted', noteId: note.id, notebookId: note.notebookId })
} catch (error) {
console.error('Failed to delete note:', error)
setIsHidden(false)
@@ -319,7 +318,7 @@ export const NoteCard = memo(function NoteCard({
setIsHidden(true)
try {
await restoreNote(note.id)
refreshNotes(note?.notebookId)
emitNoteChange({ type: 'updated', note: { ...note, trashedAt: null } })
toast.success(t('trash.noteRestored'))
} catch (error) {
console.error('Failed to restore note:', error)
@@ -333,7 +332,7 @@ export const NoteCard = memo(function NoteCard({
setIsHidden(true)
try {
await permanentDeleteNote(note.id)
refreshNotes(note?.notebookId)
emitNoteChange({ type: 'deleted', noteId: note.id, notebookId: note.notebookId })
toast.success(t('trash.notePermanentlyDeleted'))
} catch (error) {
console.error('Failed to permanently delete note:', error)
@@ -345,8 +344,8 @@ export const NoteCard = memo(function NoteCard({
const handleTogglePin = async () => {
startTransition(async () => {
addOptimisticNote({ isPinned: !note.isPinned })
await togglePin(note.id, !note.isPinned)
refreshNotes(note?.notebookId)
await togglePin(note.id, !note.isPinned, { skipRevalidation: true })
emitNoteChange({ type: 'updated', note: { ...note, isPinned: !note.isPinned } })
if (!note.isPinned) {
toast.success(t('notes.pinned'))
@@ -359,8 +358,8 @@ export const NoteCard = memo(function NoteCard({
const handleToggleArchive = async () => {
startTransition(async () => {
addOptimisticNote({ isArchived: !note.isArchived })
await toggleArchive(note.id, !note.isArchived)
refreshNotes(note?.notebookId)
await toggleArchive(note.id, !note.isArchived, { skipRevalidation: true })
emitNoteChange({ type: 'updated', note: { ...note, isArchived: !note.isArchived } })
})
}
@@ -368,7 +367,7 @@ export const NoteCard = memo(function NoteCard({
setLocalColor(color) // instant visual update, survives transition
startTransition(async () => {
addOptimisticNote({ color })
await updateNote(note.id, { color }, { skipRevalidation: false })
await updateNote(note.id, { color }, { skipRevalidation: true })
})
}
@@ -403,7 +402,7 @@ export const NoteCard = memo(function NoteCard({
setLocalCheckItems(updatedItems) // instant visual update, survives transition
startTransition(async () => {
addOptimisticNote({ checkItems: updatedItems })
await updateNote(note.id, { checkItems: updatedItems })
await updateNote(note.id, { checkItems: updatedItems }, { skipRevalidation: true })
})
}
}
@@ -821,12 +820,6 @@ export const NoteCard = memo(function NoteCard({
isOpen={!!comparisonNotes}
onClose={() => setComparisonNotes(null)}
notes={comparisonNotesData}
onOpenNote={(noteId) => {
const foundNote = comparisonNotesData.find(n => n.id === noteId)
if (foundNote) {
onEdit?.(foundNote, false)
}
}}
/>
</div>
)}
@@ -839,7 +832,7 @@ export const NoteCard = memo(function NoteCard({
onClose={() => setFusionNotes([])}
notes={fusionNotes}
onConfirmFusion={async ({ title, content }, options) => {
await createNote({
const created = await createNote({
title,
content,
labels: options.keepAllTags
@@ -854,12 +847,12 @@ export const NoteCard = memo(function NoteCard({
})
if (options.archiveOriginals) {
for (const n of fusionNotes) {
if (n.id) await updateNote(n.id, { isArchived: true })
if (n.id) await updateNote(n.id, { isArchived: true }, { skipRevalidation: true })
}
}
toast.success(t('toast.notesFusionSuccess'))
setFusionNotes([])
refreshNotes(note?.notebookId)
if (created) emitNoteChange({ type: 'created', note: created })
}}
/>
</div>