[feat] Support Multi-Version Workflows (#11990)
Co-authored-by: hobo.l <hobo.l@binance.com> Co-authored-by: crazywoola <427733928@qq.com>pull/12182/head
parent
adfbfc1255
commit
901028f1e8
@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { WorkflowVersion } from '../types'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
import type { VersionHistory } from '@/types/workflow'
|
||||||
|
|
||||||
|
type VersionHistoryItemProps = {
|
||||||
|
item: VersionHistory
|
||||||
|
selectedVersion: string
|
||||||
|
onClick: (item: VersionHistory) => void
|
||||||
|
curIdx: number
|
||||||
|
page: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatVersion = (version: string, curIdx: number, page: number): string => {
|
||||||
|
if (curIdx === 0 && page === 1)
|
||||||
|
return WorkflowVersion.Draft
|
||||||
|
if (curIdx === 1 && page === 1)
|
||||||
|
return WorkflowVersion.Latest
|
||||||
|
try {
|
||||||
|
const date = new Date(version)
|
||||||
|
if (isNaN(date.getTime()))
|
||||||
|
return version
|
||||||
|
|
||||||
|
// format as YYYY-MM-DD HH:mm:ss
|
||||||
|
return date.toISOString().slice(0, 19).replace('T', ' ')
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VersionHistoryItem: React.FC<VersionHistoryItemProps> = ({ item, selectedVersion, onClick, curIdx, page }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const formatTime = (time: number) => dayjs.unix(time).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
const formattedVersion = formatVersion(item.version, curIdx, page)
|
||||||
|
const renderVersionLabel = (version: string) => (
|
||||||
|
(version === WorkflowVersion.Draft || version === WorkflowVersion.Latest)
|
||||||
|
? (
|
||||||
|
<div className="shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate">
|
||||||
|
{version}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex items-center p-2 h-12 text-xs font-medium text-gray-700 justify-between',
|
||||||
|
formattedVersion === selectedVersion ? '' : 'hover:bg-gray-100',
|
||||||
|
formattedVersion === WorkflowVersion.Draft ? 'cursor-not-allowed' : 'cursor-pointer',
|
||||||
|
)}
|
||||||
|
onClick={() => item.version !== WorkflowVersion.Draft && onClick(item)}
|
||||||
|
>
|
||||||
|
<div className='flex flex-col gap-1 py-2'>
|
||||||
|
<span className="text-left">{formatTime(formattedVersion === WorkflowVersion.Draft ? item.updated_at : item.created_at)}</span>
|
||||||
|
<span className="text-left">{t('workflow.panel.createdBy')} {item.created_by.name}</span>
|
||||||
|
</div>
|
||||||
|
{renderVersionLabel(formattedVersion)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(VersionHistoryItem)
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
'use client'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
import { useWorkflowRun } from '../hooks'
|
||||||
|
import VersionHistoryItem from './version-history-item'
|
||||||
|
import type { VersionHistory } from '@/types/workflow'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
import { fetchPublishedAllWorkflow } from '@/service/workflow'
|
||||||
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
|
const limit = 10
|
||||||
|
|
||||||
|
const VersionHistoryModal = () => {
|
||||||
|
const [selectedVersion, setSelectedVersion] = useState('draft')
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const { handleRestoreFromPublishedWorkflow } = useWorkflowRun()
|
||||||
|
const appDetail = useAppStore.getState().appDetail
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const {
|
||||||
|
data: versionHistory,
|
||||||
|
isLoading,
|
||||||
|
} = useSWR(
|
||||||
|
`/apps/${appDetail?.id}/workflows?page=${page}&limit=${limit}`,
|
||||||
|
fetchPublishedAllWorkflow,
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleVersionClick = (item: VersionHistory) => {
|
||||||
|
if (item.version !== selectedVersion) {
|
||||||
|
setSelectedVersion(item.version)
|
||||||
|
handleRestoreFromPublishedWorkflow(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleNextPage = () => {
|
||||||
|
if (versionHistory?.has_more)
|
||||||
|
setPage(page => page + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-[336px] bg-white rounded-2xl border-[0.5px] border-gray-200 shadow-xl p-2'>
|
||||||
|
<div className="max-h-[400px] overflow-auto">
|
||||||
|
{(isLoading && page) === 1
|
||||||
|
? (
|
||||||
|
<div className='flex items-center justify-center h-10'>
|
||||||
|
<Loading/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<>
|
||||||
|
{versionHistory?.items?.map((item, idx) => (
|
||||||
|
<VersionHistoryItem
|
||||||
|
key={item.version}
|
||||||
|
item={item}
|
||||||
|
selectedVersion={selectedVersion}
|
||||||
|
onClick={handleVersionClick}
|
||||||
|
curIdx={idx}
|
||||||
|
page={page}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{isLoading && page > 1 && (
|
||||||
|
<div className='flex items-center justify-center h-10'>
|
||||||
|
<Loading/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isLoading && versionHistory?.has_more && (
|
||||||
|
<div className='flex items-center justify-center h-10 mt-2'>
|
||||||
|
<Button
|
||||||
|
className='text-sm'
|
||||||
|
onClick={handleNextPage}
|
||||||
|
>
|
||||||
|
{t('workflow.common.loadMore')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isLoading && !versionHistory?.items?.length && (
|
||||||
|
<div className='flex items-center justify-center h-10 text-gray-500'>
|
||||||
|
{t('workflow.common.noHistory')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(VersionHistoryModal)
|
||||||
Loading…
Reference in New Issue