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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user