mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 17:16:52 +08:00
Fix: Updated color parsing functions and optimized component logic. (#10159)
### What problem does this PR solve? refactor(timeline, modal, dataflow-result, dataset-overview): Updated color parsing functions and optimized component logic. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
import { TimelineNode } from '@/components/originui/timeline';
|
||||
import message from '@/components/ui/message';
|
||||
import {
|
||||
RAGFlowPagination,
|
||||
@ -23,9 +24,16 @@ import {
|
||||
useUpdateChunk,
|
||||
} from './hooks';
|
||||
import styles from './index.less';
|
||||
const ChunkerContainer = () => {
|
||||
|
||||
interface IProps {
|
||||
isChange: boolean;
|
||||
setIsChange: (isChange: boolean) => void;
|
||||
step?: TimelineNode;
|
||||
}
|
||||
const ChunkerContainer = (props: IProps) => {
|
||||
const { isChange, setIsChange, step } = props;
|
||||
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
||||
const [isChange, setIsChange] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
data: { documentInfo, data = [], total },
|
||||
@ -135,17 +143,21 @@ const ChunkerContainer = () => {
|
||||
setIsChange(true);
|
||||
onChunkUpdatingOk(e);
|
||||
};
|
||||
|
||||
const handleReRunFunc = () => {
|
||||
setIsChange(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="w-full h-full">
|
||||
{isChange && (
|
||||
<div className=" absolute top-2 right-6">
|
||||
<RerunButton />
|
||||
<RerunButton step={step} onRerun={handleReRunFunc} />
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={classNames(
|
||||
{ [styles.pagePdfWrapper]: isPdf },
|
||||
'flex flex-col w-3/5',
|
||||
'flex flex-col w-full',
|
||||
)}
|
||||
>
|
||||
<Spin spinning={loading} className={styles.spin} size="large">
|
||||
@ -176,7 +188,7 @@ const ChunkerContainer = () => {
|
||||
selectedChunkIds={selectedChunkIds}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-[calc(100vh-280px)] overflow-y-auto pr-2 scrollbar-thin">
|
||||
<div className="h-[calc(100vh-280px)] overflow-y-auto pr-2 scrollbar-auto">
|
||||
<div
|
||||
className={classNames(
|
||||
styles.chunkContainer,
|
||||
@ -227,7 +239,7 @@ const ChunkerContainer = () => {
|
||||
parserId={documentInfo.parser_id}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,16 +1,45 @@
|
||||
import { TimelineNode } from '@/components/originui/timeline';
|
||||
import SvgIcon from '@/components/svg-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import { CircleAlert } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRerunDataflow } from '../../hooks';
|
||||
interface RerunButtonProps {
|
||||
className?: string;
|
||||
step?: TimelineNode;
|
||||
onRerun?: () => void;
|
||||
}
|
||||
const RerunButton = (props: RerunButtonProps) => {
|
||||
const { className, step, onRerun } = props;
|
||||
const { t } = useTranslation();
|
||||
const { loading } = useRerunDataflow();
|
||||
const clickFunc = () => {
|
||||
console.log('click rerun button');
|
||||
Modal.show({
|
||||
visible: true,
|
||||
className: '!w-[560px]',
|
||||
title: t('dataflowParser.confirmRerun'),
|
||||
children: (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('dataflowParser.confirmRerunModalContent', {
|
||||
step: step?.title,
|
||||
}),
|
||||
}}
|
||||
></div>
|
||||
),
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
},
|
||||
onOk: () => {
|
||||
onRerun?.();
|
||||
Modal.hide();
|
||||
},
|
||||
onCancel: () => {
|
||||
Modal.hide();
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
@ -7,40 +7,61 @@ import {
|
||||
PlayIcon,
|
||||
} from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
export const TimelineNodeObj = {
|
||||
begin: {
|
||||
export enum TimelineNodeType {
|
||||
begin = 'begin',
|
||||
parser = 'parser',
|
||||
chunk = 'chunk',
|
||||
indexer = 'indexer',
|
||||
complete = 'complete',
|
||||
end = 'end',
|
||||
}
|
||||
export const TimelineNodeArr = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Begin',
|
||||
icon: <PlayIcon size={13} />,
|
||||
clickable: false,
|
||||
type: TimelineNodeType.begin,
|
||||
},
|
||||
parser: { id: 2, title: 'Parser', icon: <FilePlayIcon size={13} /> },
|
||||
chunker: { id: 3, title: 'Chunker', icon: <Grid3x2 size={13} /> },
|
||||
indexer: {
|
||||
{
|
||||
id: 2,
|
||||
title: 'Parser',
|
||||
icon: <FilePlayIcon size={13} />,
|
||||
type: TimelineNodeType.parser,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Chunker',
|
||||
icon: <Grid3x2 size={13} />,
|
||||
type: TimelineNodeType.chunk,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Indexer',
|
||||
icon: <ListPlus size={13} />,
|
||||
clickable: false,
|
||||
type: TimelineNodeType.indexer,
|
||||
},
|
||||
complete: {
|
||||
{
|
||||
id: 5,
|
||||
title: 'Complete',
|
||||
icon: <CheckLine size={13} />,
|
||||
clickable: false,
|
||||
type: TimelineNodeType.complete,
|
||||
},
|
||||
};
|
||||
];
|
||||
|
||||
export interface TimelineDataFlowProps {
|
||||
activeId: number | string;
|
||||
activeFunc: (id: number | string) => void;
|
||||
activeFunc: (id: number | string, step: TimelineNode) => void;
|
||||
}
|
||||
const TimelineDataFlow = ({ activeFunc, activeId }: TimelineDataFlowProps) => {
|
||||
// const [activeStep, setActiveStep] = useState(2);
|
||||
const timelineNodes: TimelineNode[] = useMemo(() => {
|
||||
const nodes: TimelineNode[] = [];
|
||||
Object.keys(TimelineNodeObj).forEach((key) => {
|
||||
TimelineNodeArr.forEach((node) => {
|
||||
nodes.push({
|
||||
...TimelineNodeObj[key as keyof typeof TimelineNodeObj],
|
||||
...node,
|
||||
className: 'w-32',
|
||||
completed: false,
|
||||
});
|
||||
@ -54,7 +75,10 @@ const TimelineDataFlow = ({ activeFunc, activeId }: TimelineDataFlowProps) => {
|
||||
}, [activeId, timelineNodes]);
|
||||
const handleStepChange = (step: number, id: string | number) => {
|
||||
// setActiveStep(step);
|
||||
activeFunc?.(id);
|
||||
activeFunc?.(
|
||||
id,
|
||||
timelineNodes.find((node) => node.id === activeStep) as TimelineNode,
|
||||
);
|
||||
console.log(step, id);
|
||||
};
|
||||
|
||||
|
||||
@ -140,8 +140,12 @@ export const useFetchParserList = () => {
|
||||
|
||||
export const useRerunDataflow = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isChange, setIsChange] = useState(false);
|
||||
return {
|
||||
loading,
|
||||
setLoading,
|
||||
isChange,
|
||||
setIsChange,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -2,11 +2,17 @@ import { useFetchNextChunkList } from '@/hooks/use-chunk-request';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DocumentPreview from './components/document-preview';
|
||||
import { useGetChunkHighlights, useHandleChunkCardClick } from './hooks';
|
||||
import {
|
||||
useGetChunkHighlights,
|
||||
useHandleChunkCardClick,
|
||||
useRerunDataflow,
|
||||
} from './hooks';
|
||||
|
||||
import DocumentHeader from './components/document-preview/document-header';
|
||||
|
||||
import { TimelineNode } from '@/components/originui/timeline';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import Spotlight from '@/components/spotlight';
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
@ -15,6 +21,8 @@ import {
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from '@/components/ui/breadcrumb';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import {
|
||||
QueryStringMap,
|
||||
useNavigatePage,
|
||||
@ -23,7 +31,10 @@ import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||
import { ChunkerContainer } from './chunker';
|
||||
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
||||
import TimelineDataFlow, { TimelineNodeObj } from './components/time-line';
|
||||
import TimelineDataFlow, {
|
||||
TimelineNodeArr,
|
||||
TimelineNodeType,
|
||||
} from './components/time-line';
|
||||
import styles from './index.less';
|
||||
import ParserContainer from './parser';
|
||||
|
||||
@ -34,7 +45,7 @@ const Chunk = () => {
|
||||
const { selectedChunkId } = useHandleChunkCardClick();
|
||||
const [activeStepId, setActiveStepId] = useState<number | string>(0);
|
||||
const { data: dataset } = useFetchKnowledgeBaseConfiguration();
|
||||
|
||||
const { isChange, setIsChange } = useRerunDataflow();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { navigateToDataset, getQueryString, navigateToDatasetList } =
|
||||
@ -58,10 +69,57 @@ const Chunk = () => {
|
||||
return 'unknown';
|
||||
}, [documentInfo]);
|
||||
|
||||
const handleStepChange = (id: number | string) => {
|
||||
setActiveStepId(id);
|
||||
const handleStepChange = (id: number | string, step: TimelineNode) => {
|
||||
console.log(id, step);
|
||||
if (isChange) {
|
||||
Modal.show({
|
||||
visible: true,
|
||||
className: '!w-[560px]',
|
||||
title: t('dataflowParser.changeStepModalTitle'),
|
||||
children: (
|
||||
<div
|
||||
className="text-sm text-text-secondary"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('dataflowParser.changeStepModalContent', {
|
||||
step: step?.title,
|
||||
}),
|
||||
}}
|
||||
></div>
|
||||
),
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
},
|
||||
footer: (
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant={'outline'} onClick={() => Modal.hide()}>
|
||||
{t('dataflowParser.changeStepModalCancelText')}
|
||||
</Button>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
className="!bg-state-error text-text-primary"
|
||||
onClick={() => {
|
||||
Modal.hide();
|
||||
setActiveStepId(id);
|
||||
setIsChange(false);
|
||||
}}
|
||||
>
|
||||
{t('dataflowParser.changeStepModalConfirmText')}
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
} else {
|
||||
setActiveStepId(id);
|
||||
}
|
||||
};
|
||||
|
||||
const { type } = useGetKnowledgeSearchParams();
|
||||
const currentTimeNode: TimelineNode = useMemo(() => {
|
||||
return (
|
||||
TimelineNodeArr.find((node) => node.id === activeStepId) ||
|
||||
({} as TimelineNode)
|
||||
);
|
||||
}, [activeStepId]);
|
||||
return (
|
||||
<>
|
||||
<PageHeader>
|
||||
@ -114,9 +172,23 @@ const Chunk = () => {
|
||||
</section>
|
||||
</div>
|
||||
<div className="h-dvh border-r -mt-3"></div>
|
||||
{(activeStepId === TimelineNodeObj.chunker.id ||
|
||||
type === 'chunk') && <ChunkerContainer />}
|
||||
{activeStepId === TimelineNodeObj.parser.id && <ParserContainer />}
|
||||
<div className="w-3/5 h-full">
|
||||
{currentTimeNode?.type === TimelineNodeType.chunk && (
|
||||
<ChunkerContainer
|
||||
isChange={isChange}
|
||||
setIsChange={setIsChange}
|
||||
step={currentTimeNode as TimelineNode}
|
||||
/>
|
||||
)}
|
||||
{currentTimeNode?.type === TimelineNodeType.parser && (
|
||||
<ParserContainer
|
||||
isChange={isChange}
|
||||
setIsChange={setIsChange}
|
||||
step={currentTimeNode as TimelineNode}
|
||||
/>
|
||||
)}
|
||||
<Spotlight opcity={0.6} coverage={60} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { TimelineNode } from '@/components/originui/timeline';
|
||||
import Spotlight from '@/components/spotlight';
|
||||
import { Spin } from '@/components/ui/spin';
|
||||
import classNames from 'classnames';
|
||||
@ -6,13 +7,18 @@ import { useTranslation } from 'react-i18next';
|
||||
import FormatPreserveEditor from './components/parse-editer';
|
||||
import RerunButton from './components/rerun-button';
|
||||
import { useFetchParserList, useFetchPaserText } from './hooks';
|
||||
const ParserContainer = () => {
|
||||
interface IProps {
|
||||
isChange: boolean;
|
||||
setIsChange: (isChange: boolean) => void;
|
||||
step?: TimelineNode;
|
||||
}
|
||||
const ParserContainer = (props: IProps) => {
|
||||
const { isChange, setIsChange, step } = props;
|
||||
const { data: initialValue, rerun: onSave } = useFetchPaserText();
|
||||
const { t } = useTranslation();
|
||||
const { loading } = useFetchParserList();
|
||||
|
||||
const [initialText, setInitialText] = useState(initialValue);
|
||||
const [isChange, setIsChange] = useState(false);
|
||||
const handleSave = (newContent: string) => {
|
||||
console.log('保存内容:', newContent);
|
||||
if (newContent !== initialText) {
|
||||
@ -23,14 +29,17 @@ const ParserContainer = () => {
|
||||
}
|
||||
// Here, the API is called to send newContent to the backend
|
||||
};
|
||||
const handleReRunFunc = () => {
|
||||
setIsChange(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{isChange && (
|
||||
<div className=" absolute top-2 right-6">
|
||||
<RerunButton />
|
||||
<RerunButton step={step} onRerun={handleReRunFunc} />
|
||||
</div>
|
||||
)}
|
||||
<div className={classNames('flex flex-col w-3/5')}>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user