feat: version tag (#14949)

This commit is contained in:
Wu Tianwei
2025-03-07 18:10:40 +08:00
committed by GitHub
parent 4aaf07d62a
commit 3ca1373274
41 changed files with 1695 additions and 423 deletions

View File

@@ -0,0 +1,84 @@
import React, { type FC, useCallback } from 'react'
import { RiMoreFill } from '@remixicon/react'
import { VersionHistoryContextMenuOptions } from '../../../types'
import MenuItem from './menu-item'
import useContextMenu from './use-context-menu'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
export type ContextMenuProps = {
isShowDelete: boolean
isNamedVersion: boolean
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
handleClickMenuItem: (operation: VersionHistoryContextMenuOptions) => void
}
const ContextMenu: FC<ContextMenuProps> = (props: ContextMenuProps) => {
const { isShowDelete, handleClickMenuItem, open, setOpen } = props
const {
deleteOperation,
options,
} = useContextMenu(props)
const handleClickTrigger = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation()
setOpen(v => !v)
}, [setOpen])
return (
<PortalToFollowElem
placement={'bottom-end'}
offset={{
mainAxis: 4,
crossAxis: 0,
}}
open={open}
onOpenChange={setOpen}
>
<PortalToFollowElemTrigger>
<Button size='small' className='px-1' onClick={handleClickTrigger}>
<RiMoreFill className='w-4 h-4' />
</Button>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-10'>
<div className='flex flex-col w-[184px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg shadow-shadow-shadow-5 backdrop-blur-[5px]'>
<div className='flex flex-col p-1'>
{
options.map((option) => {
return (
<MenuItem
key={option.key}
item={option}
onClick={handleClickMenuItem.bind(null, option.key)}
/>
)
})
}
</div>
{
isShowDelete && (
<>
<Divider type='horizontal' className='h-[1px] bg-divider-subtle my-0' />
<div className='p-1'>
<MenuItem
item={deleteOperation}
isDestructive
onClick={handleClickMenuItem.bind(null, VersionHistoryContextMenuOptions.delete)}
/>
</div>
</>
)
}
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>
)
}
export default React.memo(ContextMenu)

View File

@@ -0,0 +1,39 @@
import React, { type FC } from 'react'
import type { VersionHistoryContextMenuOptions } from '../../../types'
import cn from '@/utils/classnames'
type MenuItemProps = {
item: {
key: VersionHistoryContextMenuOptions
name: string
}
onClick: (operation: VersionHistoryContextMenuOptions) => void
isDestructive?: boolean
}
const MenuItem: FC<MenuItemProps> = ({
item,
onClick,
isDestructive = false,
}) => {
return (
<div
className={cn(
'flex items-center justify-between px-2 py-1.5 cursor-pointer rounded-lg ',
isDestructive ? 'hover:bg-state-destructive-hover' : 'hover:bg-state-base-hover',
)}
onClick={() => {
onClick(item.key)
}}
>
<div className={cn(
'flex-1 text-text-primary system-md-regular',
isDestructive && 'hover:text-text-destructive',
)}>
{item.name}
</div>
</div>
)
}
export default React.memo(MenuItem)

View File

@@ -0,0 +1,42 @@
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { VersionHistoryContextMenuOptions } from '../../../types'
import type { ContextMenuProps } from './index'
const useContextMenu = (props: ContextMenuProps) => {
const {
isNamedVersion,
} = props
const { t } = useTranslation()
const deleteOperation = {
key: VersionHistoryContextMenuOptions.delete,
name: t('common.operation.delete'),
}
const options = useMemo(() => {
return [
{
key: VersionHistoryContextMenuOptions.restore,
name: t('workflow.common.restore'),
},
isNamedVersion
? {
key: VersionHistoryContextMenuOptions.edit,
name: t('workflow.versionHistory.editVersionInfo'),
}
: {
key: VersionHistoryContextMenuOptions.edit,
name: t('workflow.versionHistory.nameThisVersion'),
},
]
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isNamedVersion])
return {
deleteOperation,
options,
}
}
export default useContextMenu