diff --git a/web/app/components/workflow/header/checklist/__tests__/index.spec.tsx b/web/app/components/workflow/header/checklist/__tests__/index.spec.tsx index 9255d13bd3b..e79c66da2ef 100644 --- a/web/app/components/workflow/header/checklist/__tests__/index.spec.tsx +++ b/web/app/components/workflow/header/checklist/__tests__/index.spec.tsx @@ -1,9 +1,11 @@ import type { ReactNode } from 'react' +import type { ChecklistItem } from '../../../hooks/use-checklist' import { fireEvent, render, screen } from '@testing-library/react' +import userEvent from '@testing-library/user-event' import { BlockEnum } from '../../../types' import WorkflowChecklist from '../index' -let mockChecklistItems = [ +let mockChecklistItems: ChecklistItem[] = [ { id: 'plugin-1', type: BlockEnum.Tool, @@ -23,6 +25,7 @@ let mockChecklistItems = [ ] const mockHandleNodeSelect = vi.fn() +const mockSetOpenInlineAgentPanelNodeId = vi.fn() type PopoverProps = { children: ReactNode @@ -50,6 +53,17 @@ vi.mock('../../../hooks/use-nodes-interactions', () => ({ }), })) +vi.mock('../../../store', () => ({ + useStore: ( + selector: (state: { + setOpenInlineAgentPanelNodeId: typeof mockSetOpenInlineAgentPanelNodeId + }) => unknown, + ) => + selector({ + setOpenInlineAgentPanelNodeId: mockSetOpenInlineAgentPanelNodeId, + }), +})) + vi.mock('../../../hooks-store/store', () => ({ useHooksStore: (selector: (state: { configsMap: { flowType: string } }) => unknown) => selector({ @@ -129,6 +143,7 @@ describe('WorkflowChecklist', () => { fireEvent.click(screen.getByTestId('node-group-Broken Node')) expect(mockHandleNodeSelect).toHaveBeenCalledWith('node-1') + expect(mockSetOpenInlineAgentPanelNodeId).not.toHaveBeenCalled() }) it('should use the custom item click handler when provided', () => { @@ -141,6 +156,22 @@ describe('WorkflowChecklist', () => { expect(mockHandleNodeSelect).not.toHaveBeenCalled() }) + it('should open the inline agent editor after selecting an inline agent reference warning', async () => { + const user = userEvent.setup() + mockChecklistItems[1] = { + ...mockChecklistItems[1]!, + type: BlockEnum.AgentV2, + title: 'Inline Agent', + openInlineAgentPanel: true, + } + render() + + await user.click(screen.getByTestId('node-group-Inline Agent')) + + expect(mockHandleNodeSelect).toHaveBeenCalledWith('node-1') + expect(mockSetOpenInlineAgentPanelNodeId).toHaveBeenCalledWith('node-1') + }) + it('should render the resolved state when there are no checklist warnings', () => { mockChecklistItems = [] diff --git a/web/app/components/workflow/header/checklist/index.tsx b/web/app/components/workflow/header/checklist/index.tsx index 76a9b85bc84..2b6511d5e8e 100644 --- a/web/app/components/workflow/header/checklist/index.tsx +++ b/web/app/components/workflow/header/checklist/index.tsx @@ -16,6 +16,7 @@ import useNodes from '@/app/components/workflow/store/workflow/use-nodes' import { useHooksStore } from '../../hooks-store/store' import { useChecklist } from '../../hooks/use-checklist' import { useNodesInteractions } from '../../hooks/use-nodes-interactions' +import { useStore } from '../../store' import { ChecklistNodeGroup } from './node-group' import { ChecklistPluginGroup } from './plugin-group' @@ -33,6 +34,7 @@ const WorkflowChecklist = ({ disabled, showGoTo = true, onItemClick }: WorkflowC const flowType = useHooksStore((s) => s.configsMap?.flowType) const needWarningNodes = useChecklist(nodes, edges, { flowType }) const { handleNodeSelect } = useNodesInteractions() + const setOpenInlineAgentPanelNodeId = useStore((state) => state.setOpenInlineAgentPanelNodeId) const checklistLabel = t(($) => $['panel.checklist'], { ns: 'workflow' }) const { pluginItems, nodeItems } = useMemo(() => { @@ -47,7 +49,10 @@ const WorkflowChecklist = ({ disabled, showGoTo = true, onItemClick }: WorkflowC const handleItemClick = (item: ChecklistItem) => { if (onItemClick) onItemClick(item) - else handleNodeSelect(item.id) + else { + handleNodeSelect(item.id) + if (item.openInlineAgentPanel) setOpenInlineAgentPanelNodeId(item.id) + } setOpen(false) } diff --git a/web/app/components/workflow/hooks/__tests__/use-checklist.spec.ts b/web/app/components/workflow/hooks/__tests__/use-checklist.spec.ts index 2468f528df1..8872342821c 100644 --- a/web/app/components/workflow/hooks/__tests__/use-checklist.spec.ts +++ b/web/app/components/workflow/hooks/__tests__/use-checklist.spec.ts @@ -327,6 +327,7 @@ describe('useChecklist', () => { expect.objectContaining({ id: nodeId, errorMessages: [scenario.errorMessage], + openInlineAgentPanel: true, }), ]) }) diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts index ea9ebb9d45b..98582076d6d 100644 --- a/web/app/components/workflow/hooks/use-checklist.ts +++ b/web/app/components/workflow/hooks/use-checklist.ts @@ -81,6 +81,7 @@ export type ChecklistItem = { disableGoTo?: boolean isPluginMissing?: boolean pluginUniqueIdentifier?: string + openInlineAgentPanel?: boolean } type CheckValidExtraData = Record | undefined @@ -352,6 +353,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[], options?: { flowType? }) const errorMessages: string[] = [] + const missingReferences = inlineAgentMissingReferences[node!.id] if (isPluginMissing) { errorMessages.push(t(($) => $['nodes.common.pluginNotInstalled'], { ns: 'workflow' })) @@ -379,7 +381,6 @@ export const useChecklist = (nodes: Node[], edges: Edge[], options?: { flowType? if (validationError) errorMessages.push(validationError) } - const missingReferences = inlineAgentMissingReferences[node!.id] if (missingReferences?.hasMissingFiles) errorMessages.push( t(($) => $['agentDetail.configure.files.missing'], { ns: 'agentV2' }), @@ -429,6 +430,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[], options?: { flowType? pluginUniqueIdentifier: isPluginMissing ? (node!.data as { plugin_unique_identifier?: string }).plugin_unique_identifier : undefined, + ...(missingReferences ? { openInlineAgentPanel: true } : {}), }) } }