mirror of
https://github.com/langgenius/dify.git
synced 2026-04-26 02:06:35 +08:00
Merge remote-tracking branch 'origin/main' into feat/tax-text
This commit is contained in:
commit
97b5d4bba1
@ -362,11 +362,11 @@ class HttpConfig(BaseSettings):
|
|||||||
)
|
)
|
||||||
|
|
||||||
HTTP_REQUEST_MAX_READ_TIMEOUT: int = Field(
|
HTTP_REQUEST_MAX_READ_TIMEOUT: int = Field(
|
||||||
ge=1, description="Maximum read timeout in seconds for HTTP requests", default=60
|
ge=1, description="Maximum read timeout in seconds for HTTP requests", default=600
|
||||||
)
|
)
|
||||||
|
|
||||||
HTTP_REQUEST_MAX_WRITE_TIMEOUT: int = Field(
|
HTTP_REQUEST_MAX_WRITE_TIMEOUT: int = Field(
|
||||||
ge=1, description="Maximum write timeout in seconds for HTTP requests", default=20
|
ge=1, description="Maximum write timeout in seconds for HTTP requests", default=600
|
||||||
)
|
)
|
||||||
|
|
||||||
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: PositiveInt = Field(
|
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: PositiveInt = Field(
|
||||||
@ -771,7 +771,7 @@ class MailConfig(BaseSettings):
|
|||||||
|
|
||||||
MAIL_TEMPLATING_TIMEOUT: int = Field(
|
MAIL_TEMPLATING_TIMEOUT: int = Field(
|
||||||
description="""
|
description="""
|
||||||
Timeout for email templating in seconds. Used to prevent infinite loops in malicious templates.
|
Timeout for email templating in seconds. Used to prevent infinite loops in malicious templates.
|
||||||
Only available in sandbox mode.""",
|
Only available in sandbox mode.""",
|
||||||
default=3,
|
default=3,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import TypeVar, Union, cast
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
from core.agent.entities import AgentInvokeMessage
|
from core.agent.entities import AgentInvokeMessage
|
||||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||||
@ -87,7 +87,8 @@ def merge_blob_chunks(
|
|||||||
),
|
),
|
||||||
meta=resp.meta,
|
meta=resp.meta,
|
||||||
)
|
)
|
||||||
yield cast(MessageType, merged_message)
|
assert isinstance(merged_message, (ToolInvokeMessage, AgentInvokeMessage))
|
||||||
|
yield merged_message # type: ignore
|
||||||
# Clean up the buffer
|
# Clean up the buffer
|
||||||
del files[chunk_id]
|
del files[chunk_id]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from typing import Any, cast
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class KnowledgeIndexNode(Node):
|
|||||||
return self._node_data
|
return self._node_data
|
||||||
|
|
||||||
def _run(self) -> NodeRunResult: # type: ignore
|
def _run(self) -> NodeRunResult: # type: ignore
|
||||||
node_data = cast(KnowledgeIndexNodeData, self._node_data)
|
node_data = self._node_data
|
||||||
variable_pool = self.graph_runtime_state.variable_pool
|
variable_pool = self.graph_runtime_state.variable_pool
|
||||||
dataset_id = variable_pool.get(["sys", SystemVariableKey.DATASET_ID])
|
dataset_id = variable_pool.get(["sys", SystemVariableKey.DATASET_ID])
|
||||||
if not dataset_id:
|
if not dataset_id:
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
"reportMissingParameterType": "hint",
|
"reportMissingParameterType": "hint",
|
||||||
"reportMissingTypeArgument": "hint",
|
"reportMissingTypeArgument": "hint",
|
||||||
"reportUnnecessaryComparison": "hint",
|
"reportUnnecessaryComparison": "hint",
|
||||||
"reportUnnecessaryCast": "hint",
|
|
||||||
"reportUnnecessaryIsInstance": "hint",
|
"reportUnnecessaryIsInstance": "hint",
|
||||||
"reportUntypedFunctionDecorator": "hint",
|
"reportUntypedFunctionDecorator": "hint",
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, cast
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
@ -55,7 +55,7 @@ class MCPToolManageService:
|
|||||||
cache=NoOpProviderCredentialCache(),
|
cache=NoOpProviderCredentialCache(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cast(dict[str, str], encrypter_instance.encrypt(headers))
|
return encrypter_instance.encrypt(headers)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_mcp_provider_by_provider_id(provider_id: str, tenant_id: str) -> MCPToolProvider:
|
def get_mcp_provider_by_provider_id(provider_id: str, tenant_id: str) -> MCPToolProvider:
|
||||||
|
|||||||
@ -15,13 +15,13 @@ def test_dify_config(monkeypatch: pytest.MonkeyPatch):
|
|||||||
# Set environment variables using monkeypatch
|
# Set environment variables using monkeypatch
|
||||||
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
||||||
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
||||||
monkeypatch.setenv("HTTP_REQUEST_MAX_WRITE_TIMEOUT", "30")
|
monkeypatch.setenv("HTTP_REQUEST_MAX_WRITE_TIMEOUT", "30") # Custom value for testing
|
||||||
monkeypatch.setenv("DB_USERNAME", "postgres")
|
monkeypatch.setenv("DB_USERNAME", "postgres")
|
||||||
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
||||||
monkeypatch.setenv("DB_HOST", "localhost")
|
monkeypatch.setenv("DB_HOST", "localhost")
|
||||||
monkeypatch.setenv("DB_PORT", "5432")
|
monkeypatch.setenv("DB_PORT", "5432")
|
||||||
monkeypatch.setenv("DB_DATABASE", "dify")
|
monkeypatch.setenv("DB_DATABASE", "dify")
|
||||||
monkeypatch.setenv("HTTP_REQUEST_MAX_READ_TIMEOUT", "600")
|
monkeypatch.setenv("HTTP_REQUEST_MAX_READ_TIMEOUT", "300") # Custom value for testing
|
||||||
|
|
||||||
# load dotenv file with pydantic-settings
|
# load dotenv file with pydantic-settings
|
||||||
config = DifyConfig()
|
config = DifyConfig()
|
||||||
@ -35,16 +35,36 @@ def test_dify_config(monkeypatch: pytest.MonkeyPatch):
|
|||||||
assert config.SENTRY_TRACES_SAMPLE_RATE == 1.0
|
assert config.SENTRY_TRACES_SAMPLE_RATE == 1.0
|
||||||
assert config.TEMPLATE_TRANSFORM_MAX_LENGTH == 400_000
|
assert config.TEMPLATE_TRANSFORM_MAX_LENGTH == 400_000
|
||||||
|
|
||||||
# annotated field with default value
|
# annotated field with custom configured value
|
||||||
assert config.HTTP_REQUEST_MAX_READ_TIMEOUT == 600
|
assert config.HTTP_REQUEST_MAX_READ_TIMEOUT == 300
|
||||||
|
|
||||||
# annotated field with configured value
|
# annotated field with custom configured value
|
||||||
assert config.HTTP_REQUEST_MAX_WRITE_TIMEOUT == 30
|
assert config.HTTP_REQUEST_MAX_WRITE_TIMEOUT == 30
|
||||||
|
|
||||||
# values from pyproject.toml
|
# values from pyproject.toml
|
||||||
assert Version(config.project.version) >= Version("1.0.0")
|
assert Version(config.project.version) >= Version("1.0.0")
|
||||||
|
|
||||||
|
|
||||||
|
def test_http_timeout_defaults(monkeypatch: pytest.MonkeyPatch):
|
||||||
|
"""Test that HTTP timeout defaults are correctly set"""
|
||||||
|
# clear system environment variables
|
||||||
|
os.environ.clear()
|
||||||
|
|
||||||
|
# Set minimal required env vars
|
||||||
|
monkeypatch.setenv("DB_USERNAME", "postgres")
|
||||||
|
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
||||||
|
monkeypatch.setenv("DB_HOST", "localhost")
|
||||||
|
monkeypatch.setenv("DB_PORT", "5432")
|
||||||
|
monkeypatch.setenv("DB_DATABASE", "dify")
|
||||||
|
|
||||||
|
config = DifyConfig()
|
||||||
|
|
||||||
|
# Verify default timeout values
|
||||||
|
assert config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT == 10
|
||||||
|
assert config.HTTP_REQUEST_MAX_READ_TIMEOUT == 600
|
||||||
|
assert config.HTTP_REQUEST_MAX_WRITE_TIMEOUT == 600
|
||||||
|
|
||||||
|
|
||||||
# NOTE: If there is a `.env` file in your Workspace, this test might not succeed as expected.
|
# NOTE: If there is a `.env` file in your Workspace, this test might not succeed as expected.
|
||||||
# This is due to `pymilvus` loading all the variables from the `.env` file into `os.environ`.
|
# This is due to `pymilvus` loading all the variables from the `.env` file into `os.environ`.
|
||||||
def test_flask_configs(monkeypatch: pytest.MonkeyPatch):
|
def test_flask_configs(monkeypatch: pytest.MonkeyPatch):
|
||||||
@ -55,7 +75,6 @@ def test_flask_configs(monkeypatch: pytest.MonkeyPatch):
|
|||||||
# Set environment variables using monkeypatch
|
# Set environment variables using monkeypatch
|
||||||
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
||||||
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
||||||
monkeypatch.setenv("HTTP_REQUEST_MAX_WRITE_TIMEOUT", "30")
|
|
||||||
monkeypatch.setenv("DB_USERNAME", "postgres")
|
monkeypatch.setenv("DB_USERNAME", "postgres")
|
||||||
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
||||||
monkeypatch.setenv("DB_HOST", "localhost")
|
monkeypatch.setenv("DB_HOST", "localhost")
|
||||||
@ -105,7 +124,6 @@ def test_inner_api_config_exist(monkeypatch: pytest.MonkeyPatch):
|
|||||||
# Set environment variables using monkeypatch
|
# Set environment variables using monkeypatch
|
||||||
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_API_URL", "https://example.com")
|
||||||
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
monkeypatch.setenv("CONSOLE_WEB_URL", "https://example.com")
|
||||||
monkeypatch.setenv("HTTP_REQUEST_MAX_WRITE_TIMEOUT", "30")
|
|
||||||
monkeypatch.setenv("DB_USERNAME", "postgres")
|
monkeypatch.setenv("DB_USERNAME", "postgres")
|
||||||
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
monkeypatch.setenv("DB_PASSWORD", "postgres")
|
||||||
monkeypatch.setenv("DB_HOST", "localhost")
|
monkeypatch.setenv("DB_HOST", "localhost")
|
||||||
|
|||||||
@ -930,6 +930,16 @@ WORKFLOW_LOG_CLEANUP_BATCH_SIZE=100
|
|||||||
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
|
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
|
||||||
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
|
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
|
||||||
HTTP_REQUEST_NODE_SSL_VERIFY=True
|
HTTP_REQUEST_NODE_SSL_VERIFY=True
|
||||||
|
|
||||||
|
# HTTP request node timeout configuration
|
||||||
|
# Maximum timeout values (in seconds) that users can set in HTTP request nodes
|
||||||
|
# - Connect timeout: Time to wait for establishing connection (default: 10s)
|
||||||
|
# - Read timeout: Time to wait for receiving response data (default: 600s, 10 minutes)
|
||||||
|
# - Write timeout: Time to wait for sending request data (default: 600s, 10 minutes)
|
||||||
|
HTTP_REQUEST_MAX_CONNECT_TIMEOUT=10
|
||||||
|
HTTP_REQUEST_MAX_READ_TIMEOUT=600
|
||||||
|
HTTP_REQUEST_MAX_WRITE_TIMEOUT=600
|
||||||
|
|
||||||
# Base64 encoded CA certificate data for custom certificate verification (PEM format, optional)
|
# Base64 encoded CA certificate data for custom certificate verification (PEM format, optional)
|
||||||
# HTTP_REQUEST_NODE_SSL_CERT_DATA=LS0tLS1CRUdJTi...
|
# HTTP_REQUEST_NODE_SSL_CERT_DATA=LS0tLS1CRUdJTi...
|
||||||
# Base64 encoded client certificate data for mutual TLS authentication (PEM format, optional)
|
# Base64 encoded client certificate data for mutual TLS authentication (PEM format, optional)
|
||||||
|
|||||||
@ -418,6 +418,9 @@ x-shared-env: &shared-api-worker-env
|
|||||||
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: ${HTTP_REQUEST_NODE_MAX_BINARY_SIZE:-10485760}
|
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: ${HTTP_REQUEST_NODE_MAX_BINARY_SIZE:-10485760}
|
||||||
HTTP_REQUEST_NODE_MAX_TEXT_SIZE: ${HTTP_REQUEST_NODE_MAX_TEXT_SIZE:-1048576}
|
HTTP_REQUEST_NODE_MAX_TEXT_SIZE: ${HTTP_REQUEST_NODE_MAX_TEXT_SIZE:-1048576}
|
||||||
HTTP_REQUEST_NODE_SSL_VERIFY: ${HTTP_REQUEST_NODE_SSL_VERIFY:-True}
|
HTTP_REQUEST_NODE_SSL_VERIFY: ${HTTP_REQUEST_NODE_SSL_VERIFY:-True}
|
||||||
|
HTTP_REQUEST_MAX_CONNECT_TIMEOUT: ${HTTP_REQUEST_MAX_CONNECT_TIMEOUT:-10}
|
||||||
|
HTTP_REQUEST_MAX_READ_TIMEOUT: ${HTTP_REQUEST_MAX_READ_TIMEOUT:-600}
|
||||||
|
HTTP_REQUEST_MAX_WRITE_TIMEOUT: ${HTTP_REQUEST_MAX_WRITE_TIMEOUT:-600}
|
||||||
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-false}
|
RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-false}
|
||||||
SSRF_PROXY_HTTP_URL: ${SSRF_PROXY_HTTP_URL:-http://ssrf_proxy:3128}
|
SSRF_PROXY_HTTP_URL: ${SSRF_PROXY_HTTP_URL:-http://ssrf_proxy:3128}
|
||||||
SSRF_PROXY_HTTPS_URL: ${SSRF_PROXY_HTTPS_URL:-http://ssrf_proxy:3128}
|
SSRF_PROXY_HTTPS_URL: ${SSRF_PROXY_HTTPS_URL:-http://ssrf_proxy:3128}
|
||||||
|
|||||||
@ -276,7 +276,7 @@ function Form<
|
|||||||
<div key={variable} className={cn(itemClassName, 'py-3')}>
|
<div key={variable} className={cn(itemClassName, 'py-3')}>
|
||||||
<div className='system-sm-semibold flex items-center justify-between py-2 text-text-secondary'>
|
<div className='system-sm-semibold flex items-center justify-between py-2 text-text-secondary'>
|
||||||
<div className='flex items-center space-x-2'>
|
<div className='flex items-center space-x-2'>
|
||||||
<span className={cn(fieldLabelClassName, 'system-sm-regular flex items-center py-2 text-text-secondary')}>{label[language] || label.en_US}</span>
|
<span className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>{label[language] || label.en_US}</span>
|
||||||
{required && (
|
{required && (
|
||||||
<span className='ml-1 text-red-500'>*</span>
|
<span className='ml-1 text-red-500'>*</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -78,15 +78,15 @@ const Result: FC<IResultProps> = ({
|
|||||||
setRespondingFalse()
|
setRespondingFalse()
|
||||||
}, [controlStopResponding])
|
}, [controlStopResponding])
|
||||||
|
|
||||||
const [completionRes, doSetCompletionRes] = useState<any>('')
|
const [completionRes, doSetCompletionRes] = useState<string>('')
|
||||||
const completionResRef = useRef<any>()
|
const completionResRef = useRef<string>('')
|
||||||
const setCompletionRes = (res: any) => {
|
const setCompletionRes = (res: string) => {
|
||||||
completionResRef.current = res
|
completionResRef.current = res
|
||||||
doSetCompletionRes(res)
|
doSetCompletionRes(res)
|
||||||
}
|
}
|
||||||
const getCompletionRes = () => completionResRef.current
|
const getCompletionRes = () => completionResRef.current
|
||||||
const [workflowProcessData, doSetWorkflowProcessData] = useState<WorkflowProcess>()
|
const [workflowProcessData, doSetWorkflowProcessData] = useState<WorkflowProcess>()
|
||||||
const workflowProcessDataRef = useRef<WorkflowProcess>()
|
const workflowProcessDataRef = useRef<WorkflowProcess | undefined>(undefined)
|
||||||
const setWorkflowProcessData = (data: WorkflowProcess) => {
|
const setWorkflowProcessData = (data: WorkflowProcess) => {
|
||||||
workflowProcessDataRef.current = data
|
workflowProcessDataRef.current = data
|
||||||
doSetWorkflowProcessData(data)
|
doSetWorkflowProcessData(data)
|
||||||
|
|||||||
@ -45,6 +45,7 @@ export const toolCredentialToFormSchemas = (parameters: ToolCredential[]) => {
|
|||||||
return {
|
return {
|
||||||
...parameter,
|
...parameter,
|
||||||
variable: parameter.name,
|
variable: parameter.name,
|
||||||
|
type: toType(parameter.type),
|
||||||
label: parameter.label,
|
label: parameter.label,
|
||||||
tooltip: parameter.help,
|
tooltip: parameter.help,
|
||||||
show_on: [],
|
show_on: [],
|
||||||
|
|||||||
@ -41,16 +41,16 @@ export const useWorkflowHistory = () => {
|
|||||||
const { store: workflowHistoryStore } = useWorkflowHistoryStore()
|
const { store: workflowHistoryStore } = useWorkflowHistoryStore()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const [undoCallbacks, setUndoCallbacks] = useState<any[]>([])
|
const [undoCallbacks, setUndoCallbacks] = useState<(() => void)[]>([])
|
||||||
const [redoCallbacks, setRedoCallbacks] = useState<any[]>([])
|
const [redoCallbacks, setRedoCallbacks] = useState<(() => void)[]>([])
|
||||||
|
|
||||||
const onUndo = useCallback((callback: unknown) => {
|
const onUndo = useCallback((callback: () => void) => {
|
||||||
setUndoCallbacks((prev: any) => [...prev, callback])
|
setUndoCallbacks(prev => [...prev, callback])
|
||||||
return () => setUndoCallbacks(prev => prev.filter(cb => cb !== callback))
|
return () => setUndoCallbacks(prev => prev.filter(cb => cb !== callback))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onRedo = useCallback((callback: unknown) => {
|
const onRedo = useCallback((callback: () => void) => {
|
||||||
setRedoCallbacks((prev: any) => [...prev, callback])
|
setRedoCallbacks(prev => [...prev, callback])
|
||||||
return () => setRedoCallbacks(prev => prev.filter(cb => cb !== callback))
|
return () => setRedoCallbacks(prev => prev.filter(cb => cb !== callback))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,7 @@ const VarReferencePicker: FC<Props> = ({
|
|||||||
|
|
||||||
const reactflow = useReactFlow()
|
const reactflow = useReactFlow()
|
||||||
|
|
||||||
const startNode = availableNodes.find((node: any) => {
|
const startNode = availableNodes.find((node: Node) => {
|
||||||
return node.data.type === BlockEnum.Start
|
return node.data.type === BlockEnum.Start
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import type { Timeout as TimeoutPayloadType } from '../../types'
|
import type { Timeout as TimeoutPayloadType } from '../../types'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
|
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
|
||||||
|
import { useStore } from '@/app/components/workflow/store'
|
||||||
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
readonly: boolean
|
readonly: boolean
|
||||||
@ -61,6 +63,11 @@ const Timeout: FC<Props> = ({ readonly, payload, onChange }) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { connect, read, write, max_connect_timeout, max_read_timeout, max_write_timeout } = payload ?? {}
|
const { connect, read, write, max_connect_timeout, max_read_timeout, max_write_timeout } = payload ?? {}
|
||||||
|
|
||||||
|
// Get default config from store for max timeout values
|
||||||
|
const nodesDefaultConfigs = useStore(s => s.nodesDefaultConfigs)
|
||||||
|
const defaultConfig = nodesDefaultConfigs?.[BlockEnum.HttpRequest]
|
||||||
|
const defaultTimeout = defaultConfig?.timeout || {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldCollapse title={t(`${i18nPrefix}.timeout.title`)}>
|
<FieldCollapse title={t(`${i18nPrefix}.timeout.title`)}>
|
||||||
<div className='mt-2 space-y-1'>
|
<div className='mt-2 space-y-1'>
|
||||||
@ -73,7 +80,7 @@ const Timeout: FC<Props> = ({ readonly, payload, onChange }) => {
|
|||||||
value={connect}
|
value={connect}
|
||||||
onChange={v => onChange?.({ ...payload, connect: v })}
|
onChange={v => onChange?.({ ...payload, connect: v })}
|
||||||
min={1}
|
min={1}
|
||||||
max={max_connect_timeout || 300}
|
max={max_connect_timeout || defaultTimeout.max_connect_timeout || 10}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
title={t('workflow.nodes.http.timeout.readLabel')!}
|
title={t('workflow.nodes.http.timeout.readLabel')!}
|
||||||
@ -83,7 +90,7 @@ const Timeout: FC<Props> = ({ readonly, payload, onChange }) => {
|
|||||||
value={read}
|
value={read}
|
||||||
onChange={v => onChange?.({ ...payload, read: v })}
|
onChange={v => onChange?.({ ...payload, read: v })}
|
||||||
min={1}
|
min={1}
|
||||||
max={max_read_timeout || 600}
|
max={max_read_timeout || defaultTimeout.max_read_timeout || 600}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
title={t('workflow.nodes.http.timeout.writeLabel')!}
|
title={t('workflow.nodes.http.timeout.writeLabel')!}
|
||||||
@ -93,7 +100,7 @@ const Timeout: FC<Props> = ({ readonly, payload, onChange }) => {
|
|||||||
value={write}
|
value={write}
|
||||||
onChange={v => onChange?.({ ...payload, write: v })}
|
onChange={v => onChange?.({ ...payload, write: v })}
|
||||||
min={1}
|
min={1}
|
||||||
max={max_write_timeout || 600}
|
max={max_write_timeout || defaultTimeout.max_write_timeout || 600}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -120,7 +120,7 @@ const JsonSchemaConfig: FC<JsonSchemaConfigProps> = ({
|
|||||||
setJson(JSON.stringify(schema, null, 2))
|
setJson(JSON.stringify(schema, null, 2))
|
||||||
}, [currentTab])
|
}, [currentTab])
|
||||||
|
|
||||||
const handleSubmit = useCallback((schema: any) => {
|
const handleSubmit = useCallback((schema: Record<string, unknown>) => {
|
||||||
const jsonSchema = jsonToSchema(schema) as SchemaRoot
|
const jsonSchema = jsonToSchema(schema) as SchemaRoot
|
||||||
if (currentTab === SchemaView.VisualEditor)
|
if (currentTab === SchemaView.VisualEditor)
|
||||||
setJsonSchema(jsonSchema)
|
setJsonSchema(jsonSchema)
|
||||||
|
|||||||
@ -152,14 +152,16 @@ const EditCard: FC<EditCardProps> = ({
|
|||||||
}, [isAdvancedEditing, emitPropertyOptionsChange, currentFields])
|
}, [isAdvancedEditing, emitPropertyOptionsChange, currentFields])
|
||||||
|
|
||||||
const handleAdvancedOptionsChange = useCallback((options: AdvancedOptionsType) => {
|
const handleAdvancedOptionsChange = useCallback((options: AdvancedOptionsType) => {
|
||||||
let enumValue: any = options.enum
|
let enumValue: SchemaEnumType | undefined
|
||||||
if (enumValue === '') {
|
if (options.enum === '') {
|
||||||
enumValue = undefined
|
enumValue = undefined
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
enumValue = options.enum.replace(/\s/g, '').split(',')
|
const stringArray = options.enum.replace(/\s/g, '').split(',')
|
||||||
if (currentFields.type === Type.number)
|
if (currentFields.type === Type.number)
|
||||||
enumValue = (enumValue as SchemaEnumType).map(value => Number(value)).filter(num => !Number.isNaN(num))
|
enumValue = stringArray.map(value => Number(value)).filter(num => !Number.isNaN(num))
|
||||||
|
else
|
||||||
|
enumValue = stringArray
|
||||||
}
|
}
|
||||||
setCurrentFields(prev => ({ ...prev, enum: enumValue }))
|
setCurrentFields(prev => ({ ...prev, enum: enumValue }))
|
||||||
if (isAdvancedEditing) return
|
if (isAdvancedEditing) return
|
||||||
|
|||||||
@ -180,7 +180,7 @@ const handleStream = (
|
|||||||
let isFirstMessage = true
|
let isFirstMessage = true
|
||||||
function read() {
|
function read() {
|
||||||
let hasError = false
|
let hasError = false
|
||||||
reader?.read().then((result: any) => {
|
reader?.read().then((result: ReadableStreamReadResult<Uint8Array>) => {
|
||||||
if (result.done) {
|
if (result.done) {
|
||||||
onCompleted?.()
|
onCompleted?.()
|
||||||
return
|
return
|
||||||
@ -322,7 +322,21 @@ const handleStream = (
|
|||||||
|
|
||||||
const baseFetch = base
|
const baseFetch = base
|
||||||
|
|
||||||
export const upload = async (options: any, isPublicAPI?: boolean, url?: string, searchParams?: string): Promise<any> => {
|
type UploadOptions = {
|
||||||
|
xhr: XMLHttpRequest
|
||||||
|
method: string
|
||||||
|
url?: string
|
||||||
|
headers?: Record<string, string>
|
||||||
|
data: FormData
|
||||||
|
onprogress?: (this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadResponse = {
|
||||||
|
id: string
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
export const upload = async (options: UploadOptions, isPublicAPI?: boolean, url?: string, searchParams?: string): Promise<UploadResponse> => {
|
||||||
const urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX
|
const urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX
|
||||||
const token = await getAccessToken(isPublicAPI)
|
const token = await getAccessToken(isPublicAPI)
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
@ -331,18 +345,18 @@ export const upload = async (options: any, isPublicAPI?: boolean, url?: string,
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
data: {},
|
|
||||||
}
|
}
|
||||||
options = {
|
const mergedOptions = {
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
...options,
|
...options,
|
||||||
headers: { ...defaultOptions.headers, ...options.headers },
|
url: options.url || defaultOptions.url,
|
||||||
|
headers: { ...defaultOptions.headers, ...options.headers } as Record<string, string>,
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = options.xhr
|
const xhr = mergedOptions.xhr
|
||||||
xhr.open(options.method, options.url)
|
xhr.open(mergedOptions.method, mergedOptions.url)
|
||||||
for (const key in options.headers)
|
for (const key in mergedOptions.headers)
|
||||||
xhr.setRequestHeader(key, options.headers[key])
|
xhr.setRequestHeader(key, mergedOptions.headers[key])
|
||||||
|
|
||||||
xhr.withCredentials = true
|
xhr.withCredentials = true
|
||||||
xhr.responseType = 'json'
|
xhr.responseType = 'json'
|
||||||
@ -354,8 +368,9 @@ export const upload = async (options: any, isPublicAPI?: boolean, url?: string,
|
|||||||
reject(xhr)
|
reject(xhr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xhr.upload.onprogress = options.onprogress
|
if (mergedOptions.onprogress)
|
||||||
xhr.send(options.data)
|
xhr.upload.onprogress = mergedOptions.onprogress
|
||||||
|
xhr.send(mergedOptions.data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +447,7 @@ export const ssePost = async (
|
|||||||
if (!/^[23]\d{2}$/.test(String(res.status))) {
|
if (!/^[23]\d{2}$/.test(String(res.status))) {
|
||||||
if (res.status === 401) {
|
if (res.status === 401) {
|
||||||
if (isPublicAPI) {
|
if (isPublicAPI) {
|
||||||
res.json().then((data: any) => {
|
res.json().then((data: { code?: string; message?: string }) => {
|
||||||
if (isPublicAPI) {
|
if (isPublicAPI) {
|
||||||
if (data.code === 'web_app_access_denied')
|
if (data.code === 'web_app_access_denied')
|
||||||
requiredWebSSOLogin(data.message, 403)
|
requiredWebSSOLogin(data.message, 403)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user