mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Feat: Add agent-log-list page (#9076)
### What problem does this PR solve? Fix: Add agent-log-list page And RAPTOR:Save directly after enabling, incomplete form submission #3221 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
186
web/src/components/originui/time-range-picker.tsx
Normal file
186
web/src/components/originui/time-range-picker.tsx
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import {
|
||||||
|
endOfMonth,
|
||||||
|
endOfYear,
|
||||||
|
format,
|
||||||
|
startOfMonth,
|
||||||
|
startOfYear,
|
||||||
|
subDays,
|
||||||
|
subMonths,
|
||||||
|
subYears,
|
||||||
|
} from 'date-fns';
|
||||||
|
import { useEffect, useId, useState } from 'react';
|
||||||
|
|
||||||
|
import { Calendar, DateRange } from '@/components/originui/calendar';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/components/ui/popover';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { CalendarIcon } from 'lucide-react';
|
||||||
|
|
||||||
|
const CalendarComp = ({
|
||||||
|
selectDateRange,
|
||||||
|
onSelect,
|
||||||
|
...props
|
||||||
|
}: ITimeRangePickerProps) => {
|
||||||
|
const today = new Date();
|
||||||
|
const yesterday = {
|
||||||
|
from: subDays(today, 1),
|
||||||
|
to: subDays(today, 1),
|
||||||
|
};
|
||||||
|
const last7Days = {
|
||||||
|
from: subDays(today, 6),
|
||||||
|
to: today,
|
||||||
|
};
|
||||||
|
const last30Days = {
|
||||||
|
from: subDays(today, 29),
|
||||||
|
to: today,
|
||||||
|
};
|
||||||
|
const monthToDate = {
|
||||||
|
from: startOfMonth(today),
|
||||||
|
to: today,
|
||||||
|
};
|
||||||
|
const lastMonth = {
|
||||||
|
from: startOfMonth(subMonths(today, 1)),
|
||||||
|
to: endOfMonth(subMonths(today, 1)),
|
||||||
|
};
|
||||||
|
const yearToDate = {
|
||||||
|
from: startOfYear(today),
|
||||||
|
to: today,
|
||||||
|
};
|
||||||
|
const lastYear = {
|
||||||
|
from: startOfYear(subYears(today, 1)),
|
||||||
|
to: endOfYear(subYears(today, 1)),
|
||||||
|
};
|
||||||
|
const dateRangeList = [
|
||||||
|
{ key: 'yestday', value: yesterday },
|
||||||
|
{ key: 'last7Days', value: last7Days },
|
||||||
|
{ key: 'last30Days', value: last30Days },
|
||||||
|
{ key: 'monthToDate', value: monthToDate },
|
||||||
|
{ key: 'lastMonth', value: lastMonth },
|
||||||
|
{ key: 'yearToDate', value: yearToDate },
|
||||||
|
{ key: 'lastYear', value: lastYear },
|
||||||
|
];
|
||||||
|
const [month, setMonth] = useState(today);
|
||||||
|
const [date, setDate] = useState<DateRange>(selectDateRange || last7Days);
|
||||||
|
useEffect(() => {
|
||||||
|
onSelect?.(date);
|
||||||
|
}, [date, onSelect]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<div className="flex max-sm:flex-col">
|
||||||
|
<div className="relative py-4 max-sm:order-1 max-sm:border-t sm:w-32">
|
||||||
|
<div className="h-full sm:border-e">
|
||||||
|
<div className="flex flex-col px-2 gap-2">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="w-full justify-start"
|
||||||
|
onClick={() => {
|
||||||
|
setDate({
|
||||||
|
from: today,
|
||||||
|
to: today,
|
||||||
|
});
|
||||||
|
setMonth(today);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Today
|
||||||
|
</Button>
|
||||||
|
{dateRangeList.map((dateRange) => (
|
||||||
|
<Button
|
||||||
|
key={dateRange.key}
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="w-full justify-start"
|
||||||
|
onClick={() => {
|
||||||
|
setDate(dateRange.value);
|
||||||
|
setMonth(dateRange.value.to);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dateRange.key}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Calendar
|
||||||
|
mode="range"
|
||||||
|
selected={date}
|
||||||
|
onSelect={(newDate) => {
|
||||||
|
if (newDate) {
|
||||||
|
setDate(newDate as DateRange);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
month={month}
|
||||||
|
onMonthChange={setMonth}
|
||||||
|
className="p-2"
|
||||||
|
{...props}
|
||||||
|
// disabled={[
|
||||||
|
// { after: today }, // Dates before today
|
||||||
|
// ]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ITimeRangePickerProps = {
|
||||||
|
onSelect: (e: DateRange) => void;
|
||||||
|
selectDateRange: DateRange;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
const TimeRangePicker = ({
|
||||||
|
onSelect,
|
||||||
|
selectDateRange,
|
||||||
|
...props
|
||||||
|
}: ITimeRangePickerProps) => {
|
||||||
|
const id = useId();
|
||||||
|
const today = new Date();
|
||||||
|
const [date, setDate] = useState<DateRange | undefined>(
|
||||||
|
selectDateRange || { from: today, to: today },
|
||||||
|
);
|
||||||
|
const onChange = (e: DateRange | undefined) => {
|
||||||
|
if (!e) return;
|
||||||
|
setDate(e);
|
||||||
|
onSelect?.(e);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
id={id}
|
||||||
|
variant="outline"
|
||||||
|
className="group bg-muted-foreground/10 hover:bg-muted-foreground/10 border-input w-full justify-between px-3 font-normal outline-offset-0 outline-none focus-visible:outline-[3px]"
|
||||||
|
>
|
||||||
|
<span className={cn('truncate', !date && 'text-muted-foreground')}>
|
||||||
|
{date?.from ? (
|
||||||
|
date.to ? (
|
||||||
|
<>
|
||||||
|
{format(date.from, 'LLL dd, y')} -{' '}
|
||||||
|
{format(date.to, 'LLL dd, y')}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
format(date.from, 'LLL dd, y')
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
'Pick a date range'
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<CalendarIcon
|
||||||
|
size={16}
|
||||||
|
className="text-muted-foreground/80 group-hover:text-foreground shrink-0 transition-colors"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-2" align="start">
|
||||||
|
<CalendarComp selectDateRange={date} onSelect={onChange} {...props} />
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default TimeRangePicker;
|
||||||
@ -54,6 +54,13 @@ export const useNavigatePage = () => {
|
|||||||
[navigate],
|
[navigate],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const navigateToAgentLogs = useCallback(
|
||||||
|
(id: string) => () => {
|
||||||
|
navigate(`${Routes.AgentLogPage}/${id}`);
|
||||||
|
},
|
||||||
|
[navigate],
|
||||||
|
);
|
||||||
|
|
||||||
const navigateToAgentTemplates = useCallback(() => {
|
const navigateToAgentTemplates = useCallback(() => {
|
||||||
navigate(Routes.AgentTemplates);
|
navigate(Routes.AgentTemplates);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
@ -120,6 +127,7 @@ export const useNavigatePage = () => {
|
|||||||
navigateToChunk,
|
navigateToChunk,
|
||||||
navigateToAgents,
|
navigateToAgents,
|
||||||
navigateToAgent,
|
navigateToAgent,
|
||||||
|
navigateToAgentLogs,
|
||||||
navigateToAgentTemplates,
|
navigateToAgentTemplates,
|
||||||
navigateToSearchList,
|
navigateToSearchList,
|
||||||
navigateToSearch,
|
navigateToSearch,
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
import { FileUploadProps } from '@/components/file-upload';
|
import { FileUploadProps } from '@/components/file-upload';
|
||||||
import message from '@/components/ui/message';
|
import message from '@/components/ui/message';
|
||||||
import { AgentGlobals } from '@/constants/agent';
|
import { AgentGlobals } from '@/constants/agent';
|
||||||
import { ITraceData } from '@/interfaces/database/agent';
|
import {
|
||||||
|
IAgentLogsRequest,
|
||||||
|
IAgentLogsResponse,
|
||||||
|
ITraceData,
|
||||||
|
} from '@/interfaces/database/agent';
|
||||||
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
||||||
import { IDebugSingleRequestBody } from '@/interfaces/request/agent';
|
import { IDebugSingleRequestBody } from '@/interfaces/request/agent';
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import { BeginId } from '@/pages/agent/constant';
|
import { BeginId } from '@/pages/agent/constant';
|
||||||
import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks';
|
import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks';
|
||||||
import agentService, { fetchTrace } from '@/services/agent-service';
|
import agentService, {
|
||||||
|
fetchAgentLogsByCanvasId,
|
||||||
|
fetchTrace,
|
||||||
|
} from '@/services/agent-service';
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
import { buildMessageListWithUuid } from '@/utils/chat';
|
import { buildMessageListWithUuid } from '@/utils/chat';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
@ -558,3 +565,22 @@ export const useFetchAgentAvatar = (): {
|
|||||||
|
|
||||||
return { data, loading, refetch };
|
return { data, loading, refetch };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useFetchAgentLog = (searchParams: IAgentLogsRequest) => {
|
||||||
|
const { id } = useParams();
|
||||||
|
const { data, isFetching: loading } = useQuery<IAgentLogsResponse>({
|
||||||
|
queryKey: ['fetchAgentLog', id, searchParams],
|
||||||
|
initialData: {} as IAgentLogsResponse,
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async () => {
|
||||||
|
console.log('useFetchAgentLog', searchParams);
|
||||||
|
const { data } = await fetchAgentLogsByCanvasId(id as string, {
|
||||||
|
...searchParams,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data?.data ?? [];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading };
|
||||||
|
};
|
||||||
|
|||||||
@ -229,3 +229,38 @@ export interface ITraceData {
|
|||||||
component_id: string;
|
component_id: string;
|
||||||
trace: Array<Record<string, any>>;
|
trace: Array<Record<string, any>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAgentLogResponse {
|
||||||
|
id: string;
|
||||||
|
message: IAgentLogMessage[];
|
||||||
|
update_date: string;
|
||||||
|
create_date: string;
|
||||||
|
update_time: number;
|
||||||
|
create_time: number;
|
||||||
|
round: number;
|
||||||
|
thumb_up: number;
|
||||||
|
errors: string;
|
||||||
|
source: string;
|
||||||
|
user_id: string;
|
||||||
|
dsl: string;
|
||||||
|
reference: IReference;
|
||||||
|
}
|
||||||
|
export interface IAgentLogsResponse {
|
||||||
|
total: number;
|
||||||
|
sessions: IAgentLogResponse[];
|
||||||
|
}
|
||||||
|
export interface IAgentLogsRequest {
|
||||||
|
keywords?: string;
|
||||||
|
to_date?: string | Date;
|
||||||
|
from_date?: string | Date;
|
||||||
|
orderby?: string;
|
||||||
|
desc?: boolean;
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAgentLogMessage {
|
||||||
|
content: string;
|
||||||
|
role: 'user' | 'assistant';
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|||||||
@ -25,7 +25,6 @@ import {
|
|||||||
CirclePlay,
|
CirclePlay,
|
||||||
Download,
|
Download,
|
||||||
History,
|
History,
|
||||||
Key,
|
|
||||||
LaptopMinimalCheck,
|
LaptopMinimalCheck,
|
||||||
Logs,
|
Logs,
|
||||||
ScreenShare,
|
ScreenShare,
|
||||||
@ -42,7 +41,6 @@ import {
|
|||||||
useGetBeginNodeDataInputs,
|
useGetBeginNodeDataInputs,
|
||||||
useGetBeginNodeDataQueryIsSafe,
|
useGetBeginNodeDataQueryIsSafe,
|
||||||
} from './hooks/use-get-begin-query';
|
} from './hooks/use-get-begin-query';
|
||||||
import { useOpenDocument } from './hooks/use-open-document';
|
|
||||||
import {
|
import {
|
||||||
useSaveGraph,
|
useSaveGraph,
|
||||||
useSaveGraphBeforeOpeningDebugDrawer,
|
useSaveGraphBeforeOpeningDebugDrawer,
|
||||||
@ -73,7 +71,7 @@ export default function Agent() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data: userInfo } = useFetchUserInfo();
|
const { data: userInfo } = useFetchUserInfo();
|
||||||
|
|
||||||
const openDocument = useOpenDocument();
|
// const openDocument = useOpenDocument();
|
||||||
const {
|
const {
|
||||||
handleExportJson,
|
handleExportJson,
|
||||||
handleImportJson,
|
handleImportJson,
|
||||||
@ -100,7 +98,7 @@ export default function Agent() {
|
|||||||
|
|
||||||
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
||||||
useShowEmbedModal();
|
useShowEmbedModal();
|
||||||
|
const { navigateToAgentLogs } = useNavigatePage();
|
||||||
const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe();
|
const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -135,7 +133,10 @@ export default function Agent() {
|
|||||||
<History />
|
<History />
|
||||||
{t('flow.historyversion')}
|
{t('flow.historyversion')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant={'secondary'}>
|
<Button
|
||||||
|
variant={'secondary'}
|
||||||
|
onClick={navigateToAgentLogs(id as string)}
|
||||||
|
>
|
||||||
<Logs />
|
<Logs />
|
||||||
{t('flow.log')}
|
{t('flow.log')}
|
||||||
</Button>
|
</Button>
|
||||||
@ -147,11 +148,11 @@ export default function Agent() {
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<AgentDropdownMenuItem onClick={openDocument}>
|
{/* <AgentDropdownMenuItem onClick={openDocument}>
|
||||||
<Key />
|
<Key />
|
||||||
API
|
API
|
||||||
</AgentDropdownMenuItem>
|
</AgentDropdownMenuItem> */}
|
||||||
<DropdownMenuSeparator />
|
{/* <DropdownMenuSeparator /> */}
|
||||||
<AgentDropdownMenuItem onClick={handleImportJson}>
|
<AgentDropdownMenuItem onClick={handleImportJson}>
|
||||||
<Download />
|
<Download />
|
||||||
{t('flow.import')}
|
{t('flow.import')}
|
||||||
|
|||||||
319
web/src/pages/agents/agent-log-page.tsx
Normal file
319
web/src/pages/agents/agent-log-page.tsx
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import TimeRangePicker from '@/components/originui/time-range-picker';
|
||||||
|
import { PageHeader } from '@/components/page-header';
|
||||||
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
} from '@/components/ui/breadcrumb';
|
||||||
|
import { SearchInput } from '@/components/ui/input';
|
||||||
|
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||||
|
import { Spin } from '@/components/ui/spin';
|
||||||
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
|
import { useFetchAgentLog } from '@/hooks/use-agent-request';
|
||||||
|
import { IAgentLogResponse } from '@/interfaces/database/agent';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useParams } from 'umi';
|
||||||
|
import { DateRange } from '../../components/originui/calendar/index';
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from '../../components/ui/table';
|
||||||
|
import { useFetchDataOnMount } from '../agent/hooks/use-fetch-data';
|
||||||
|
|
||||||
|
const AgentLogPage: React.FC = () => {
|
||||||
|
const { navigateToAgentList, navigateToAgent } = useNavigatePage();
|
||||||
|
const { flowDetail: agentDetail } = useFetchDataOnMount();
|
||||||
|
const { id: canvasId } = useParams();
|
||||||
|
const today = new Date();
|
||||||
|
const init = {
|
||||||
|
keywords: '',
|
||||||
|
from_date: today,
|
||||||
|
to_date: today,
|
||||||
|
orderby: 'create_time',
|
||||||
|
desc: false,
|
||||||
|
page: 1,
|
||||||
|
page_size: 10,
|
||||||
|
};
|
||||||
|
const [searchParams, setSearchParams] = useState(init);
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Title',
|
||||||
|
dataIndex: 'title',
|
||||||
|
key: 'title',
|
||||||
|
render: (text, record: IAgentLogResponse) => (
|
||||||
|
<span>
|
||||||
|
{record?.message?.length ? record?.message[0]?.content : ''}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'State',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
render: (text, record: IAgentLogResponse) => (
|
||||||
|
<div
|
||||||
|
className="size-2 rounded-full"
|
||||||
|
style={{ backgroundColor: record.errors ? 'red' : 'green' }}
|
||||||
|
></div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Number',
|
||||||
|
dataIndex: 'round',
|
||||||
|
key: 'round',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Latest Date',
|
||||||
|
dataIndex: 'update_date',
|
||||||
|
key: 'update_date',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Create Date',
|
||||||
|
dataIndex: 'create_date',
|
||||||
|
key: 'create_date',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { data: logData, loading } = useFetchAgentLog(searchParams);
|
||||||
|
const { sessions: data, total } = logData || {};
|
||||||
|
const [currentDate, setCurrentDate] = useState<DateRange>({
|
||||||
|
from: searchParams.from_date,
|
||||||
|
to: searchParams.to_date,
|
||||||
|
});
|
||||||
|
const [keywords, setKeywords] = useState(searchParams.keywords);
|
||||||
|
const handleDateRangeChange = ({
|
||||||
|
from: startDate,
|
||||||
|
to: endDate,
|
||||||
|
}: DateRange) => {
|
||||||
|
setCurrentDate({ from: startDate, to: endDate });
|
||||||
|
};
|
||||||
|
|
||||||
|
const [pagination, setPagination] = useState<{
|
||||||
|
current: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
}>({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: total,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPagination((pre) => {
|
||||||
|
return {
|
||||||
|
...pre,
|
||||||
|
total: total,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [total]);
|
||||||
|
|
||||||
|
const [sortConfig, setSortConfig] = useState<{
|
||||||
|
orderby: string;
|
||||||
|
desc: boolean;
|
||||||
|
} | null>({ orderby: init.orderby, desc: init.desc ? true : false });
|
||||||
|
|
||||||
|
const handlePageChange = (current?: number, pageSize?: number) => {
|
||||||
|
console.log('current', current, 'pageSize', pageSize);
|
||||||
|
setPagination((pre) => {
|
||||||
|
return {
|
||||||
|
...pre,
|
||||||
|
current: current ?? pre.current,
|
||||||
|
pageSize: pageSize ?? pre.pageSize,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
setSearchParams((pre) => {
|
||||||
|
return {
|
||||||
|
...pre,
|
||||||
|
from_date: currentDate.from as Date,
|
||||||
|
to_date: currentDate.to as Date,
|
||||||
|
page: pagination.current,
|
||||||
|
page_size: pagination.pageSize,
|
||||||
|
orderby: sortConfig?.orderby || '',
|
||||||
|
desc: sortConfig?.desc as boolean,
|
||||||
|
keywords: keywords,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleSearch();
|
||||||
|
}, [pagination.current, pagination.pageSize, sortConfig]);
|
||||||
|
// handle sort
|
||||||
|
const handleSort = (key: string) => {
|
||||||
|
let desc = false;
|
||||||
|
if (sortConfig && sortConfig.orderby === key) {
|
||||||
|
desc = !sortConfig.desc;
|
||||||
|
}
|
||||||
|
setSortConfig({ orderby: key, desc });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
setSearchParams(init);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className=" text-white">
|
||||||
|
<PageHeader>
|
||||||
|
<Breadcrumb>
|
||||||
|
<BreadcrumbList>
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink onClick={navigateToAgentList}>
|
||||||
|
Agent
|
||||||
|
</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink onClick={navigateToAgent(canvasId as string)}>
|
||||||
|
{agentDetail.title}
|
||||||
|
</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>Log</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
|
</PageHeader>
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<h1 className="text-2xl font-bold mb-4">Log</h1>
|
||||||
|
|
||||||
|
<div className="flex justify-end space-x-2 mb-4">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span>ID/Title</span>
|
||||||
|
<SearchInput
|
||||||
|
value={keywords}
|
||||||
|
onChange={(e) => {
|
||||||
|
setKeywords(e.target.value);
|
||||||
|
}}
|
||||||
|
className="w-32"
|
||||||
|
></SearchInput>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span className="whitespace-nowrap">Latest Date</span>
|
||||||
|
<TimeRangePicker
|
||||||
|
onSelect={handleDateRangeChange}
|
||||||
|
selectDateRange={{ from: currentDate.from, to: currentDate.to }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="bg-foreground text-text-title-invert px-4 py-1 rounded"
|
||||||
|
onClick={() => {
|
||||||
|
setPagination({ ...pagination, current: 1 });
|
||||||
|
handleSearch();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="bg-transparent text-foreground px-4 py-1 rounded border"
|
||||||
|
onClick={() => handleReset()}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border rounded-md overflow-auto">
|
||||||
|
{/* <div className="max-h-[500px] overflow-y-auto w-full"> */}
|
||||||
|
<Table rootClassName="max-h-[calc(100vh-200px)]">
|
||||||
|
<TableHeader className="sticky top-0 bg-background z-10 shadow-sm">
|
||||||
|
<TableRow>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableHead
|
||||||
|
key={column.dataIndex}
|
||||||
|
onClick={
|
||||||
|
column.sortable
|
||||||
|
? () => handleSort(column.dataIndex)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
className={
|
||||||
|
column.sortable ? 'cursor-pointer hover:bg-muted/50' : ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{column.title}
|
||||||
|
{column.sortable &&
|
||||||
|
sortConfig?.orderby === column.dataIndex && (
|
||||||
|
<span className="ml-1">
|
||||||
|
{sortConfig.desc ? '↓' : '↑'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{loading && (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="h-24 text-center"
|
||||||
|
>
|
||||||
|
<Spin size="large">
|
||||||
|
<span className="sr-only">Loading...</span>
|
||||||
|
</Spin>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{!loading &&
|
||||||
|
data?.map((item) => (
|
||||||
|
<TableRow key={item.id}>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableCell key={column.dataIndex}>
|
||||||
|
{column.render
|
||||||
|
? column.render(item[column.dataIndex], item)
|
||||||
|
: item[column.dataIndex]}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
{!loading && (!data || data.length === 0) && (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="h-24 text-center"
|
||||||
|
>
|
||||||
|
No data
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
{/* </div> */}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end mt-4 w-full">
|
||||||
|
<div className="space-x-2">
|
||||||
|
<RAGFlowPagination
|
||||||
|
{...pagination}
|
||||||
|
total={pagination.total}
|
||||||
|
onChange={(page, pageSize) => {
|
||||||
|
handlePageChange(page, pageSize);
|
||||||
|
}}
|
||||||
|
></RAGFlowPagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AgentLogPage;
|
||||||
@ -88,13 +88,17 @@ export function ChunkMethodForm() {
|
|||||||
let beValid = await form.formControl.trigger();
|
let beValid = await form.formControl.trigger();
|
||||||
if (beValid) {
|
if (beValid) {
|
||||||
// setSubmitLoading(true);
|
// setSubmitLoading(true);
|
||||||
let postData = form.formState.values;
|
// let postData = form.formState.values;
|
||||||
delete postData['avatar']; // has submitted in first form general
|
// console.log('submit form -->', form);
|
||||||
|
// delete postData['avatar']; // has submitted in first form general
|
||||||
saveKnowledgeConfiguration({
|
form.handleSubmit(async (values) => {
|
||||||
...postData,
|
console.log('saveKnowledgeConfiguration: ', values);
|
||||||
|
delete values['avatar'];
|
||||||
|
await saveKnowledgeConfiguration({
|
||||||
kb_id,
|
kb_id,
|
||||||
|
...values,
|
||||||
});
|
});
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export enum Routes {
|
|||||||
Result = '/result',
|
Result = '/result',
|
||||||
ResultView = `${Chunk}${Result}`,
|
ResultView = `${Chunk}${Result}`,
|
||||||
KnowledgeGraph = '/knowledge-graph',
|
KnowledgeGraph = '/knowledge-graph',
|
||||||
|
AgentLogPage = '/agent-log-page',
|
||||||
}
|
}
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -244,6 +245,11 @@ const routes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `${Routes.AgentLogPage}/:id`,
|
||||||
|
layout: false,
|
||||||
|
component: `@/pages${Routes.Agents}${Routes.AgentLogPage}`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `${Routes.Agent}/:id`,
|
path: `${Routes.Agent}/:id`,
|
||||||
layout: false,
|
layout: false,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { IAgentLogsRequest } from '@/interfaces/database/agent';
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
import { registerNextServer } from '@/utils/register-server';
|
import { registerNextServer } from '@/utils/register-server';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
@ -22,6 +23,7 @@ const {
|
|||||||
fetchVersion,
|
fetchVersion,
|
||||||
fetchCanvas,
|
fetchCanvas,
|
||||||
fetchAgentAvatar,
|
fetchAgentAvatar,
|
||||||
|
fetchAgentLogs,
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
@ -101,6 +103,10 @@ const methods = {
|
|||||||
url: fetchAgentAvatar,
|
url: fetchAgentAvatar,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
},
|
},
|
||||||
|
fetchAgentLogs: {
|
||||||
|
url: fetchAgentLogs,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const agentService = registerNextServer<keyof typeof methods>(methods);
|
const agentService = registerNextServer<keyof typeof methods>(methods);
|
||||||
@ -108,5 +114,11 @@ const agentService = registerNextServer<keyof typeof methods>(methods);
|
|||||||
export const fetchTrace = (data: { canvas_id: string; message_id: string }) => {
|
export const fetchTrace = (data: { canvas_id: string; message_id: string }) => {
|
||||||
return request.get(methods.trace.url, { params: data });
|
return request.get(methods.trace.url, { params: data });
|
||||||
};
|
};
|
||||||
|
export const fetchAgentLogsByCanvasId = (
|
||||||
|
canvasId: string,
|
||||||
|
params: IAgentLogsRequest,
|
||||||
|
) => {
|
||||||
|
return request.get(methods.fetchAgentLogs.url(canvasId), { params: params });
|
||||||
|
};
|
||||||
|
|
||||||
export default agentService;
|
export default agentService;
|
||||||
|
|||||||
@ -153,6 +153,8 @@ export default {
|
|||||||
fetchCanvas: (id: string) => `${api_host}/canvas/get/${id}`,
|
fetchCanvas: (id: string) => `${api_host}/canvas/get/${id}`,
|
||||||
fetchAgentAvatar: (id: string) => `${api_host}/canvas/getsse/${id}`,
|
fetchAgentAvatar: (id: string) => `${api_host}/canvas/getsse/${id}`,
|
||||||
uploadAgentFile: (id?: string) => `${api_host}/canvas/upload/${id}`,
|
uploadAgentFile: (id?: string) => `${api_host}/canvas/upload/${id}`,
|
||||||
|
fetchAgentLogs: (canvasId: string) =>
|
||||||
|
`${api_host}/canvas/${canvasId}/sessions`,
|
||||||
|
|
||||||
// mcp server
|
// mcp server
|
||||||
listMcpServer: `${api_host}/mcp_server/list`,
|
listMcpServer: `${api_host}/mcp_server/list`,
|
||||||
|
|||||||
@ -32,3 +32,14 @@ export function formatPureDate(date: any) {
|
|||||||
}
|
}
|
||||||
return dayjs(date).format('DD/MM/YYYY');
|
return dayjs(date).format('DD/MM/YYYY');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatStandardDate(date: any) {
|
||||||
|
if (!date) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const parsedDate = dayjs(date);
|
||||||
|
if (!parsedDate.isValid()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return parsedDate.format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user