mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 17:16:52 +08:00
### What problem does this PR solve? Fix: Added read-only mode support and optimized navigation logic #9869 - Added the `isReadonly` property to the parseResult component to control the enabled state of editing and interactive features - Added the `navigateToDataFile` navigation method to navigate to the data file details page - Refactored the `navigateToDataflowResult` method to use an object parameter to support more flexible query parameter configuration - Unified the `var(--accent-primary)` CSS variable format to `rgb(var(--accent-primary))` to accommodate more styling scenarios - Extracted the parser initialization logic into a separate hook (`useParserInit`) ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -7,28 +7,17 @@ import { ChunkTextMode } from '../../constant';
|
||||
interface ChunkResultBarProps {
|
||||
changeChunkTextMode: React.Dispatch<React.SetStateAction<string | number>>;
|
||||
createChunk: (text: string) => void;
|
||||
isReadonly: boolean;
|
||||
}
|
||||
export default ({ changeChunkTextMode, createChunk }: ChunkResultBarProps) => {
|
||||
export default ({
|
||||
changeChunkTextMode,
|
||||
createChunk,
|
||||
isReadonly,
|
||||
}: 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 textSelectOptions = [
|
||||
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
||||
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
||||
@ -57,31 +46,15 @@ export default ({ changeChunkTextMode, createChunk }: ChunkResultBarProps) => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* <Input
|
||||
className="bg-bg-card text-muted-foreground"
|
||||
style={{ width: 200 }}
|
||||
placeholder={t('search')}
|
||||
icon={<SearchOutlined />}
|
||||
onChange={handleInputChange}
|
||||
value={searchString}
|
||||
/>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button className="bg-bg-card text-muted-foreground hover:bg-card">
|
||||
<ListFilter />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0 w-[200px]">
|
||||
{filterContent}
|
||||
</PopoverContent>
|
||||
</Popover> */}
|
||||
<Button
|
||||
onClick={() => createChunk('')}
|
||||
variant={'secondary'}
|
||||
className="bg-bg-card text-muted-foreground hover:bg-card"
|
||||
>
|
||||
<Plus size={44} />
|
||||
</Button>
|
||||
{!isReadonly && (
|
||||
<Button
|
||||
onClick={() => createChunk('')}
|
||||
variant={'secondary'}
|
||||
className="bg-bg-card text-muted-foreground hover:bg-card"
|
||||
>
|
||||
<Plus size={44} />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { IJsonContainerProps, IObjContainerProps } from './interface';
|
||||
|
||||
export const useParserInit = ({
|
||||
initialValue,
|
||||
}: {
|
||||
initialValue:
|
||||
| Pick<IJsonContainerProps, 'initialValue'>
|
||||
| Pick<IObjContainerProps, 'initialValue'>;
|
||||
}) => {
|
||||
const [content, setContent] = useState(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
setContent(initialValue);
|
||||
console.log('initialValue json parse', initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
const [activeEditIndex, setActiveEditIndex] = useState<number | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const editDivRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return {
|
||||
content,
|
||||
setContent,
|
||||
activeEditIndex,
|
||||
setActiveEditIndex,
|
||||
editDivRef,
|
||||
};
|
||||
};
|
||||
@ -1,22 +1,8 @@
|
||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import { ArrayContainer, parserKeyMap } from './json-parser';
|
||||
import { FormatPreserveEditorProps } from './interface';
|
||||
import { ArrayContainer } from './json-parser';
|
||||
import { ObjectContainer } from './object-parser';
|
||||
interface FormatPreserveEditorProps {
|
||||
initialValue: {
|
||||
key: keyof typeof parserKeyMap | 'text' | 'html';
|
||||
type: string;
|
||||
value: Array<{ [key: string]: string }>;
|
||||
};
|
||||
onSave: (value: any) => void;
|
||||
className?: string;
|
||||
isSelect?: boolean;
|
||||
isDelete?: boolean;
|
||||
isChunck?: boolean;
|
||||
handleCheckboxClick?: (id: string | number, checked: boolean) => void;
|
||||
selectedChunkIds?: string[];
|
||||
textMode?: ChunkTextMode;
|
||||
}
|
||||
|
||||
const FormatPreserveEditor = ({
|
||||
initialValue,
|
||||
onSave,
|
||||
@ -25,6 +11,8 @@ const FormatPreserveEditor = ({
|
||||
handleCheckboxClick,
|
||||
selectedChunkIds,
|
||||
textMode,
|
||||
clickChunk,
|
||||
isReadonly,
|
||||
}: FormatPreserveEditorProps) => {
|
||||
console.log('initialValue', initialValue);
|
||||
|
||||
@ -42,6 +30,7 @@ const FormatPreserveEditor = ({
|
||||
<div className="editor-container">
|
||||
{['json', 'chunks'].includes(initialValue.key) && (
|
||||
<ArrayContainer
|
||||
isReadonly={isReadonly}
|
||||
className={className}
|
||||
initialValue={initialValue}
|
||||
handleCheck={handleCheck}
|
||||
@ -51,11 +40,13 @@ const FormatPreserveEditor = ({
|
||||
unescapeNewlines={unescapeNewlines}
|
||||
textMode={textMode}
|
||||
isChunck={isChunck}
|
||||
clickChunk={clickChunk}
|
||||
/>
|
||||
)}
|
||||
|
||||
{['text', 'html'].includes(initialValue.key) && (
|
||||
<ObjectContainer
|
||||
isReadonly={isReadonly}
|
||||
className={className}
|
||||
initialValue={initialValue}
|
||||
handleCheck={handleCheck}
|
||||
@ -65,6 +56,7 @@ const FormatPreserveEditor = ({
|
||||
unescapeNewlines={unescapeNewlines}
|
||||
textMode={textMode}
|
||||
isChunck={isChunck}
|
||||
clickChunk={clickChunk}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import { IChunk } from '../../interface';
|
||||
import { parserKeyMap } from './json-parser';
|
||||
|
||||
export interface FormatPreserveEditorProps {
|
||||
initialValue: {
|
||||
key: keyof typeof parserKeyMap | 'text' | 'html';
|
||||
type: string;
|
||||
value: Array<{ [key: string]: string }>;
|
||||
};
|
||||
onSave: (value: any) => void;
|
||||
className?: string;
|
||||
isSelect?: boolean;
|
||||
isDelete?: boolean;
|
||||
isChunck?: boolean;
|
||||
handleCheckboxClick?: (id: string | number, checked: boolean) => void;
|
||||
selectedChunkIds?: string[];
|
||||
textMode?: ChunkTextMode;
|
||||
clickChunk: (chunk: IChunk) => void;
|
||||
isReadonly: boolean;
|
||||
}
|
||||
|
||||
export type IJsonContainerProps = {
|
||||
initialValue: {
|
||||
key: keyof typeof parserKeyMap;
|
||||
type: string;
|
||||
value: {
|
||||
[key: string]: string;
|
||||
}[];
|
||||
};
|
||||
isChunck?: boolean;
|
||||
handleCheck: (e: CheckedState, index: number) => void;
|
||||
selectedChunkIds: string[] | undefined;
|
||||
unescapeNewlines: (text: string) => string;
|
||||
escapeNewlines: (text: string) => string;
|
||||
onSave: (data: {
|
||||
value: {
|
||||
text: string;
|
||||
}[];
|
||||
key: string;
|
||||
type: string;
|
||||
}) => void;
|
||||
className?: string;
|
||||
textMode?: ChunkTextMode;
|
||||
clickChunk: (chunk: IChunk) => void;
|
||||
isReadonly: boolean;
|
||||
};
|
||||
|
||||
export type IObjContainerProps = {
|
||||
initialValue: {
|
||||
key: string;
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
isChunck?: boolean;
|
||||
handleCheck: (e: CheckedState, index: number) => void;
|
||||
unescapeNewlines: (text: string) => string;
|
||||
escapeNewlines: (text: string) => string;
|
||||
onSave: (data: { value: string; key: string; type: string }) => void;
|
||||
className?: string;
|
||||
textMode?: ChunkTextMode;
|
||||
clickChunk: (chunk: IChunk) => void;
|
||||
isReadonly: boolean;
|
||||
};
|
||||
@ -1,37 +1,16 @@
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import styles from '../../index.less';
|
||||
import { useParserInit } from './hook';
|
||||
import { IJsonContainerProps } from './interface';
|
||||
export const parserKeyMap = {
|
||||
json: 'text',
|
||||
chunks: 'content_with_weight',
|
||||
chunks: 'text',
|
||||
};
|
||||
type IProps = {
|
||||
initialValue: {
|
||||
key: keyof typeof parserKeyMap;
|
||||
type: string;
|
||||
value: {
|
||||
[key: string]: string;
|
||||
}[];
|
||||
};
|
||||
isChunck?: boolean;
|
||||
handleCheck: (e: CheckedState, index: number) => void;
|
||||
selectedChunkIds: string[] | undefined;
|
||||
unescapeNewlines: (text: string) => string;
|
||||
escapeNewlines: (text: string) => string;
|
||||
onSave: (data: {
|
||||
value: {
|
||||
text: string;
|
||||
}[];
|
||||
key: string;
|
||||
type: string;
|
||||
}) => void;
|
||||
className?: string;
|
||||
textMode?: ChunkTextMode;
|
||||
};
|
||||
export const ArrayContainer = (props: IProps) => {
|
||||
|
||||
export const ArrayContainer = (props: IJsonContainerProps) => {
|
||||
const {
|
||||
initialValue,
|
||||
isChunck,
|
||||
@ -42,29 +21,27 @@ export const ArrayContainer = (props: IProps) => {
|
||||
onSave,
|
||||
className,
|
||||
textMode,
|
||||
clickChunk,
|
||||
isReadonly,
|
||||
} = props;
|
||||
|
||||
const [content, setContent] = useState(initialValue);
|
||||
const {
|
||||
content,
|
||||
setContent,
|
||||
activeEditIndex,
|
||||
setActiveEditIndex,
|
||||
editDivRef,
|
||||
} = useParserInit({ initialValue });
|
||||
|
||||
useEffect(() => {
|
||||
setContent(initialValue);
|
||||
console.log('initialValue json parse', initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
const [activeEditIndex, setActiveEditIndex] = useState<number | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const editDivRef = useRef<HTMLDivElement>(null);
|
||||
const handleEdit = useCallback(
|
||||
(e?: any, index?: number) => {
|
||||
console.log(e, e.target.innerText);
|
||||
setContent((pre) => ({
|
||||
...pre,
|
||||
value: pre.value.map((item, i) => {
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
[parserKeyMap[content.key]]: e.target.innerText,
|
||||
[parserKeyMap[content.key]]: unescapeNewlines(e.target.innerText),
|
||||
};
|
||||
}
|
||||
return item;
|
||||
@ -76,14 +53,13 @@ export const ArrayContainer = (props: IProps) => {
|
||||
);
|
||||
const handleSave = useCallback(
|
||||
(e: any) => {
|
||||
console.log(e, e.target.innerText);
|
||||
const saveData = {
|
||||
...content,
|
||||
value: content.value?.map((item, index) => {
|
||||
if (index === activeEditIndex) {
|
||||
return {
|
||||
...item,
|
||||
[parserKeyMap[content.key]]: unescapeNewlines(e.target.innerText),
|
||||
[parserKeyMap[content.key]]: e.target.innerText,
|
||||
};
|
||||
} else {
|
||||
return item;
|
||||
@ -99,8 +75,9 @@ export const ArrayContainer = (props: IProps) => {
|
||||
useEffect(() => {
|
||||
if (activeEditIndex !== undefined && editDivRef.current) {
|
||||
editDivRef.current.focus();
|
||||
editDivRef.current.textContent =
|
||||
content.value[activeEditIndex][parserKeyMap[content.key]];
|
||||
editDivRef.current.textContent = escapeNewlines(
|
||||
content.value[activeEditIndex][parserKeyMap[content.key]],
|
||||
);
|
||||
}
|
||||
}, [activeEditIndex, content]);
|
||||
|
||||
@ -119,7 +96,7 @@ export const ArrayContainer = (props: IProps) => {
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{isChunck && (
|
||||
{isChunck && !isReadonly && (
|
||||
<Checkbox
|
||||
onCheckedChange={(e) => {
|
||||
handleCheck(e, index);
|
||||
@ -132,16 +109,8 @@ export const ArrayContainer = (props: IProps) => {
|
||||
{activeEditIndex === index && (
|
||||
<div
|
||||
ref={editDivRef}
|
||||
contentEditable={true}
|
||||
contentEditable={!isReadonly}
|
||||
onBlur={handleSave}
|
||||
// onKeyUp={handleChange}
|
||||
// dangerouslySetInnerHTML={{
|
||||
// __html: DOMPurify.sanitize(
|
||||
// escapeNewlines(
|
||||
// content.value[index][parserKeyMap[content.key]],
|
||||
// ),
|
||||
// ),
|
||||
// }}
|
||||
className={cn(
|
||||
'w-full bg-transparent text-text-secondary border-none focus-visible:border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none p-0',
|
||||
className,
|
||||
@ -159,7 +128,10 @@ export const ArrayContainer = (props: IProps) => {
|
||||
)}
|
||||
key={index}
|
||||
onClick={(e) => {
|
||||
handleEdit(e, index);
|
||||
clickChunk(item);
|
||||
if (!isReadonly) {
|
||||
handleEdit(e, index);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{escapeNewlines(item[parserKeyMap[content.key]])}
|
||||
|
||||
@ -1,24 +1,10 @@
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { ChunkTextMode } from '../../constant';
|
||||
import styles from '../../index.less';
|
||||
|
||||
type IProps = {
|
||||
initialValue: {
|
||||
key: string;
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
isChunck?: boolean;
|
||||
handleCheck: (e: CheckedState, index: number) => void;
|
||||
unescapeNewlines: (text: string) => string;
|
||||
escapeNewlines: (text: string) => string;
|
||||
onSave: (data: { value: string; key: string; type: string }) => void;
|
||||
className?: string;
|
||||
textMode?: ChunkTextMode;
|
||||
};
|
||||
export const ObjectContainer = (props: IProps) => {
|
||||
import { useParserInit } from './hook';
|
||||
import { IObjContainerProps } from './interface';
|
||||
export const ObjectContainer = (props: IObjContainerProps) => {
|
||||
const {
|
||||
initialValue,
|
||||
isChunck,
|
||||
@ -27,36 +13,34 @@ export const ObjectContainer = (props: IProps) => {
|
||||
onSave,
|
||||
className,
|
||||
textMode,
|
||||
clickChunk,
|
||||
isReadonly,
|
||||
} = props;
|
||||
|
||||
const [content, setContent] = useState(initialValue);
|
||||
const {
|
||||
content,
|
||||
setContent,
|
||||
activeEditIndex,
|
||||
setActiveEditIndex,
|
||||
editDivRef,
|
||||
} = useParserInit({ initialValue });
|
||||
|
||||
useEffect(() => {
|
||||
setContent(initialValue);
|
||||
console.log('initialValue object parse', initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
const [activeEditIndex, setActiveEditIndex] = useState<number | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const editDivRef = useRef<HTMLDivElement>(null);
|
||||
const handleEdit = useCallback(
|
||||
(e?: any) => {
|
||||
console.log(e, e.target.innerText);
|
||||
setContent((pre) => ({
|
||||
...pre,
|
||||
value: e.target.innerText,
|
||||
value: escapeNewlines(e.target.innerText),
|
||||
}));
|
||||
setActiveEditIndex(1);
|
||||
},
|
||||
[setContent, setActiveEditIndex],
|
||||
);
|
||||
|
||||
const handleSave = useCallback(
|
||||
(e: any) => {
|
||||
console.log(e, e.target.innerText);
|
||||
const saveData = {
|
||||
...content,
|
||||
value: unescapeNewlines(e.target.innerText),
|
||||
value: e.target.innerText,
|
||||
};
|
||||
onSave(saveData);
|
||||
setActiveEditIndex(undefined);
|
||||
@ -83,7 +67,7 @@ export const ObjectContainer = (props: IProps) => {
|
||||
{activeEditIndex && (
|
||||
<div
|
||||
ref={editDivRef}
|
||||
contentEditable={true}
|
||||
contentEditable={!isReadonly}
|
||||
onBlur={handleSave}
|
||||
className={cn(
|
||||
'w-full bg-transparent text-text-secondary border-none focus-visible:border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none p-0',
|
||||
@ -100,7 +84,10 @@ export const ObjectContainer = (props: IProps) => {
|
||||
},
|
||||
)}
|
||||
onClick={(e) => {
|
||||
handleEdit(e);
|
||||
clickChunk(content);
|
||||
if (!isReadonly) {
|
||||
handleEdit(e);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{escapeNewlines(content.value)}
|
||||
|
||||
@ -83,8 +83,8 @@ const TimelineDataFlow = ({
|
||||
nodeSize={24}
|
||||
activeStyle={{
|
||||
nodeSize: 30,
|
||||
iconColor: 'var(--accent-primary)',
|
||||
textColor: 'var(--accent-primary)',
|
||||
iconColor: 'rgb(var(--accent-primary))',
|
||||
textColor: 'rgb(var(--accent-primary))',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -9,6 +9,15 @@ export enum TimelineNodeType {
|
||||
contextGenerator = 'extractor',
|
||||
titleSplitter = 'hierarchicalMerger',
|
||||
characterSplitter = 'splitter',
|
||||
tokenizer = 'indexer',
|
||||
tokenizer = 'tokenizer',
|
||||
end = 'end',
|
||||
}
|
||||
|
||||
export enum PipelineResultSearchParams {
|
||||
DocumentId = 'doc_id',
|
||||
KnowledgeId = 'knowledgeId',
|
||||
Type = 'type',
|
||||
IsReadOnly = 'is_read_only',
|
||||
AgentId = 'agent_id',
|
||||
AgentTitle = 'agent_title',
|
||||
}
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { TimelineNode } from '@/components/originui/timeline';
|
||||
import message from '@/components/ui/message';
|
||||
import {
|
||||
useCreateChunk,
|
||||
useDeleteChunk,
|
||||
useSelectChunkList,
|
||||
} from '@/hooks/chunk-hooks';
|
||||
import { useCreateChunk, useDeleteChunk } from '@/hooks/chunk-hooks';
|
||||
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||
import { IChunk } from '@/interfaces/database/knowledge';
|
||||
@ -18,7 +14,11 @@ import { useCallback, useMemo, useState } from 'react';
|
||||
import { IHighlight } from 'react-pdf-highlighter';
|
||||
import { useParams, useSearchParams } from 'umi';
|
||||
import { ITimelineNodeObj, TimelineNodeObj } from './components/time-line';
|
||||
import { ChunkTextMode, TimelineNodeType } from './constant';
|
||||
import {
|
||||
ChunkTextMode,
|
||||
PipelineResultSearchParams,
|
||||
TimelineNodeType,
|
||||
} from './constant';
|
||||
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
||||
|
||||
export const useFetchPipelineFileLogDetail = (props?: {
|
||||
@ -55,28 +55,21 @@ export const useFetchPipelineFileLogDetail = (props?: {
|
||||
};
|
||||
|
||||
export const useHandleChunkCardClick = () => {
|
||||
const [selectedChunkId, setSelectedChunkId] = useState<string>('');
|
||||
const [selectedChunk, setSelectedChunk] = useState<IChunk>();
|
||||
|
||||
const handleChunkCardClick = useCallback((chunkId: string) => {
|
||||
setSelectedChunkId(chunkId);
|
||||
const handleChunkCardClick = useCallback((chunk: IChunk) => {
|
||||
console.log('click-chunk-->', chunk);
|
||||
setSelectedChunk(chunk);
|
||||
}, []);
|
||||
|
||||
return { handleChunkCardClick, selectedChunkId };
|
||||
return { handleChunkCardClick, selectedChunk };
|
||||
};
|
||||
|
||||
export const useGetSelectedChunk = (selectedChunkId: string) => {
|
||||
const data = useSelectChunkList();
|
||||
return (
|
||||
data?.data?.find((x) => x.chunk_id === selectedChunkId) ?? ({} as IChunk)
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetChunkHighlights = (selectedChunkId: string) => {
|
||||
export const useGetChunkHighlights = (selectedChunk?: IChunk) => {
|
||||
const [size, setSize] = useState({ width: 849, height: 1200 });
|
||||
const selectedChunk: IChunk = useGetSelectedChunk(selectedChunkId);
|
||||
|
||||
const highlights: IHighlight[] = useMemo(() => {
|
||||
return buildChunkHighlights(selectedChunk, size);
|
||||
return selectedChunk ? buildChunkHighlights(selectedChunk, size) : [];
|
||||
}, [selectedChunk, size]);
|
||||
|
||||
const setWidthAndHeight = useCallback((width: number, height: number) => {
|
||||
@ -276,3 +269,23 @@ export const useTimelineDataFlow = (data: IPipelineFileLogDetail) => {
|
||||
timelineNodes,
|
||||
};
|
||||
};
|
||||
|
||||
export const useGetPipelineResultSearchParams = () => {
|
||||
const [currentQueryParameters] = useSearchParams();
|
||||
const is_read_only = currentQueryParameters.get(
|
||||
PipelineResultSearchParams.IsReadOnly,
|
||||
) as 'true' | 'false';
|
||||
console.log('is_read_only', is_read_only);
|
||||
return {
|
||||
type: currentQueryParameters.get(PipelineResultSearchParams.Type) || '',
|
||||
documentId:
|
||||
currentQueryParameters.get(PipelineResultSearchParams.DocumentId) || '',
|
||||
knowledgeId:
|
||||
currentQueryParameters.get(PipelineResultSearchParams.KnowledgeId) || '',
|
||||
isReadOnly: is_read_only === 'true',
|
||||
agentId:
|
||||
currentQueryParameters.get(PipelineResultSearchParams.AgentId) || '',
|
||||
agentTitle:
|
||||
currentQueryParameters.get(PipelineResultSearchParams.AgentTitle) || '',
|
||||
};
|
||||
};
|
||||
|
||||
@ -5,6 +5,7 @@ import DocumentPreview from './components/document-preview';
|
||||
import {
|
||||
useFetchPipelineFileLogDetail,
|
||||
useGetChunkHighlights,
|
||||
useGetPipelineResultSearchParams,
|
||||
useHandleChunkCardClick,
|
||||
useRerunDataflow,
|
||||
useTimelineDataFlow,
|
||||
@ -25,10 +26,7 @@ import {
|
||||
} from '@/components/ui/breadcrumb';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import {
|
||||
QueryStringMap,
|
||||
useNavigatePage,
|
||||
} from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
||||
import TimelineDataFlow from './components/time-line';
|
||||
@ -38,22 +36,29 @@ import { IDslComponent } from './interface';
|
||||
import ParserContainer from './parser';
|
||||
|
||||
const Chunk = () => {
|
||||
const { isReadOnly, knowledgeId, agentId, agentTitle } =
|
||||
useGetPipelineResultSearchParams();
|
||||
|
||||
const {
|
||||
data: { documentInfo },
|
||||
} = useFetchNextChunkList();
|
||||
const { selectedChunkId } = useHandleChunkCardClick();
|
||||
const { selectedChunk, handleChunkCardClick } = useHandleChunkCardClick();
|
||||
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
||||
const { data: dataset } = useFetchPipelineFileLogDetail();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { timelineNodes } = useTimelineDataFlow(dataset);
|
||||
|
||||
const { navigateToDataset, getQueryString, navigateToDatasetList } =
|
||||
useNavigatePage();
|
||||
const {
|
||||
navigateToDataset,
|
||||
navigateToDatasetList,
|
||||
navigateToAgents,
|
||||
navigateToDataflow,
|
||||
} = useNavigatePage();
|
||||
const fileUrl = useGetDocumentUrl();
|
||||
|
||||
const { highlights, setWidthAndHeight } =
|
||||
useGetChunkHighlights(selectedChunkId);
|
||||
useGetChunkHighlights(selectedChunk);
|
||||
|
||||
const fileType = useMemo(() => {
|
||||
switch (documentInfo?.type) {
|
||||
@ -77,6 +82,7 @@ const Chunk = () => {
|
||||
} = useRerunDataflow({
|
||||
data: dataset,
|
||||
});
|
||||
|
||||
const handleStepChange = (id: number | string, step: TimelineNode) => {
|
||||
if (isChange) {
|
||||
Modal.show({
|
||||
@ -135,18 +141,32 @@ const Chunk = () => {
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink onClick={navigateToDatasetList}>
|
||||
{t('knowledgeDetails.dataset')}
|
||||
<BreadcrumbLink
|
||||
onClick={() => {
|
||||
if (knowledgeId) {
|
||||
navigateToDatasetList();
|
||||
}
|
||||
if (agentId) {
|
||||
navigateToAgents();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{knowledgeId ? t('knowledgeDetails.dataset') : t('header.flow')}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
onClick={navigateToDataset(
|
||||
getQueryString(QueryStringMap.KnowledgeId) as string,
|
||||
)}
|
||||
onClick={() => {
|
||||
if (knowledgeId) {
|
||||
navigateToDataset(knowledgeId)();
|
||||
}
|
||||
if (agentId) {
|
||||
navigateToDataflow(agentId)();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('knowledgeDetails.overview')}
|
||||
{knowledgeId ? t('knowledgeDetails.overview') : agentTitle}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
@ -194,8 +214,10 @@ const Chunk = () => {
|
||||
{/* {currentTimeNode?.type === TimelineNodeType.parser && ( */}
|
||||
{(currentTimeNode?.type === TimelineNodeType.parser ||
|
||||
currentTimeNode?.type === TimelineNodeType.characterSplitter ||
|
||||
currentTimeNode?.type === TimelineNodeType.titleSplitter) && (
|
||||
currentTimeNode?.type === TimelineNodeType.titleSplitter ||
|
||||
currentTimeNode?.type === TimelineNodeType.contextGenerator) && (
|
||||
<ParserContainer
|
||||
isReadonly={isReadOnly}
|
||||
isChange={isChange}
|
||||
reRunLoading={reRunLoading}
|
||||
setIsChange={setIsChange}
|
||||
@ -206,6 +228,7 @@ const Chunk = () => {
|
||||
key: string;
|
||||
}
|
||||
}
|
||||
clickChunk={handleChunkCardClick}
|
||||
reRunFunc={handleReRunFunc}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { PipelineResultSearchParams } from './constant';
|
||||
|
||||
interface ComponentParams {
|
||||
debug_inputs: Record<string, any>;
|
||||
delay_after_error: number;
|
||||
@ -60,3 +62,19 @@ export interface IPipelineFileLogDetail {
|
||||
update_date: string;
|
||||
update_time: number;
|
||||
}
|
||||
|
||||
export interface IChunk {
|
||||
positions: number[][];
|
||||
image_id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface NavigateToDataflowResultProps {
|
||||
id: string;
|
||||
[PipelineResultSearchParams.KnowledgeId]?: string;
|
||||
[PipelineResultSearchParams.DocumentId]: string;
|
||||
[PipelineResultSearchParams.AgentId]?: string;
|
||||
[PipelineResultSearchParams.AgentTitle]?: string;
|
||||
[PipelineResultSearchParams.IsReadOnly]?: string;
|
||||
[PipelineResultSearchParams.Type]: string;
|
||||
}
|
||||
|
||||
@ -10,17 +10,28 @@ import FormatPreserEditor from './components/parse-editer';
|
||||
import RerunButton from './components/rerun-button';
|
||||
import { TimelineNodeType } from './constant';
|
||||
import { useChangeChunkTextMode } from './hooks';
|
||||
import { IDslComponent } from './interface';
|
||||
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;
|
||||
reRunFunc: (data: { value: IDslComponent; key: string }) => void;
|
||||
}
|
||||
const ParserContainer = (props: IProps) => {
|
||||
const { isChange, setIsChange, step, data, reRunFunc, reRunLoading } = props;
|
||||
const {
|
||||
isChange,
|
||||
setIsChange,
|
||||
step,
|
||||
data,
|
||||
reRunFunc,
|
||||
reRunLoading,
|
||||
clickChunk,
|
||||
isReadonly,
|
||||
} = props;
|
||||
const { t } = useTranslation();
|
||||
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
||||
const { changeChunkTextMode, textMode } = useChangeChunkTextMode();
|
||||
@ -83,13 +94,13 @@ const ParserContainer = (props: IProps) => {
|
||||
initialText.value = initialText.value.filter(
|
||||
(item: any, index: number) => !selectedChunkIds.includes(index + ''),
|
||||
);
|
||||
setIsChange(true);
|
||||
setSelectedChunkIds([]);
|
||||
}
|
||||
}, [selectedChunkIds, initialText]);
|
||||
}, [selectedChunkIds, initialText, setIsChange]);
|
||||
|
||||
const handleCheckboxClick = useCallback(
|
||||
(id: string | number, checked: boolean) => {
|
||||
console.log('handleCheckboxClick', id, checked, selectedChunkIds);
|
||||
setSelectedChunkIds((prev) => {
|
||||
if (checked) {
|
||||
return [...prev, id.toString()];
|
||||
@ -116,20 +127,18 @@ const ParserContainer = (props: IProps) => {
|
||||
|
||||
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 && (
|
||||
{isChange && !isReadonly && (
|
||||
<div className=" absolute top-2 right-6">
|
||||
<RerunButton
|
||||
step={step}
|
||||
@ -163,13 +172,16 @@ const ParserContainer = (props: IProps) => {
|
||||
|
||||
{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}
|
||||
/>
|
||||
{!isReadonly && (
|
||||
<CheckboxSets
|
||||
selectAllChunk={selectAllChunk}
|
||||
removeChunk={handleRemoveChunk}
|
||||
checked={selectedChunkIds.length === initialText.value.length}
|
||||
selectedChunkIds={selectedChunkIds}
|
||||
/>
|
||||
)}
|
||||
<ChunkResultBar
|
||||
isReadonly={isReadonly}
|
||||
changeChunkTextMode={changeChunkTextMode}
|
||||
createChunk={handleCreateChunk}
|
||||
/>
|
||||
@ -189,15 +201,14 @@ const ParserContainer = (props: IProps) => {
|
||||
<FormatPreserEditor
|
||||
initialValue={initialText}
|
||||
onSave={handleSave}
|
||||
// className={
|
||||
// initialText.key !== 'json' ? '!h-[calc(100vh-220px)]' : ''
|
||||
// }
|
||||
isReadonly={isReadonly}
|
||||
isChunck={isChunck}
|
||||
textMode={textMode}
|
||||
isDelete={
|
||||
step?.type === TimelineNodeType.characterSplitter ||
|
||||
step?.type === TimelineNodeType.titleSplitter
|
||||
}
|
||||
clickChunk={clickChunk}
|
||||
handleCheckboxClick={handleCheckboxClick}
|
||||
selectedChunkIds={selectedChunkIds}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user