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

@@ -1,6 +1,7 @@
import { useState, useEffect } from 'react'
import { useSearchParams } from 'next/navigation'
import { useSession } from 'next-auth/react'
import { useAiConsent } from '@/components/legal/ai-consent-provider'
/**
* Hook to check if auto label suggestions should be shown for the current notebook
@@ -8,6 +9,7 @@ import { useSession } from 'next-auth/react'
*/
export function useAutoLabelSuggestion() {
const { data: session } = useSession()
const { hasAiConsent } = useAiConsent()
const searchParams = useSearchParams()
const [shouldSuggest, setShouldSuggest] = useState(false)
const [notebookId, setNotebookId] = useState<string | null>(searchParams.get('notebook'))
@@ -23,11 +25,11 @@ export function useAutoLabelSuggestion() {
setShouldSuggest(false)
// Check if we should suggest labels for this notebook
if (currentNotebookId && session?.user?.id) {
if (currentNotebookId && session?.user?.id && hasAiConsent) {
checkNotebookForSuggestions(currentNotebookId)
}
}
}, [searchParams, notebookId, session])
}, [searchParams, notebookId, session, hasAiConsent])
const checkNotebookForSuggestions = async (nbId: string) => {
try {

View File

@@ -1,4 +1,5 @@
import { useLanguage } from '@/lib/i18n'
import { useAiConsent } from '@/components/legal/ai-consent-provider'
import { useState, useEffect, useRef, useCallback } from 'react';
import { useDebounce } from './use-debounce';
import { TagSuggestion } from '@/lib/ai/types';
@@ -11,6 +12,7 @@ interface UseAutoTaggingProps {
export function useAutoTagging({ content, notebookId, enabled = true }: UseAutoTaggingProps) {
const { language } = useLanguage();
const { hasAiConsent, requestAiConsent } = useAiConsent();
const [suggestions, setSuggestions] = useState<TagSuggestion[]>([]);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -29,6 +31,14 @@ export function useAutoTagging({ content, notebookId, enabled = true }: UseAutoT
return;
}
if (!hasAiConsent) {
const consented = await requestAiConsent();
if (!consented) {
setSuggestions([]);
return;
}
}
// Cancel previous request
abortRef.current?.abort();
const controller = new AbortController();
@@ -65,7 +75,7 @@ export function useAutoTagging({ content, notebookId, enabled = true }: UseAutoT
setIsAnalyzing(false);
}
}
}, []);
}, [hasAiConsent, requestAiConsent]);
// Trigger on content change
useEffect(() => {

View File

@@ -1,5 +1,6 @@
import { useState, useEffect, useRef } from 'react'
import { useDebounce } from './use-debounce'
import { useAiConsent } from '@/components/legal/ai-consent-provider'
export interface TitleSuggestion {
title: string
@@ -13,6 +14,7 @@ interface UseTitleSuggestionsProps {
}
export function useTitleSuggestions({ content, enabled = true }: UseTitleSuggestionsProps) {
const { requestAiConsent, hasAiConsent } = useAiConsent()
const [suggestions, setSuggestions] = useState<TitleSuggestion[]>([])
const [isAnalyzing, setIsAnalyzing] = useState(false)
const [error, setError] = useState<string | null>(null)
@@ -41,6 +43,14 @@ export function useTitleSuggestions({ content, enabled = true }: UseTitleSuggest
abortRef.current = controller
const generateTitles = async () => {
if (!hasAiConsent) {
const consented = await requestAiConsent()
if (!consented) {
setSuggestions([])
return
}
}
setIsAnalyzing(true)
setError(null)
@@ -73,7 +83,7 @@ export function useTitleSuggestions({ content, enabled = true }: UseTitleSuggest
}
generateTitles()
}, [debouncedContent, enabled])
}, [debouncedContent, enabled, hasAiConsent, requestAiConsent])
// Cleanup on unmount
useEffect(() => {