mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 18:27:19 +08:00
fix(web): custom metric display
This commit is contained in:
parent
48c38ace54
commit
da482ec455
@ -258,6 +258,7 @@ describe('evaluation store', () => {
|
||||
])
|
||||
expect(hydratedState.metrics[1].kind).toBe('custom-workflow')
|
||||
expect(hydratedState.metrics[1].customConfig?.workflowId).toBe('workflow-precision-review')
|
||||
expect(hydratedState.metrics[1].customConfig?.workflowAppId).toBe('workflow-precision-review')
|
||||
expect(hydratedState.metrics[1].customConfig?.mappings[0].inputVariableId).toBe('query')
|
||||
expect(hydratedState.metrics[1].customConfig?.mappings[0].outputVariableId).toBe('answer')
|
||||
expect(hydratedState.metrics[1].customConfig?.outputs).toEqual([{ id: 'reason', valueType: 'string' }])
|
||||
|
||||
@ -199,6 +199,10 @@ describe('CustomMetricEditorCard', () => {
|
||||
mockUseSnippetPublishedWorkflow.mockReturnValue({ data: undefined })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
// Verify the selected evaluation workflow still drives the output summary section.
|
||||
describe('Outputs', () => {
|
||||
it('should render the selected workflow outputs from the end node', () => {
|
||||
@ -274,6 +278,33 @@ describe('CustomMetricEditorCard', () => {
|
||||
|
||||
// Verify mapping rows use workflow start variables on the left and current published graph variables on the right.
|
||||
describe('Variable Mapping', () => {
|
||||
it('should preserve saved mappings and outputs while the selected workflow is loading', () => {
|
||||
const baseMetric = createMetric()
|
||||
const metric = {
|
||||
...baseMetric,
|
||||
customConfig: {
|
||||
...baseMetric.customConfig!,
|
||||
outputs: [{ id: 'score', valueType: 'number' }],
|
||||
},
|
||||
}
|
||||
const syncMappingsSpy = vi.spyOn(useEvaluationStore.getState(), 'syncCustomMetricMappings')
|
||||
const syncOutputsSpy = vi.spyOn(useEvaluationStore.getState(), 'syncCustomMetricOutputs')
|
||||
|
||||
mockUseAppWorkflow.mockReturnValue({ data: undefined })
|
||||
|
||||
render(
|
||||
<CustomMetricEditorCard
|
||||
resourceType="apps"
|
||||
resourceId="app-under-test"
|
||||
metric={metric}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Evaluation Workflow')).toBeInTheDocument()
|
||||
expect(syncMappingsSpy).not.toHaveBeenCalled()
|
||||
expect(syncOutputsSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should pass the current app published graph and saved selector values to the picker', () => {
|
||||
const selectedWorkflow = createWorkflow([
|
||||
createStartNode(),
|
||||
|
||||
@ -44,6 +44,7 @@ const getWorkflowOutputs = (nodes?: Array<Node>) => {
|
||||
.map(output => ({
|
||||
id: output.variable,
|
||||
valueType: typeof output.value_type === 'string' ? output.value_type : null,
|
||||
nodeId: endNode.id,
|
||||
nodeTitle: typeof endNode.data.title === 'string' && endNode.data.title ? endNode.data.title : 'End',
|
||||
}))
|
||||
})
|
||||
@ -110,9 +111,10 @@ const CustomMetricEditorCard = ({
|
||||
])
|
||||
const inputVariableIds = useMemo(() => inputVariables.map(variable => variable.id), [inputVariables])
|
||||
const isConfigured = isCustomMetricConfigured(metric)
|
||||
const isSelectedWorkflowLoaded = !!selectedWorkflow
|
||||
|
||||
useEffect(() => {
|
||||
if (!metric.customConfig?.workflowId)
|
||||
if (!metric.customConfig?.workflowId || !isSelectedWorkflowLoaded)
|
||||
return
|
||||
|
||||
const currentInputVariableIds = metric.customConfig.mappings
|
||||
@ -125,10 +127,10 @@ const CustomMetricEditorCard = ({
|
||||
}
|
||||
|
||||
syncCustomMetricMappings(resourceType, resourceId, metric.id, inputVariableIds)
|
||||
}, [inputVariableIds, metric.customConfig?.mappings, metric.customConfig?.workflowId, metric.id, resourceId, resourceType, syncCustomMetricMappings])
|
||||
}, [inputVariableIds, isSelectedWorkflowLoaded, metric.customConfig?.mappings, metric.customConfig?.workflowId, metric.id, resourceId, resourceType, syncCustomMetricMappings])
|
||||
|
||||
useEffect(() => {
|
||||
if (!metric.customConfig?.workflowId)
|
||||
if (!metric.customConfig?.workflowId || !isSelectedWorkflowLoaded)
|
||||
return
|
||||
|
||||
const currentOutputs = metric.customConfig.outputs
|
||||
@ -142,7 +144,7 @@ const CustomMetricEditorCard = ({
|
||||
}
|
||||
|
||||
syncCustomMetricOutputs(resourceType, resourceId, metric.id, workflowOutputs)
|
||||
}, [metric.customConfig?.outputs, metric.customConfig?.workflowId, metric.id, resourceId, resourceType, syncCustomMetricOutputs, workflowOutputs])
|
||||
}, [isSelectedWorkflowLoaded, metric.customConfig?.outputs, metric.customConfig?.workflowId, metric.id, resourceId, resourceType, syncCustomMetricOutputs, workflowOutputs])
|
||||
|
||||
if (!metric.customConfig)
|
||||
return null
|
||||
@ -197,7 +199,7 @@ const CustomMetricEditorCard = ({
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-y-1 px-2 py-2 system-xs-regular text-text-tertiary">
|
||||
{workflowOutputs.map((output, index) => (
|
||||
<div key={`${output.nodeTitle}-${output.id}-${index}`} className="flex items-center">
|
||||
<div key={`${output.nodeId}-${output.id}`} className="flex items-center">
|
||||
<span className="px-1 system-xs-medium text-text-secondary">{output.id}</span>
|
||||
{output.valueType && (
|
||||
<span>{output.valueType}</span>
|
||||
|
||||
@ -130,7 +130,7 @@ const normalizeCustomMetricMappings = (
|
||||
const normalizeCustomMetricOutputs = (
|
||||
value: EvaluationCustomizedMetric['output_fields'],
|
||||
) => {
|
||||
if (!value)
|
||||
if (!Array.isArray(value))
|
||||
return []
|
||||
|
||||
return value
|
||||
@ -165,6 +165,7 @@ const normalizeCustomMetric = (
|
||||
? {
|
||||
...customMetric.customConfig,
|
||||
workflowId,
|
||||
workflowAppId: workflowId,
|
||||
mappings: normalizeCustomMetricMappings(value.input_fields),
|
||||
outputs: normalizeCustomMetricOutputs(value.output_fields),
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user