123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- 'use client'
- import type { FC, SVGProps } from 'react'
- import React, { useState } from 'react'
- import useSWR from 'swr'
- import { usePathname } from 'next/navigation'
- import { useDebounce } from 'ahooks'
- import { omit } from 'lodash-es'
- import dayjs from 'dayjs'
- import utc from 'dayjs/plugin/utc'
- import timezone from 'dayjs/plugin/timezone'
- import { Trans, useTranslation } from 'react-i18next'
- import Link from 'next/link'
- import List from './list'
- import Filter, { TIME_PERIOD_MAPPING } from './filter'
- import Pagination from '@/app/components/base/pagination'
- import Loading from '@/app/components/base/loading'
- import { fetchWorkflowLogs } from '@/service/log'
- import { APP_PAGE_LIMIT } from '@/config'
- import type { App, AppMode } from '@/types/app'
- import { useAppContext } from '@/context/app-context'
- dayjs.extend(utc)
- dayjs.extend(timezone)
- export type ILogsProps = {
- appDetail: App
- }
- export type QueryParam = {
- period: string
- status?: string
- keyword?: string
- }
- const ThreeDotsIcon = ({ className }: SVGProps<SVGElement>) => {
- return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
- <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
- </svg>
- }
- const EmptyElement: FC<{ appUrl: string }> = ({ appUrl }) => {
- const { t } = useTranslation()
- const pathname = usePathname()
- const pathSegments = pathname.split('/')
- pathSegments.pop()
- return <div className='flex items-center justify-center h-full'>
- <div className='bg-background-section-burn w-[560px] h-fit box-border px-5 py-4 rounded-2xl'>
- <span className='text-text-secondary system-md-semibold'>{t('appLog.table.empty.element.title')}<ThreeDotsIcon className='inline relative -top-3 -left-1.5' /></span>
- <div className='mt-2 text-text-tertiary system-sm-regular'>
- <Trans
- i18nKey="appLog.table.empty.element.content"
- components={{ shareLink: <Link href={`${pathSegments.join('/')}/overview`} className='text-util-colors-blue-blue-600' />, testLink: <Link href={appUrl} className='text-util-colors-blue-blue-600' target='_blank' rel='noopener noreferrer' /> }}
- />
- </div>
- </div>
- </div>
- }
- const Logs: FC<ILogsProps> = ({ appDetail }) => {
- const { t } = useTranslation()
- const { userProfile: { timezone } } = useAppContext()
- const [queryParams, setQueryParams] = useState<QueryParam>({ status: 'all', period: '2' })
- const [currPage, setCurrPage] = React.useState<number>(0)
- const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
- const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
- const query = {
- page: currPage + 1,
- limit,
- ...(debouncedQueryParams.status !== 'all' ? { status: debouncedQueryParams.status } : {}),
- ...(debouncedQueryParams.keyword ? { keyword: debouncedQueryParams.keyword } : {}),
- ...((debouncedQueryParams.period !== '9')
- ? {
- created_at__after: dayjs().subtract(TIME_PERIOD_MAPPING[debouncedQueryParams.period].value, 'day').startOf('day').tz(timezone).format('YYYY-MM-DDTHH:mm:ssZ'),
- created_at__before: dayjs().endOf('day').tz(timezone).format('YYYY-MM-DDTHH:mm:ssZ'),
- }
- : {}),
- ...omit(debouncedQueryParams, ['period', 'status']),
- }
- const getWebAppType = (appType: AppMode) => {
- if (appType !== 'completion' && appType !== 'workflow')
- return 'chat'
- return appType
- }
- const { data: workflowLogs, mutate } = useSWR({
- url: `/apps/${appDetail.id}/workflow-app-logs`,
- params: query,
- }, fetchWorkflowLogs)
- const total = workflowLogs?.total
- return (
- <div className='flex flex-col h-full'>
- <h1 className='text-text-primary system-xl-semibold'>{t('appLog.workflowTitle')}</h1>
- <p className='text-text-tertiary system-sm-regular'>{t('appLog.workflowSubtitle')}</p>
- <div className='flex flex-col py-4 flex-1 max-h-[calc(100%-16px)]'>
- <Filter queryParams={queryParams} setQueryParams={setQueryParams} />
- {/* workflow log */}
- {total === undefined
- ? <Loading type='app' />
- : total > 0
- ? <List logs={workflowLogs} appDetail={appDetail} onRefresh={mutate} />
- : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} />
- }
- {/* Show Pagination only if the total is more than the limit */}
- {(total && total > APP_PAGE_LIMIT)
- ? <Pagination
- current={currPage}
- onChange={setCurrPage}
- total={total}
- limit={limit}
- onLimitChange={setLimit}
- />
- : null}
- </div>
- </div>
- )
- }
- export default Logs
|