feat: brainstorm sessions, PDF document Q&A, embedding fixes, and UI improvements
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
- Add brainstorm feature with collaborative canvas, AI idea generation, live cursors, playback, and export - Add PDF upload/extraction/ingestion pipeline with pgvector document search (RAG) - Add document Q&A overlay with streaming chat and PDF preview - Add note attachments UI with status polling, grid layout, and auto-scroll - Add task extraction AI tool and agent executor improvements - Fix NoteEmbedding missing updatedAt column, re-index 66 notes with 1536-dim embeddings - Fix brainstorm 'Create Note' button: add success toast and redirect to created note - Fix memory echo notification infinite polling - Fix chat route to always include document_search tool - Add brainstorm i18n keys across all 14 locales - Add socket server for real-time brainstorm collaboration - Add hierarchical notebook selector and organize notebook dialog improvements - Add sidebar brainstorm section with session management - Update prisma schema with brainstorm tables, attachments, and document chunks
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, useTransition } from 'react'
|
||||
import { format } from 'date-fns'
|
||||
import { fr } from 'date-fns/locale/fr'
|
||||
import { enUS } from 'date-fns/locale/en-US'
|
||||
import { faIR } from 'date-fns/locale/fa-IR'
|
||||
import { formatAbsoluteDateLocalized } from '@/lib/utils/format-localized-date'
|
||||
import * as Diff from 'diff'
|
||||
import {
|
||||
History, Loader2, RotateCcw, Trash2, GitBranchPlus, Check, GitCompare, X,
|
||||
@@ -36,12 +37,14 @@ interface NoteHistoryModalProps {
|
||||
type ViewMode = 'preview' | 'diff'
|
||||
|
||||
function getDateLocale(language: string) {
|
||||
return language === 'fr' ? fr : enUS
|
||||
if (language === 'fr') return fr
|
||||
if (language === 'fa') return faIR
|
||||
return enUS
|
||||
}
|
||||
|
||||
function fmtDate(date: Date | string, language: string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date
|
||||
return format(d, 'd MMM yyyy HH:mm', { locale: getDateLocale(language) })
|
||||
return formatAbsoluteDateLocalized(d, language, 'd MMM yyyy HH:mm', getDateLocale(language))
|
||||
}
|
||||
|
||||
function VersionPreview({ entry, language }: { entry: NoteHistoryEntry; language: string }) {
|
||||
@@ -306,7 +309,7 @@ export function NoteHistoryModal({
|
||||
)}
|
||||
>
|
||||
{/* ── Header ── */}
|
||||
<div className="border-b border-border/60 px-5 py-3 pr-10">
|
||||
<div className="border-b border-border/60 px-5 py-3 pe-10">
|
||||
<DialogTitle className="flex items-center gap-2 text-sm">
|
||||
<History className="h-4 w-4 text-primary" />
|
||||
{t('notes.history') || 'Historique'}
|
||||
@@ -329,7 +332,7 @@ export function NoteHistoryModal({
|
||||
{t('notes.historyDisabledDesc') || "Activez l'historique pour enregistrer les versions."}
|
||||
</p>
|
||||
<Button onClick={handleEnable} disabled={isEnabling} size="lg" className="rounded-full px-8">
|
||||
{isEnabling && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{isEnabling && <Loader2 className="me-2 h-4 w-4 animate-spin" />}
|
||||
{t('notes.enableHistory') || "Activer l'historique"}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -346,7 +349,7 @@ export function NoteHistoryModal({
|
||||
) : (
|
||||
<div className="grid grid-cols-[210px_1fr]">
|
||||
{/* ── Left: Version list ── */}
|
||||
<div className="max-h-[65vh] overflow-y-auto border-r border-border/60 p-2 space-y-1">
|
||||
<div className="max-h-[65vh] overflow-y-auto border-e border-border/60 p-2 space-y-1">
|
||||
{entries.map((entry) => {
|
||||
const isCurrent = entry.version === currentVersion?.version
|
||||
const isSelected = viewMode === 'preview' && selectedId === entry.id
|
||||
@@ -373,7 +376,7 @@ export function NoteHistoryModal({
|
||||
: isSelected ? 'border-primary/40 bg-primary/8' : 'border-transparent hover:bg-muted/60'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-1.5 pr-10">
|
||||
<div className="flex items-center gap-1.5 pe-10">
|
||||
<span className="text-xs font-semibold text-foreground">v{entry.version}</span>
|
||||
{isCurrent && (
|
||||
<span className="rounded bg-primary/15 px-1.5 py-px text-[10px] font-medium text-primary whitespace-nowrap">
|
||||
@@ -386,7 +389,7 @@ export function NoteHistoryModal({
|
||||
</p>
|
||||
|
||||
<div className={cn(
|
||||
'absolute right-1 top-1/2 -translate-y-1/2 flex items-center gap-0.5',
|
||||
'absolute end-1 top-1/2 -translate-y-1/2 flex items-center gap-0.5',
|
||||
isSelected || isDiffSel ? 'opacity-100' : 'opacity-0 group-hover/entry:opacity-100'
|
||||
)}>
|
||||
{viewMode === 'preview' && (
|
||||
|
||||
Reference in New Issue
Block a user