mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +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:
@ -1,5 +1,6 @@
|
|||||||
(window._iconfont_svg_string_4909832 =
|
(window._iconfont_svg_string_4909832 =
|
||||||
'<svg>' +
|
'<svg>' +
|
||||||
|
'<symbol id="icon-play" viewBox="0 0 1024 1024"><path d="M0 0h1024v1024H0z" fill="#00BEB4" opacity=".01" ></path><path d="M161.206857 839.972571V185.929143a72.850286 72.850286 0 0 1 109.275429-63.049143l566.345143 326.948571a72.850286 72.850286 0 0 1 0 126.244572l-566.418286 326.948571a72.850286 72.850286 0 0 1-109.202286-63.049143z" fill="#00BEB4" ></path></symbol>' +
|
||||||
'<symbol id="icon-Pipeline" viewBox="0 0 1024 1024"><path d="M610.9184 729.6a59.392 59.392 0 0 1 59.3408 59.392v79.104a59.3408 59.3408 0 0 1-59.392 59.3408H413.1328a59.392 59.392 0 0 1-59.3408-59.392V788.992a59.392 59.392 0 0 1 59.392-59.3408h197.7856z m0-316.4672a59.392 59.392 0 0 1 59.3408 59.3408v79.104a59.3408 59.3408 0 0 1-59.392 59.392H413.1328a59.3408 59.3408 0 0 1-59.3408-59.392V472.4736a59.392 59.392 0 0 1 59.392-59.392h197.7856z m0-316.5184a59.392 59.392 0 0 1 59.3408 59.3408V235.008a59.3408 59.3408 0 0 1-59.392 59.392H413.1328A59.3408 59.3408 0 0 1 353.792 235.008V155.9552a59.392 59.392 0 0 1 59.392-59.392h197.7856z" fill="#00BEB4" ></path><path d="M749.3632 472.4224a197.8368 197.8368 0 0 1 0 395.6224l-4.608-0.256a39.5776 39.5776 0 0 1 4.608-78.848l6.9632-0.2048a118.6816 118.6816 0 0 0-6.9632-237.2096l-4.608-0.256a39.5776 39.5776 0 0 1 4.608-78.848zM274.6368 155.904l4.608 0.256a39.5776 39.5776 0 0 1-4.608 78.848 118.6816 118.6816 0 1 0 0 237.4144 39.5776 39.5776 0 1 1 0 79.104 197.7856 197.7856 0 1 1 0-395.6224z" fill="#1177D7" ></path></symbol>' +
|
'<symbol id="icon-Pipeline" viewBox="0 0 1024 1024"><path d="M610.9184 729.6a59.392 59.392 0 0 1 59.3408 59.392v79.104a59.3408 59.3408 0 0 1-59.392 59.3408H413.1328a59.392 59.392 0 0 1-59.3408-59.392V788.992a59.392 59.392 0 0 1 59.392-59.3408h197.7856z m0-316.4672a59.392 59.392 0 0 1 59.3408 59.3408v79.104a59.3408 59.3408 0 0 1-59.392 59.392H413.1328a59.3408 59.3408 0 0 1-59.3408-59.392V472.4736a59.392 59.392 0 0 1 59.392-59.392h197.7856z m0-316.5184a59.392 59.392 0 0 1 59.3408 59.3408V235.008a59.3408 59.3408 0 0 1-59.392 59.392H413.1328A59.3408 59.3408 0 0 1 353.792 235.008V155.9552a59.392 59.392 0 0 1 59.392-59.392h197.7856z" fill="#00BEB4" ></path><path d="M749.3632 472.4224a197.8368 197.8368 0 0 1 0 395.6224l-4.608-0.256a39.5776 39.5776 0 0 1 4.608-78.848l6.9632-0.2048a118.6816 118.6816 0 0 0-6.9632-237.2096l-4.608-0.256a39.5776 39.5776 0 0 1 4.608-78.848zM274.6368 155.904l4.608 0.256a39.5776 39.5776 0 0 1-4.608 78.848 118.6816 118.6816 0 1 0 0 237.4144 39.5776 39.5776 0 1 1 0 79.104 197.7856 197.7856 0 1 1 0-395.6224z" fill="#1177D7" ></path></symbol>' +
|
||||||
'<symbol id="icon-dataflow-01" viewBox="0 0 1024 1024"><path d="M636.202667 214.954667c-18.688 1.493333-28.288 4.266667-34.944 7.68a85.333333 85.333333 0 0 0-37.290667 37.290666c-3.413333 6.656-6.186667 16.213333-7.68 34.944C554.666667 314.069333 554.666667 338.901333 554.666667 375.466667V469.333333h135.253333a128.042667 128.042667 0 1 1 0 85.333334H554.666667v93.866666c0 36.565333 0 61.397333 1.621333 80.597334 1.493333 18.688 4.266667 28.288 7.68 34.944a85.333333 85.333333 0 0 0 37.290667 37.290666c6.656 3.413333 16.213333 6.186667 34.944 7.68 14.08 1.152 31.232 1.493333 53.76 1.578667A128.042667 128.042667 0 0 1 938.666667 853.333333a128 128 0 0 1-248.746667 42.666667 814.037333 814.037333 0 0 1-60.672-1.877333c-23.978667-1.962667-46.037333-6.186667-66.730667-16.725334a170.666667 170.666667 0 0 1-74.581333-74.581333c-10.538667-20.693333-14.762667-42.752-16.725333-66.730667C469.333333 712.96 469.333333 684.629333 469.333333 650.325333V554.666667H334.08a128.042667 128.042667 0 1 1 0-85.333334H469.333333V373.717333c0-34.346667 0-62.72 1.877334-85.76 1.962667-24.021333 6.186667-46.08 16.725333-66.773333a170.666667 170.666667 0 0 1 74.581333-74.581333c20.693333-10.538667 42.752-14.762667 66.730667-16.725334a813.653333 813.653333 0 0 1 60.714667-1.834666 128.042667 128.042667 0 1 1 0 85.333333c-22.528 0.085333-39.68 0.426667-53.76 1.578667z" ></path></symbol>' +
|
'<symbol id="icon-dataflow-01" viewBox="0 0 1024 1024"><path d="M636.202667 214.954667c-18.688 1.493333-28.288 4.266667-34.944 7.68a85.333333 85.333333 0 0 0-37.290667 37.290666c-3.413333 6.656-6.186667 16.213333-7.68 34.944C554.666667 314.069333 554.666667 338.901333 554.666667 375.466667V469.333333h135.253333a128.042667 128.042667 0 1 1 0 85.333334H554.666667v93.866666c0 36.565333 0 61.397333 1.621333 80.597334 1.493333 18.688 4.266667 28.288 7.68 34.944a85.333333 85.333333 0 0 0 37.290667 37.290666c6.656 3.413333 16.213333 6.186667 34.944 7.68 14.08 1.152 31.232 1.493333 53.76 1.578667A128.042667 128.042667 0 0 1 938.666667 853.333333a128 128 0 0 1-248.746667 42.666667 814.037333 814.037333 0 0 1-60.672-1.877333c-23.978667-1.962667-46.037333-6.186667-66.730667-16.725334a170.666667 170.666667 0 0 1-74.581333-74.581333c-10.538667-20.693333-14.762667-42.752-16.725333-66.730667C469.333333 712.96 469.333333 684.629333 469.333333 650.325333V554.666667H334.08a128.042667 128.042667 0 1 1 0-85.333334H469.333333V373.717333c0-34.346667 0-62.72 1.877334-85.76 1.962667-24.021333 6.186667-46.08 16.725333-66.773333a170.666667 170.666667 0 0 1 74.581333-74.581333c20.693333-10.538667 42.752-14.762667 66.730667-16.725334a813.653333 813.653333 0 0 1 60.714667-1.834666 128.042667 128.042667 0 1 1 0 85.333333c-22.528 0.085333-39.68 0.426667-53.76 1.578667z" ></path></symbol>' +
|
||||||
'<symbol id="icon-knowledgegraph" viewBox="0 0 1024 1024"><path d="M190.464 489.472h327.68v40.96h-327.68z" ></path><path d="M482.34496 516.5056l111.26784-308.20352 38.54336 13.9264L520.86784 530.432z" ></path><path d="M620.544 196.608m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M182.272 509.952m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M558.65344 520.9088l283.77088 163.84-20.48 35.47136-283.77088-163.84z" ></path><path d="M841.728 686.08m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M448.67584 803.77856l49.60256-323.91168 40.48896 6.20544-49.60256 323.91168z" ></path><path d="M512 530.432m-143.36 0a143.36 143.36 0 1 0 286.72 0 143.36 143.36 0 1 0-286.72 0Z" ></path><path d="M462.848 843.776m-102.4 0a102.4 102.4 0 1 0 204.8 0 102.4 102.4 0 1 0-204.8 0Z"></path></symbol>' +
|
'<symbol id="icon-knowledgegraph" viewBox="0 0 1024 1024"><path d="M190.464 489.472h327.68v40.96h-327.68z" ></path><path d="M482.34496 516.5056l111.26784-308.20352 38.54336 13.9264L520.86784 530.432z" ></path><path d="M620.544 196.608m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M182.272 509.952m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M558.65344 520.9088l283.77088 163.84-20.48 35.47136-283.77088-163.84z" ></path><path d="M841.728 686.08m-122.88 0a122.88 122.88 0 1 0 245.76 0 122.88 122.88 0 1 0-245.76 0Z" ></path><path d="M448.67584 803.77856l49.60256-323.91168 40.48896 6.20544-49.60256 323.91168z" ></path><path d="M512 530.432m-143.36 0a143.36 143.36 0 1 0 286.72 0 143.36 143.36 0 1 0-286.72 0Z" ></path><path d="M462.848 843.776m-102.4 0a102.4 102.4 0 1 0 204.8 0 102.4 102.4 0 1 0-204.8 0Z"></path></symbol>' +
|
||||||
|
|||||||
@ -246,7 +246,7 @@ const CustomTimeline = ({
|
|||||||
orientation = 'horizontal',
|
orientation = 'horizontal',
|
||||||
lineStyle = 'solid',
|
lineStyle = 'solid',
|
||||||
lineColor = 'var(--text-secondary)',
|
lineColor = 'var(--text-secondary)',
|
||||||
indicatorColor = 'var(--accent-primary)',
|
indicatorColor = 'rgb(var(--accent-primary))',
|
||||||
defaultValue = 1,
|
defaultValue = 1,
|
||||||
className,
|
className,
|
||||||
activeStyle,
|
activeStyle,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { NavigateToDataflowResultProps } from '@/pages/dataflow-result/interface';
|
||||||
import { Routes } from '@/routes';
|
import { Routes } from '@/routes';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useNavigate, useParams, useSearchParams } from 'umi';
|
import { useNavigate, useParams, useSearchParams } from 'umi';
|
||||||
@ -23,6 +24,13 @@ export const useNavigatePage = () => {
|
|||||||
[navigate],
|
[navigate],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const navigateToDataFile = useCallback(
|
||||||
|
(id: string) => () => {
|
||||||
|
navigate(`${Routes.DatasetBase}${Routes.DatasetBase}/${id}`);
|
||||||
|
},
|
||||||
|
[navigate],
|
||||||
|
);
|
||||||
|
|
||||||
const navigateToHome = useCallback(() => {
|
const navigateToHome = useCallback(() => {
|
||||||
navigate(Routes.Root);
|
navigate(Routes.Root);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
@ -133,10 +141,16 @@ export const useNavigatePage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const navigateToDataflowResult = useCallback(
|
const navigateToDataflowResult = useCallback(
|
||||||
(id: string, knowledgeId: string, doc_id?: string) => () => {
|
(props: NavigateToDataflowResultProps) => () => {
|
||||||
|
let params: string[] = [];
|
||||||
|
Object.keys(props).forEach((key) => {
|
||||||
|
if (props[key]) {
|
||||||
|
params.push(`${key}=${props[key]}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
navigate(
|
navigate(
|
||||||
// `${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`,
|
// `${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`,
|
||||||
`${Routes.DataflowResult}?id=${id}&doc_id=${doc_id}&${QueryStringMap.KnowledgeId}=${knowledgeId}&type=dataflow`,
|
`${Routes.DataflowResult}?${params.join('&')}`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[navigate],
|
[navigate],
|
||||||
@ -163,5 +177,6 @@ export const useNavigatePage = () => {
|
|||||||
navigateToOldProfile,
|
navigateToOldProfile,
|
||||||
navigateToDataflowResult,
|
navigateToDataflowResult,
|
||||||
navigateToDataflow,
|
navigateToDataflow,
|
||||||
|
navigateToDataFile,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -39,7 +39,9 @@ function InnerButtonEdge({
|
|||||||
targetPosition,
|
targetPosition,
|
||||||
});
|
});
|
||||||
const selectedStyle = useMemo(() => {
|
const selectedStyle = useMemo(() => {
|
||||||
return selected ? { strokeWidth: 1, stroke: 'var(--accent-primary)' } : {};
|
return selected
|
||||||
|
? { strokeWidth: 1, stroke: 'rgb(var(--accent-primary))' }
|
||||||
|
: {};
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
const onEdgeClick = () => {
|
const onEdgeClick = () => {
|
||||||
@ -56,7 +58,7 @@ function InnerButtonEdge({
|
|||||||
let index = idx - 1;
|
let index = idx - 1;
|
||||||
while (index >= 0) {
|
while (index >= 0) {
|
||||||
if (path[index] === source) {
|
if (path[index] === source) {
|
||||||
return { strokeWidth: 1, stroke: 'var(--accent-primary)' };
|
return { strokeWidth: 1, stroke: 'rgb(var(--accent-primary))' };
|
||||||
}
|
}
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,7 +72,7 @@ const Chunk = () => {
|
|||||||
chunkUpdatingVisible,
|
chunkUpdatingVisible,
|
||||||
documentId,
|
documentId,
|
||||||
} = useUpdateChunk();
|
} = useUpdateChunk();
|
||||||
const { navigateToDataset, getQueryString, navigateToDatasetList } =
|
const { navigateToDataFile, getQueryString, navigateToDatasetList } =
|
||||||
useNavigatePage();
|
useNavigatePage();
|
||||||
const fileUrl = useGetDocumentUrl();
|
const fileUrl = useGetDocumentUrl();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -188,7 +188,7 @@ const Chunk = () => {
|
|||||||
<BreadcrumbSeparator />
|
<BreadcrumbSeparator />
|
||||||
<BreadcrumbItem>
|
<BreadcrumbItem>
|
||||||
<BreadcrumbLink
|
<BreadcrumbLink
|
||||||
onClick={navigateToDataset(
|
onClick={navigateToDataFile(
|
||||||
getQueryString(QueryStringMap.id) as string,
|
getQueryString(QueryStringMap.id) as string,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -6,8 +6,10 @@ import {
|
|||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
} from '@/components/ui/sheet';
|
} from '@/components/ui/sheet';
|
||||||
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
|
||||||
import {
|
import {
|
||||||
ArrowUpRight,
|
ArrowUpRight,
|
||||||
CirclePause,
|
CirclePause,
|
||||||
@ -41,7 +43,7 @@ export function LogSheet({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { handleDownloadJson } = useDownloadOutput(logs);
|
const { handleDownloadJson } = useDownloadOutput(logs);
|
||||||
|
const { navigateToDataflowResult } = useNavigatePage();
|
||||||
return (
|
return (
|
||||||
<Sheet open onOpenChange={hideModal} modal={false}>
|
<Sheet open onOpenChange={hideModal} modal={false}>
|
||||||
<SheetContent
|
<SheetContent
|
||||||
@ -51,7 +53,20 @@ export function LogSheet({
|
|||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetTitle className="flex items-center gap-2.5">
|
<SheetTitle className="flex items-center gap-2.5">
|
||||||
<Logs className="size-4" /> {t('flow.log')}
|
<Logs className="size-4" /> {t('flow.log')}
|
||||||
<Button variant={'ghost'} disabled={!isCompleted}>
|
<Button
|
||||||
|
variant={'ghost'}
|
||||||
|
disabled={!isCompleted}
|
||||||
|
onClick={navigateToDataflowResult({
|
||||||
|
id: 'cfc28d6c9c4911f088bf047c16ec874f', // 'log_id',
|
||||||
|
[PipelineResultSearchParams.AgentId]:
|
||||||
|
'cfc28d6c9c4911f088bf047c16ec874f', // 'agent_id',
|
||||||
|
[PipelineResultSearchParams.DocumentId]:
|
||||||
|
'05b0e19a9d9d11f0b674047c16ec874f', //'doc_id',
|
||||||
|
[PipelineResultSearchParams.AgentTitle]: 'full', //'title',
|
||||||
|
[PipelineResultSearchParams.IsReadOnly]: 'true',
|
||||||
|
[PipelineResultSearchParams.Type]: 'dataflow',
|
||||||
|
})}
|
||||||
|
>
|
||||||
{t('dataflow.viewResult')} <ArrowUpRight />
|
{t('dataflow.viewResult')} <ArrowUpRight />
|
||||||
</Button>
|
</Button>
|
||||||
</SheetTitle>
|
</SheetTitle>
|
||||||
|
|||||||
@ -7,28 +7,17 @@ import { ChunkTextMode } from '../../constant';
|
|||||||
interface ChunkResultBarProps {
|
interface ChunkResultBarProps {
|
||||||
changeChunkTextMode: React.Dispatch<React.SetStateAction<string | number>>;
|
changeChunkTextMode: React.Dispatch<React.SetStateAction<string | number>>;
|
||||||
createChunk: (text: string) => void;
|
createChunk: (text: string) => void;
|
||||||
|
isReadonly: boolean;
|
||||||
}
|
}
|
||||||
export default ({ changeChunkTextMode, createChunk }: ChunkResultBarProps) => {
|
export default ({
|
||||||
|
changeChunkTextMode,
|
||||||
|
createChunk,
|
||||||
|
isReadonly,
|
||||||
|
}: ChunkResultBarProps) => {
|
||||||
const { t } = useTranslate('chunk');
|
const { t } = useTranslate('chunk');
|
||||||
const [textSelectValue, setTextSelectValue] = useState<string | number>(
|
const [textSelectValue, setTextSelectValue] = useState<string | number>(
|
||||||
ChunkTextMode.Full,
|
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 = [
|
const textSelectOptions = [
|
||||||
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
||||||
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
||||||
@ -57,31 +46,15 @@ export default ({ changeChunkTextMode, createChunk }: ChunkResultBarProps) => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{/* <Input
|
{!isReadonly && (
|
||||||
className="bg-bg-card text-muted-foreground"
|
<Button
|
||||||
style={{ width: 200 }}
|
onClick={() => createChunk('')}
|
||||||
placeholder={t('search')}
|
variant={'secondary'}
|
||||||
icon={<SearchOutlined />}
|
className="bg-bg-card text-muted-foreground hover:bg-card"
|
||||||
onChange={handleInputChange}
|
>
|
||||||
value={searchString}
|
<Plus size={44} />
|
||||||
/>
|
</Button>
|
||||||
<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>
|
|
||||||
</div>
|
</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 { CheckedState } from '@radix-ui/react-checkbox';
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { FormatPreserveEditorProps } from './interface';
|
||||||
import { ArrayContainer, parserKeyMap } from './json-parser';
|
import { ArrayContainer } from './json-parser';
|
||||||
import { ObjectContainer } from './object-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 = ({
|
const FormatPreserveEditor = ({
|
||||||
initialValue,
|
initialValue,
|
||||||
onSave,
|
onSave,
|
||||||
@ -25,6 +11,8 @@ const FormatPreserveEditor = ({
|
|||||||
handleCheckboxClick,
|
handleCheckboxClick,
|
||||||
selectedChunkIds,
|
selectedChunkIds,
|
||||||
textMode,
|
textMode,
|
||||||
|
clickChunk,
|
||||||
|
isReadonly,
|
||||||
}: FormatPreserveEditorProps) => {
|
}: FormatPreserveEditorProps) => {
|
||||||
console.log('initialValue', initialValue);
|
console.log('initialValue', initialValue);
|
||||||
|
|
||||||
@ -42,6 +30,7 @@ const FormatPreserveEditor = ({
|
|||||||
<div className="editor-container">
|
<div className="editor-container">
|
||||||
{['json', 'chunks'].includes(initialValue.key) && (
|
{['json', 'chunks'].includes(initialValue.key) && (
|
||||||
<ArrayContainer
|
<ArrayContainer
|
||||||
|
isReadonly={isReadonly}
|
||||||
className={className}
|
className={className}
|
||||||
initialValue={initialValue}
|
initialValue={initialValue}
|
||||||
handleCheck={handleCheck}
|
handleCheck={handleCheck}
|
||||||
@ -51,11 +40,13 @@ const FormatPreserveEditor = ({
|
|||||||
unescapeNewlines={unescapeNewlines}
|
unescapeNewlines={unescapeNewlines}
|
||||||
textMode={textMode}
|
textMode={textMode}
|
||||||
isChunck={isChunck}
|
isChunck={isChunck}
|
||||||
|
clickChunk={clickChunk}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{['text', 'html'].includes(initialValue.key) && (
|
{['text', 'html'].includes(initialValue.key) && (
|
||||||
<ObjectContainer
|
<ObjectContainer
|
||||||
|
isReadonly={isReadonly}
|
||||||
className={className}
|
className={className}
|
||||||
initialValue={initialValue}
|
initialValue={initialValue}
|
||||||
handleCheck={handleCheck}
|
handleCheck={handleCheck}
|
||||||
@ -65,6 +56,7 @@ const FormatPreserveEditor = ({
|
|||||||
unescapeNewlines={unescapeNewlines}
|
unescapeNewlines={unescapeNewlines}
|
||||||
textMode={textMode}
|
textMode={textMode}
|
||||||
isChunck={isChunck}
|
isChunck={isChunck}
|
||||||
|
clickChunk={clickChunk}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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 { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { ChunkTextMode } from '../../constant';
|
||||||
import styles from '../../index.less';
|
import styles from '../../index.less';
|
||||||
|
import { useParserInit } from './hook';
|
||||||
|
import { IJsonContainerProps } from './interface';
|
||||||
export const parserKeyMap = {
|
export const parserKeyMap = {
|
||||||
json: 'text',
|
json: 'text',
|
||||||
chunks: 'content_with_weight',
|
chunks: 'text',
|
||||||
};
|
};
|
||||||
type IProps = {
|
|
||||||
initialValue: {
|
export const ArrayContainer = (props: IJsonContainerProps) => {
|
||||||
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) => {
|
|
||||||
const {
|
const {
|
||||||
initialValue,
|
initialValue,
|
||||||
isChunck,
|
isChunck,
|
||||||
@ -42,29 +21,27 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
onSave,
|
onSave,
|
||||||
className,
|
className,
|
||||||
textMode,
|
textMode,
|
||||||
|
clickChunk,
|
||||||
|
isReadonly,
|
||||||
} = props;
|
} = 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(
|
const handleEdit = useCallback(
|
||||||
(e?: any, index?: number) => {
|
(e?: any, index?: number) => {
|
||||||
console.log(e, e.target.innerText);
|
|
||||||
setContent((pre) => ({
|
setContent((pre) => ({
|
||||||
...pre,
|
...pre,
|
||||||
value: pre.value.map((item, i) => {
|
value: pre.value.map((item, i) => {
|
||||||
if (i === index) {
|
if (i === index) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
[parserKeyMap[content.key]]: e.target.innerText,
|
[parserKeyMap[content.key]]: unescapeNewlines(e.target.innerText),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
@ -76,14 +53,13 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
);
|
);
|
||||||
const handleSave = useCallback(
|
const handleSave = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
console.log(e, e.target.innerText);
|
|
||||||
const saveData = {
|
const saveData = {
|
||||||
...content,
|
...content,
|
||||||
value: content.value?.map((item, index) => {
|
value: content.value?.map((item, index) => {
|
||||||
if (index === activeEditIndex) {
|
if (index === activeEditIndex) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
[parserKeyMap[content.key]]: unescapeNewlines(e.target.innerText),
|
[parserKeyMap[content.key]]: e.target.innerText,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return item;
|
return item;
|
||||||
@ -99,8 +75,9 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeEditIndex !== undefined && editDivRef.current) {
|
if (activeEditIndex !== undefined && editDivRef.current) {
|
||||||
editDivRef.current.focus();
|
editDivRef.current.focus();
|
||||||
editDivRef.current.textContent =
|
editDivRef.current.textContent = escapeNewlines(
|
||||||
content.value[activeEditIndex][parserKeyMap[content.key]];
|
content.value[activeEditIndex][parserKeyMap[content.key]],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [activeEditIndex, content]);
|
}, [activeEditIndex, content]);
|
||||||
|
|
||||||
@ -119,7 +96,7 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isChunck && (
|
{isChunck && !isReadonly && (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
onCheckedChange={(e) => {
|
onCheckedChange={(e) => {
|
||||||
handleCheck(e, index);
|
handleCheck(e, index);
|
||||||
@ -132,16 +109,8 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
{activeEditIndex === index && (
|
{activeEditIndex === index && (
|
||||||
<div
|
<div
|
||||||
ref={editDivRef}
|
ref={editDivRef}
|
||||||
contentEditable={true}
|
contentEditable={!isReadonly}
|
||||||
onBlur={handleSave}
|
onBlur={handleSave}
|
||||||
// onKeyUp={handleChange}
|
|
||||||
// dangerouslySetInnerHTML={{
|
|
||||||
// __html: DOMPurify.sanitize(
|
|
||||||
// escapeNewlines(
|
|
||||||
// content.value[index][parserKeyMap[content.key]],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// }}
|
|
||||||
className={cn(
|
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',
|
'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,
|
className,
|
||||||
@ -159,7 +128,10 @@ export const ArrayContainer = (props: IProps) => {
|
|||||||
)}
|
)}
|
||||||
key={index}
|
key={index}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
handleEdit(e, index);
|
clickChunk(item);
|
||||||
|
if (!isReadonly) {
|
||||||
|
handleEdit(e, index);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{escapeNewlines(item[parserKeyMap[content.key]])}
|
{escapeNewlines(item[parserKeyMap[content.key]])}
|
||||||
|
|||||||
@ -1,24 +1,10 @@
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { ChunkTextMode } from '../../constant';
|
||||||
import styles from '../../index.less';
|
import styles from '../../index.less';
|
||||||
|
import { useParserInit } from './hook';
|
||||||
type IProps = {
|
import { IObjContainerProps } from './interface';
|
||||||
initialValue: {
|
export const ObjectContainer = (props: IObjContainerProps) => {
|
||||||
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) => {
|
|
||||||
const {
|
const {
|
||||||
initialValue,
|
initialValue,
|
||||||
isChunck,
|
isChunck,
|
||||||
@ -27,36 +13,34 @@ export const ObjectContainer = (props: IProps) => {
|
|||||||
onSave,
|
onSave,
|
||||||
className,
|
className,
|
||||||
textMode,
|
textMode,
|
||||||
|
clickChunk,
|
||||||
|
isReadonly,
|
||||||
} = props;
|
} = 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(
|
const handleEdit = useCallback(
|
||||||
(e?: any) => {
|
(e?: any) => {
|
||||||
console.log(e, e.target.innerText);
|
|
||||||
setContent((pre) => ({
|
setContent((pre) => ({
|
||||||
...pre,
|
...pre,
|
||||||
value: e.target.innerText,
|
value: escapeNewlines(e.target.innerText),
|
||||||
}));
|
}));
|
||||||
setActiveEditIndex(1);
|
setActiveEditIndex(1);
|
||||||
},
|
},
|
||||||
[setContent, setActiveEditIndex],
|
[setContent, setActiveEditIndex],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSave = useCallback(
|
const handleSave = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
console.log(e, e.target.innerText);
|
|
||||||
const saveData = {
|
const saveData = {
|
||||||
...content,
|
...content,
|
||||||
value: unescapeNewlines(e.target.innerText),
|
value: e.target.innerText,
|
||||||
};
|
};
|
||||||
onSave(saveData);
|
onSave(saveData);
|
||||||
setActiveEditIndex(undefined);
|
setActiveEditIndex(undefined);
|
||||||
@ -83,7 +67,7 @@ export const ObjectContainer = (props: IProps) => {
|
|||||||
{activeEditIndex && (
|
{activeEditIndex && (
|
||||||
<div
|
<div
|
||||||
ref={editDivRef}
|
ref={editDivRef}
|
||||||
contentEditable={true}
|
contentEditable={!isReadonly}
|
||||||
onBlur={handleSave}
|
onBlur={handleSave}
|
||||||
className={cn(
|
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',
|
'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) => {
|
onClick={(e) => {
|
||||||
handleEdit(e);
|
clickChunk(content);
|
||||||
|
if (!isReadonly) {
|
||||||
|
handleEdit(e);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{escapeNewlines(content.value)}
|
{escapeNewlines(content.value)}
|
||||||
|
|||||||
@ -83,8 +83,8 @@ const TimelineDataFlow = ({
|
|||||||
nodeSize={24}
|
nodeSize={24}
|
||||||
activeStyle={{
|
activeStyle={{
|
||||||
nodeSize: 30,
|
nodeSize: 30,
|
||||||
iconColor: 'var(--accent-primary)',
|
iconColor: 'rgb(var(--accent-primary))',
|
||||||
textColor: 'var(--accent-primary)',
|
textColor: 'rgb(var(--accent-primary))',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,6 +9,15 @@ export enum TimelineNodeType {
|
|||||||
contextGenerator = 'extractor',
|
contextGenerator = 'extractor',
|
||||||
titleSplitter = 'hierarchicalMerger',
|
titleSplitter = 'hierarchicalMerger',
|
||||||
characterSplitter = 'splitter',
|
characterSplitter = 'splitter',
|
||||||
tokenizer = 'indexer',
|
tokenizer = 'tokenizer',
|
||||||
end = 'end',
|
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 { TimelineNode } from '@/components/originui/timeline';
|
||||||
import message from '@/components/ui/message';
|
import message from '@/components/ui/message';
|
||||||
import {
|
import { useCreateChunk, useDeleteChunk } from '@/hooks/chunk-hooks';
|
||||||
useCreateChunk,
|
|
||||||
useDeleteChunk,
|
|
||||||
useSelectChunkList,
|
|
||||||
} from '@/hooks/chunk-hooks';
|
|
||||||
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
@ -18,7 +14,11 @@ import { useCallback, useMemo, useState } from 'react';
|
|||||||
import { IHighlight } from 'react-pdf-highlighter';
|
import { IHighlight } from 'react-pdf-highlighter';
|
||||||
import { useParams, useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import { ITimelineNodeObj, TimelineNodeObj } from './components/time-line';
|
import { ITimelineNodeObj, TimelineNodeObj } from './components/time-line';
|
||||||
import { ChunkTextMode, TimelineNodeType } from './constant';
|
import {
|
||||||
|
ChunkTextMode,
|
||||||
|
PipelineResultSearchParams,
|
||||||
|
TimelineNodeType,
|
||||||
|
} from './constant';
|
||||||
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
import { IDslComponent, IPipelineFileLogDetail } from './interface';
|
||||||
|
|
||||||
export const useFetchPipelineFileLogDetail = (props?: {
|
export const useFetchPipelineFileLogDetail = (props?: {
|
||||||
@ -55,28 +55,21 @@ export const useFetchPipelineFileLogDetail = (props?: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useHandleChunkCardClick = () => {
|
export const useHandleChunkCardClick = () => {
|
||||||
const [selectedChunkId, setSelectedChunkId] = useState<string>('');
|
const [selectedChunk, setSelectedChunk] = useState<IChunk>();
|
||||||
|
|
||||||
const handleChunkCardClick = useCallback((chunkId: string) => {
|
const handleChunkCardClick = useCallback((chunk: IChunk) => {
|
||||||
setSelectedChunkId(chunkId);
|
console.log('click-chunk-->', chunk);
|
||||||
|
setSelectedChunk(chunk);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return { handleChunkCardClick, selectedChunkId };
|
return { handleChunkCardClick, selectedChunk };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetSelectedChunk = (selectedChunkId: string) => {
|
export const useGetChunkHighlights = (selectedChunk?: IChunk) => {
|
||||||
const data = useSelectChunkList();
|
|
||||||
return (
|
|
||||||
data?.data?.find((x) => x.chunk_id === selectedChunkId) ?? ({} as IChunk)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useGetChunkHighlights = (selectedChunkId: string) => {
|
|
||||||
const [size, setSize] = useState({ width: 849, height: 1200 });
|
const [size, setSize] = useState({ width: 849, height: 1200 });
|
||||||
const selectedChunk: IChunk = useGetSelectedChunk(selectedChunkId);
|
|
||||||
|
|
||||||
const highlights: IHighlight[] = useMemo(() => {
|
const highlights: IHighlight[] = useMemo(() => {
|
||||||
return buildChunkHighlights(selectedChunk, size);
|
return selectedChunk ? buildChunkHighlights(selectedChunk, size) : [];
|
||||||
}, [selectedChunk, size]);
|
}, [selectedChunk, size]);
|
||||||
|
|
||||||
const setWidthAndHeight = useCallback((width: number, height: number) => {
|
const setWidthAndHeight = useCallback((width: number, height: number) => {
|
||||||
@ -276,3 +269,23 @@ export const useTimelineDataFlow = (data: IPipelineFileLogDetail) => {
|
|||||||
timelineNodes,
|
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 {
|
import {
|
||||||
useFetchPipelineFileLogDetail,
|
useFetchPipelineFileLogDetail,
|
||||||
useGetChunkHighlights,
|
useGetChunkHighlights,
|
||||||
|
useGetPipelineResultSearchParams,
|
||||||
useHandleChunkCardClick,
|
useHandleChunkCardClick,
|
||||||
useRerunDataflow,
|
useRerunDataflow,
|
||||||
useTimelineDataFlow,
|
useTimelineDataFlow,
|
||||||
@ -25,10 +26,7 @@ import {
|
|||||||
} from '@/components/ui/breadcrumb';
|
} from '@/components/ui/breadcrumb';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Modal } from '@/components/ui/modal/modal';
|
import { Modal } from '@/components/ui/modal/modal';
|
||||||
import {
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
QueryStringMap,
|
|
||||||
useNavigatePage,
|
|
||||||
} from '@/hooks/logic-hooks/navigate-hooks';
|
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
import { useGetDocumentUrl } from './components/document-preview/hooks';
|
||||||
import TimelineDataFlow from './components/time-line';
|
import TimelineDataFlow from './components/time-line';
|
||||||
@ -38,22 +36,29 @@ import { IDslComponent } from './interface';
|
|||||||
import ParserContainer from './parser';
|
import ParserContainer from './parser';
|
||||||
|
|
||||||
const Chunk = () => {
|
const Chunk = () => {
|
||||||
|
const { isReadOnly, knowledgeId, agentId, agentTitle } =
|
||||||
|
useGetPipelineResultSearchParams();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { documentInfo },
|
data: { documentInfo },
|
||||||
} = useFetchNextChunkList();
|
} = useFetchNextChunkList();
|
||||||
const { selectedChunkId } = useHandleChunkCardClick();
|
const { selectedChunk, handleChunkCardClick } = useHandleChunkCardClick();
|
||||||
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
const [activeStepId, setActiveStepId] = useState<number | string>(2);
|
||||||
const { data: dataset } = useFetchPipelineFileLogDetail();
|
const { data: dataset } = useFetchPipelineFileLogDetail();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { timelineNodes } = useTimelineDataFlow(dataset);
|
const { timelineNodes } = useTimelineDataFlow(dataset);
|
||||||
|
|
||||||
const { navigateToDataset, getQueryString, navigateToDatasetList } =
|
const {
|
||||||
useNavigatePage();
|
navigateToDataset,
|
||||||
|
navigateToDatasetList,
|
||||||
|
navigateToAgents,
|
||||||
|
navigateToDataflow,
|
||||||
|
} = useNavigatePage();
|
||||||
const fileUrl = useGetDocumentUrl();
|
const fileUrl = useGetDocumentUrl();
|
||||||
|
|
||||||
const { highlights, setWidthAndHeight } =
|
const { highlights, setWidthAndHeight } =
|
||||||
useGetChunkHighlights(selectedChunkId);
|
useGetChunkHighlights(selectedChunk);
|
||||||
|
|
||||||
const fileType = useMemo(() => {
|
const fileType = useMemo(() => {
|
||||||
switch (documentInfo?.type) {
|
switch (documentInfo?.type) {
|
||||||
@ -77,6 +82,7 @@ const Chunk = () => {
|
|||||||
} = useRerunDataflow({
|
} = useRerunDataflow({
|
||||||
data: dataset,
|
data: dataset,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleStepChange = (id: number | string, step: TimelineNode) => {
|
const handleStepChange = (id: number | string, step: TimelineNode) => {
|
||||||
if (isChange) {
|
if (isChange) {
|
||||||
Modal.show({
|
Modal.show({
|
||||||
@ -135,18 +141,32 @@ const Chunk = () => {
|
|||||||
<Breadcrumb>
|
<Breadcrumb>
|
||||||
<BreadcrumbList>
|
<BreadcrumbList>
|
||||||
<BreadcrumbItem>
|
<BreadcrumbItem>
|
||||||
<BreadcrumbLink onClick={navigateToDatasetList}>
|
<BreadcrumbLink
|
||||||
{t('knowledgeDetails.dataset')}
|
onClick={() => {
|
||||||
|
if (knowledgeId) {
|
||||||
|
navigateToDatasetList();
|
||||||
|
}
|
||||||
|
if (agentId) {
|
||||||
|
navigateToAgents();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{knowledgeId ? t('knowledgeDetails.dataset') : t('header.flow')}
|
||||||
</BreadcrumbLink>
|
</BreadcrumbLink>
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
<BreadcrumbSeparator />
|
<BreadcrumbSeparator />
|
||||||
<BreadcrumbItem>
|
<BreadcrumbItem>
|
||||||
<BreadcrumbLink
|
<BreadcrumbLink
|
||||||
onClick={navigateToDataset(
|
onClick={() => {
|
||||||
getQueryString(QueryStringMap.KnowledgeId) as string,
|
if (knowledgeId) {
|
||||||
)}
|
navigateToDataset(knowledgeId)();
|
||||||
|
}
|
||||||
|
if (agentId) {
|
||||||
|
navigateToDataflow(agentId)();
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('knowledgeDetails.overview')}
|
{knowledgeId ? t('knowledgeDetails.overview') : agentTitle}
|
||||||
</BreadcrumbLink>
|
</BreadcrumbLink>
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
<BreadcrumbSeparator />
|
<BreadcrumbSeparator />
|
||||||
@ -194,8 +214,10 @@ const Chunk = () => {
|
|||||||
{/* {currentTimeNode?.type === TimelineNodeType.parser && ( */}
|
{/* {currentTimeNode?.type === TimelineNodeType.parser && ( */}
|
||||||
{(currentTimeNode?.type === TimelineNodeType.parser ||
|
{(currentTimeNode?.type === TimelineNodeType.parser ||
|
||||||
currentTimeNode?.type === TimelineNodeType.characterSplitter ||
|
currentTimeNode?.type === TimelineNodeType.characterSplitter ||
|
||||||
currentTimeNode?.type === TimelineNodeType.titleSplitter) && (
|
currentTimeNode?.type === TimelineNodeType.titleSplitter ||
|
||||||
|
currentTimeNode?.type === TimelineNodeType.contextGenerator) && (
|
||||||
<ParserContainer
|
<ParserContainer
|
||||||
|
isReadonly={isReadOnly}
|
||||||
isChange={isChange}
|
isChange={isChange}
|
||||||
reRunLoading={reRunLoading}
|
reRunLoading={reRunLoading}
|
||||||
setIsChange={setIsChange}
|
setIsChange={setIsChange}
|
||||||
@ -206,6 +228,7 @@ const Chunk = () => {
|
|||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clickChunk={handleChunkCardClick}
|
||||||
reRunFunc={handleReRunFunc}
|
reRunFunc={handleReRunFunc}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { PipelineResultSearchParams } from './constant';
|
||||||
|
|
||||||
interface ComponentParams {
|
interface ComponentParams {
|
||||||
debug_inputs: Record<string, any>;
|
debug_inputs: Record<string, any>;
|
||||||
delay_after_error: number;
|
delay_after_error: number;
|
||||||
@ -60,3 +62,19 @@ export interface IPipelineFileLogDetail {
|
|||||||
update_date: string;
|
update_date: string;
|
||||||
update_time: number;
|
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 RerunButton from './components/rerun-button';
|
||||||
import { TimelineNodeType } from './constant';
|
import { TimelineNodeType } from './constant';
|
||||||
import { useChangeChunkTextMode } from './hooks';
|
import { useChangeChunkTextMode } from './hooks';
|
||||||
import { IDslComponent } from './interface';
|
import { IChunk, IDslComponent } from './interface';
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
isReadonly: boolean;
|
||||||
isChange: boolean;
|
isChange: boolean;
|
||||||
setIsChange: (isChange: boolean) => void;
|
setIsChange: (isChange: boolean) => void;
|
||||||
step?: TimelineNode;
|
step?: TimelineNode;
|
||||||
data: { value: IDslComponent; key: string };
|
data: { value: IDslComponent; key: string };
|
||||||
reRunLoading: boolean;
|
reRunLoading: boolean;
|
||||||
|
clickChunk: (chunk: IChunk) => void;
|
||||||
reRunFunc: (data: { value: IDslComponent; key: string }) => void;
|
reRunFunc: (data: { value: IDslComponent; key: string }) => void;
|
||||||
}
|
}
|
||||||
const ParserContainer = (props: IProps) => {
|
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 { t } = useTranslation();
|
||||||
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
||||||
const { changeChunkTextMode, textMode } = useChangeChunkTextMode();
|
const { changeChunkTextMode, textMode } = useChangeChunkTextMode();
|
||||||
@ -83,13 +94,13 @@ const ParserContainer = (props: IProps) => {
|
|||||||
initialText.value = initialText.value.filter(
|
initialText.value = initialText.value.filter(
|
||||||
(item: any, index: number) => !selectedChunkIds.includes(index + ''),
|
(item: any, index: number) => !selectedChunkIds.includes(index + ''),
|
||||||
);
|
);
|
||||||
|
setIsChange(true);
|
||||||
setSelectedChunkIds([]);
|
setSelectedChunkIds([]);
|
||||||
}
|
}
|
||||||
}, [selectedChunkIds, initialText]);
|
}, [selectedChunkIds, initialText, setIsChange]);
|
||||||
|
|
||||||
const handleCheckboxClick = useCallback(
|
const handleCheckboxClick = useCallback(
|
||||||
(id: string | number, checked: boolean) => {
|
(id: string | number, checked: boolean) => {
|
||||||
console.log('handleCheckboxClick', id, checked, selectedChunkIds);
|
|
||||||
setSelectedChunkIds((prev) => {
|
setSelectedChunkIds((prev) => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
return [...prev, id.toString()];
|
return [...prev, id.toString()];
|
||||||
@ -116,20 +127,18 @@ const ParserContainer = (props: IProps) => {
|
|||||||
|
|
||||||
const handleCreateChunk = useCallback(
|
const handleCreateChunk = useCallback(
|
||||||
(text: string) => {
|
(text: string) => {
|
||||||
console.log('handleCreateChunk', text);
|
|
||||||
const newText = [...initialText.value, { text: text || ' ' }];
|
const newText = [...initialText.value, { text: text || ' ' }];
|
||||||
setInitialText({
|
setInitialText({
|
||||||
...initialText,
|
...initialText,
|
||||||
value: newText,
|
value: newText,
|
||||||
});
|
});
|
||||||
console.log('newText', newText, initialText);
|
|
||||||
},
|
},
|
||||||
[initialText],
|
[initialText],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isChange && (
|
{isChange && !isReadonly && (
|
||||||
<div className=" absolute top-2 right-6">
|
<div className=" absolute top-2 right-6">
|
||||||
<RerunButton
|
<RerunButton
|
||||||
step={step}
|
step={step}
|
||||||
@ -163,13 +172,16 @@ const ParserContainer = (props: IProps) => {
|
|||||||
|
|
||||||
{isChunck && (
|
{isChunck && (
|
||||||
<div className="pt-[5px] pb-[5px] flex justify-between items-center">
|
<div className="pt-[5px] pb-[5px] flex justify-between items-center">
|
||||||
<CheckboxSets
|
{!isReadonly && (
|
||||||
selectAllChunk={selectAllChunk}
|
<CheckboxSets
|
||||||
removeChunk={handleRemoveChunk}
|
selectAllChunk={selectAllChunk}
|
||||||
checked={selectedChunkIds.length === initialText.value.length}
|
removeChunk={handleRemoveChunk}
|
||||||
selectedChunkIds={selectedChunkIds}
|
checked={selectedChunkIds.length === initialText.value.length}
|
||||||
/>
|
selectedChunkIds={selectedChunkIds}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<ChunkResultBar
|
<ChunkResultBar
|
||||||
|
isReadonly={isReadonly}
|
||||||
changeChunkTextMode={changeChunkTextMode}
|
changeChunkTextMode={changeChunkTextMode}
|
||||||
createChunk={handleCreateChunk}
|
createChunk={handleCreateChunk}
|
||||||
/>
|
/>
|
||||||
@ -189,15 +201,14 @@ const ParserContainer = (props: IProps) => {
|
|||||||
<FormatPreserEditor
|
<FormatPreserEditor
|
||||||
initialValue={initialText}
|
initialValue={initialText}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
// className={
|
isReadonly={isReadonly}
|
||||||
// initialText.key !== 'json' ? '!h-[calc(100vh-220px)]' : ''
|
|
||||||
// }
|
|
||||||
isChunck={isChunck}
|
isChunck={isChunck}
|
||||||
textMode={textMode}
|
textMode={textMode}
|
||||||
isDelete={
|
isDelete={
|
||||||
step?.type === TimelineNodeType.characterSplitter ||
|
step?.type === TimelineNodeType.characterSplitter ||
|
||||||
step?.type === TimelineNodeType.titleSplitter
|
step?.type === TimelineNodeType.titleSplitter
|
||||||
}
|
}
|
||||||
|
clickChunk={clickChunk}
|
||||||
handleCheckboxClick={handleCheckboxClick}
|
handleCheckboxClick={handleCheckboxClick}
|
||||||
selectedChunkIds={selectedChunkIds}
|
selectedChunkIds={selectedChunkIds}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
|
||||||
import {
|
import {
|
||||||
useGetPaginationWithRouter,
|
useGetPaginationWithRouter,
|
||||||
useHandleSearchChange,
|
useHandleSearchChange,
|
||||||
@ -32,6 +33,7 @@ const useFetchFileLogList = () => {
|
|||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const { searchString, handleInputChange } = useHandleSearchChange();
|
const { searchString, handleInputChange } = useHandleSearchChange();
|
||||||
const { pagination, setPagination } = useGetPaginationWithRouter();
|
const { pagination, setPagination } = useGetPaginationWithRouter();
|
||||||
|
const { filterValue, handleFilterSubmit } = useHandleFilterSubmit();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [active, setActive] = useState<(typeof LogTabs)[keyof typeof LogTabs]>(
|
const [active, setActive] = useState<(typeof LogTabs)[keyof typeof LogTabs]>(
|
||||||
LogTabs.FILE_LOGS,
|
LogTabs.FILE_LOGS,
|
||||||
@ -48,6 +50,7 @@ const useFetchFileLogList = () => {
|
|||||||
pagination,
|
pagination,
|
||||||
searchString,
|
searchString,
|
||||||
active,
|
active,
|
||||||
|
filterValue,
|
||||||
],
|
],
|
||||||
placeholderData: (previousData) => {
|
placeholderData: (previousData) => {
|
||||||
if (previousData === undefined) {
|
if (previousData === undefined) {
|
||||||
@ -57,13 +60,16 @@ const useFetchFileLogList = () => {
|
|||||||
},
|
},
|
||||||
enabled: true,
|
enabled: true,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data: res = {} } = await fetchFunc({
|
const { data: res = {} } = await fetchFunc(
|
||||||
kb_id: knowledgeBaseId,
|
{
|
||||||
page: pagination.current,
|
kb_id: knowledgeBaseId,
|
||||||
page_size: pagination.pageSize,
|
page: pagination.current,
|
||||||
keywords: searchString,
|
page_size: pagination.pageSize,
|
||||||
// order_by: '',
|
keywords: searchString,
|
||||||
});
|
// order_by: '',
|
||||||
|
},
|
||||||
|
{ ...filterValue },
|
||||||
|
);
|
||||||
return res.data || [];
|
return res.data || [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -82,6 +88,8 @@ const useFetchFileLogList = () => {
|
|||||||
setPagination,
|
setPagination,
|
||||||
active,
|
active,
|
||||||
setActive,
|
setActive,
|
||||||
|
filterValue,
|
||||||
|
handleFilterSubmit,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
import { FilterCollection } from '@/components/list-filter-bar/interface';
|
||||||
import SvgIcon from '@/components/svg-icon';
|
import SvgIcon from '@/components/svg-icon';
|
||||||
import { useIsDarkTheme } from '@/components/theme-provider';
|
import { useIsDarkTheme } from '@/components/theme-provider';
|
||||||
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
||||||
import { parseColorToRGBA } from '@/utils/common-util';
|
import { t } from 'i18next';
|
||||||
import { CircleQuestionMark } from 'lucide-react';
|
import { CircleQuestionMark } from 'lucide-react';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { RunningStatus, RunningStatusMap } from '../dataset/constant';
|
||||||
import { LogTabs } from './dataset-common';
|
import { LogTabs } from './dataset-common';
|
||||||
import { DatasetFilter } from './dataset-filter';
|
import { DatasetFilter } from './dataset-filter';
|
||||||
import { useFetchFileLogList, useFetchOverviewTital } from './hook';
|
import { useFetchFileLogList, useFetchOverviewTital } from './hook';
|
||||||
@ -16,6 +18,10 @@ interface StatCardProps {
|
|||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}
|
}
|
||||||
|
interface CardFooterProcessProps {
|
||||||
|
success: number;
|
||||||
|
failed: number;
|
||||||
|
}
|
||||||
|
|
||||||
const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
|
const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
|
||||||
return (
|
return (
|
||||||
@ -35,10 +41,6 @@ const StatCard: FC<StatCardProps> = ({ title, value, children, icon }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface CardFooterProcessProps {
|
|
||||||
success: number;
|
|
||||||
failed: number;
|
|
||||||
}
|
|
||||||
const CardFooterProcess: FC<CardFooterProcessProps> = ({
|
const CardFooterProcess: FC<CardFooterProcessProps> = ({
|
||||||
success = 0,
|
success = 0,
|
||||||
failed = 0,
|
failed = 0,
|
||||||
@ -47,12 +49,7 @@ const CardFooterProcess: FC<CardFooterProcessProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center flex-col gap-2">
|
<div className="flex items-center flex-col gap-2">
|
||||||
<div className="w-full flex justify-between gap-4 rounded-lg text-sm font-bold text-text-primary">
|
<div className="w-full flex justify-between gap-4 rounded-lg text-sm font-bold text-text-primary">
|
||||||
<div
|
<div className="flex items-center justify-between rounded-md w-1/2 p-2 bg-state-success-5">
|
||||||
className="flex items-center justify-between rounded-md w-1/2 p-2"
|
|
||||||
style={{
|
|
||||||
backgroundColor: `${parseColorToRGBA('var(--state-success)', 0.05)}`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex items-center rounded-lg gap-1">
|
<div className="flex items-center rounded-lg gap-1">
|
||||||
<div className="w-2 h-2 rounded-full bg-state-success"></div>
|
<div className="w-2 h-2 rounded-full bg-state-success"></div>
|
||||||
<div>{t('knowledgeDetails.success')}</div>
|
<div>{t('knowledgeDetails.success')}</div>
|
||||||
@ -70,6 +67,35 @@ const CardFooterProcess: FC<CardFooterProcessProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
{
|
||||||
|
field: 'operation_status',
|
||||||
|
label: t('knowledgeDetails.status'),
|
||||||
|
list: Object.values(RunningStatus).map((value) => {
|
||||||
|
// const value = key as RunningStatus;
|
||||||
|
console.log(value);
|
||||||
|
return {
|
||||||
|
id: value,
|
||||||
|
label: RunningStatusMap[value].label,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'types',
|
||||||
|
label: t('knowledgeDetails.task'),
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
id: 'Parse',
|
||||||
|
label: 'Parse',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Download',
|
||||||
|
label: 'Download',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
const FileLogsPage: FC = () => {
|
const FileLogsPage: FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -89,12 +115,11 @@ const FileLogsPage: FC = () => {
|
|||||||
failed: 0,
|
failed: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: topData } = useFetchOverviewTital();
|
const { data: topData } = useFetchOverviewTital();
|
||||||
const {
|
const {
|
||||||
pagination: { total: fileTotal },
|
pagination: { total: fileTotal },
|
||||||
} = useFetchDocumentList();
|
} = useFetchDocumentList();
|
||||||
console.log('topData --> ', topData);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTopAllData((prev) => {
|
setTopAllData((prev) => {
|
||||||
return {
|
return {
|
||||||
@ -127,6 +152,8 @@ const FileLogsPage: FC = () => {
|
|||||||
pagination,
|
pagination,
|
||||||
setPagination,
|
setPagination,
|
||||||
active,
|
active,
|
||||||
|
filterValue,
|
||||||
|
handleFilterSubmit,
|
||||||
setActive,
|
setActive,
|
||||||
} = useFetchFileLogList();
|
} = useFetchFileLogList();
|
||||||
|
|
||||||
@ -156,6 +183,7 @@ const FileLogsPage: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isDark = useIsDarkTheme();
|
const isDark = useIsDarkTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-5 min-w-[880px] border-border border rounded-lg mr-5">
|
<div className="p-5 min-w-[880px] border-border border rounded-lg mr-5">
|
||||||
{/* Stats Cards */}
|
{/* Stats Cards */}
|
||||||
@ -215,10 +243,13 @@ const FileLogsPage: FC = () => {
|
|||||||
|
|
||||||
{/* Tabs & Search */}
|
{/* Tabs & Search */}
|
||||||
<DatasetFilter
|
<DatasetFilter
|
||||||
|
filters={filters as FilterCollection[]}
|
||||||
|
value={filterValue}
|
||||||
active={active}
|
active={active}
|
||||||
setActive={changeActiveLogs}
|
setActive={changeActiveLogs}
|
||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
onSearchChange={handleInputChange}
|
onSearchChange={handleInputChange}
|
||||||
|
onChange={handleFilterSubmit}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Table */}
|
{/* Table */}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import {
|
|||||||
import { RunningStatusMap } from '@/constants/knowledge';
|
import { RunningStatusMap } from '@/constants/knowledge';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
|
import { PipelineResultSearchParams } from '@/pages/dataflow-result/constant';
|
||||||
|
import { NavigateToDataflowResultProps } from '@/pages/dataflow-result/interface';
|
||||||
import { formatDate, formatSecondsToHumanReadable } from '@/utils/date';
|
import { formatDate, formatSecondsToHumanReadable } from '@/utils/date';
|
||||||
import {
|
import {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
@ -41,9 +43,7 @@ export const getFileLogsTableColumns = (
|
|||||||
showLog: (row: Row<IFileLogItem & DocumentLog>, active: LogTabs) => void,
|
showLog: (row: Row<IFileLogItem & DocumentLog>, active: LogTabs) => void,
|
||||||
kowledgeId: string,
|
kowledgeId: string,
|
||||||
navigateToDataflowResult: (
|
navigateToDataflowResult: (
|
||||||
id: string,
|
props: NavigateToDataflowResultProps,
|
||||||
knowledgeId: string,
|
|
||||||
doc_id?: string,
|
|
||||||
) => () => void,
|
) => () => void,
|
||||||
) => {
|
) => {
|
||||||
// const { t } = useTranslate('knowledgeDetails');
|
// const { t } = useTranslate('knowledgeDetails');
|
||||||
@ -165,18 +165,23 @@ export const getFileLogsTableColumns = (
|
|||||||
>
|
>
|
||||||
<Eye />
|
<Eye />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{row.original.pipeline_id && (
|
||||||
variant="ghost"
|
<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
className="p-1"
|
size="sm"
|
||||||
onClick={navigateToDataflowResult(
|
className="p-1"
|
||||||
row.original.id,
|
onClick={navigateToDataflowResult({
|
||||||
kowledgeId,
|
id: row.original.id,
|
||||||
row.original.document_id,
|
[PipelineResultSearchParams.KnowledgeId]: kowledgeId,
|
||||||
)}
|
[PipelineResultSearchParams.DocumentId]:
|
||||||
>
|
row.original.document_id,
|
||||||
<ClipboardList />
|
[PipelineResultSearchParams.IsReadOnly]: 'false',
|
||||||
</Button>
|
[PipelineResultSearchParams.Type]: 'dataflow',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ClipboardList />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -371,6 +376,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
|
|||||||
? Math.ceil(pagination.total / pagination.pageSize)
|
? Math.ceil(pagination.total / pagination.pageSize)
|
||||||
: 0,
|
: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-[calc(100vh-360px)]">
|
<div className="w-full h-[calc(100vh-360px)]">
|
||||||
<Table rootClassName="max-h-[calc(100vh-380px)]">
|
<Table rootClassName="max-h-[calc(100vh-380px)]">
|
||||||
|
|||||||
@ -3,14 +3,20 @@ import { RunningStatus } from '@/constants/knowledge';
|
|||||||
export const RunningStatusMap = {
|
export const RunningStatusMap = {
|
||||||
[RunningStatus.UNSTART]: {
|
[RunningStatus.UNSTART]: {
|
||||||
label: 'UNSTART',
|
label: 'UNSTART',
|
||||||
color: 'var(--accent-primary)',
|
color: 'rgba(var(--accent-primary))',
|
||||||
},
|
},
|
||||||
[RunningStatus.RUNNING]: {
|
[RunningStatus.RUNNING]: {
|
||||||
label: 'Parsing',
|
label: 'Parsing',
|
||||||
color: 'var(--team-member)',
|
color: 'var(--team-member)',
|
||||||
},
|
},
|
||||||
[RunningStatus.CANCEL]: { label: 'CANCEL', color: 'var(--state-warning)' },
|
[RunningStatus.CANCEL]: {
|
||||||
[RunningStatus.DONE]: { label: 'SUCCESS', color: 'var(--state-success)' },
|
label: 'CANCEL',
|
||||||
|
color: 'rgba(var(--state-warning))',
|
||||||
|
},
|
||||||
|
[RunningStatus.DONE]: {
|
||||||
|
label: 'SUCCESS',
|
||||||
|
color: 'rgba(var(--state-success))',
|
||||||
|
},
|
||||||
[RunningStatus.FAIL]: { label: 'FAIL', color: 'rgba(var(--state-error))' },
|
[RunningStatus.FAIL]: { label: 'FAIL', color: 'rgba(var(--state-error))' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { UseSaveMetaShowType } from './use-save-meta';
|
|||||||
import { isParserRunning } from './utils';
|
import { isParserRunning } from './utils';
|
||||||
const IconMap = {
|
const IconMap = {
|
||||||
[RunningStatus.UNSTART]: (
|
[RunningStatus.UNSTART]: (
|
||||||
<div className="w-0 h-0 border-l-[10px] border-l-accent-primary border-t-8 border-r-4 border-b-8 border-transparent"></div>
|
<IconFontFill name="play" className="text-accent-primary" />
|
||||||
),
|
),
|
||||||
[RunningStatus.RUNNING]: (
|
[RunningStatus.RUNNING]: (
|
||||||
<CircleX size={14} color="rgba(var(--state-error))" />
|
<CircleX size={14} color="rgba(var(--state-error))" />
|
||||||
|
|||||||
@ -210,6 +210,10 @@ const methods = {
|
|||||||
url: traceRaptor,
|
url: traceRaptor,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
},
|
},
|
||||||
|
pipelineRerun: {
|
||||||
|
url: api.pipelineRerun,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const kbService = registerServer<keyof typeof methods>(methods, request);
|
const kbService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
|||||||
@ -174,6 +174,32 @@ export function parseColorToRGB(color: string): [number, number, number] {
|
|||||||
colorStr = getCSSVariableValue(varName);
|
colorStr = getCSSVariableValue(varName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle rgb(var(--accent-primary)) format
|
||||||
|
if (colorStr.startsWith('rgb(var(')) {
|
||||||
|
const varMatch = colorStr.match(/rgb\(var\(([^)]+)\)\)/);
|
||||||
|
if (!varMatch) {
|
||||||
|
console.error(`Invalid nested CSS variable: ${color}`);
|
||||||
|
return [0, 0, 0];
|
||||||
|
}
|
||||||
|
const varName = varMatch[1];
|
||||||
|
if (!varName) {
|
||||||
|
console.error(`Invalid nested CSS variable: ${colorStr}`);
|
||||||
|
return [0, 0, 0];
|
||||||
|
}
|
||||||
|
// Get the CSS variable value which should be in format "r, g, b"
|
||||||
|
const rgbValues = getCSSVariableValue(varName);
|
||||||
|
const rgbMatch = rgbValues.match(/^(\d+),?\s*(\d+),?\s*(\d+)$/);
|
||||||
|
if (rgbMatch) {
|
||||||
|
return [
|
||||||
|
parseInt(rgbMatch[1]),
|
||||||
|
parseInt(rgbMatch[2]),
|
||||||
|
parseInt(rgbMatch[3]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
console.error(`Unsupported RGB CSS variable format: ${rgbValues}`);
|
||||||
|
return [0, 0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
// Handles hexadecimal colors (e.g. #FF5733)
|
// Handles hexadecimal colors (e.g. #FF5733)
|
||||||
if (colorStr.startsWith('#')) {
|
if (colorStr.startsWith('#')) {
|
||||||
const cleanedHex = colorStr.replace(/^#/, '');
|
const cleanedHex = colorStr.replace(/^#/, '');
|
||||||
|
|||||||
@ -81,8 +81,14 @@ module.exports = {
|
|||||||
5: 'rgba(var(--accent-primary) / 0.05)', // 5%
|
5: 'rgba(var(--accent-primary) / 0.05)', // 5%
|
||||||
},
|
},
|
||||||
'bg-accent': 'var(--bg-accent)',
|
'bg-accent': 'var(--bg-accent)',
|
||||||
'state-success': 'var(--state-success)',
|
'state-success': {
|
||||||
'state-warning': 'var(--state-warning)',
|
DEFAULT: 'rgb(var(--state-success) / <alpha-value>)',
|
||||||
|
5: 'rgba(var(--state-success) / 0.05)', // 5%
|
||||||
|
},
|
||||||
|
'state-warning': {
|
||||||
|
DEFAULT: 'rgb(var(--state-warning) / <alpha-value>)',
|
||||||
|
5: 'rgba(var(--state-warning) / 0.05)', // 5%
|
||||||
|
},
|
||||||
'state-error': {
|
'state-error': {
|
||||||
DEFAULT: 'rgb(var(--state-error) / <alpha-value>)',
|
DEFAULT: 'rgb(var(--state-error) / <alpha-value>)',
|
||||||
5: 'rgba(var(--state-error) / 0.05)', // 5%
|
5: 'rgba(var(--state-error) / 0.05)', // 5%
|
||||||
|
|||||||
@ -116,8 +116,10 @@
|
|||||||
/* Output Variables Box */
|
/* Output Variables Box */
|
||||||
--bg-accent: rgba(76, 164, 231, 0.05);
|
--bg-accent: rgba(76, 164, 231, 0.05);
|
||||||
|
|
||||||
--state-success: #3ba05c;
|
/* --state-success: #3ba05c; */
|
||||||
--state-warning: #faad14;
|
--state-success: 59 160 92;
|
||||||
|
/* --state-warning: #767573; */
|
||||||
|
--state-warning: 118 117 115;
|
||||||
--state-error: 216 73 75;
|
--state-error: 216 73 75;
|
||||||
|
|
||||||
--team-group: #5ab77e;
|
--team-group: #5ab77e;
|
||||||
|
|||||||
Reference in New Issue
Block a user