Merge branch 'main' into sandboxed-agent-rebase

Made-with: Cursor

# Conflicts:
#	api/tests/unit_tests/controllers/console/app/test_message.py
#	api/tests/unit_tests/controllers/console/app/test_statistic.py
#	api/tests/unit_tests/controllers/console/app/test_workflow_draft_variable.py
#	api/tests/unit_tests/controllers/console/auth/test_data_source_bearer_auth.py
#	api/tests/unit_tests/controllers/console/auth/test_data_source_oauth.py
#	api/tests/unit_tests/controllers/console/auth/test_oauth_server.py
#	web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx
#	web/app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx
#	web/app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx
#	web/app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx
#	web/app/components/header/account-setting/data-source-page/panel/config-item.tsx
#	web/app/components/header/account-setting/data-source-page/panel/index.tsx
#	web/app/components/workflow/nodes/knowledge-retrieval/node.tsx
#	web/package.json
#	web/pnpm-lock.yaml
This commit is contained in:
Novice
2026-03-24 11:19:50 +08:00
294 changed files with 20298 additions and 13491 deletions

View File

@ -0,0 +1,224 @@
import type { ReactNode } from 'react'
import type { Variable } from '../../../types'
import type { TemplateTransformNodeType } from '../types'
import type { PanelProps } from '@/types/workflow'
import { fireEvent, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { BlockEnum, VarType } from '../../../types'
import Node from '../node'
import Panel from '../panel'
import useConfig from '../use-config'
vi.mock('@/app/components/workflow/nodes/_base/components/field', () => ({
__esModule: true,
default: ({ title, operations, children }: { title: ReactNode, operations?: ReactNode, children: ReactNode }) => (
<div>
<div>{title}</div>
<div>{operations}</div>
{children}
</div>
),
}))
vi.mock('@/app/components/workflow/nodes/_base/components/output-vars', () => ({
__esModule: true,
default: ({ children }: { children: ReactNode }) => <div>{children}</div>,
VarItem: ({ name, type }: { name: string, type: string }) => <div>{`${name}:${type}`}</div>,
}))
vi.mock('@/app/components/workflow/nodes/_base/components/split', () => ({
__esModule: true,
default: () => <div>split</div>,
}))
vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-list', () => ({
__esModule: true,
default: ({
onChange,
onVarNameChange,
}: {
onChange: (value: Variable[]) => void
onVarNameChange: (oldName: string, newName: string) => void
}) => (
<div>
<button
type="button"
onClick={() => onChange([{
variable: 'updated_input',
value_selector: ['node-1', 'updated_input'],
value_type: VarType.string,
}])}
>
change-var-list
</button>
<button type="button" onClick={() => onVarNameChange('input_text', 'renamed_input')}>
rename-var
</button>
</div>
),
}))
vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars', () => ({
__esModule: true,
default: ({
onAddVar,
headerRight,
value,
onChange,
}: {
onAddVar: (value: Variable) => void
headerRight?: ReactNode
value: string
onChange: (value: string) => void
}) => (
<div>
<div>{headerRight}</div>
<button
type="button"
onClick={() => onAddVar({
variable: 'result_text',
value_selector: ['node-2', 'result_text'],
value_type: VarType.string,
})}
>
add-var
</button>
<textarea
aria-label="template-editor"
value={value}
onChange={event => onChange(event.target.value)}
/>
</div>
),
}))
vi.mock('../use-config', () => ({
__esModule: true,
default: vi.fn(),
}))
const mockUseConfig = vi.mocked(useConfig)
const createVariable = (overrides: Partial<Variable> = {}): Variable => ({
variable: 'input_text',
value_selector: ['node-1', 'input_text'],
value_type: VarType.string,
...overrides,
})
const createData = (overrides: Partial<TemplateTransformNodeType> = {}): TemplateTransformNodeType => ({
title: 'Template Transform',
desc: '',
type: BlockEnum.TemplateTransform,
variables: [createVariable()],
template: '{{ input_text }}',
...overrides,
})
const createConfigResult = (overrides: Partial<ReturnType<typeof useConfig>> = {}): ReturnType<typeof useConfig> => ({
readOnly: false,
inputs: createData(),
availableVars: [],
handleVarListChange: vi.fn(),
handleVarNameChange: vi.fn(),
handleAddVariable: vi.fn(),
handleAddEmptyVariable: vi.fn(),
handleCodeChange: vi.fn(),
filterVar: () => true,
...overrides,
})
const panelProps: PanelProps = {
getInputVars: vi.fn(() => []),
toVarInputs: vi.fn(() => []),
runInputData: {},
runInputDataRef: { current: {} },
setRunInputData: vi.fn(),
runResult: null,
}
describe('template-transform path', () => {
beforeEach(() => {
vi.clearAllMocks()
mockUseConfig.mockReturnValue(createConfigResult())
})
it('should render the node shell without summary content', () => {
const { container } = render(
<Node
id="template-node"
data={createData()}
/>,
)
expect(container.firstElementChild).toBeEmptyDOMElement()
})
it('should wire variable list and code editor actions from the panel', async () => {
const user = userEvent.setup()
const handleVarListChange = vi.fn()
const handleVarNameChange = vi.fn()
const handleAddVariable = vi.fn()
const handleAddEmptyVariable = vi.fn()
const handleCodeChange = vi.fn()
mockUseConfig.mockReturnValueOnce(createConfigResult({
handleVarListChange,
handleVarNameChange,
handleAddVariable,
handleAddEmptyVariable,
handleCodeChange,
}))
render(
<Panel
id="template-node"
data={createData()}
panelProps={panelProps}
/>,
)
await user.click(screen.getByTestId('add-button'))
await user.click(screen.getByRole('button', { name: 'change-var-list' }))
await user.click(screen.getByRole('button', { name: 'rename-var' }))
await user.click(screen.getByRole('button', { name: 'add-var' }))
fireEvent.change(screen.getByLabelText('template-editor'), { target: { value: '{{ renamed_input }}' } })
expect(handleAddEmptyVariable).toHaveBeenCalled()
expect(handleVarListChange).toHaveBeenCalledWith([
{
variable: 'updated_input',
value_selector: ['node-1', 'updated_input'],
value_type: VarType.string,
},
])
expect(handleVarNameChange).toHaveBeenCalledWith('input_text', 'renamed_input')
expect(handleAddVariable).toHaveBeenCalledWith({
variable: 'result_text',
value_selector: ['node-2', 'result_text'],
value_type: VarType.string,
})
expect(handleCodeChange).toHaveBeenCalledWith('{{ renamed_input }}')
expect(screen.getByText('output:string')).toBeInTheDocument()
expect(screen.getByRole('link', { name: /workflow.nodes.templateTransform.codeSupportTip/i })).toHaveAttribute(
'href',
'https://jinja.palletsprojects.com/en/3.1.x/templates/',
)
})
it('should hide the add-variable operation when the panel is read only', () => {
mockUseConfig.mockReturnValueOnce(createConfigResult({
readOnly: true,
}))
render(
<Panel
id="template-node"
data={createData()}
panelProps={panelProps}
/>,
)
expect(screen.queryByTestId('add-button')).not.toBeInTheDocument()
})
})