mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Fix: Switch the default theme from light mode to dark mode and improve some styles #9869 -Update UI component styles such as input boxes, tables, and prompt boxes -Optimize login page layout and style details -Revise some of the wording, such as uniformly changing "data flow" to "pipeline" -Adjust the parser to support the markdown type ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
228 lines
6.9 KiB
TypeScript
228 lines
6.9 KiB
TypeScript
import { TimelineNode } from '@/components/originui/timeline';
|
|
import Spotlight from '@/components/spotlight';
|
|
import { cn } from '@/lib/utils';
|
|
import classNames from 'classnames';
|
|
import { useCallback, useEffect, 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 } from './hooks';
|
|
import { IChunk, IDslComponent } from './interface';
|
|
interface IProps {
|
|
isReadonly: boolean;
|
|
isChange: boolean;
|
|
setIsChange: (isChange: boolean) => void;
|
|
step?: TimelineNode;
|
|
data: { value: IDslComponent; key: string };
|
|
reRunLoading: boolean;
|
|
clickChunk: (chunk: IChunk) => void;
|
|
summaryInfo: string;
|
|
reRunFunc: (data: { value: IDslComponent; key: string }) => void;
|
|
}
|
|
const ParserContainer = (props: IProps) => {
|
|
const {
|
|
isChange,
|
|
setIsChange,
|
|
step,
|
|
data,
|
|
reRunFunc,
|
|
reRunLoading,
|
|
clickChunk,
|
|
isReadonly,
|
|
summaryInfo,
|
|
} = props;
|
|
const { t } = useTranslation();
|
|
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;
|
|
if (!outputs || !key) return { key: '', type: '', value: [] };
|
|
const value = outputs[key]?.value;
|
|
const type = outputs[key]?.type;
|
|
console.log('outputs-->', outputs, data, key, value);
|
|
return {
|
|
key,
|
|
type,
|
|
value,
|
|
params: data?.value?.obj?.params,
|
|
};
|
|
}, [data]);
|
|
|
|
const [initialText, setInitialText] = useState(initialValue);
|
|
|
|
useEffect(() => {
|
|
setInitialText(initialValue);
|
|
}, [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 + ''),
|
|
);
|
|
setIsChange(true);
|
|
setSelectedChunkIds([]);
|
|
}
|
|
}, [selectedChunkIds, initialText, setIsChange]);
|
|
|
|
const handleCheckboxClick = useCallback(
|
|
(id: string | number, checked: boolean) => {
|
|
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;
|
|
|
|
const handleCreateChunk = useCallback(
|
|
(text: string) => {
|
|
const newText = [...initialText.value, { text: text || ' ' }];
|
|
setInitialText({
|
|
...initialText,
|
|
value: newText as any,
|
|
});
|
|
},
|
|
[initialText],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
{isChange && !isReadonly && (
|
|
<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={false} 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')} */}
|
|
{summaryInfo}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{isChunck && (
|
|
<div>
|
|
<h2 className="text-[16px]">{t('dataflowParser.result')}</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">
|
|
{!isReadonly && (
|
|
<CheckboxSets
|
|
selectAllChunk={selectAllChunk}
|
|
removeChunk={handleRemoveChunk}
|
|
checked={selectedChunkIds.length === initialText.value.length}
|
|
selectedChunkIds={selectedChunkIds}
|
|
/>
|
|
)}
|
|
<ChunkResultBar
|
|
isReadonly={isReadonly}
|
|
changeChunkTextMode={changeChunkTextMode}
|
|
createChunk={handleCreateChunk}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
className={cn(
|
|
' border rounded-lg p-[20px] box-border w-[calc(100%-20px)] overflow-auto scrollbar-auto',
|
|
{
|
|
'h-[calc(100vh-240px)]': isChunck,
|
|
'h-[calc(100vh-180px)]': !isChunck,
|
|
},
|
|
)}
|
|
>
|
|
{initialText && (
|
|
<FormatPreserEditor
|
|
initialValue={initialText}
|
|
onSave={handleSave}
|
|
isReadonly={isReadonly}
|
|
isChunck={isChunck}
|
|
textMode={textMode}
|
|
isDelete={
|
|
step?.type === TimelineNodeType.characterSplitter ||
|
|
step?.type === TimelineNodeType.titleSplitter
|
|
}
|
|
clickChunk={clickChunk}
|
|
handleCheckboxClick={handleCheckboxClick}
|
|
selectedChunkIds={selectedChunkIds}
|
|
/>
|
|
)}
|
|
<Spotlight opcity={0.6} coverage={60} />
|
|
</div>
|
|
{/* </Spin> */}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
export default ParserContainer;
|