fix: stabilize local folder AI document workflow
- scope local-folder PageTree revision and document sidebar rendering to fileTreeScope - preserve projected table/image attrs for local Markdown aggregate fallback - avoid FileTree restore forced layouts on cold design open - add API ChatOnly provider runtime and local OCR task handling regressions
This commit is contained in:
@@ -51,11 +51,12 @@ export const legacyStylesToTiptapMarks = (styles) => {
|
||||
export const legacyMarkArrayToTiptapMarks = (inlineMarks) => {
|
||||
if (!Array.isArray(inlineMarks)) return [];
|
||||
return inlineMarks.flatMap((mark) => {
|
||||
if (!mark || typeof mark !== 'object') return [];
|
||||
if (mark.type === 'bold' || mark.type === 'italic' || mark.type === 'underline' || mark.type === 'strike' || mark.type === 'code') {
|
||||
return [{ type: mark.type }];
|
||||
const markType = typeof mark === 'string' ? mark : typeof mark?.type === 'string' ? mark.type : '';
|
||||
if (!markType) return [];
|
||||
if (markType === 'bold' || markType === 'italic' || markType === 'underline' || markType === 'strike' || markType === 'code') {
|
||||
return [{ type: markType }];
|
||||
}
|
||||
if (mark.type === 'link') {
|
||||
if (markType === 'link') {
|
||||
const href = typeof mark?.attrs?.href === 'string' ? mark.attrs.href.trim() : '';
|
||||
return href ? [{ type: 'link', attrs: { href } }] : [];
|
||||
}
|
||||
@@ -77,10 +78,19 @@ export const legacyInlineContentToTiptap = (value) => {
|
||||
if (typeof value === 'string') return value ? [{ type: 'text', text: value }] : [];
|
||||
if (Array.isArray(value)) return value.flatMap(legacyInlineContentToTiptap);
|
||||
if (value && typeof value === 'object') {
|
||||
const text = typeof value.text === 'string' ? value.text : '';
|
||||
const payload = value.payload && typeof value.payload === 'object' ? value.payload : null;
|
||||
if (payload?.type === 'hard_break') return [{ type: 'hardBreak' }];
|
||||
const text = typeof value.text === 'string'
|
||||
? value.text
|
||||
: typeof payload?.text === 'string'
|
||||
? payload.text
|
||||
: '';
|
||||
if (text) {
|
||||
const attrs = value.attrs && typeof value.attrs === 'object' ? value.attrs : {};
|
||||
const marks = mergeTiptapMarks(
|
||||
legacyStylesToTiptapMarks(attrs.styles),
|
||||
legacyStylesToTiptapMarks(value.styles),
|
||||
legacyMarkArrayToTiptapMarks(payload?.marks),
|
||||
legacyMarkArrayToTiptapMarks(value.marks)
|
||||
);
|
||||
return [{ type: 'text', text, ...(marks.length ? { marks } : {}) }];
|
||||
@@ -182,7 +192,7 @@ export const legacyBlockToTiptap = (block, index = 0) => {
|
||||
return { type: 'paragraph', attrs: withTextAlign({ blockId }), content: mediaContent };
|
||||
}
|
||||
if (type === 'table') {
|
||||
const tableSnapshot = block?.props?.tiptapTable;
|
||||
const tableSnapshot = block?.props?.tiptapTable || block?.attrs?.tiptapTable;
|
||||
if (tableSnapshot && typeof tableSnapshot === 'object' && tableSnapshot.type === 'table') return tableSnapshot;
|
||||
return {
|
||||
type: 'table',
|
||||
@@ -209,12 +219,13 @@ export const legacyBlockToTiptap = (block, index = 0) => {
|
||||
};
|
||||
}
|
||||
if (type === 'image') {
|
||||
const imageSnapshot = block?.props?.tiptapImage;
|
||||
const imageSnapshot = block?.props?.tiptapImage || block?.attrs?.tiptapImage;
|
||||
if (imageSnapshot && typeof imageSnapshot === 'object' && imageSnapshot.type === 'image') return imageSnapshot;
|
||||
const attrsSource = block?.attrs && typeof block.attrs === 'object' ? block.attrs : {};
|
||||
const attrs = {
|
||||
src: String(block?.props?.src || block?.src || ''),
|
||||
alt: block?.props?.alt || block?.alt || null,
|
||||
title: block?.props?.title || block?.title || null,
|
||||
src: String(block?.props?.src || attrsSource.src || block?.src || ''),
|
||||
alt: block?.props?.alt || attrsSource.alt || block?.alt || null,
|
||||
title: block?.props?.title || attrsSource.title || block?.title || null,
|
||||
};
|
||||
return attrs.src ? { type: 'image', attrs: { blockId, ...attrs } } : null;
|
||||
}
|
||||
@@ -318,7 +329,7 @@ export const localMarkdownDirectoryFromDocumentId = (documentId) => {
|
||||
};
|
||||
|
||||
export const isExternalOrSpecialUrl = (value) => {
|
||||
const text = String(value || '').trim();
|
||||
const text = unwrapMarkdownLinkTarget(value);
|
||||
return !text
|
||||
|| text.startsWith('#')
|
||||
|| text.startsWith('data:')
|
||||
@@ -329,8 +340,16 @@ export const isExternalOrSpecialUrl = (value) => {
|
||||
|| text.startsWith('/api/');
|
||||
};
|
||||
|
||||
export const normalizeLocalAssetRelativePath = (value, context) => {
|
||||
export const unwrapMarkdownLinkTarget = (value) => {
|
||||
const text = String(value || '').trim();
|
||||
if (text.length >= 2 && text.startsWith('<') && text.endsWith('>')) {
|
||||
return text.slice(1, -1).trim();
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
export const normalizeLocalAssetRelativePath = (value, context) => {
|
||||
const text = unwrapMarkdownLinkTarget(value);
|
||||
if (!text || isExternalOrSpecialUrl(text)) return text;
|
||||
if (text.startsWith('/')) return text.replace(/^\/+/, '');
|
||||
const baseDir = localMarkdownDirectoryFromDocumentId(context?.documentId);
|
||||
|
||||
Reference in New Issue
Block a user