Files
ragflow/web/src/components/document-preview/md/index.tsx
monsterDavid a851228ded fix(preview): authenticate markdown document preview requests (#15589)
## 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>
2026-06-11 15:46:20 +08:00

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;