Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
2691164f
Commit
2691164f
authored
Mar 01, 2024
by
JzoNg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
workflow log list
parent
b113711a
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
455 additions
and
15 deletions
+455
-15
layout.tsx
...p/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx
+8
-3
page.tsx
...commonLayout)/app/(appDetailLayout)/[appId]/logs/page.tsx
+4
-1
index.tsx
web/app/components/app/log-annotation/index.tsx
+18
-10
filter.tsx
web/app/components/app/workflow-log/filter.tsx
+55
-0
index.tsx
web/app/components/app/workflow-log/index.tsx
+131
-0
list.tsx
web/app/components/app/workflow-log/list.tsx
+146
-0
style.module.css
web/app/components/app/workflow-log/style.module.css
+9
-0
app-log.ts
web/i18n/en-US/app-log.ts
+8
-0
app.ts
web/i18n/en-US/app.ts
+1
-0
app.ts
web/i18n/pt-BR/app.ts
+1
-0
app.ts
web/i18n/uk-UA/app.ts
+1
-0
app-log.ts
web/i18n/zh-Hans/app-log.ts
+8
-0
app.ts
web/i18n/zh-Hans/app.ts
+1
-0
log.ts
web/models/log.ts
+47
-0
log.ts
web/service/log.ts
+16
-0
app.ts
web/types/app.ts
+1
-1
No files found.
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx
View file @
2691164f
...
@@ -27,12 +27,15 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
...
@@ -27,12 +27,15 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
const
{
data
:
response
}
=
useSWR
(
detailParams
,
fetchAppDetail
)
const
{
data
:
response
}
=
useSWR
(
detailParams
,
fetchAppDetail
)
const
appModeName
=
(()
=>
{
const
appModeName
=
(()
=>
{
if
(
response
?.
mode
===
'chat'
)
if
(
response
?.
mode
===
'chat'
||
response
?.
mode
===
'advanced-chat'
)
return
t
(
'app.types.chatbot'
)
return
t
(
'app.types.chatbot'
)
if
(
response
?.
mode
===
'agent'
)
if
(
response
?.
mode
===
'agent
-chat
'
)
return
t
(
'app.types.agent'
)
return
t
(
'app.types.agent'
)
if
(
response
?.
mode
===
'completion'
)
return
t
(
'app.types.completion'
)
return
t
(
'app.types.workflow'
)
return
t
(
'app.types.workflow'
)
})()
})()
...
@@ -55,7 +58,9 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
...
@@ -55,7 +58,9 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
return
(
return
(
<
div
className=
{
cn
(
s
.
app
,
'flex'
,
'overflow-hidden'
)
}
>
<
div
className=
{
cn
(
s
.
app
,
'flex'
,
'overflow-hidden'
)
}
>
<
AppSideBar
title=
{
response
.
name
}
icon=
{
response
.
icon
}
icon_background=
{
response
.
icon_background
}
desc=
{
appModeName
}
navigation=
{
navigation
}
/>
<
AppSideBar
title=
{
response
.
name
}
icon=
{
response
.
icon
}
icon_background=
{
response
.
icon_background
}
desc=
{
appModeName
}
navigation=
{
navigation
}
/>
<
div
className=
"bg-white grow overflow-hidden"
>
{
children
}
</
div
>
<
div
className=
"bg-white grow overflow-hidden"
>
{
React
.
cloneElement
(
children
as
React
.
ReactElement
<
any
>
,
{
appMode
:
response
.
mode
})
}
</
div
>
</
div
>
</
div
>
)
)
}
}
...
...
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/logs/page.tsx
View file @
2691164f
import
React
from
'react'
import
React
from
'react'
import
Main
from
'@/app/components/app/log-annotation'
import
Main
from
'@/app/components/app/log-annotation'
import
{
PageType
}
from
'@/app/components/app/configuration/toolbox/annotation/type'
import
{
PageType
}
from
'@/app/components/app/configuration/toolbox/annotation/type'
import
type
{
AppMode
}
from
'@/types/app'
export
type
IProps
=
{
export
type
IProps
=
{
params
:
{
appId
:
string
}
params
:
{
appId
:
string
}
appMode
:
AppMode
}
}
const
Logs
=
async
({
const
Logs
=
async
({
params
:
{
appId
},
params
:
{
appId
},
appMode
,
}:
IProps
)
=>
{
}:
IProps
)
=>
{
return
(
return
(
<
Main
pageType=
{
PageType
.
log
}
appId=
{
appId
}
/>
<
Main
appMode=
{
'workflow'
}
pageType=
{
PageType
.
log
}
appId=
{
appId
}
/>
)
)
}
}
...
...
web/app/components/app/log-annotation/index.tsx
View file @
2691164f
'use client'
'use client'
import
type
{
FC
}
from
'react'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
useRouter
}
from
'next/navigation'
import
{
useRouter
}
from
'next/navigation'
import
Log
from
'@/app/components/app/log'
import
Log
from
'@/app/components/app/log'
import
WorkflowLog
from
'@/app/components/app/workflow-log'
import
Annotation
from
'@/app/components/app/annotation'
import
Annotation
from
'@/app/components/app/annotation'
import
{
PageType
}
from
'@/app/components/app/configuration/toolbox/annotation/type'
import
{
PageType
}
from
'@/app/components/app/configuration/toolbox/annotation/type'
import
TabSlider
from
'@/app/components/base/tab-slider-plain'
import
TabSlider
from
'@/app/components/base/tab-slider-plain'
import
type
{
AppMode
}
from
'@/types/app'
type
Props
=
{
type
Props
=
{
pageType
:
PageType
pageType
:
PageType
appId
:
string
appId
:
string
appMode
:
AppMode
}
}
const
LogAnnotation
:
FC
<
Props
>
=
({
const
LogAnnotation
:
FC
<
Props
>
=
({
pageType
,
pageType
,
appId
,
appId
,
appMode
,
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
router
=
useRouter
()
const
router
=
useRouter
()
...
@@ -27,17 +32,20 @@ const LogAnnotation: FC<Props> = ({
...
@@ -27,17 +32,20 @@ const LogAnnotation: FC<Props> = ({
return
(
return
(
<
div
className=
'pt-4 px-6 h-full flex flex-col'
>
<
div
className=
'pt-4 px-6 h-full flex flex-col'
>
<
TabSlider
{
appMode
!==
'workflow'
&&
(
className=
'shrink-0'
<
TabSlider
value=
{
pageType
}
className=
'shrink-0'
onChange=
{
(
value
)
=>
{
value=
{
pageType
}
router
.
push
(
`/app/${appId}/${value === PageType.log ? 'logs' : 'annotations'}`
)
onChange=
{
(
value
)
=>
{
}
}
router
.
push
(
`/app/${appId}/${value === PageType.log ? 'logs' : 'annotations'}`
)
options=
{
options
}
}
}
/>
options=
{
options
}
<
div
className=
'mt-3 grow'
>
/>
{
pageType
===
PageType
.
log
&&
(<
Log
appId=
{
appId
}
/>)
}
)
}
<
div
className=
{
cn
(
'grow'
,
appMode
!==
'workflow'
&&
'mt-3'
)
}
>
{
pageType
===
PageType
.
log
&&
appMode
!==
'workflow'
&&
(<
Log
appId=
{
appId
}
/>)
}
{
pageType
===
PageType
.
annotation
&&
(<
Annotation
appId=
{
appId
}
/>)
}
{
pageType
===
PageType
.
annotation
&&
(<
Annotation
appId=
{
appId
}
/>)
}
{
pageType
===
PageType
.
log
&&
appMode
===
'workflow'
&&
(<
WorkflowLog
appId=
{
appId
}
/>)
}
</
div
>
</
div
>
</
div
>
</
div
>
)
)
...
...
web/app/components/app/workflow-log/filter.tsx
0 → 100644
View file @
2691164f
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
MagnifyingGlassIcon
,
}
from
'@heroicons/react/24/solid'
import
type
{
QueryParam
}
from
'./index'
import
{
SimpleSelect
}
from
'@/app/components/base/select'
type
IFilterProps
=
{
queryParams
:
QueryParam
setQueryParams
:
(
v
:
QueryParam
)
=>
void
}
const
Filter
:
FC
<
IFilterProps
>
=
({
queryParams
,
setQueryParams
}:
IFilterProps
)
=>
{
const
{
t
}
=
useTranslation
()
return
(
<
div
className=
'flex flex-row flex-wrap gap-y-2 gap-x-4 items-center mb-4 text-gray-900 text-base'
>
<
div
className=
"relative rounded-md"
>
<
SimpleSelect
defaultValue=
{
'all'
}
className=
'!w-[100px]'
onSelect=
{
(
item
)
=>
{
setQueryParams
({
...
queryParams
,
status
:
item
.
value
as
string
})
}
}
items=
{
[{
value
:
'all'
,
name
:
'All'
},
{
value
:
'succeeded'
,
name
:
'Success'
},
{
value
:
'failed'
,
name
:
'Fail'
},
{
value
:
'stopped'
,
name
:
'Stop'
},
]
}
/>
</
div
>
<
div
className=
"relative"
>
<
div
className=
"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
>
<
MagnifyingGlassIcon
className=
"h-5 w-5 text-gray-400"
aria
-
hidden=
"true"
/>
</
div
>
<
input
type=
"text"
name=
"query"
className=
"block w-[240px] bg-gray-100 shadow-sm rounded-md border-0 py-1.5 pl-10 text-gray-900 placeholder:text-gray-400 focus:ring-1 focus:ring-inset focus:ring-gray-200 focus-visible:outline-none sm:text-sm sm:leading-6"
placeholder=
{
t
(
'common.operation.search'
)
!
}
value=
{
queryParams
.
keyword
}
onChange=
{
(
e
)
=>
{
setQueryParams
({
...
queryParams
,
keyword
:
e
.
target
.
value
})
}
}
/>
</
div
>
</
div
>
)
}
export
default
Filter
web/app/components/app/workflow-log/index.tsx
0 → 100644
View file @
2691164f
'use client'
import
type
{
FC
,
SVGProps
}
from
'react'
import
React
,
{
useState
}
from
'react'
import
useSWR
from
'swr'
import
{
usePathname
}
from
'next/navigation'
import
{
Pagination
}
from
'react-headless-pagination'
import
{
ArrowLeftIcon
,
ArrowRightIcon
}
from
'@heroicons/react/24/outline'
import
{
Trans
,
useTranslation
}
from
'react-i18next'
import
Link
from
'next/link'
import
List
from
'./list'
import
Filter
from
'./filter'
import
s
from
'./style.module.css'
import
Loading
from
'@/app/components/base/loading'
import
{
fetchWorkflowLogs
}
from
'@/service/log'
import
{
fetchAppDetail
}
from
'@/service/apps'
import
{
APP_PAGE_LIMIT
}
from
'@/config'
import
type
{
AppMode
}
from
'@/types/app'
export
type
ILogsProps
=
{
appId
:
string
}
export
type
QueryParam
=
{
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-gray-50 w-[560px] h-fit box-border px-5 py-4 rounded-2xl'
>
<
span
className=
'text-gray-700 font-semibold'
>
{
t
(
'appLog.table.empty.element.title'
)
}
<
ThreeDotsIcon
className=
'inline relative -top-3 -left-1.5'
/></
span
>
<
div
className=
'mt-2 text-gray-500 text-sm font-normal'
>
<
Trans
i18nKey=
"appLog.table.empty.element.content"
components=
{
{
shareLink
:
<
Link
href=
{
`${pathSegments.join('/')}/overview`
}
className=
'text-primary-600'
/>,
testLink
:
<
Link
href=
{
appUrl
}
className=
'text-primary-600'
target=
'_blank'
rel=
'noopener noreferrer'
/>
}
}
/>
</
div
>
</
div
>
</
div
>
}
const
Logs
:
FC
<
ILogsProps
>
=
({
appId
})
=>
{
const
{
t
}
=
useTranslation
()
const
[
queryParams
,
setQueryParams
]
=
useState
<
QueryParam
>
({
status
:
'all'
})
const
[
currPage
,
setCurrPage
]
=
React
.
useState
<
number
>
(
0
)
const
query
=
{
page
:
currPage
+
1
,
limit
:
APP_PAGE_LIMIT
,
...
queryParams
,
}
// Get the app type first
const
{
data
:
appDetail
}
=
useSWR
({
url
:
'/apps'
,
id
:
appId
},
fetchAppDetail
)
const
getWebAppType
=
(
appType
?:
AppMode
)
=>
{
if
(
!
appType
)
return
''
if
(
appType
===
'completion'
||
appType
===
'workflow'
)
return
'completion'
return
'chat'
}
const
{
data
:
workflowLogs
,
mutate
}
=
useSWR
({
url
:
`/apps/
${
appId
}
/workflow-app-logs`
,
params
:
query
,
},
fetchWorkflowLogs
)
const
total
=
workflowLogs
?.
total
return
(
<
div
className=
'flex flex-col h-full'
>
<
h1
className=
'text-md font-semibold text-gray-900'
>
{
t
(
'appLog.workflowTitle'
)
}
</
h1
>
<
p
className=
'flex text-sm font-normal text-gray-500'
>
{
t
(
'appLog.workflowSubtitle'
)
}
</
p
>
<
div
className=
'flex flex-col py-4 flex-1'
>
<
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
className=
"flex items-center w-full h-10 text-sm select-none mt-8"
currentPage=
{
currPage
}
edgePageCount=
{
2
}
middlePagesSiblingCount=
{
1
}
setCurrentPage=
{
setCurrPage
}
totalPages=
{
Math
.
ceil
(
total
/
APP_PAGE_LIMIT
)
}
truncableClassName=
"w-8 px-0.5 text-center"
truncableText=
"..."
>
<
Pagination
.
PrevButton
disabled=
{
currPage
===
0
}
className=
{
`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`
}
>
<
ArrowLeftIcon
className=
"mr-3 h-3 w-3"
/>
{
t
(
'appLog.table.pagination.previous'
)
}
</
Pagination
.
PrevButton
>
<
div
className=
{
`flex items-center justify-center flex-grow ${s.pagination}`
}
>
<
Pagination
.
PageButton
activeClassName=
"bg-primary-50 dark:bg-opacity-0 text-primary-600 dark:text-white"
className=
"flex items-center justify-center h-8 w-8 rounded-full cursor-pointer"
inactiveClassName=
"text-gray-500"
/>
</
div
>
<
Pagination
.
NextButton
disabled=
{
currPage
===
Math
.
ceil
(
total
/
APP_PAGE_LIMIT
)
-
1
}
className=
{
`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`
}
>
{
t
(
'appLog.table.pagination.next'
)
}
<
ArrowRightIcon
className=
"ml-3 h-3 w-3"
/>
</
Pagination
.
NextButton
>
</
Pagination
>
:
null
}
</
div
>
</
div
>
)
}
export
default
Logs
web/app/components/app/workflow-log/list.tsx
0 → 100644
View file @
2691164f
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
useState
}
from
'react'
import
dayjs
from
'dayjs'
import
{
createContext
}
from
'use-context-selector'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
s
from
'./style.module.css'
import
type
{
WorkflowAppLogDetail
,
WorkflowLogsResponse
}
from
'@/models/log'
import
type
{
App
}
from
'@/types/app'
import
Loading
from
'@/app/components/base/loading'
import
Drawer
from
'@/app/components/base/drawer'
import
Indicator
from
'@/app/components/header/indicator'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
type
ILogs
=
{
logs
?:
WorkflowLogsResponse
appDetail
?:
App
onRefresh
:
()
=>
void
}
const
defaultValue
=
'N/A'
type
IDrawerContext
=
{
onClose
:
()
=>
void
appDetail
?:
App
}
const
DrawerContext
=
createContext
<
IDrawerContext
>
({}
as
IDrawerContext
)
const
WorkflowAppLogList
:
FC
<
ILogs
>
=
({
logs
,
appDetail
,
onRefresh
})
=>
{
const
{
t
}
=
useTranslation
()
const
media
=
useBreakpoints
()
const
isMobile
=
media
===
MediaType
.
mobile
const
[
showDrawer
,
setShowDrawer
]
=
useState
<
boolean
>
(
false
)
const
[
currentLog
,
setCurrentLog
]
=
useState
<
WorkflowAppLogDetail
|
undefined
>
()
const
statusTdRender
=
(
status
:
string
)
=>
{
if
(
status
===
'succeeded'
)
{
return
(
<
div
className=
'inline-flex items-center gap-1'
>
<
Indicator
color=
{
'green'
}
/>
<
span
>
Success
</
span
>
</
div
>
)
}
if
(
status
===
'failed'
)
{
return
(
<
div
className=
'inline-flex items-center gap-1'
>
<
Indicator
color=
{
'red'
}
/>
<
span
className=
'text-red-600'
>
Fail
</
span
>
</
div
>
)
}
if
(
status
===
'stopped'
)
{
return
(
<
div
className=
'inline-flex items-center gap-1'
>
<
Indicator
color=
{
'gray'
}
/>
<
span
>
Stop
</
span
>
</
div
>
)
}
if
(
status
===
'running'
)
{
return
(
<
div
className=
'inline-flex items-center gap-1'
>
<
Indicator
color=
{
'blue'
}
/>
<
span
className=
'text-primary-600'
>
Running
</
span
>
</
div
>
)
}
}
const
onCloseDrawer
=
()
=>
{
onRefresh
()
setShowDrawer
(
false
)
setCurrentLog
(
undefined
)
}
if
(
!
logs
)
return
<
Loading
/>
return
(
<
div
className=
'overflow-x-auto'
>
<
table
className=
{
`w-full min-w-[440px] border-collapse border-0 text-sm mt-3 ${s.logTable}`
}
>
<
thead
className=
"h-8 !pl-3 py-2 leading-[18px] border-b border-gray-200 text-xs text-gray-500 font-medium"
>
<
tr
>
<
td
className=
'w-[1.375rem] whitespace-nowrap'
></
td
>
<
td
className=
'whitespace-nowrap'
>
{
t
(
'appLog.table.header.startTime'
)
}
</
td
>
<
td
className=
'whitespace-nowrap'
>
{
t
(
'appLog.table.header.status'
)
}
</
td
>
<
td
className=
'whitespace-nowrap'
>
{
t
(
'appLog.table.header.runtime'
)
}
</
td
>
<
td
className=
'whitespace-nowrap'
>
{
t
(
'appLog.table.header.tokens'
)
}
</
td
>
<
td
className=
'whitespace-nowrap'
>
{
t
(
'appLog.table.header.user'
)
}
</
td
>
{
/* <td className='whitespace-nowrap'>{t('appLog.table.header.version')}</td> */
}
</
tr
>
</
thead
>
<
tbody
className=
"text-gray-700 text-[13px]"
>
{
logs
.
data
.
map
((
log
:
WorkflowAppLogDetail
)
=>
{
const
endUser
=
log
.
created_by_end_user
?
log
.
created_by_end_user
.
session_id
:
defaultValue
return
<
tr
key=
{
log
.
id
}
className=
{
`border-b border-gray-200 h-8 hover:bg-gray-50 cursor-pointer ${currentLog?.id !== log.id ? '' : 'bg-gray-50'}`
}
onClick=
{
()
=>
{
setShowDrawer
(
true
)
setCurrentLog
(
log
)
}
}
>
<
td
className=
'text-center align-middle'
>
{
!
log
.
read_at
&&
<
span
className=
'inline-block bg-[#3F83F8] h-1.5 w-1.5 rounded'
></
span
>
}
</
td
>
<
td
className=
'w-[160px]'
>
{
dayjs
.
unix
(
log
.
created_at
).
format
(
t
(
'appLog.dateTimeFormat'
)
as
string
)
}
</
td
>
<
td
>
{
statusTdRender
(
log
.
workflow_run
.
status
)
}
</
td
>
<
td
>
<
div
className=
{
cn
(
log
.
workflow_run
.
elapsed_time
===
0
&&
'text-gray-400'
,
log
.
workflow_run
.
elapsed_time
>
10
&&
'text-orange-400'
,
)
}
>
{
`${log.workflow_run.elapsed_time}s`
}
</
div
>
</
td
>
<
td
>
{
log
.
workflow_run
.
total_tokens
}
</
td
>
<
td
>
<
div
className=
{
cn
(
endUser
===
defaultValue
?
'text-gray-400'
:
'text-gray-700'
,
'text-sm overflow-hidden text-ellipsis whitespace-nowrap'
)
}
>
{
endUser
}
</
div
>
</
td
>
{
/* <td>VERSION</td> */
}
</
tr
>
})
}
</
tbody
>
</
table
>
<
Drawer
isOpen=
{
showDrawer
}
onClose=
{
onCloseDrawer
}
mask=
{
isMobile
}
footer=
{
null
}
panelClassname=
'mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'
>
<
DrawerContext
.
Provider
value=
{
{
onClose
:
onCloseDrawer
,
appDetail
,
}
}
>
{
<
div
>
TODO
</
div
>
}
</
DrawerContext
.
Provider
>
</
Drawer
>
</
div
>
)
}
export
default
WorkflowAppLogList
web/app/components/app/workflow-log/style.module.css
0 → 100644
View file @
2691164f
.logTable
td
{
padding
:
7px
8px
;
box-sizing
:
border-box
;
max-width
:
200px
;
}
.pagination
li
{
list-style
:
none
;
}
web/i18n/en-US/app-log.ts
View file @
2691164f
...
@@ -12,6 +12,12 @@ const translation = {
...
@@ -12,6 +12,12 @@ const translation = {
messageCount
:
'Message Count'
,
messageCount
:
'Message Count'
,
userRate
:
'User Rate'
,
userRate
:
'User Rate'
,
adminRate
:
'Op. Rate'
,
adminRate
:
'Op. Rate'
,
startTime
:
'START TIME'
,
status
:
'STATUS'
,
runtime
:
'RUN TIME'
,
tokens
:
'TOKENS'
,
user
:
'END-USER'
,
version
:
'VERSION'
,
},
},
pagination
:
{
pagination
:
{
previous
:
'Prev'
,
previous
:
'Prev'
,
...
@@ -64,6 +70,8 @@ const translation = {
...
@@ -64,6 +70,8 @@ const translation = {
not_annotated
:
'Not Annotated'
,
not_annotated
:
'Not Annotated'
,
},
},
},
},
workflowTitle
:
'Workflow Logs'
,
workflowSubtitle
:
'The log recorded the operation of Automate.'
,
}
}
export
default
translation
export
default
translation
web/i18n/en-US/app.ts
View file @
2691164f
...
@@ -5,6 +5,7 @@ const translation = {
...
@@ -5,6 +5,7 @@ const translation = {
chatbot
:
'Chatbot'
,
chatbot
:
'Chatbot'
,
agent
:
'Agent'
,
agent
:
'Agent'
,
workflow
:
'Workflow'
,
workflow
:
'Workflow'
,
completion
:
'Completion'
,
},
},
duplicate
:
'Duplicate'
,
duplicate
:
'Duplicate'
,
duplicateTitle
:
'Duplicate App'
,
duplicateTitle
:
'Duplicate App'
,
...
...
web/i18n/pt-BR/app.ts
View file @
2691164f
...
@@ -5,6 +5,7 @@ const translation = {
...
@@ -5,6 +5,7 @@ const translation = {
chatbot
:
'Chatbot'
,
chatbot
:
'Chatbot'
,
agent
:
'Agente'
,
agent
:
'Agente'
,
workflow
:
'Fluxo de trabalho'
,
workflow
:
'Fluxo de trabalho'
,
completion
:
'Gerador de Texto'
,
},
},
duplicate
:
'Duplicar'
,
duplicate
:
'Duplicar'
,
duplicateTitle
:
'Duplicate aplicativo'
,
duplicateTitle
:
'Duplicate aplicativo'
,
...
...
web/i18n/uk-UA/app.ts
View file @
2691164f
...
@@ -5,6 +5,7 @@ const translation = { // Add the Ukrainian translation object
...
@@ -5,6 +5,7 @@ const translation = { // Add the Ukrainian translation object
chatbot
:
'Чатбот'
,
chatbot
:
'Чатбот'
,
agent
:
'Агент'
,
agent
:
'Агент'
,
workflow
:
'Робочий Процес'
,
workflow
:
'Робочий Процес'
,
completion
:
'Автодоповнення'
,
},
},
duplicate
:
'Дублювати'
,
duplicate
:
'Дублювати'
,
duplicateTitle
:
'Дублювати додаток'
,
duplicateTitle
:
'Дублювати додаток'
,
...
...
web/i18n/zh-Hans/app-log.ts
View file @
2691164f
...
@@ -12,6 +12,12 @@ const translation = {
...
@@ -12,6 +12,12 @@ const translation = {
messageCount
:
'消息数'
,
messageCount
:
'消息数'
,
userRate
:
'用户反馈'
,
userRate
:
'用户反馈'
,
adminRate
:
'管理员反馈'
,
adminRate
:
'管理员反馈'
,
startTime
:
'开始时间'
,
status
:
'状态'
,
runtime
:
'运行时间'
,
tokens
:
'TOKENS'
,
user
:
'用户'
,
version
:
'版本'
,
},
},
pagination
:
{
pagination
:
{
previous
:
'上一页'
,
previous
:
'上一页'
,
...
@@ -64,6 +70,8 @@ const translation = {
...
@@ -64,6 +70,8 @@ const translation = {
not_annotated
:
'未标注'
,
not_annotated
:
'未标注'
,
},
},
},
},
workflowTitle
:
'Workflow Logs'
,
workflowSubtitle
:
'The log recorded the operation of Automate.'
,
}
}
export
default
translation
export
default
translation
web/i18n/zh-Hans/app.ts
View file @
2691164f
...
@@ -5,6 +5,7 @@ const translation = {
...
@@ -5,6 +5,7 @@ const translation = {
chatbot
:
'聊天助手'
,
chatbot
:
'聊天助手'
,
agent
:
'Agent'
,
agent
:
'Agent'
,
workflow
:
'工作流'
,
workflow
:
'工作流'
,
completion
:
'文本生成'
,
},
},
duplicate
:
'复制'
,
duplicate
:
'复制'
,
duplicateTitle
:
'复制应用'
,
duplicateTitle
:
'复制应用'
,
...
...
web/models/log.ts
View file @
2691164f
...
@@ -217,3 +217,50 @@ export type LogMessageAnnotationsResponse = LogMessageFeedbacksResponse
...
@@ -217,3 +217,50 @@ export type LogMessageAnnotationsResponse = LogMessageFeedbacksResponse
export
type
AnnotationsCountResponse
=
{
export
type
AnnotationsCountResponse
=
{
count
:
number
count
:
number
}
}
export
type
WorkflowRunDetail
=
{
id
:
string
version
:
string
status
:
'running'
|
'succeeded'
|
'failed'
|
'stopped'
error
?:
string
elapsed_time
:
number
total_tokens
:
number
total_price
:
number
currency
:
string
total_steps
:
number
finished_at
:
number
}
export
type
AccountInfo
=
{
id
:
string
name
:
string
email
:
string
}
export
type
EndUserInfo
=
{
id
:
string
type
:
'browser'
|
'service_api'
is_anonymous
:
boolean
session_id
:
string
}
export
type
WorkflowAppLogDetail
=
{
id
:
string
workflow_run
:
WorkflowRunDetail
created_from
:
'service-api'
|
'web-app'
|
'explore'
created_by_role
:
'account'
|
'end_user'
created_by_account
?:
AccountInfo
created_by_end_user
?:
EndUserInfo
created_at
:
number
read_at
?:
number
}
export
type
WorkflowLogsResponse
=
{
data
:
Array
<
WorkflowAppLogDetail
>
has_more
:
boolean
limit
:
number
total
:
number
page
:
number
}
export
type
WorkflowLogsRequest
=
{
keyword
:
string
status
:
string
page
:
number
limit
:
number
// The default value is 20 and the range is 1-100
}
web/service/log.ts
View file @
2691164f
...
@@ -15,6 +15,8 @@ import type {
...
@@ -15,6 +15,8 @@ import type {
LogMessageAnnotationsResponse
,
LogMessageAnnotationsResponse
,
LogMessageFeedbacksRequest
,
LogMessageFeedbacksRequest
,
LogMessageFeedbacksResponse
,
LogMessageFeedbacksResponse
,
WorkflowLogsRequest
,
WorkflowLogsResponse
,
}
from
'@/models/log'
}
from
'@/models/log'
export
const
fetchConversationList
:
Fetcher
<
ConversationListResponse
,
{
name
:
string
;
appId
:
string
;
params
?:
Record
<
string
,
any
>
}
>
=
({
appId
,
params
})
=>
{
export
const
fetchConversationList
:
Fetcher
<
ConversationListResponse
,
{
name
:
string
;
appId
:
string
;
params
?:
Record
<
string
,
any
>
}
>
=
({
appId
,
params
})
=>
{
...
@@ -57,3 +59,17 @@ export const updateLogMessageAnnotations: Fetcher<LogMessageAnnotationsResponse,
...
@@ -57,3 +59,17 @@ export const updateLogMessageAnnotations: Fetcher<LogMessageAnnotationsResponse,
export
const
fetchAnnotationsCount
:
Fetcher
<
AnnotationsCountResponse
,
{
url
:
string
}
>
=
({
url
})
=>
{
export
const
fetchAnnotationsCount
:
Fetcher
<
AnnotationsCountResponse
,
{
url
:
string
}
>
=
({
url
})
=>
{
return
get
<
AnnotationsCountResponse
>
(
url
)
return
get
<
AnnotationsCountResponse
>
(
url
)
}
}
export
const
fetchWorkflowLogs
:
Fetcher
<
WorkflowLogsResponse
,
{
url
:
string
;
params
?:
WorkflowLogsRequest
}
>
=
({
url
,
params
})
=>
{
return
get
<
WorkflowLogsResponse
>
(
url
,
{
params
})
}
// TODO
export
const
fetchFullRunDetail
:
Fetcher
<
WorkflowLogsResponse
,
{
url
:
string
;
params
?:
WorkflowLogsRequest
}
>
=
({
url
,
params
})
=>
{
return
get
<
WorkflowLogsResponse
>
(
url
,
{
params
})
}
// TODO
export
const
fetchTracingDetail
:
Fetcher
<
WorkflowLogsResponse
,
{
url
:
string
;
params
?:
WorkflowLogsRequest
}
>
=
({
url
,
params
})
=>
{
return
get
<
WorkflowLogsResponse
>
(
url
,
{
params
})
}
web/types/app.ts
View file @
2691164f
...
@@ -44,7 +44,7 @@ export type VariableInput = {
...
@@ -44,7 +44,7 @@ export type VariableInput = {
/**
/**
* App modes
* App modes
*/
*/
export
const
AppModes
=
[
'a
gent'
,
'chat
'
,
'workflow'
]
as
const
export
const
AppModes
=
[
'a
dvanced-chat'
,
'agent-chat'
,
'chat'
,
'completion
'
,
'workflow'
]
as
const
export
type
AppMode
=
typeof
AppModes
[
number
]
export
type
AppMode
=
typeof
AppModes
[
number
]
/**
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment