feat: aide contextuelle dans les paramètres (SettingsHelpBox)
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m18s
CI / Deploy production (on server) (push) Has been skipped

- Nouveau composant SettingsHelpBox (accordéon bleu, étapes numérotées)
- Intégrations: aide Google Calendar + aide Readwise (inline, avant les boutons)
- MCP: explication de ce qu'est MCP et comment l'utiliser
- IA: explication des fournisseurs, BYOK, Ollama, quotas
- Données: explication import/export/ré-indexation/suppression compte

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Antigravity
2026-05-29 15:30:15 +00:00
parent cd1be630d2
commit c7d2e35ea6
5 changed files with 133 additions and 20 deletions

View File

@@ -1,13 +1,21 @@
'use client'
import { useLanguage } from '@/lib/i18n'
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
export function AISettingsHeader() {
const { t } = useLanguage()
return (
<h3 className="text-[10px] font-bold uppercase tracking-[0.4em] text-concrete opacity-60">
{t('aiSettings.description')}
</h3>
<SettingsHelpBox
title="Comment configurer votre IA ?"
steps={[
{ text: 'Choisissez un fournisseur IA parmi 8 disponibles : OpenAI, Anthropic, Google, Mistral, Groq, DeepSeek, Perplexity, ou Ollama (local).' },
{ text: 'Sélectionnez le modèle — chaque fournisseur propose plusieurs modèles avec des capacités différentes (rapidité, coût, contexte).' },
{ text: 'Mode BYOK (Bring Your Own Key) : entrez votre propre clé API pour utiliser votre quota directement — sans passer par les quotas Momento.' },
{ text: 'Les crédits Momento (quota mensuel) sont utilisés quand vous n\'avez pas de clé personnelle. Le plan Free inclut 10 crédits/mois.' },
{ icon: '💡', text: 'Conseil : Ollama permet de faire tourner un LLM entièrement en local sur votre machine — 100% privé, zéro coût.' },
]}
/>
)
}

View File

