feat(insights): fix DBSCAN, Persian embeddings crash, D3 physics layouts, and D3 node not found runtime error
Some checks failed
CI / Lint, Test & Build (push) Failing after 1m7s
CI / Deploy production (on server) (push) Has been skipped

This commit is contained in:
Antigravity
2026-05-24 18:57:33 +00:00
parent e2672cd2c2
commit e881004c77
63 changed files with 5729 additions and 563 deletions

View File

@@ -25,9 +25,13 @@ import { ChartExtension } from './tiptap-chart-extension'
import { ChartSuggestionsDialog } from './chart-suggestions-dialog'
import { UniqueIdExtension } from './tiptap-unique-id-extension'
import { LiveBlockExtension } from './tiptap-live-block-extension'
import { RtlPreserveExtension } from './tiptap-rtl-preserve-extension'
import { ClipArticleExtension } from './tiptap-clip-article-extension'
import { BlockPicker, type BlockSuggestion } from './block-picker'
import { detectTextDirection } from '@/lib/clip/rtl-content'
import { stripHtmlToPlainText } from '@/lib/text/plain-text'
import { NoteLinkPicker, type NoteLinkOption } from './note-link-picker'
import { NOTE_REQUEST_SAVE_EVENT } from '@/lib/note-change-sync'
import { applyClipRtlDirection } from '@/lib/editor/apply-clip-rtl-direction'
import { useAiConsent } from '@/components/legal/ai-consent-provider'
import type { Editor } from '@tiptap/core'
import type { EditorState } from '@tiptap/pm/state'
@@ -60,6 +64,8 @@ interface RichTextEditorProps {
placeholder?: string
onImageUpload?: (file: File) => Promise<string>
noteId?: string
/** URL source du clip (BBC Persian, etc.) — pour RTL explicite des listes */
sourceUrl?: string | null
}
interface RichTextEditorRef {
@@ -227,7 +233,7 @@ function useImageInsert() {
}
export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(
function RichTextEditor({ content, onChange, className, placeholder, onImageUpload, noteId }, ref) {
function RichTextEditor({ content, onChange, className, placeholder, onImageUpload, noteId, sourceUrl }, ref) {
const { t } = useLanguage()
const { requestAiConsent } = useAiConsent()
const imageInsert = useImageInsert()
@@ -350,6 +356,8 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
ChartExtension,
UniqueIdExtension,
LiveBlockExtension,
ClipArticleExtension,
RtlPreserveExtension,
Placeholder.configure({ placeholder: placeholder || t('richTextEditor.placeholder') || "Tapez '/' pour voir les commandes..." }),
],
content: content || '',
@@ -428,6 +436,11 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
noteLinkRangeRef.current = null
}
},
onCreate: ({ editor: e }) => {
requestAnimationFrame(() => {
applyClipRtlDirection(e, { sourceUrl })
})
},
})
useEffect(() => {
@@ -442,12 +455,15 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
if (editor && content !== undefined && content !== lastEmittedContent.current) {
editor.commands.setContent(content || '')
lastEmittedContent.current = content || ''
// TipTap #7338 : dir explicite rtl sur listes (pas auto) après chargement HTML
requestAnimationFrame(() => {
applyClipRtlDirection(editor, { sourceUrl })
})
}
// Update current note content for chart suggestions
if (content !== undefined) {
setCurrentNoteContent(content || '')
}
}, [content, editor])
}, [content, editor, sourceUrl])
// Chart suggestion handlers
const handleOpenChartSuggestions = useCallback(async () => {
@@ -463,8 +479,10 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
options?: { atEnd?: boolean }
) => {
if (!editor || !editor.isEditable) return false
const plainExcerpt = payload.excerpt.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()
const plainExcerpt = stripHtmlToPlainText(payload.excerpt)
if (!plainExcerpt) return false
const isRtl = detectTextDirection(`${payload.noteTitle}\n${plainExcerpt}`) === 'rtl'
const rtlAttrs = isRtl ? { dir: 'rtl' as const, lang: 'fa' as const } : {}
const chain = editor.chain()
if (options?.atEnd !== false) {
chain.focus('end')
@@ -475,10 +493,16 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
{ type: 'paragraph', content: [] },
{
type: 'blockquote',
content: [{ type: 'paragraph', content: [{ type: 'text', text: plainExcerpt }] }],
attrs: rtlAttrs.dir ? { dir: rtlAttrs.dir } : {},
content: [{
type: 'paragraph',
attrs: rtlAttrs,
content: [{ type: 'text', text: plainExcerpt }],
}],
},
{
type: 'paragraph',
attrs: rtlAttrs,
content: [
{ type: 'text', text: '— ' },
{