Merge branch 'xuhd' into 'master'
fix(notebook): 来源搜索导入后立刻显示占位卡并刷新来源列表 See merge request knowledge-base-bj/deerflow-server!148
This commit is contained in:
commit
ed71df1b60
2 files changed
+45
-14
No files matched your search
@@ -405,8 +405,15 @@ const DocumentUploadPopupContent: FC<{
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json() as { imported_count?: number };
|
const data = await response.json() as { imported_count?: number };
|
||||||
toast.success(`成功导入 ${data.imported_count || dataList.length} 个来源`);
|
toast.success(`成功导入 ${data.imported_count || dataList.length} 个来源`);
|
||||||
setListData([]);
|
onUploadComplete?.(
|
||||||
handleBatchDelete();
|
selectedSearchSources.map((s) => ({
|
||||||
|
id: undefined,
|
||||||
|
title: s.title,
|
||||||
|
task_id: undefined,
|
||||||
|
status: "success" as const,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
onOpenChange(false);
|
||||||
} else {
|
} else {
|
||||||
const errorData = await response.json() as { detail?: string };
|
const errorData = await response.json() as { detail?: string };
|
||||||
toast.error(errorData.detail || "导入失败,请重试");
|
toast.error(errorData.detail || "导入失败,请重试");
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ function SourcesDialog({
|
|||||||
isLoadingSources,
|
isLoadingSources,
|
||||||
selectedSourceIds,
|
selectedSourceIds,
|
||||||
pendingSources,
|
pendingSources,
|
||||||
|
pendingImportTitles,
|
||||||
onToggle,
|
onToggle,
|
||||||
onDelete,
|
onDelete,
|
||||||
}: {
|
}: {
|
||||||
@@ -164,6 +165,7 @@ function SourcesDialog({
|
|||||||
isLoadingSources: boolean;
|
isLoadingSources: boolean;
|
||||||
selectedSourceIds: number[];
|
selectedSourceIds: number[];
|
||||||
pendingSources: Map<string, { id?: number; title: string }>;
|
pendingSources: Map<string, { id?: number; title: string }>;
|
||||||
|
pendingImportTitles: string[];
|
||||||
onToggle: (id: number) => void;
|
onToggle: (id: number) => void;
|
||||||
onDelete: (id: number) => void;
|
onDelete: (id: number) => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -216,6 +218,14 @@ function SourcesDialog({
|
|||||||
.map(([taskId, s]) => (
|
.map(([taskId, s]) => (
|
||||||
<PendingSourceCard key={taskId} title={s.title} />
|
<PendingSourceCard key={taskId} title={s.title} />
|
||||||
))}
|
))}
|
||||||
|
{pendingImportTitles
|
||||||
|
.filter((t) => !sources.some((src) => {
|
||||||
|
const srcTitle = src.title ?? (src.document as { title?: string } | undefined)?.title ?? "";
|
||||||
|
return srcTitle === t;
|
||||||
|
}))
|
||||||
|
.map((t) => (
|
||||||
|
<PendingSourceCard key={`import-${t}`} title={t} />
|
||||||
|
))}
|
||||||
{sources.map((src) => (
|
{sources.map((src) => (
|
||||||
<SourceCard
|
<SourceCard
|
||||||
key={src.id}
|
key={src.id}
|
||||||
@@ -269,6 +279,8 @@ export default function StudioNotebookDetailPage({
|
|||||||
// 轮询任务管理:task_id -> 来源信息
|
// 轮询任务管理:task_id -> 来源信息
|
||||||
const [pendingSources, setPendingSources] = useState<Map<string, { id?: number; title: string }>>(new Map());
|
const [pendingSources, setPendingSources] = useState<Map<string, { id?: number; title: string }>>(new Map());
|
||||||
const pollingIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
const pollingIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||||
|
// 同步导入(搜索导入)的占位标题列表,sources 刷新后按标题匹配移除
|
||||||
|
const [pendingImportTitles, setPendingImportTitles] = useState<string[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedModel && models.length > 0) {
|
if (!selectedModel && models.length > 0) {
|
||||||
@@ -287,20 +299,25 @@ export default function StudioNotebookDetailPage({
|
|||||||
}
|
}
|
||||||
}, [sources, notebook?.id, initializedForNotebook]);
|
}, [sources, notebook?.id, initializedForNotebook]);
|
||||||
|
|
||||||
// sources 刷新后,将轮询成功的来源(按标题匹配)自动选中
|
// sources 刷新后,将轮询成功/同步导入的来源(按标题匹配)自动选中,并移除占位卡
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pendingSelectTitlesRef.current.size === 0) return;
|
const getTitle = (s: SourceItem) =>
|
||||||
const matched = sources.filter((s) => {
|
s.title ?? (s.document as { title?: string } | undefined)?.title ?? "";
|
||||||
const title = s.title ?? (s.document as { title?: string } | undefined)?.title ?? "";
|
|
||||||
return pendingSelectTitlesRef.current.has(title);
|
if (pendingSelectTitlesRef.current.size > 0) {
|
||||||
});
|
const matched = sources.filter((s) => pendingSelectTitlesRef.current.has(getTitle(s)));
|
||||||
if (matched.length > 0) {
|
if (matched.length > 0) {
|
||||||
setSelectedSourceIds((prev) => [...new Set([...prev, ...matched.map((s) => s.id)])]);
|
setSelectedSourceIds((prev) => [...new Set([...prev, ...matched.map((s) => s.id)])]);
|
||||||
matched.forEach((s) => {
|
matched.forEach((s) => pendingSelectTitlesRef.current.delete(getTitle(s)));
|
||||||
const title = s.title ?? (s.document as { title?: string } | undefined)?.title ?? "";
|
}
|
||||||
pendingSelectTitlesRef.current.delete(title);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPendingImportTitles((prev) => {
|
||||||
|
if (prev.length === 0) return prev;
|
||||||
|
const sourceTitles = new Set(sources.map(getTitle));
|
||||||
|
const remaining = prev.filter((t) => !sourceTitles.has(t));
|
||||||
|
return remaining.length === prev.length ? prev : remaining;
|
||||||
|
});
|
||||||
}, [sources]);
|
}, [sources]);
|
||||||
const citationRehypePlugins = useMemo(() => {
|
const citationRehypePlugins = useMemo(() => {
|
||||||
const mapped = sources.map((s) => ({
|
const mapped = sources.map((s) => ({
|
||||||
@@ -392,6 +409,12 @@ export default function StudioNotebookDetailPage({
|
|||||||
return newMap;
|
return newMap;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// 同步导入(status=success,无 task_id):立刻显示占位卡 + 等 sources 刷新后自动选中
|
||||||
|
const syncTitles = uploadedSources.filter(s => s.status === 'success' && s.title).map(s => s.title);
|
||||||
|
if (syncTitles.length > 0) {
|
||||||
|
syncTitles.forEach(t => pendingSelectTitlesRef.current.add(t));
|
||||||
|
setPendingImportTitles(prev => [...new Set([...prev, ...syncTitles])]);
|
||||||
|
}
|
||||||
// 刷新来源列表
|
// 刷新来源列表
|
||||||
void queryClient.invalidateQueries({ queryKey: ["studio", "sources", notebook.id] });
|
void queryClient.invalidateQueries({ queryKey: ["studio", "sources", notebook.id] });
|
||||||
// 刷新 notebooks 数据以更新 source_count
|
// 刷新 notebooks 数据以更新 source_count
|
||||||
@@ -854,6 +877,7 @@ export default function StudioNotebookDetailPage({
|
|||||||
isLoadingSources={isLoadingSources}
|
isLoadingSources={isLoadingSources}
|
||||||
selectedSourceIds={selectedSourceIds}
|
selectedSourceIds={selectedSourceIds}
|
||||||
pendingSources={pendingSources}
|
pendingSources={pendingSources}
|
||||||
|
pendingImportTitles={pendingImportTitles}
|
||||||
onToggle={handleToggleSource}
|
onToggle={handleToggleSource}
|
||||||
onDelete={handleDeleteSource}
|
onDelete={handleDeleteSource}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user