feat(insights): fix DBSCAN, Persian embeddings crash, D3 physics layouts, and D3 node not found runtime error
This commit is contained in:
@@ -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: '— ' },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user