Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: version tag #14949

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const ConfigPopup: FC<PopupProps> = ({
<div className='flex justify-between items-center'>
<div className='flex items-center'>
<TracingIcon size='md' className='mr-2' />
<div className='text-text-primary title-2xl-semibold'>{t(`${I18N_PREFIX}.tracing`)}</div>
<div className='text-text-primary title-2xl-semi-bold'>{t(`${I18N_PREFIX}.tracing`)}</div>
</div>
<div className='flex items-center'>
<Indicator color={enabled ? 'green' : 'gray'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const ProviderConfigModal: FC<Props> = ({
<div className='mx-2 w-[640px] max-h-[calc(100vh-120px)] bg-components-panel-bg shadow-xl rounded-2xl overflow-y-auto'>
<div className='px-8 pt-8'>
<div className='flex justify-between items-center mb-4'>
<div className='title-2xl-semibold text-text-primary'>{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}</div>
<div className='title-2xl-semi-bold text-text-primary'>{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}</div>
</div>

<div className='space-y-4'>
Expand Down
88 changes: 53 additions & 35 deletions web/app/components/app/app-publisher/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import dayjs from 'dayjs'
import { RiArrowDownSLine, RiPlanetLine } from '@remixicon/react'
import {
RiArrowDownSLine,
RiPlanetLine,
RiPlayCircleLine,
RiPlayList2Line,
RiTerminalBoxLine,
} from '@remixicon/react'
import { useKeyPress } from 'ahooks'
import Toast from '../../base/toast'
import type { ModelAndParameter } from '../configuration/debug/types'
import { getKeyboardKeyCodeBySystem } from '../../workflow/utils'
import SuggestedAction from './suggested-action'
import PublishWithMultipleModel from './publish-with-multiple-model'
import Button from '@/app/components/base/button'
Expand All @@ -20,10 +28,7 @@ import { fetchInstalledAppList } from '@/service/explore'
import EmbeddedModal from '@/app/components/app/overview/embedded'
import { useStore as useAppStore } from '@/app/components/app/store'
import { useGetLanguage } from '@/context/i18n'
import { PlayCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { CodeBrowser } from '@/app/components/base/icons/src/vender/line/development'
import { LeftIndent02 } from '@/app/components/base/icons/src/vender/line/editor'
import { FileText } from '@/app/components/base/icons/src/vender/line/files'
import WorkflowToolConfigureButton from '@/app/components/tools/workflow-tool/configure-button'
import type { InputVar } from '@/app/components/workflow/types'
import { appDefaultIconBackground } from '@/config'
Expand All @@ -38,14 +43,15 @@ export type AppPublisherProps = {
multipleModelConfigs?: ModelAndParameter[]
/** modelAndParameter is passed when debugWithMultipleModel is true */
onPublish?: (modelAndParameter?: ModelAndParameter) => Promise<any> | any
onRestore?: () => Promise<any> | any
onToggle?: (state: boolean) => void
crossAxisOffset?: number
toolPublished?: boolean
inputs?: InputVar[]
onRefreshData?: () => void
}

const PUBLISH_SHORTCUT = ['⌘', '⇧', 'P']

const AppPublisher = ({
disabled = false,
publishDisabled = false,
Expand All @@ -54,7 +60,6 @@ const AppPublisher = ({
debugWithMultipleModel = false,
multipleModelConfigs = [],
onPublish,
onRestore,
onToggle,
crossAxisOffset = 0,
toolPublished,
Expand Down Expand Up @@ -84,14 +89,6 @@ const AppPublisher = ({
}
}

const handleRestore = useCallback(async () => {
try {
await onRestore?.()
setOpen(false)
}
catch (e) { }
}, [onRestore])

const handleTrigger = useCallback(() => {
const state = !open

Expand Down Expand Up @@ -122,6 +119,14 @@ const AppPublisher = ({

const [embeddingModalOpen, setEmbeddingModalOpen] = useState(false)

useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.p`, (e) => {
e.preventDefault()
if (publishDisabled || published)
return
handlePublish()
}
, { exactMatch: true, useCapture: true })

return (
<PortalToFollowElem
open={open}
Expand All @@ -135,37 +140,27 @@ const AppPublisher = ({
<PortalToFollowElemTrigger onClick={handleTrigger}>
<Button
variant='primary'
className='pl-3 pr-2'
className='p-2'
disabled={disabled}
>
{t('workflow.common.publish')}
<RiArrowDownSLine className='w-4 h-4 ml-0.5' />
<RiArrowDownSLine className='w-4 h-4 text-components-button-primary-text' />
</Button>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-[11]'>
<div className='w-[336px] bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl'>
<div className='w-[320px] bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl shadow-shadow-shadow-5'>
<div className='p-4 pt-3'>
<div className='flex items-center h-6 system-xs-medium-uppercase text-text-tertiary'>
{publishedAt ? t('workflow.common.latestPublished') : t('workflow.common.currentDraftUnpublished')}
</div>
{publishedAt
? (
<div className='flex justify-between items-center h-[18px]'>
<div className='flex items-center mt-[3px] mb-[3px] leading-[18px] text-[13px] font-medium text-text-secondary'>
{t('workflow.common.publishedAt')} {formatTimeFromNow(publishedAt)}
</div>
<Button
variant='secondary-accent'
size='small'
onClick={handleRestore}
disabled={published}
>
{t('workflow.common.restore')}
</Button>
<div className='flex items-center system-sm-medium text-text-secondary'>
{t('workflow.common.publishedAt')} {formatTimeFromNow(publishedAt)}
</div>
)
: (
<div className='flex items-center h-[18px] leading-[18px] text-[13px] font-medium text-text-secondary'>
<div className='flex items-center system-sm-medium text-text-secondary'>
{t('workflow.common.autoSaved')} · {Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
</div>
)}
Expand All @@ -187,20 +182,37 @@ const AppPublisher = ({
{
published
? t('workflow.common.published')
: publishedAt ? t('workflow.common.update') : t('workflow.common.publish')
: (
<div className='flex gap-1'>
<span>{t('workflow.common.publishUpdate')}</span>
<div className='flex gap-0.5'>
{PUBLISH_SHORTCUT.map(key => (
<span key={key} className='w-4 h-4 text-text-primary-on-surface system-kbd rounded-[4px] bg-components-kbd-bg-white'>
{key}
</span>
))}
</div>
</div>
)
}
</Button>
)
}
</div>
<div className='p-4 pt-3 border-t-[0.5px] border-divider-regular'>
<SuggestedAction disabled={!publishedAt} link={appURL} icon={<PlayCircle />}>{t('workflow.common.runApp')}</SuggestedAction>
<div className='p-4 pt-3 border-t-[0.5px] border-t-divider-regular'>
<SuggestedAction
disabled={!publishedAt}
link={appURL}
icon={<RiPlayCircleLine className='w-4 h-4' />}
>
{t('workflow.common.runApp')}
</SuggestedAction>
{appDetail?.mode === 'workflow'
? (
<SuggestedAction
disabled={!publishedAt}
link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
icon={<LeftIndent02 className='w-4 h-4' />}
icon={<RiPlayList2Line className='w-4 h-4' />}
>
{t('workflow.common.batchRunApp')}
</SuggestedAction>
Expand All @@ -226,7 +238,13 @@ const AppPublisher = ({
>
{t('workflow.common.openInExplore')}
</SuggestedAction>
<SuggestedAction disabled={!publishedAt} link='./develop' icon={<FileText className='w-4 h-4' />}>{t('workflow.common.accessAPIReference')}</SuggestedAction>
<SuggestedAction
disabled={!publishedAt}
link='./develop'
icon={<RiTerminalBoxLine className='w-4 h-4' />}
>
{t('workflow.common.accessAPIReference')}
</SuggestedAction>
{appDetail?.mode === 'workflow' && (
<WorkflowToolConfigureButton
disabled={!publishedAt}
Expand Down
10 changes: 5 additions & 5 deletions web/app/components/app/app-publisher/suggested-action.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HTMLProps, PropsWithChildren } from 'react'
import { RiArrowRightUpLine } from '@remixicon/react'
import classNames from '@/utils/classnames'
import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'

export type SuggestedActionProps = PropsWithChildren<HTMLProps<HTMLAnchorElement> & {
icon?: React.ReactNode
Expand All @@ -14,15 +14,15 @@ const SuggestedAction = ({ icon, link, disabled, children, className, ...props }
target='_blank'
rel='noreferrer'
className={classNames(
'flex justify-start items-center gap-2 h-[34px] px-2.5 bg-background-section-burn rounded-lg transition-colors text-text-secondary [&:not(:first-child)]:mt-1',
disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'hover:bg-state-accent-hover hover:text-text-accent cursor-pointer',
'flex justify-start items-center gap-2 py-2 px-2.5 bg-background-section-burn rounded-lg transition-colors [&:not(:first-child)]:mt-1',
disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'text-text-secondary hover:bg-state-accent-hover hover:text-text-accent cursor-pointer',
className,
)}
{...props}
>
<div className='relative w-4 h-4'>{icon}</div>
<div className='grow shrink basis-0 text-[13px] font-medium leading-[18px]'>{children}</div>
<ArrowUpRight />
<div className='grow shrink basis-0 system-sm-medium'>{children}</div>
<RiArrowRightUpLine className='w-3.5 h-3.5' />
</a>
)

Expand Down
112 changes: 112 additions & 0 deletions web/app/components/app/app-publisher/version-info-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React, { type FC, useCallback, useState } from 'react'
import Modal from '@/app/components/base/modal'
import type { VersionHistory } from '@/types/workflow'
import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react'
import Input from '../../base/input'
import Textarea from '../../base/textarea'
import Button from '../../base/button'
import Toast from '@/app/components/base/toast'

type VersionInfoModalProps = {
isOpen: boolean
versionInfo: VersionHistory
onClose: () => void
onPublish: (params: { title: string; releaseNotes: string }) => void
}

const TITLE_MAX_LENGTH = 15
const RELEASE_NOTES_MAX_LENGTH = 100

const VersionInfoModal: FC<VersionInfoModalProps> = ({
isOpen,
versionInfo,
onClose,
onPublish,
}) => {
const { t } = useTranslation()
const [title, setTitle] = useState(versionInfo.marked_name || '')
const [releaseNotes, setReleaseNotes] = useState(versionInfo.marked_comment || '')
const [titleError, setTitleError] = useState(false)
const [releaseNotesError, setReleaseNotesError] = useState(false)

const handlePublish = () => {
if (title.length > TITLE_MAX_LENGTH) {
setTitleError(true)
Toast.notify({
type: 'error',
message: t('workflow.versionHistory.editField.titleLengthLimit', { limit: TITLE_MAX_LENGTH }),
})
return
}
else {
titleError && setTitleError(false)
}

if (releaseNotes.length > RELEASE_NOTES_MAX_LENGTH) {
setReleaseNotesError(true)
Toast.notify({
type: 'error',
message: t('workflow.versionHistory.editField.releaseNotesLengthLimit', { limit: TITLE_MAX_LENGTH }),
})
return
}
else {
releaseNotesError && setReleaseNotesError(false)
}

onPublish({ title, releaseNotes })
onClose()
}

const handleTitleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setTitle(e.target.value)
}, [])

const handleDescriptionChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
setReleaseNotes(e.target.value)
}, [])

return <Modal className='p-0' isShow={isOpen} onClose={onClose}>
<div className='relative w-full p-6 pb-4 pr-14'>
<div className='text-text-primary title-2xl-semi-bold first-letter:capitalize'>
{versionInfo.marked_name ? t('workflow.versionHistory.editVersionInfo') : t('workflow.versionHistory.nameThisVersion')}
</div>
<div className='w-8 h-8 flex items-center justify-center p-1.5 absolute top-5 right-5 cursor-pointer' onClick={onClose}>
<RiCloseLine className='w-[18px] h-[18px] text-text-tertiary' />
</div>
</div>
<div className='flex flex-col gap-y-4 px-6 py-3'>
<div className='flex flex-col gap-y-1'>
<div className='flex items-center h-6 text-text-secondary system-sm-semibold'>
{t('workflow.versionHistory.editField.title')}
</div>
<Input
value={title}
placeholder={t('workflow.versionHistory.nameThisVersion')}
onChange={handleTitleChange}
destructive={titleError}
/>
</div>
<div className='flex flex-col gap-y-1'>
<div className='flex items-center h-6 text-text-secondary system-sm-semibold'>
{t('workflow.versionHistory.editField.releaseNotes')}
</div>
<Textarea
value={releaseNotes}
placeholder={t('workflow.versionHistory.releaseNotesPlaceholder')}
onChange={handleDescriptionChange}
destructive={releaseNotesError}
/>
</div>
</div>
<div className='flex justify-end p-6 pt-5'>
<div className='flex items-center gap-x-3'>
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
<Button variant='primary' onClick={handlePublish}>{t('workflow.common.publish')}</Button>
</div>
</div>
</Modal>
}

export default VersionInfoModal
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const ConfigParamModal: FC<Props> = ({
onClose={onHide}
className='!p-6 !mt-14 !max-w-none !w-[640px]'
>
<div className='mb-2 title-2xl-semibold text-text-primary'>
<div className='mb-2 title-2xl-semi-bold text-text-primary'>
{t(`appAnnotation.initSetup.${isInit ? 'title' : 'configTitle'}`)}
</div>

Expand Down
Loading
Loading