feat(dashboard): tableau de bord Second Brain configurable avec chargement progressif
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m3s
CI / Deploy production (on server) (push) Successful in 23s

Briefing granulaire, pistes rapides puis enrichissement async, layout persisté v5,
suggestions agents, intégration Gmail et navigation sidebar alignée sur /home.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Antigravity
2026-07-14 16:50:53 +00:00
parent d38a99586b
commit 30da592ba2
62 changed files with 7741 additions and 335 deletions

View File

@@ -6,6 +6,7 @@ import { NoteChart } from './note-chart'
import { suggestCharts, chartSuggestionToMarkdown, type ChartSuggestion, type SuggestChartsResponse } from '@/lib/ai/services/chart-suggestion.service'
import { BarChart3, X, Search, AlertCircle, Sparkles } from 'lucide-react'
import { cn } from '@/lib/utils'
import { useLanguage } from '@/lib/i18n'
// Chart type to color mapping for visual variety
const CHART_TYPE_COLORS: Record<string, string> = {
@@ -36,6 +37,7 @@ export function ChartSuggestionsDialog({
onClose,
onSelectChart,
}: ChartSuggestionsDialogProps) {
const { t } = useLanguage()
const [response, setResponse] = useState<SuggestChartsResponse | null>(null)
const [loading, setLoading] = useState(false)
const [selectedIndex, setSelectedIndex] = useState<number | null>(null)
@@ -127,12 +129,12 @@ export function ChartSuggestionsDialog({
{loading ? (
<span className="flex items-center gap-2">
<Search className="w-3 h-3 animate-spin" />
Analyzing {isAnalyzingSelection ? 'selection' : 'note'} ({wordCount} words)...
{isAnalyzingSelection ? t('chart.analyzingSelection') : t('chart.analyzingNote')} ({wordCount} {t('chart.words')})...
</span>
) : response?.hasData ? (
`Found ${response?.detectedData || 'data'}`
`${t('chart.found')} ${response?.detectedData || ''}`
) : (
'No data detected'
t('chart.noDataDetected')
)}
</p>
</div>
@@ -140,7 +142,7 @@ export function ChartSuggestionsDialog({
<button
onClick={onClose}
className="p-2 hover:bg-muted rounded-lg transition-colors"
aria-label="Close"
aria-label={t('common.close')}
>
<X className="w-5 h-5" />
</button>
@@ -152,7 +154,7 @@ export function ChartSuggestionsDialog({
<div className="flex items-center justify-center py-12">
<div className="text-center">
<Search className="w-12 h-12 mx-auto mb-4 text-muted-foreground animate-pulse" />
<p className="text-muted-foreground">Analyzing your content for chart data...</p>
<p className="text-muted-foreground">{t('chart.analyzing')}</p>
</div>
</div>
) : response?.quotaExceeded ? (
@@ -167,7 +169,7 @@ export function ChartSuggestionsDialog({
className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
onClick={() => (window.location.href = '/settings/billing')}
>
Upgrade Plan
{t('ai.featureLocked')}
</button>
</div>
</div>
@@ -175,10 +177,10 @@ export function ChartSuggestionsDialog({
<div className="flex items-center justify-center py-12">
<div className="text-center max-w-md">
<AlertCircle className="w-12 h-12 mx-auto mb-4 text-destructive" />
<h3 className="text-lg font-semibold mb-2">Error</h3>
<h3 className="text-lg font-semibold mb-2">{t('common.error')}</h3>
<p className="text-sm text-muted-foreground mb-2">{response.error}</p>
<details className="text-left text-xs text-muted-foreground mt-4">
<summary className="cursor-pointer hover:text-foreground">Debug info</summary>
<summary className="cursor-pointer hover:text-foreground">{t('chart.debugInfo')}</summary>
<pre className="mt-2 bg-muted p-2 rounded overflow-auto max-h-32">
analyzedText: {response.analyzedText}
{'\n'}detectedData: {response.detectedData}
@@ -190,20 +192,20 @@ export function ChartSuggestionsDialog({
<div className="flex items-center justify-center py-12">
<div className="text-center max-w-md">
<AlertCircle className="w-12 h-12 mx-auto mb-4 text-muted-foreground" />
<h3 className="text-lg font-semibold mb-2">No Data Detected</h3>
<h3 className="text-lg font-semibold mb-2">{t('chart.noDataDetected')}</h3>
<p className="text-muted-foreground mb-4">
Try adding numerical data to your note. Charts work best with:
{t('chart.noDataHint')}
</p>
<ul className="text-sm text-muted-foreground text-left inline-block">
<li> Sales figures, metrics, or measurements</li>
<li> Lists with values (e.g., "Jan: 5000, Feb: 7500")</li>
<li> Percentages or proportions</li>
<li> Time-series data</li>
<li>{t('chart.dataHint1')}</li>
<li>{t('chart.dataHint2')}</li>
<li>{t('chart.dataHint3')}</li>
<li>{t('chart.dataHint4')}</li>
</ul>
<div className="mt-4 pt-4 border-t border-border/50">
<details className="text-left">
<summary className="text-xs text-muted-foreground cursor-pointer hover:text-foreground">
Debug: Show what was analyzed
{t('chart.debugShowAnalyzed')}
</summary>
<pre className="mt-2 text-xs bg-muted p-2 rounded overflow-auto max-h-32">
{textToAnalyze.substring(0, 500)}
@@ -276,7 +278,7 @@ export function ChartSuggestionsDialog({
{/* Data preview */}
<div className="mt-2 pt-2 border-t border-border/50">
<p className="text-xs text-muted-foreground">
{suggestion.data.length} data points
{suggestion.data.length} {t('chart.dataPoints')}
</p>
</div>
</button>
@@ -286,9 +288,9 @@ export function ChartSuggestionsDialog({
{/* Keyboard hint */}
<div className="flex items-center justify-center gap-4 pt-4 text-xs text-muted-foreground">
<span> Navigate</span>
<span> Select</span>
<span>Esc Cancel</span>
<span>{t('chart.navigateHint')}</span>
<span>{t('chart.selectHint')}</span>
<span>{t('chart.escCancel')}</span>
</div>
</div>
)}