mirror of
https://github.com/langgenius/dify.git
synced 2026-05-07 02:46:32 +08:00
fix: publish as evaluation
This commit is contained in:
parent
7c8a87af05
commit
bcd87ddc58
@ -126,7 +126,7 @@ const AppInfoDetailPanel = ({
|
||||
secondaryOperations={secondaryOperations}
|
||||
/>
|
||||
</div>
|
||||
{appDetail.workflow_type !== AppTypeEnum.EVALUATION && (
|
||||
{appDetail.workflow_kind !== AppTypeEnum.EVALUATION && (
|
||||
<CardView
|
||||
appId={appDetail.id}
|
||||
isInPanel={true}
|
||||
|
||||
@ -491,7 +491,7 @@ describe('AppPublisher', () => {
|
||||
it('should switch workflow type, refresh app detail, and close the popover for published apps', async () => {
|
||||
mockFetchAppDetailDirect.mockResolvedValueOnce({
|
||||
id: 'app-1',
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
})
|
||||
|
||||
render(
|
||||
@ -511,16 +511,49 @@ describe('AppPublisher', () => {
|
||||
expect(mockFetchAppDetailDirect).toHaveBeenCalledWith({ url: '/apps', id: 'app-1' })
|
||||
expect(mockSetAppDetail).toHaveBeenCalledWith({
|
||||
id: 'app-1',
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
})
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('publisher-summary-publish')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should publish an unpublished workflow as evaluation workflow through the evaluation publish endpoint', async () => {
|
||||
mockOnPublish.mockResolvedValue(undefined)
|
||||
mockFetchAppDetailDirect.mockResolvedValueOnce({
|
||||
id: 'app-1',
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
})
|
||||
|
||||
render(
|
||||
<AppPublisher
|
||||
onPublish={mockOnPublish}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByText('common.publish'))
|
||||
fireEvent.click(screen.getByText('publisher-switch-workflow-type'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnPublish).toHaveBeenCalledWith({
|
||||
url: '/apps/app-1/workflows/publish/evaluation',
|
||||
title: '',
|
||||
releaseNotes: '',
|
||||
})
|
||||
expect(mockConvertWorkflowType).not.toHaveBeenCalled()
|
||||
expect(mockFetchAppDetailDirect).toHaveBeenCalledWith({ url: '/apps', id: 'app-1' })
|
||||
expect(mockSetAppDetail).toHaveBeenCalledWith({
|
||||
id: 'app-1',
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
})
|
||||
})
|
||||
expect(screen.queryByText('publisher-summary-publish')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should hide access and actions sections for evaluation workflow apps', () => {
|
||||
mockAppDetail = {
|
||||
...mockAppDetail,
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
}
|
||||
|
||||
render(
|
||||
@ -545,7 +578,7 @@ describe('AppPublisher', () => {
|
||||
it('should confirm before switching an evaluation workflow with associated targets to a standard workflow', async () => {
|
||||
mockAppDetail = {
|
||||
...mockAppDetail,
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
}
|
||||
mockEvaluationWorkflowAssociatedTargets = {
|
||||
items: [
|
||||
@ -595,7 +628,7 @@ describe('AppPublisher', () => {
|
||||
it('should switch an evaluation workflow directly when there are no associated targets', async () => {
|
||||
mockAppDetail = {
|
||||
...mockAppDetail,
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
}
|
||||
|
||||
render(
|
||||
@ -620,7 +653,7 @@ describe('AppPublisher', () => {
|
||||
it('should block switching an evaluation workflow when associated targets fail to load', async () => {
|
||||
mockAppDetail = {
|
||||
...mockAppDetail,
|
||||
type: AppTypeEnum.EVALUATION,
|
||||
workflow_kind: AppTypeEnum.EVALUATION,
|
||||
}
|
||||
mockRefetchEvaluationWorkflowAssociatedTargets.mockResolvedValueOnce({
|
||||
data: undefined,
|
||||
|
||||
@ -147,15 +147,15 @@ const AppPublisher = ({
|
||||
const appURL = getPublisherAppUrl({ appBaseUrl: appBaseURL, accessToken, mode: appDetail?.mode })
|
||||
const isChatApp = [AppModeEnum.CHAT, AppModeEnum.AGENT_CHAT, AppModeEnum.COMPLETION].includes(appDetail?.mode || AppModeEnum.CHAT)
|
||||
const workflowTypeSwitchConfig = useMemo(() => {
|
||||
if (!appDetail?.workflow_type)
|
||||
if (!appDetail?.workflow_kind)
|
||||
return WORKFLOW_TYPE_SWITCH_CONFIG.workflow
|
||||
|
||||
if (!isWorkflowTypeConversionTarget(appDetail?.workflow_type))
|
||||
if (!isWorkflowTypeConversionTarget(appDetail?.workflow_kind))
|
||||
return undefined
|
||||
|
||||
return WORKFLOW_TYPE_SWITCH_CONFIG[appDetail.workflow_type]
|
||||
}, [appDetail?.workflow_type])
|
||||
const isEvaluationWorkflowType = appDetail?.workflow_type === AppTypeEnum.EVALUATION
|
||||
return WORKFLOW_TYPE_SWITCH_CONFIG[appDetail.workflow_kind]
|
||||
}, [appDetail?.workflow_kind])
|
||||
const isEvaluationWorkflowType = appDetail?.workflow_kind === AppTypeEnum.EVALUATION
|
||||
const {
|
||||
refetch: refetchEvaluationWorkflowAssociatedTargets,
|
||||
isFetching: isFetchingEvaluationWorkflowAssociatedTargets,
|
||||
@ -281,11 +281,42 @@ const AppPublisher = ({
|
||||
}
|
||||
}, [appDetail, setAppDetail])
|
||||
|
||||
const getWorkflowTypeSwitchPublishUrl = useCallback(() => {
|
||||
if (!appDetail?.id || !workflowTypeSwitchConfig)
|
||||
return undefined
|
||||
|
||||
if (workflowTypeSwitchConfig.targetType === AppTypeEnum.EVALUATION)
|
||||
return `/apps/${appDetail.id}/workflows/publish/evaluation`
|
||||
|
||||
return `/apps/${appDetail.id}/workflows/publish`
|
||||
}, [appDetail?.id, workflowTypeSwitchConfig])
|
||||
|
||||
const performWorkflowTypeSwitch = useCallback(async () => {
|
||||
if (!appDetail?.id || !workflowTypeSwitchConfig)
|
||||
return false
|
||||
|
||||
try {
|
||||
if (!publishedAt) {
|
||||
const publishUrl = getWorkflowTypeSwitchPublishUrl()
|
||||
if (!publishUrl)
|
||||
return false
|
||||
|
||||
await handlePublish({
|
||||
url: publishUrl,
|
||||
title: '',
|
||||
releaseNotes: '',
|
||||
})
|
||||
|
||||
const latestAppDetail = await fetchAppDetailDirect({
|
||||
url: '/apps',
|
||||
id: appDetail.id,
|
||||
})
|
||||
setAppDetail(latestAppDetail)
|
||||
setShowEvaluationWorkflowSwitchConfirm(false)
|
||||
setEvaluationWorkflowSwitchTargets([])
|
||||
return true
|
||||
}
|
||||
|
||||
await convertWorkflowType({
|
||||
params: {
|
||||
appId: appDetail.id,
|
||||
@ -295,9 +326,6 @@ const AppPublisher = ({
|
||||
},
|
||||
})
|
||||
|
||||
if (!publishedAt)
|
||||
await handlePublish()
|
||||
|
||||
const latestAppDetail = await fetchAppDetailDirect({
|
||||
url: '/apps',
|
||||
id: appDetail.id,
|
||||
@ -314,7 +342,7 @@ const AppPublisher = ({
|
||||
catch {
|
||||
return false
|
||||
}
|
||||
}, [appDetail?.id, convertWorkflowType, handlePublish, publishedAt, setAppDetail, workflowTypeSwitchConfig])
|
||||
}, [appDetail?.id, convertWorkflowType, getWorkflowTypeSwitchPublishUrl, handlePublish, publishedAt, setAppDetail, workflowTypeSwitchConfig])
|
||||
|
||||
const handleWorkflowTypeSwitch = useCallback(async () => {
|
||||
if (!appDetail?.id || !workflowTypeSwitchConfig)
|
||||
@ -324,7 +352,7 @@ const AppPublisher = ({
|
||||
return
|
||||
}
|
||||
|
||||
if (appDetail.workflow_type === AppTypeEnum.EVALUATION && workflowTypeSwitchConfig.targetType === AppTypeEnum.WORKFLOW) {
|
||||
if (appDetail.workflow_kind === AppTypeEnum.EVALUATION && workflowTypeSwitchConfig.targetType === AppTypeEnum.WORKFLOW) {
|
||||
const associatedTargetsResult = await refetchEvaluationWorkflowAssociatedTargets()
|
||||
|
||||
if (associatedTargetsResult.isError) {
|
||||
@ -343,7 +371,7 @@ const AppPublisher = ({
|
||||
await performWorkflowTypeSwitch()
|
||||
}, [
|
||||
appDetail?.id,
|
||||
appDetail?.workflow_type,
|
||||
appDetail?.workflow_kind,
|
||||
performWorkflowTypeSwitch,
|
||||
refetchEvaluationWorkflowAssociatedTargets,
|
||||
t,
|
||||
|
||||
@ -127,6 +127,9 @@ vi.mock('@/app/components/app/app-publisher', () => ({
|
||||
<button type="button" onClick={() => { Promise.resolve(props.onPublish?.({ title: 'Test title', releaseNotes: 'Test notes' })).catch(() => undefined) }}>
|
||||
publisher-publish-with-params
|
||||
</button>
|
||||
<button type="button" onClick={() => { Promise.resolve(props.onPublish?.({ url: '/apps/app-id/workflows/publish/evaluation', title: 'Evaluation title', releaseNotes: 'Evaluation notes' })).catch(() => undefined) }}>
|
||||
publisher-publish-evaluation
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
@ -457,6 +460,24 @@ describe('FeaturesTrigger', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should respect the publish url passed by the publisher', async () => {
|
||||
// Arrange
|
||||
const user = userEvent.setup()
|
||||
renderWithToast(<FeaturesTrigger />)
|
||||
|
||||
// Act
|
||||
await user.click(screen.getByRole('button', { name: 'publisher-publish-evaluation' }))
|
||||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(mockPublishWorkflow).toHaveBeenCalledWith({
|
||||
url: '/apps/app-id/workflows/publish/evaluation',
|
||||
title: 'Evaluation title',
|
||||
releaseNotes: 'Evaluation notes',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should skip success side effects when publish mutation returns no workflow version', async () => {
|
||||
// Arrange
|
||||
const user = userEvent.setup()
|
||||
|
||||
@ -158,7 +158,7 @@ const FeaturesTrigger = () => {
|
||||
// Then perform the detailed validation
|
||||
if (await handleCheckBeforePublish()) {
|
||||
const res = await publishWorkflow({
|
||||
url: `/apps/${appID}/workflows/publish`,
|
||||
url: publishParams?.url || `/apps/${appID}/workflows/publish`,
|
||||
title: publishParams?.title || '',
|
||||
releaseNotes: publishParams?.releaseNotes || '',
|
||||
})
|
||||
|
||||
@ -21,7 +21,7 @@ const StartNodeSelectionPanel: FC<StartNodeSelectionPanelProps> = ({
|
||||
onSelectTrigger,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_type)
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_kind)
|
||||
const [showTriggerSelector, setShowTriggerSelector] = useState(false)
|
||||
const isEvaluationWorkflowType = isEvaluationWorkflow(appType)
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import { useIsChatMode } from './use-is-chat-mode'
|
||||
export const useAvailableNodesMetaData = () => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_type)
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_kind)
|
||||
const docLink = useDocLink()
|
||||
const isEvaluationWorkflowType = isEvaluationWorkflow(appType)
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ const AllStartBlocks = ({
|
||||
const { t } = useTranslation()
|
||||
const [hasStartBlocksContent, setHasStartBlocksContent] = useState(false)
|
||||
const [hasPluginContent, setHasPluginContent] = useState(false)
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_type)
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_kind)
|
||||
const { data: enable_marketplace } = useSuspenseQuery({
|
||||
...systemFeaturesQueryOptions(),
|
||||
select: s => s.enable_marketplace,
|
||||
|
||||
@ -31,7 +31,7 @@ const Blocks = ({
|
||||
}: BlocksProps) => {
|
||||
const { t } = useTranslation()
|
||||
const store = useStoreApi()
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_type)
|
||||
const appType = useAppStore(s => s.appDetail?.workflow_kind)
|
||||
const blocksFromHooks = useBlocks()
|
||||
const filteredAvailableBlocksTypes = useMemo(() => {
|
||||
if (!isEvaluationWorkflow(appType))
|
||||
|
||||
@ -391,7 +391,7 @@ export type App = {
|
||||
/** whether workflow trigger has un-published draft */
|
||||
has_draft_trigger?: boolean
|
||||
/** Type */
|
||||
workflow_type?: AppTypeEnum
|
||||
workflow_kind?: AppTypeEnum
|
||||
}
|
||||
|
||||
export type AppSSO = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user