mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 18:27:19 +08:00
feat(web): only one evaluation workflow can be added
This commit is contained in:
parent
5069694bba
commit
c29245c1cb
@ -41,6 +41,24 @@ describe('evaluation store', () => {
|
||||
expect(configuredMetric!.customConfig!.workflowName).toBe(config.workflowOptions[0].label)
|
||||
})
|
||||
|
||||
it('should only add one custom metric', () => {
|
||||
const resourceType = 'apps'
|
||||
const resourceId = 'app-custom-limit'
|
||||
const store = useEvaluationStore.getState()
|
||||
|
||||
store.ensureResource(resourceType, resourceId)
|
||||
store.addCustomMetric(resourceType, resourceId)
|
||||
store.addCustomMetric(resourceType, resourceId)
|
||||
|
||||
expect(
|
||||
useEvaluationStore
|
||||
.getState()
|
||||
.resources['apps:app-custom-limit']
|
||||
.metrics
|
||||
.filter(metric => metric.kind === 'custom-workflow'),
|
||||
).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should add and remove builtin metrics', () => {
|
||||
const resourceType = 'apps'
|
||||
const resourceId = 'app-2'
|
||||
|
||||
@ -210,5 +210,20 @@ describe('MetricSection', () => {
|
||||
expect(screen.getByText('evaluation.metrics.custom.workflowPlaceholder')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'evaluation.metrics.custom.addMapping' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should disable adding another custom metric when one already exists', () => {
|
||||
// Arrange
|
||||
act(() => {
|
||||
useEvaluationStore.getState().addCustomMetric(resourceType, resourceId)
|
||||
})
|
||||
|
||||
// Act
|
||||
renderMetricSection()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'evaluation.metrics.add' }))
|
||||
|
||||
// Assert
|
||||
expect(screen.getByRole('button', { name: /evaluation.metrics.custom.footerTitle/i })).toBeDisabled()
|
||||
expect(screen.getByText('evaluation.metrics.custom.limitDescription')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useEvaluationStore } from '../../store'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../../store'
|
||||
import SelectorEmptyState from './selector-empty-state'
|
||||
import SelectorFooter from './selector-footer'
|
||||
import SelectorMetricSection from './selector-metric-section'
|
||||
@ -26,12 +26,14 @@ const MetricSelector = ({
|
||||
triggerStyle = 'button',
|
||||
}: MetricSelectorProps) => {
|
||||
const { t } = useTranslation('evaluation')
|
||||
const resource = useEvaluationResource(resourceType, resourceId)
|
||||
const addCustomMetric = useEvaluationStore(state => state.addCustomMetric)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [query, setQuery] = useState('')
|
||||
const [nodeInfoMap, setNodeInfoMap] = useState<Record<string, Array<{ node_id: string, title: string, type: string }>>>({})
|
||||
const [collapsedMetricMap, setCollapsedMetricMap] = useState<Record<string, boolean>>({})
|
||||
const [expandedMetricNodesMap, setExpandedMetricNodesMap] = useState<Record<string, boolean>>({})
|
||||
const hasCustomMetric = resource.metrics.some(metric => metric.kind === 'custom-workflow')
|
||||
|
||||
const {
|
||||
builtinMetricMap,
|
||||
@ -134,7 +136,8 @@ const MetricSelector = ({
|
||||
|
||||
<SelectorFooter
|
||||
title={t('metrics.custom.footerTitle')}
|
||||
description={t('metrics.custom.footerDescription')}
|
||||
description={hasCustomMetric ? t('metrics.custom.limitDescription') : t('metrics.custom.footerDescription')}
|
||||
disabled={hasCustomMetric}
|
||||
onClick={() => {
|
||||
addCustomMetric(resourceType, resourceId)
|
||||
setOpen(false)
|
||||
|
||||
@ -1,18 +1,21 @@
|
||||
type SelectorFooterProps = {
|
||||
title: string
|
||||
description: string
|
||||
disabled?: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const SelectorFooter = ({
|
||||
title,
|
||||
description,
|
||||
disabled = false,
|
||||
onClick,
|
||||
}: SelectorFooterProps) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="relative flex items-center gap-3 overflow-hidden border-t border-divider-subtle bg-background-default-subtle px-4 py-5 text-left hover:bg-state-base-hover-alt"
|
||||
disabled={disabled}
|
||||
className="relative flex items-center gap-3 overflow-hidden border-t border-divider-subtle bg-background-default-subtle px-4 py-5 text-left enabled:hover:bg-state-base-hover-alt disabled:cursor-not-allowed disabled:opacity-60"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="absolute -left-6 -top-6 h-28 w-28 rounded-full bg-util-colors-indigo-indigo-100 opacity-50 blur-2xl" />
|
||||
|
||||
@ -142,7 +142,9 @@ export const useEvaluationStore = create<EvaluationStore>((set, get) => ({
|
||||
set(state => ({
|
||||
resources: updateResourceState(state.resources, resourceType, resourceId, resource => ({
|
||||
...resource,
|
||||
metrics: [...resource.metrics, createCustomMetric()],
|
||||
metrics: resource.metrics.some(metric => metric.kind === 'custom-workflow')
|
||||
? resource.metrics
|
||||
: [...resource.metrics, createCustomMetric()],
|
||||
})),
|
||||
}))
|
||||
},
|
||||
|
||||
@ -67,6 +67,7 @@
|
||||
"metrics.custom.description": "Select an evaluation workflow and map your variables before running tests.",
|
||||
"metrics.custom.footerDescription": "Connect your published evaluation workflows",
|
||||
"metrics.custom.footerTitle": "Custom metrics",
|
||||
"metrics.custom.limitDescription": "Only one custom metric can be added.",
|
||||
"metrics.custom.mappingTitle": "Variable Mapping",
|
||||
"metrics.custom.mappingWarning": "Complete the workflow selection and each variable mapping to enable batch tests.",
|
||||
"metrics.custom.sourcePlaceholder": "Source variable",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user