index.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 'use client'
  2. import type { FC, SVGProps } from 'react'
  3. import React, { useState } from 'react'
  4. import useSWR from 'swr'
  5. import { usePathname } from 'next/navigation'
  6. import { useDebounce } from 'ahooks'
  7. import { Trans, useTranslation } from 'react-i18next'
  8. import Link from 'next/link'
  9. import List from './list'
  10. import Filter from './filter'
  11. import Pagination from '@/app/components/base/pagination'
  12. import Loading from '@/app/components/base/loading'
  13. import { fetchWorkflowLogs } from '@/service/log'
  14. import { APP_PAGE_LIMIT } from '@/config'
  15. import type { App, AppMode } from '@/types/app'
  16. export type ILogsProps = {
  17. appDetail: App
  18. }
  19. export type QueryParam = {
  20. status?: string
  21. keyword?: string
  22. }
  23. const ThreeDotsIcon = ({ className }: SVGProps<SVGElement>) => {
  24. return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
  25. <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
  26. </svg>
  27. }
  28. const EmptyElement: FC<{ appUrl: string }> = ({ appUrl }) => {
  29. const { t } = useTranslation()
  30. const pathname = usePathname()
  31. const pathSegments = pathname.split('/')
  32. pathSegments.pop()
  33. return <div className='flex items-center justify-center h-full'>
  34. <div className='bg-background-section-burn w-[560px] h-fit box-border px-5 py-4 rounded-2xl'>
  35. <span className='text-text-secondary system-md-semibold'>{t('appLog.table.empty.element.title')}<ThreeDotsIcon className='inline relative -top-3 -left-1.5' /></span>
  36. <div className='mt-2 text-text-tertiary system-sm-regular'>
  37. <Trans
  38. i18nKey="appLog.table.empty.element.content"
  39. 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' /> }}
  40. />
  41. </div>
  42. </div>
  43. </div>
  44. }
  45. const Logs: FC<ILogsProps> = ({ appDetail }) => {
  46. const { t } = useTranslation()
  47. const [queryParams, setQueryParams] = useState<QueryParam>({ status: 'all' })
  48. const [currPage, setCurrPage] = React.useState<number>(0)
  49. const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
  50. const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
  51. const query = {
  52. page: currPage + 1,
  53. limit,
  54. ...(debouncedQueryParams.status !== 'all' ? { status: debouncedQueryParams.status } : {}),
  55. ...(debouncedQueryParams.keyword ? { keyword: debouncedQueryParams.keyword } : {}),
  56. }
  57. const getWebAppType = (appType: AppMode) => {
  58. if (appType !== 'completion' && appType !== 'workflow')
  59. return 'chat'
  60. return appType
  61. }
  62. const { data: workflowLogs, mutate } = useSWR({
  63. url: `/apps/${appDetail.id}/workflow-app-logs`,
  64. params: query,
  65. }, fetchWorkflowLogs)
  66. const total = workflowLogs?.total
  67. return (
  68. <div className='flex flex-col h-full'>
  69. <h1 className='text-text-primary system-xl-semibold'>{t('appLog.workflowTitle')}</h1>
  70. <p className='text-text-tertiary system-sm-regular'>{t('appLog.workflowSubtitle')}</p>
  71. <div className='flex flex-col py-4 flex-1'>
  72. <Filter queryParams={queryParams} setQueryParams={setQueryParams} />
  73. {/* workflow log */}
  74. {total === undefined
  75. ? <Loading type='app' />
  76. : total > 0
  77. ? <List logs={workflowLogs} appDetail={appDetail} onRefresh={mutate} />
  78. : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} />
  79. }
  80. {/* Show Pagination only if the total is more than the limit */}
  81. {(total && total > APP_PAGE_LIMIT)
  82. ? <Pagination
  83. current={currPage}
  84. onChange={setCurrPage}
  85. total={total}
  86. limit={limit}
  87. onLimitChange={setLimit}
  88. />
  89. : null}
  90. </div>
  91. </div>
  92. )
  93. }
  94. export default Logs