mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Fix: Optimized knowledge base file parsing and display #9869 - Optimized the ChunkMethodDialog component logic and adjusted FormSchema validation rules - Updated the document information interface definition, adding pipeline_id, pipeline_name, and suffix fields - Refactored the ChunkResultBar component, removing filter-related logic and simplifying the input box and chunk creation functionality - Improved FormatPreserveEditor to support text mode switching (full/omitted) display control - Updated timeline node titles to more accurate semantic descriptions (e.g., character splitters) - Optimized the data flow result page structure and style, dynamically adjusting height and content display - Fixed the table sorting function on the dataset overview page and enhanced the display of task type icons and status mapping. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
209 lines
6.8 KiB
TypeScript
209 lines
6.8 KiB
TypeScript
import { TimelineNode } from '@/components/originui/timeline';
|
|
import Spotlight from '@/components/spotlight';
|
|
import { Spin } from '@/components/ui/spin';
|
|
import { cn } from '@/lib/utils';
|
|
import classNames from 'classnames';
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import ChunkResultBar from './components/chunk-result-bar';
|
|
import CheckboxSets from './components/chunk-result-bar/checkbox-sets';
|
|
import FormatPreserEditor from './components/parse-editer';
|
|
import RerunButton from './components/rerun-button';
|
|
import { TimelineNodeType } from './constant';
|
|
import { useChangeChunkTextMode, useFetchParserList } from './hooks';
|
|
import { IDslComponent } from './interface';
|
|
interface IProps {
|
|
isChange: boolean;
|
|
setIsChange: (isChange: boolean) => void;
|
|
step?: TimelineNode;
|
|
data: { value: IDslComponent; key: string };
|
|
reRunLoading: boolean;
|
|
reRunFunc: (data: { value: IDslComponent; key: string }) => void;
|
|
}
|
|
const ParserContainer = (props: IProps) => {
|
|
const { isChange, setIsChange, step, data, reRunFunc, reRunLoading } = props;
|
|
const { t } = useTranslation();
|
|
const { loading } = useFetchParserList();
|
|
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
|
const { changeChunkTextMode, textMode } = useChangeChunkTextMode();
|
|
const initialValue = useMemo(() => {
|
|
const outputs = data?.value?.obj?.params?.outputs;
|
|
const key = outputs?.output_format?.value;
|
|
const value = outputs[key]?.value;
|
|
const type = outputs[key]?.type;
|
|
console.log('outputs-->', outputs);
|
|
return {
|
|
key,
|
|
type,
|
|
value,
|
|
};
|
|
}, [data]);
|
|
|
|
const [initialText, setInitialText] = useState(initialValue);
|
|
const handleSave = (newContent: any) => {
|
|
console.log('newContent-change-->', newContent, initialValue);
|
|
if (JSON.stringify(newContent) !== JSON.stringify(initialValue)) {
|
|
setIsChange(true);
|
|
setInitialText(newContent);
|
|
} else {
|
|
setIsChange(false);
|
|
}
|
|
// Here, the API is called to send newContent to the backend
|
|
};
|
|
|
|
const handleReRunFunc = useCallback(() => {
|
|
const newData: { value: IDslComponent; key: string } = {
|
|
...data,
|
|
value: {
|
|
...data.value,
|
|
obj: {
|
|
...data.value.obj,
|
|
params: {
|
|
...(data.value?.obj?.params || {}),
|
|
outputs: {
|
|
...(data.value?.obj?.params?.outputs || {}),
|
|
[initialText.key]: {
|
|
type: initialText.type,
|
|
value: initialText.value,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
reRunFunc(newData);
|
|
setIsChange(false);
|
|
}, [data, initialText, reRunFunc, setIsChange]);
|
|
|
|
const handleRemoveChunk = useCallback(async () => {
|
|
if (selectedChunkIds.length > 0) {
|
|
initialText.value = initialText.value.filter(
|
|
(item: any, index: number) => !selectedChunkIds.includes(index + ''),
|
|
);
|
|
setSelectedChunkIds([]);
|
|
}
|
|
}, [selectedChunkIds, initialText]);
|
|
|
|
const handleCheckboxClick = useCallback(
|
|
(id: string | number, checked: boolean) => {
|
|
console.log('handleCheckboxClick', id, checked, selectedChunkIds);
|
|
setSelectedChunkIds((prev) => {
|
|
if (checked) {
|
|
return [...prev, id.toString()];
|
|
} else {
|
|
return prev.filter((item) => item.toString() !== id.toString());
|
|
}
|
|
});
|
|
},
|
|
[],
|
|
);
|
|
|
|
const selectAllChunk = useCallback(
|
|
(checked: boolean) => {
|
|
setSelectedChunkIds(
|
|
checked ? initialText.value.map((x, index: number) => index) : [],
|
|
);
|
|
},
|
|
[initialText.value],
|
|
);
|
|
|
|
const isChunck =
|
|
step?.type === TimelineNodeType.characterSplitter ||
|
|
step?.type === TimelineNodeType.titleSplitter ||
|
|
step?.type === TimelineNodeType.splitter;
|
|
|
|
const handleCreateChunk = useCallback(
|
|
(text: string) => {
|
|
console.log('handleCreateChunk', text);
|
|
const newText = [...initialText.value, { text: text || ' ' }];
|
|
setInitialText({
|
|
...initialText,
|
|
value: newText,
|
|
});
|
|
console.log('newText', newText, initialText);
|
|
},
|
|
[initialText],
|
|
);
|
|
return (
|
|
<>
|
|
{isChange && (
|
|
<div className=" absolute top-2 right-6">
|
|
<RerunButton
|
|
step={step}
|
|
onRerun={handleReRunFunc}
|
|
loading={reRunLoading}
|
|
/>
|
|
</div>
|
|
)}
|
|
<div className={classNames('flex flex-col w-full')}>
|
|
<Spin spinning={loading} className="" size="large">
|
|
<div className="h-[50px] flex flex-col justify-end pb-[5px]">
|
|
{!isChunck && (
|
|
<div>
|
|
<h2 className="text-[16px]">
|
|
{t('dataflowParser.parseSummary')}
|
|
</h2>
|
|
<div className="text-[12px] text-text-secondary italic ">
|
|
{t('dataflowParser.parseSummaryTip')}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{isChunck && (
|
|
<div>
|
|
<h2 className="text-[16px]">{t('chunk.chunkResult')}</h2>
|
|
<div className="text-[12px] text-text-secondary italic">
|
|
{t('chunk.chunkResultTip')}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{isChunck && (
|
|
<div className="pt-[5px] pb-[5px] flex justify-between items-center">
|
|
<CheckboxSets
|
|
selectAllChunk={selectAllChunk}
|
|
removeChunk={handleRemoveChunk}
|
|
checked={selectedChunkIds.length === initialText.value.length}
|
|
selectedChunkIds={selectedChunkIds}
|
|
/>
|
|
<ChunkResultBar
|
|
changeChunkTextMode={changeChunkTextMode}
|
|
createChunk={handleCreateChunk}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
className={cn(
|
|
' border rounded-lg p-[20px] box-border w-[calc(100%-20px)] overflow-auto scrollbar-none',
|
|
{
|
|
'h-[calc(100vh-240px)]': isChunck,
|
|
'h-[calc(100vh-180px)]': !isChunck,
|
|
},
|
|
)}
|
|
>
|
|
<FormatPreserEditor
|
|
initialValue={initialText}
|
|
onSave={handleSave}
|
|
className={
|
|
initialText.key !== 'json' ? '!h-[calc(100vh-220px)]' : ''
|
|
}
|
|
isChunck={isChunck}
|
|
textMode={textMode}
|
|
isDelete={
|
|
step?.type === TimelineNodeType.characterSplitter ||
|
|
step?.type === TimelineNodeType.titleSplitter ||
|
|
step?.type === TimelineNodeType.splitter
|
|
}
|
|
handleCheckboxClick={handleCheckboxClick}
|
|
selectedChunkIds={selectedChunkIds}
|
|
/>
|
|
<Spotlight opcity={0.6} coverage={60} />
|
|
</div>
|
|
</Spin>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
export default ParserContainer;
|