diff --git a/web/app/components/app-sidebar/snippet-info/__tests__/dropdown.spec.tsx b/web/app/components/app-sidebar/snippet-info/__tests__/dropdown.spec.tsx index 4c24af692b..22631d35d5 100644 --- a/web/app/components/app-sidebar/snippet-info/__tests__/dropdown.spec.tsx +++ b/web/app/components/app-sidebar/snippet-info/__tests__/dropdown.spec.tsx @@ -26,14 +26,14 @@ vi.mock('@/utils/download', () => ({ downloadBlob: (args: { data: Blob, fileName: string }) => mockDownloadBlob(args), })) -vi.mock('@/app/components/base/ui/toast', () => ({ +vi.mock('@langgenius/dify-ui/toast', () => ({ toast: { success: (...args: unknown[]) => mockToastSuccess(...args), error: (...args: unknown[]) => mockToastError(...args), }, })) -vi.mock('@/app/components/base/ui/dropdown-menu', () => ({ +vi.mock('@langgenius/dify-ui/dropdown-menu', () => ({ DropdownMenu: ({ open, onOpenChange, diff --git a/web/app/components/app-sidebar/snippet-info/dropdown.tsx b/web/app/components/app-sidebar/snippet-info/dropdown.tsx index 1e1bddf615..c4edbda8cd 100644 --- a/web/app/components/app-sidebar/snippet-info/dropdown.tsx +++ b/web/app/components/app-sidebar/snippet-info/dropdown.tsx @@ -2,9 +2,6 @@ import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import type { SnippetDetail } from '@/models/snippet' -import { cn } from '@langgenius/dify-ui/cn' -import * as React from 'react' -import { useTranslation } from 'react-i18next' import { AlertDialog, AlertDialogActions, @@ -13,15 +10,18 @@ import { AlertDialogContent, AlertDialogDescription, AlertDialogTitle, -} from '@/app/components/base/ui/alert-dialog' +} from '@langgenius/dify-ui/alert-dialog' +import { cn } from '@langgenius/dify-ui/cn' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from '@/app/components/base/ui/dropdown-menu' -import { toast } from '@/app/components/base/ui/toast' +} from '@langgenius/dify-ui/dropdown-menu' +import { toast } from '@langgenius/dify-ui/toast' +import * as React from 'react' +import { useTranslation } from 'react-i18next' import CreateSnippetDialog from '@/app/components/workflow/create-snippet-dialog' import { useRouter } from '@/next/navigation' import { useDeleteSnippetMutation, useExportSnippetMutation, useUpdateSnippetMutation } from '@/service/use-snippets' diff --git a/web/app/components/app/app-publisher/__tests__/index.spec.tsx b/web/app/components/app/app-publisher/__tests__/index.spec.tsx index 987271842a..1f5ef07bcf 100644 --- a/web/app/components/app/app-publisher/__tests__/index.spec.tsx +++ b/web/app/components/app/app-publisher/__tests__/index.spec.tsx @@ -18,6 +18,7 @@ const mockToastError = vi.fn() const mockConvertWorkflowType = vi.fn() const mockRefetchEvaluationWorkflowAssociatedTargets = vi.fn() const mockInvalidateAppWorkflow = vi.fn() +let mockCanAccessSnippetsAndEvaluation = true const sectionProps = vi.hoisted(() => ({ summary: null as null | Record, @@ -72,6 +73,13 @@ vi.mock('@/hooks/use-async-window-open', () => ({ useAsyncWindowOpen: () => mockOpenAsyncWindow, })) +vi.mock('@/hooks/use-snippet-and-evaluation-plan-access', () => ({ + useSnippetAndEvaluationPlanAccess: () => ({ + canAccess: mockCanAccessSnippetsAndEvaluation, + isReady: true, + }), +})) + vi.mock('@/service/access-control', () => ({ useGetUserCanAccessApp: () => ({ data: { result: true }, @@ -194,6 +202,7 @@ describe('AppPublisher', () => { sectionProps.summary = null sectionProps.access = null sectionProps.actions = null + mockCanAccessSnippetsAndEvaluation = true mockAppDetail = { id: 'app-1', name: 'Demo App', @@ -657,4 +666,25 @@ describe('AppPublisher', () => { expect(sectionProps.summary?.workflowTypeSwitchDisabled).toBe(true) expect(sectionProps.summary?.workflowTypeSwitchDisabledReason).toBe('common.switchToEvaluationWorkflowDisabledTip') }) + + it('should keep the evaluation workflow switch visible but disabled when the current plan cannot access it', () => { + mockCanAccessSnippetsAndEvaluation = false + + render( + , + ) + + fireEvent.click(screen.getByText('common.publish')) + + expect(sectionProps.summary?.workflowTypeSwitchConfig).toEqual({ + targetType: AppTypeEnum.EVALUATION, + publishLabelKey: 'common.publishAsEvaluationWorkflow', + switchLabelKey: 'common.switchToEvaluationWorkflow', + tipKey: 'common.switchToEvaluationWorkflowTip', + }) + expect(sectionProps.summary?.workflowTypeSwitchDisabled).toBe(true) + expect(sectionProps.summary?.workflowTypeSwitchDisabledReason).toBe('compliance.sandboxUpgradeTooltip') + }) }) diff --git a/web/app/components/app/app-publisher/evaluation-workflow-switch-confirm-dialog.tsx b/web/app/components/app/app-publisher/evaluation-workflow-switch-confirm-dialog.tsx index 39aad51ffd..3caa0684a8 100644 --- a/web/app/components/app/app-publisher/evaluation-workflow-switch-confirm-dialog.tsx +++ b/web/app/components/app/app-publisher/evaluation-workflow-switch-confirm-dialog.tsx @@ -2,8 +2,6 @@ import type { EvaluationWorkflowAssociatedTarget, EvaluationWorkflowAssociatedTargetType } from '@/types/evaluation' import type { I18nKeysWithPrefix } from '@/types/i18n' -import { cn } from '@langgenius/dify-ui/cn' -import { useTranslation } from 'react-i18next' import { AlertDialog, AlertDialogActions, @@ -12,7 +10,9 @@ import { AlertDialogContent, AlertDialogDescription, AlertDialogTitle, -} from '@/app/components/base/ui/alert-dialog' +} from '@langgenius/dify-ui/alert-dialog' +import { cn } from '@langgenius/dify-ui/cn' +import { useTranslation } from 'react-i18next' import Link from '@/next/link' type EvaluationWorkflowSwitchConfirmDialogProps = { @@ -80,7 +80,7 @@ const DependentTargetItem = ({ - + {targetName} @@ -108,10 +108,10 @@ const EvaluationWorkflowSwitchConfirmDialog = ({
- + {t('common.switchToStandardWorkflowConfirm.title', { ns: 'workflow' })} - + {t('common.switchToStandardWorkflowConfirm.activeIn', { ns: 'workflow', count: targets.length })} @@ -123,7 +123,7 @@ const EvaluationWorkflowSwitchConfirmDialog = ({
- + {t('common.switchToStandardWorkflowConfirm.dependentWorkflows', { ns: 'workflow' })} diff --git a/web/app/components/app/app-publisher/index.tsx b/web/app/components/app/app-publisher/index.tsx index 16512a2dac..a9ebe99a94 100644 --- a/web/app/components/app/app-publisher/index.tsx +++ b/web/app/components/app/app-publisher/index.tsx @@ -149,11 +149,8 @@ const AppPublisher = ({ if (!isWorkflowTypeConversionTarget(appDetail?.type)) return undefined - if (appDetail.type !== AppTypeEnum.EVALUATION && !canAccessSnippetsAndEvaluation) - return undefined - return WORKFLOW_TYPE_SWITCH_CONFIG[appDetail.type] - }, [appDetail?.type, canAccessSnippetsAndEvaluation]) + }, [appDetail?.type]) const isEvaluationWorkflowType = appDetail?.type === AppTypeEnum.EVALUATION const { refetch: refetchEvaluationWorkflowAssociatedTargets, @@ -163,11 +160,14 @@ const AppPublisher = ({ if (workflowTypeSwitchConfig?.targetType !== AppTypeEnum.EVALUATION) return undefined + if (!canAccessSnippetsAndEvaluation) + return t('compliance.sandboxUpgradeTooltip', { ns: 'common' }) + if (!hasHumanInputNode && !hasTriggerNode) return undefined return t('common.switchToEvaluationWorkflowDisabledTip', { ns: 'workflow' }) - }, [hasHumanInputNode, hasTriggerNode, t, workflowTypeSwitchConfig?.targetType]) + }, [canAccessSnippetsAndEvaluation, hasHumanInputNode, hasTriggerNode, t, workflowTypeSwitchConfig?.targetType]) const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp, refetch } = useGetUserCanAccessApp({ appId: appDetail?.id, enabled: false }) const { data: appAccessSubjects, isLoading: isGettingAppWhiteListSubjects } = useAppWhiteListSubjects(appDetail?.id, open && systemFeatures.webapp_auth.enabled && appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS) diff --git a/web/app/components/app/workflow-log/evaluation-cell.tsx b/web/app/components/app/workflow-log/evaluation-cell.tsx index 3e49015454..539ae5b538 100644 --- a/web/app/components/app/workflow-log/evaluation-cell.tsx +++ b/web/app/components/app/workflow-log/evaluation-cell.tsx @@ -2,13 +2,13 @@ import type { EvaluationLogItem } from '@/models/log' import { cn } from '@langgenius/dify-ui/cn' -import { useState } from 'react' -import { useTranslation } from 'react-i18next' import { Popover, PopoverContent, PopoverTrigger, -} from '@/app/components/base/ui/popover' +} from '@langgenius/dify-ui/popover' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' import { getNodeVisual, getToneClasses } from '@/app/components/evaluation/components/metric-selector/utils' type EvaluationCellProps = { @@ -30,7 +30,7 @@ const EvaluationCell = ({ if (!evaluation.length) { return ( -
+
-
) @@ -73,19 +73,19 @@ const EvaluationCell = ({ )} >
-
{item.name}
+
{item.name}
{item.nodeInfo && nodeVisual && nodeToneClasses && (
- + {item.nodeInfo.title}
)}
-
+
{formatEvaluationValue(item.value)}
diff --git a/web/app/components/apps/creators-filter.tsx b/web/app/components/apps/creators-filter.tsx index 9a00ccab6f..aa4275a65a 100644 --- a/web/app/components/apps/creators-filter.tsx +++ b/web/app/components/apps/creators-filter.tsx @@ -1,16 +1,16 @@ 'use client' +import { Avatar } from '@langgenius/dify-ui/avatar' import { cn } from '@langgenius/dify-ui/cn' -import { useCallback, useMemo, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Checkbox from '@/app/components/base/checkbox' -import Input from '@/app/components/base/input' -import { Avatar } from '@/app/components/base/ui/avatar' import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, -} from '@/app/components/base/ui/dropdown-menu' +} from '@langgenius/dify-ui/dropdown-menu' +import { useCallback, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Checkbox from '@/app/components/base/checkbox' +import Input from '@/app/components/base/input' import { useAppContext } from '@/context/app-context' import { useMembers } from '@/service/use-common' diff --git a/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx b/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx index 4da6f6fe48..732b4df76c 100644 --- a/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx +++ b/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx @@ -1,16 +1,16 @@ import type { EvaluationResourceProps } from '../../types' import type { EvaluationLog, EvaluationLogFile } from '@/types/evaluation' import { cn } from '@langgenius/dify-ui/cn' -import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query' -import { useEffect, useMemo, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Pagination from '@/app/components/base/pagination' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/app/components/base/ui/dropdown-menu' +} from '@langgenius/dify-ui/dropdown-menu' +import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query' +import { useEffect, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Pagination from '@/app/components/base/pagination' import { consoleClient, consoleQuery } from '@/service/client' import { downloadUrl } from '@/utils/download' import { useEvaluationResource, useEvaluationStore } from '../../store' @@ -92,15 +92,15 @@ const HistoryTab = ({ - + {t('history.columns.time')} - {t('history.columns.creator')} - {t('history.columns.version')} - {t('history.columns.status')} + {t('history.columns.creator')} + {t('history.columns.version')} + {t('history.columns.status')}