@@ -9,6 +9,7 @@ import { DeleteAccountDialog } from '@/components/legal/delete-account-dialog'
import { useRouter } from 'next/navigation'
import { motion } from 'motion/react'
import { cn } from '@/lib/utils'
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
export default function DataSettingsPage() {
const { t } = useLanguage()
@@ -225,6 +226,17 @@ export default function DataSettingsPage() {
animate={{ opacity: 1, y: 0 }}
className="space-y-12"
>
<SettingsHelpBox
title="Import / Export — comment ça fonctionne ?"
steps={[
{ text: 'Export ZIP : télécharge toutes vos notes en fichiers Markdown + images + métadonnées. Format universel, lisible partout.' },
{ text: 'Export JSON : version structurée de vos données — utile pour migrer ou sauvegarder programmatiquement.' },
{ text: 'Import Markdown : importez un fichier .md existant directement dans Momento en tant que nouvelle note.' },
{ text: 'Ré-indexer : si la recherche sémantique ne trouve pas certaines notes, relancez l\'indexation pour recalculer les embeddings.' },
{ icon: '⚠️', text: 'Supprimer le compte efface définitivement toutes vos données. Pensez à exporter d\'abord.' },
]}
/>
<h3 className="text-[10px] font-bold uppercase tracking-[0.3em] text-concrete">
{t('dataManagement.toolsDescription')}
</h3>

View File

@@ -3,6 +3,7 @@
import { useState, useEffect } from 'react'
import { BookOpen, Loader2, Check, X, RefreshCw, Trash2, CalendarDays } from 'lucide-react'
import { toast } from 'sonner'
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
export default function IntegrationsPage() {
// ── Readwise ───────────────────────────────────────────────────────────
@@ -158,13 +159,24 @@ export default function IntegrationsPage() {
</div>
{!calConnected ? (
<button
onClick={handleCalConnect}
className="px-4 py-2 text-sm font-semibold bg-ink text-paper rounded-xl hover:bg-ink/80 transition-all flex items-center gap-2"
>
<CalendarDays size={14} />
Connecter Google Calendar
</button>
<div className="space-y-3">
<SettingsHelpBox
title="Comment fonctionne Google Calendar ?"
steps={[
{ text: 'Cliquez "Connecter Google Calendar" — vous serez redirigé vers Google pour autoriser l\'accès.' },
{ text: 'Une fois connecté, revenez ici et cliquez "Événements aujourd\'hui" pour voir votre agenda.' },
{ text: 'Sur chaque événement, cliquez "+ Note" pour créer automatiquement une note de réunion avec template (Ordre du jour / Notes / Actions).' },
{ text: 'La note s\'ouvre directement dans Momento — ajoutez vos notes en temps réel pendant la réunion.' },
]}
/>
<button
onClick={handleCalConnect}
className="px-4 py-2 text-sm font-semibold bg-ink text-paper rounded-xl hover:bg-ink/80 transition-all flex items-center gap-2"
>
<CalendarDays size={14} />
Connecter Google Calendar
</button>
</div>
) : (
<div className="space-y-3">
<div className="flex flex-wrap gap-2">
@@ -226,12 +238,16 @@ export default function IntegrationsPage() {
{!rwConnected && (
<div className="space-y-3">
<p className="text-[12px] text-concrete">
Trouvez votre token sur{' '}
<a href="https://readwise.io/access_token" target="_blank" rel="noopener noreferrer" className="text-brand-accent underline">
readwise.io/access_token
</a>
</p>
<SettingsHelpBox
title="Comment fonctionne Readwise ?"
steps={[
{ text: 'Copiez votre token d\'accès Readwise.', link: { label: 'readwise.io/access_token', href: 'https://readwise.io/access_token' } },
{ text: 'Collez-le dans le champ ci-dessous et cliquez "Connecter". La première synchronisation importe tous vos livres et articles.' },
{ text: 'Chaque livre devient une note dans un carnet "Readwise 📚" — avec tous vos surlignages organisés.' },
{ text: 'Pour mettre à jour avec de nouveaux surlignages, revenez ici et cliquez "Synchroniser maintenant".' },
{ icon: '💡', text: 'Astuce : créez des flashcards IA depuis une note Readwise (bouton 🎓 dans l\'éditeur) pour réviser vos lectures.' },
]}
/>
<div className="flex gap-2">
<input
type="password"

View File

@@ -2,7 +2,7 @@ import { auth } from '@/auth'
import { redirect } from 'next/navigation'
import { McpSettingsPanel } from '@/components/mcp/mcp-settings-panel'
import { listMcpKeys, getMcpServerStatus } from '@/app/actions/mcp-keys'
import { useLanguage } from '@/lib/i18n'
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
export default async function McpSettingsPage() {
const session = await auth()
@@ -15,9 +15,17 @@ export default async function McpSettingsPage() {
return (
<div className="space-y-8">
<h3 className="text-[10px] font-bold uppercase tracking-[0.3em] text-concrete">
Gérez vos clés API et serveurs MCP connectés.
</h3>
<SettingsHelpBox
title="Qu'est-ce que MCP (Model Context Protocol) ?"
defaultOpen={true}
steps={[
{ text: 'MCP est un protocole qui permet aux agents IA de Momento de se connecter à des outils externes (bases de données, APIs, fichiers, etc.).' },
{ text: 'Momento expose un serveur MCP avec 22 outils — vos agents peuvent lire/créer des notes, chercher dans votre base, gérer les carnets, etc.' },
{ text: 'Créez une clé API ici, puis configurez-la dans votre client MCP (Claude Desktop, Cursor, Continue.dev…) avec l\'URL du serveur.' },
{ text: 'Format de configuration : URL du serveur MCP + votre clé dans le header Authorization.', link: { label: 'Documentation MCP', href: 'https://modelcontextprotocol.io/docs' } },
{ icon: '⚡', text: 'Cas d\'usage : demandez à Claude Desktop d\'écrire une note dans Momento, de chercher dans vos carnets, ou de créer un agent.' },
]}
/>
<McpSettingsPanel initialKeys={keys} serverStatus={serverStatus} />
</div>
)

View File

@@ -0,0 +1,69 @@
'use client'
import { useState } from 'react'
import { HelpCircle, ChevronDown, ChevronUp, ExternalLink } from 'lucide-react'
import { cn } from '@/lib/utils'
interface HelpStep {
icon?: string
text: string
link?: { label: string; href: string }
}
interface SettingsHelpBoxProps {
title: string
steps: HelpStep[]
defaultOpen?: boolean
className?: string
}
export function SettingsHelpBox({ title, steps, defaultOpen = false, className }: SettingsHelpBoxProps) {
const [open, setOpen] = useState(defaultOpen)
return (
<div className={cn('rounded-xl border border-blue-200/60 dark:border-blue-800/30 bg-blue-50/50 dark:bg-blue-950/10 overflow-hidden', className)}>
<button
type="button"
onClick={() => setOpen((v) => !v)}
className="w-full flex items-center gap-2 px-4 py-3 text-left hover:bg-blue-100/40 dark:hover:bg-blue-900/10 transition-colors"
>
<HelpCircle size={14} className="text-blue-500 dark:text-blue-400 shrink-0" />
<span className="text-[12px] font-semibold text-blue-700 dark:text-blue-300 flex-1">{title}</span>
{open ? (
<ChevronUp size={13} className="text-blue-400 shrink-0" />
) : (
<ChevronDown size={13} className="text-blue-400 shrink-0" />
)}
</button>
{open && (
<ol className="px-4 pb-4 space-y-2">
{steps.map((step, i) => (
<li key={i} className="flex items-start gap-2.5">
<span className="w-5 h-5 rounded-full bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-300 text-[10px] font-bold flex items-center justify-center shrink-0 mt-0.5">
{step.icon ?? i + 1}
</span>
<span className="text-[12px] text-blue-800 dark:text-blue-200 leading-relaxed">
{step.text}
{step.link && (
<>
{' '}
<a
href={step.link.href}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-0.5 underline underline-offset-2 font-medium hover:text-blue-600"
>
{step.link.label}
<ExternalLink size={10} />
</a>
</>
)}
</span>
</li>
))}
</ol>
)}
</div>
)
}