view-history.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import {
  2. memo,
  3. useState,
  4. } from 'react'
  5. import cn from 'classnames'
  6. import useSWR from 'swr'
  7. import { useTranslation } from 'react-i18next'
  8. import {
  9. useIsChatMode,
  10. useWorkflow,
  11. useWorkflowRun,
  12. } from '../hooks'
  13. import { WorkflowRunningStatus } from '../types'
  14. import {
  15. PortalToFollowElem,
  16. PortalToFollowElemContent,
  17. PortalToFollowElemTrigger,
  18. } from '@/app/components/base/portal-to-follow-elem'
  19. import TooltipPlus from '@/app/components/base/tooltip-plus'
  20. import { useStore as useAppStore } from '@/app/components/app/store'
  21. import {
  22. ClockPlay,
  23. ClockPlaySlim,
  24. } from '@/app/components/base/icons/src/vender/line/time'
  25. import { CheckCircle, XClose } from '@/app/components/base/icons/src/vender/line/general'
  26. import { AlertCircle, AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
  27. import {
  28. fetcChatRunHistory,
  29. fetchWorkflowRunHistory,
  30. } from '@/service/workflow'
  31. import Loading from '@/app/components/base/loading'
  32. import {
  33. useStore,
  34. useWorkflowStore,
  35. } from '@/app/components/workflow/store'
  36. const ViewHistory = () => {
  37. const { t } = useTranslation()
  38. const isChatMode = useIsChatMode()
  39. const [open, setOpen] = useState(false)
  40. const { formatTimeFromNow } = useWorkflow()
  41. const workflowStore = useWorkflowStore()
  42. const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore()
  43. const historyWorkflowData = useStore(s => s.historyWorkflowData)
  44. const { handleBackupDraft } = useWorkflowRun()
  45. const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode && open) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
  46. const { data: chatList, isLoading: chatListLoading } = useSWR((appDetail && isChatMode && open) ? `/apps/${appDetail.id}/advanced-chat/workflow-runs` : null, fetcChatRunHistory)
  47. const data = isChatMode ? chatList : runList
  48. const isLoading = isChatMode ? chatListLoading : runListLoading
  49. return (
  50. (
  51. <PortalToFollowElem
  52. placement='bottom-end'
  53. offset={{
  54. mainAxis: 4,
  55. crossAxis: 131,
  56. }}
  57. open={open}
  58. onOpenChange={setOpen}
  59. >
  60. <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
  61. <TooltipPlus
  62. popupContent={t('workflow.common.viewRunHistory')}
  63. >
  64. <div
  65. className={`
  66. flex items-center justify-center w-7 h-7 rounded-md hover:bg-black/5 cursor-pointer
  67. ${open && 'bg-primary-50'}
  68. `}
  69. onClick={() => {
  70. setCurrentLogItem()
  71. setShowMessageLogModal(false)
  72. }}
  73. >
  74. <ClockPlay className={`w-4 h-4 ${open ? 'text-primary-600' : 'text-gray-500'}`} />
  75. </div>
  76. </TooltipPlus>
  77. </PortalToFollowElemTrigger>
  78. <PortalToFollowElemContent className='z-[12]'>
  79. <div
  80. className='flex flex-col ml-2 w-[240px] bg-white border-[0.5px] border-gray-200 shadow-xl rounded-xl overflow-y-auto'
  81. style={{
  82. maxHeight: 'calc(2 / 3 * 100vh)',
  83. }}
  84. >
  85. <div className='sticky top-0 bg-white flex items-center justify-between px-4 pt-3 text-base font-semibold text-gray-900'>
  86. <div className='grow'>{t('workflow.common.runHistory')}</div>
  87. <div
  88. className='shrink-0 flex items-center justify-center w-6 h-6 cursor-pointer'
  89. onClick={() => {
  90. setCurrentLogItem()
  91. setShowMessageLogModal(false)
  92. setOpen(false)
  93. }}
  94. >
  95. <XClose className='w-4 h-4 text-gray-500' />
  96. </div>
  97. </div>
  98. {
  99. isLoading && (
  100. <div className='flex items-center justify-center h-10'>
  101. <Loading />
  102. </div>
  103. )
  104. }
  105. {
  106. !isLoading && (
  107. <div className='p-2'>
  108. {
  109. !data?.data.length && (
  110. <div className='py-12'>
  111. <ClockPlaySlim className='mx-auto mb-2 w-8 h-8 text-gray-300' />
  112. <div className='text-center text-[13px] text-gray-400'>
  113. {t('workflow.common.notRunning')}
  114. </div>
  115. </div>
  116. )
  117. }
  118. {
  119. data?.data.map(item => (
  120. <div
  121. key={item.id}
  122. className={cn(
  123. 'flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer',
  124. item.id === historyWorkflowData?.id && 'bg-primary-50',
  125. )}
  126. onClick={() => {
  127. workflowStore.setState({
  128. historyWorkflowData: item,
  129. showInputsPanel: false,
  130. })
  131. handleBackupDraft()
  132. setOpen(false)
  133. }}
  134. >
  135. {
  136. !isChatMode && item.status === WorkflowRunningStatus.Stopped && (
  137. <AlertTriangle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]' />
  138. )
  139. }
  140. {
  141. !isChatMode && item.status === WorkflowRunningStatus.Failed && (
  142. <AlertCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F04438]' />
  143. )
  144. }
  145. {
  146. !isChatMode && item.status === WorkflowRunningStatus.Succeeded && (
  147. <CheckCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#12B76A]' />
  148. )
  149. }
  150. <div>
  151. <div
  152. className={cn(
  153. 'flex items-center text-[13px] font-medium leading-[18px]',
  154. item.id === historyWorkflowData?.id && 'text-primary-600',
  155. )}
  156. >
  157. {`Test ${isChatMode ? 'Chat' : 'Run'}#${item.sequence_number}`}
  158. </div>
  159. <div className='flex items-center text-xs text-gray-500 leading-[18px]'>
  160. {item.created_by_account.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)}
  161. </div>
  162. </div>
  163. </div>
  164. ))
  165. }
  166. </div>
  167. )
  168. }
  169. </div>
  170. </PortalToFollowElemContent>
  171. </PortalToFollowElem>
  172. )
  173. )
  174. }
  175. export default memo(ViewHistory)