mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
feat(workflow-log): enhance workflow logs UI with sorting and status filters (#24978)
This commit is contained in:
@@ -27,7 +27,9 @@ class WorkflowAppLogApi(Resource):
|
||||
"""
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument("keyword", type=str, location="args")
|
||||
parser.add_argument("status", type=str, choices=["succeeded", "failed", "stopped"], location="args")
|
||||
parser.add_argument(
|
||||
"status", type=str, choices=["succeeded", "failed", "stopped", "partial-succeeded"], location="args"
|
||||
)
|
||||
parser.add_argument(
|
||||
"created_at__before", type=str, location="args", help="Filter logs created before this timestamp"
|
||||
)
|
||||
|
||||
@@ -33,18 +33,6 @@ const Filter: FC<IFilterProps> = ({ queryParams, setQueryParams }: IFilterProps)
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='mb-2 flex flex-row flex-wrap gap-2'>
|
||||
<Chip
|
||||
value={queryParams.status || 'all'}
|
||||
onSelect={(item) => {
|
||||
setQueryParams({ ...queryParams, status: item.value as string })
|
||||
}}
|
||||
onClear={() => setQueryParams({ ...queryParams, status: 'all' })}
|
||||
items={[{ value: 'all', name: 'All' },
|
||||
{ value: 'succeeded', name: 'Success' },
|
||||
{ value: 'failed', name: 'Fail' },
|
||||
{ value: 'stopped', name: 'Stop' },
|
||||
]}
|
||||
/>
|
||||
<Chip
|
||||
className='min-w-[150px]'
|
||||
panelClassName='w-[270px]'
|
||||
@@ -56,6 +44,19 @@ const Filter: FC<IFilterProps> = ({ queryParams, setQueryParams }: IFilterProps)
|
||||
onClear={() => setQueryParams({ ...queryParams, period: '9' })}
|
||||
items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
|
||||
/>
|
||||
<Chip
|
||||
value={queryParams.status || 'all'}
|
||||
onSelect={(item) => {
|
||||
setQueryParams({ ...queryParams, status: item.value as string })
|
||||
}}
|
||||
onClear={() => setQueryParams({ ...queryParams, status: 'all' })}
|
||||
items={[{ value: 'all', name: 'All' },
|
||||
{ value: 'succeeded', name: 'Success' },
|
||||
{ value: 'partial-succeeded', name: 'Partial Success' },
|
||||
{ value: 'failed', name: 'Failure' },
|
||||
{ value: 'stopped', name: 'Stop' },
|
||||
]}
|
||||
/>
|
||||
<Input
|
||||
wrapperClassName='w-[200px]'
|
||||
showLeftIcon
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ArrowDownIcon } from '@heroicons/react/24/outline'
|
||||
import DetailPanel from './detail'
|
||||
import type { WorkflowAppLogDetail, WorkflowLogsResponse } from '@/models/log'
|
||||
import type { App } from '@/types/app'
|
||||
@@ -29,6 +30,26 @@ const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
|
||||
|
||||
const [showDrawer, setShowDrawer] = useState<boolean>(false)
|
||||
const [currentLog, setCurrentLog] = useState<WorkflowAppLogDetail | undefined>()
|
||||
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc')
|
||||
const [localLogs, setLocalLogs] = useState<WorkflowAppLogDetail[]>(logs?.data || [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!logs?.data) {
|
||||
setLocalLogs([])
|
||||
return
|
||||
}
|
||||
|
||||
const sortedLogs = [...logs.data].sort((a, b) => {
|
||||
const result = a.created_at - b.created_at
|
||||
return sortOrder === 'asc' ? result : -result
|
||||
})
|
||||
|
||||
setLocalLogs(sortedLogs)
|
||||
}, [logs?.data, sortOrder])
|
||||
|
||||
const handleSort = () => {
|
||||
setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc')
|
||||
}
|
||||
|
||||
const isWorkflow = appDetail?.mode === 'workflow'
|
||||
|
||||
@@ -45,7 +66,7 @@ const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
|
||||
return (
|
||||
<div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
|
||||
<Indicator color={'red'} />
|
||||
<span className='text-util-colors-red-red-600'>Fail</span>
|
||||
<span className='text-util-colors-red-red-600'>Failure</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -90,7 +111,17 @@ const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
|
||||
<thead className='system-xs-medium-uppercase text-text-tertiary'>
|
||||
<tr>
|
||||
<td className='w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1'></td>
|
||||
<td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.startTime')}</td>
|
||||
<td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>
|
||||
<div className='flex cursor-pointer items-center hover:text-text-secondary' onClick={handleSort}>
|
||||
{t('appLog.table.header.startTime')}
|
||||
<ArrowDownIcon
|
||||
className={cn('ml-0.5 h-3 w-3 stroke-current stroke-2 transition-all',
|
||||
'text-text-tertiary',
|
||||
sortOrder === 'asc' ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.status')}</td>
|
||||
<td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.runtime')}</td>
|
||||
<td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.tokens')}</td>
|
||||
@@ -99,7 +130,7 @@ const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="system-sm-regular text-text-secondary">
|
||||
{logs.data.map((log: WorkflowAppLogDetail) => {
|
||||
{localLogs.map((log: WorkflowAppLogDetail) => {
|
||||
const endUser = log.created_by_end_user ? log.created_by_end_user.session_id : log.created_by_account ? log.created_by_account.name : defaultValue
|
||||
return <tr
|
||||
key={log.id}
|
||||
|
||||
@@ -18,7 +18,7 @@ const translation = {
|
||||
status: 'STATUS',
|
||||
runtime: 'RUN TIME',
|
||||
tokens: 'TOKENS',
|
||||
user: 'End User or Account',
|
||||
user: 'END USER OR ACCOUNT',
|
||||
version: 'VERSION',
|
||||
triggered_from: 'TRIGGER BY',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user