mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-16 04:37:21 +08:00
## Summary Fixes [#15585](https://github.com/infiniflow/ragflow/issues/15585). - Route markdown preview through the shared `request` client (same as txt/image previewers) so `Authorization` headers and interceptors are applied consistently. - Add a unit test covering `AUTH_BETA` token loading for embedded search auth. ## Root cause Search result preview for `.md`/`.mdx` used raw `fetch`, which did not apply the same auth path as other preview types. That led to `401` on `GET /api/v1/documents/{id}/preview` even when the user was logged in or using an embedded search `auth` query param. ## Test plan - [ ] Log in, run a search, open a markdown citation link — preview loads (no 401). - [ ] Open an embedded shared search URL with `auth` query param, preview a markdown file — preview loads. - [ ] Confirm PDF/txt preview still works in the same search UI. --------- Co-authored-by: MkDev11 <89318445+bitloi@users.noreply.github.com> Co-authored-by: Wang Qi <wangq8@outlook.com>
92 lines
2.3 KiB
TypeScript
92 lines
2.3 KiB
TypeScript
import message from '@/components/ui/message';
|
|
import { Spin } from '@/components/ui/spin';
|
|
import { MarkdownRemarkPluginsLite } from '@/constants/markdown-remark-plugins';
|
|
import { cn } from '@/lib/utils';
|
|
import FileError from '@/pages/document-viewer/file-error';
|
|
import request from '@/utils/request';
|
|
import React, { useEffect, useState } from 'react';
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
|
interface MdProps {
|
|
// filePath: string;
|
|
className?: string;
|
|
url: string;
|
|
}
|
|
|
|
export const Md: React.FC<MdProps> = ({ url, className }) => {
|
|
const [content, setContent] = useState<string>('');
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!url) {
|
|
setContent('');
|
|
setError(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
let cancelled = false;
|
|
setError(null);
|
|
setLoading(true);
|
|
|
|
const fetchMarkdown = async () => {
|
|
try {
|
|
const res = await request(url, {
|
|
method: 'GET',
|
|
responseType: 'blob',
|
|
onError: (err: unknown) => {
|
|
console.error('Error loading markdown file:', err);
|
|
},
|
|
});
|
|
if (cancelled) return;
|
|
|
|
const blob = res.data;
|
|
const text = await blob.text();
|
|
if (cancelled) return;
|
|
setContent(text);
|
|
} catch (err: unknown) {
|
|
if (cancelled) return;
|
|
const messageText =
|
|
err instanceof Error ? err.message : 'Failed to fetch markdown file';
|
|
setError(messageText);
|
|
message.error('Failed to load file');
|
|
} finally {
|
|
if (!cancelled) {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
fetchMarkdown();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [url]);
|
|
|
|
if (error) return <FileError>{error}</FileError>;
|
|
|
|
return (
|
|
<div
|
|
style={{ padding: 4, overflow: 'scroll' }}
|
|
className={cn(
|
|
className,
|
|
'markdown-body relative h-[calc(100vh - 200px)]',
|
|
)}
|
|
>
|
|
{loading && (
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<Spin />
|
|
</div>
|
|
)}
|
|
{!loading && (
|
|
<ReactMarkdown remarkPlugins={MarkdownRemarkPluginsLite}>
|
|
{content}
|
|
</ReactMarkdown>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Md;
|