mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-01 17:45:28 +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)
This commit is contained in:
@ -1,55 +1,34 @@
|
||||
import { Input } from '@/components/originui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { Radio } from '@/components/ui/radio';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { ListFilter, Plus } from 'lucide-react';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
interface ChunkResultBarProps {
|
||||
changeChunkTextMode: React.Dispatch<React.SetStateAction<string | number>>;
|
||||
available: number | undefined;
|
||||
selectAllChunk: (value: boolean) => void;
|
||||
handleSetAvailable: (value: number | undefined) => void;
|
||||
createChunk: () => void;
|
||||
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
searchString: string;
|
||||
createChunk: (text: string) => void;
|
||||
}
|
||||
export default ({
|
||||
changeChunkTextMode,
|
||||
available,
|
||||
selectAllChunk,
|
||||
handleSetAvailable,
|
||||
createChunk,
|
||||
handleInputChange,
|
||||
searchString,
|
||||
}: ChunkResultBarProps) => {
|
||||
export default ({ changeChunkTextMode, createChunk }: ChunkResultBarProps) => {
|
||||
const { t } = useTranslate('chunk');
|
||||
const [textSelectValue, setTextSelectValue] = useState<string | number>(
|
||||
ChunkTextMode.Full,
|
||||
);
|
||||
const handleFilterChange = (e: string | number) => {
|
||||
const value = e === -1 ? undefined : (e as number);
|
||||
selectAllChunk(false);
|
||||
handleSetAvailable(value);
|
||||
};
|
||||
const filterContent = (
|
||||
<div className="w-[200px]">
|
||||
<Radio.Group onChange={handleFilterChange} value={available}>
|
||||
<div className="flex flex-col gap-2 p-4">
|
||||
<Radio value={-1}>{t('all')}</Radio>
|
||||
<Radio value={1}>{t('enabled')}</Radio>
|
||||
<Radio value={0}>{t('disabled')}</Radio>
|
||||
</div>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
);
|
||||
// const handleFilterChange = (e: string | number) => {
|
||||
// const value = e === -1 ? undefined : (e as number);
|
||||
// selectAllChunk(false);
|
||||
// handleSetAvailable(value);
|
||||
// };
|
||||
// const filterContent = (
|
||||
// <div className="w-[200px]">
|
||||
// <Radio.Group onChange={handleFilterChange} value={available}>
|
||||
// <div className="flex flex-col gap-2 p-4">
|
||||
// <Radio value={-1}>{t('all')}</Radio>
|
||||
// <Radio value={1}>{t('enabled')}</Radio>
|
||||
// <Radio value={0}>{t('disabled')}</Radio>
|
||||
// </div>
|
||||
// </Radio.Group>
|
||||
// </div>
|
||||
// );
|
||||
const textSelectOptions = [
|
||||
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
||||
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
||||
@ -78,7 +57,7 @@ export default ({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Input
|
||||
{/* <Input
|
||||
className="bg-bg-card text-muted-foreground"
|
||||
style={{ width: 200 }}
|
||||
placeholder={t('search')}
|
||||
@ -95,9 +74,9 @@ export default ({
|
||||
<PopoverContent className="p-0 w-[200px]">
|
||||
{filterContent}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Popover> */}
|
||||
<Button
|
||||
onClick={() => createChunk()}
|
||||
onClick={() => createChunk('')}
|
||||
variant={'secondary'}
|
||||
className="bg-bg-card text-muted-foreground hover:bg-card"
|
||||
>
|
||||
|
||||
@ -2,8 +2,9 @@ import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import styles from '../../index.less';
|
||||
interface FormatPreserveEditorProps {
|
||||
initialValue: {
|
||||
key: string;
|
||||
@ -17,6 +18,7 @@ interface FormatPreserveEditorProps {
|
||||
isChunck?: boolean;
|
||||
handleCheckboxClick?: (id: string | number, checked: boolean) => void;
|
||||
selectedChunkIds?: string[];
|
||||
textMode?: ChunkTextMode;
|
||||
}
|
||||
const FormatPreserveEditor = ({
|
||||
initialValue,
|
||||
@ -25,6 +27,7 @@ const FormatPreserveEditor = ({
|
||||
isChunck,
|
||||
handleCheckboxClick,
|
||||
selectedChunkIds,
|
||||
textMode,
|
||||
}: FormatPreserveEditorProps) => {
|
||||
const [content, setContent] = useState(initialValue);
|
||||
// const [isEditing, setIsEditing] = useState(false);
|
||||
@ -32,6 +35,10 @@ const FormatPreserveEditor = ({
|
||||
undefined,
|
||||
);
|
||||
console.log('initialValue', initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
setContent(initialValue);
|
||||
}, [initialValue]);
|
||||
const handleEdit = (e?: any, index?: number) => {
|
||||
console.log(e, index, content);
|
||||
if (content.key === 'json') {
|
||||
@ -143,7 +150,12 @@ const FormatPreserveEditor = ({
|
||||
)}
|
||||
{activeEditIndex !== index && (
|
||||
<div
|
||||
className="text-text-secondary overflow-auto scrollbar-auto whitespace-pre-wrap"
|
||||
className={cn(
|
||||
'text-text-secondary overflow-auto scrollbar-auto whitespace-pre-wrap w-full',
|
||||
{
|
||||
[styles.contentEllipsis]: textMode === ChunkTextMode.Ellipse,
|
||||
},
|
||||
)}
|
||||
key={index}
|
||||
onClick={(e) => {
|
||||
handleEdit(e, index);
|
||||
|
||||
@ -37,11 +37,11 @@ export const TimelineNodeObj = {
|
||||
icon: <Heading size={13} />,
|
||||
},
|
||||
[TimelineNodeType.characterSplitter]: {
|
||||
title: 'Title Splitter',
|
||||
title: 'Character Splitter',
|
||||
icon: <Heading size={13} />,
|
||||
},
|
||||
[TimelineNodeType.splitter]: {
|
||||
title: 'Character Splitter',
|
||||
title: 'Splitter',
|
||||
icon: <Blocks size={13} />,
|
||||
},
|
||||
[TimelineNodeType.tokenizer]: {
|
||||
@ -50,40 +50,6 @@ export const TimelineNodeObj = {
|
||||
clickable: false,
|
||||
},
|
||||
};
|
||||
// export const TimelineNodeArr = [
|
||||
// {
|
||||
// id: 1,
|
||||
// title: 'File',
|
||||
// icon: <PlayIcon size={13} />,
|
||||
// clickable: false,
|
||||
// type: TimelineNodeType.begin,
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// title: 'Context Generator',
|
||||
// icon: <PlayIcon size={13} />,
|
||||
// type: TimelineNodeType.contextGenerator,
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// title: 'Title Splitter',
|
||||
// icon: <PlayIcon size={13} />,
|
||||
// type: TimelineNodeType.titleSplitter,
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// title: 'Character Splitter',
|
||||
// icon: <PlayIcon size={13} />,
|
||||
// type: TimelineNodeType.characterSplitter,
|
||||
// },
|
||||
// {
|
||||
// id: 5,
|
||||
// title: 'Tokenizer',
|
||||
// icon: <CheckLine size={13} />,
|
||||
// clickable: false,
|
||||
// type: TimelineNodeType.tokenizer,
|
||||
// },
|
||||
// ]
|
||||
export interface TimelineDataFlowProps {
|
||||
activeId: number | string;
|
||||
activeFunc: (id: number | string, step: TimelineNode) => void;
|
||||
|
||||
@ -249,7 +249,6 @@ export const useTimelineDataFlow = (data: IPipelineFileLogDetail) => {
|
||||
}
|
||||
const timeNode = {
|
||||
...TimelineNodeObj[name],
|
||||
clickable: true,
|
||||
id: index,
|
||||
className: 'w-32',
|
||||
completed: false,
|
||||
|
||||
@ -82,15 +82,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
:global {
|
||||
.ant-card-body {
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
.contentEllipsis {
|
||||
.multipleLineEllipsis(3);
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ const Chunk = () => {
|
||||
data: { documentInfo },
|
||||
} = useFetchNextChunkList();
|
||||
const { selectedChunkId } = useHandleChunkCardClick();
|
||||
const [activeStepId, setActiveStepId] = useState<number | string>(0);
|
||||
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
||||
const { data: dataset } = useFetchPipelineFileLogDetail();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
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 { useFetchParserList } from './hooks';
|
||||
import { useChangeChunkTextMode, useFetchParserList } from './hooks';
|
||||
import { IDslComponent } from './interface';
|
||||
interface IProps {
|
||||
isChange: boolean;
|
||||
@ -23,6 +25,7 @@ const ParserContainer = (props: IProps) => {
|
||||
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;
|
||||
@ -108,6 +111,19 @@ const ParserContainer = (props: IProps) => {
|
||||
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 && (
|
||||
@ -122,28 +138,50 @@ const ParserContainer = (props: IProps) => {
|
||||
<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]">
|
||||
<div>
|
||||
<h2 className="text-[16px]">
|
||||
{t('dataflowParser.parseSummary')}
|
||||
</h2>
|
||||
<div className="text-[12px] text-text-secondary italic ">
|
||||
{t('dataflowParser.parseSummaryTip')}
|
||||
{!isChunck && (
|
||||
<div>
|
||||
<h2 className="text-[16px]">
|
||||
{t('dataflowParser.parseSummary')}
|
||||
</h2>
|
||||
<div className="text-[12px] text-text-secondary italic ">
|
||||
{t('dataflowParser.parseSummaryTip')}
|
||||
</div>
|
||||
</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]">
|
||||
<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=" border rounded-lg p-[20px] box-border h-[calc(100vh-180px)] w-[calc(100%-20px)] overflow-auto scrollbar-none">
|
||||
<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}
|
||||
@ -151,6 +189,7 @@ const ParserContainer = (props: IProps) => {
|
||||
initialText.key !== 'json' ? '!h-[calc(100vh-220px)]' : ''
|
||||
}
|
||||
isChunck={isChunck}
|
||||
textMode={textMode}
|
||||
isDelete={
|
||||
step?.type === TimelineNodeType.characterSplitter ||
|
||||
step?.type === TimelineNodeType.titleSplitter ||
|
||||
|
||||
Reference in New Issue
Block a user