dify
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
|
||||
// Constants for better maintainability and reusability
|
||||
const BASIC_TYPES = [VarType.string, VarType.number, VarType.boolean, VarType.object, VarType.file] as const
|
||||
const ARRAY_ELEMENT_TYPES = [VarType.arrayString, VarType.arrayNumber, VarType.arrayBoolean, VarType.arrayObject] as const
|
||||
|
||||
// Generate all valid parameter types programmatically
|
||||
const VALID_PARAMETER_TYPES: readonly VarType[] = [
|
||||
...BASIC_TYPES,
|
||||
...ARRAY_ELEMENT_TYPES,
|
||||
] as const
|
||||
|
||||
// Type display name mappings
|
||||
const TYPE_DISPLAY_NAMES: Record<VarType, string> = {
|
||||
[VarType.string]: 'String',
|
||||
[VarType.number]: 'Number',
|
||||
[VarType.boolean]: 'Boolean',
|
||||
[VarType.object]: 'Object',
|
||||
[VarType.file]: 'File',
|
||||
[VarType.arrayString]: 'Array[String]',
|
||||
[VarType.arrayNumber]: 'Array[Number]',
|
||||
[VarType.arrayBoolean]: 'Array[Boolean]',
|
||||
[VarType.arrayObject]: 'Array[Object]',
|
||||
[VarType.secret]: 'Secret',
|
||||
[VarType.array]: 'Array',
|
||||
'array[file]': 'Array[File]',
|
||||
[VarType.any]: 'Any',
|
||||
'array[any]': 'Array[Any]',
|
||||
[VarType.integer]: 'Integer',
|
||||
} as const
|
||||
|
||||
// Content type configurations
|
||||
const CONTENT_TYPE_CONFIGS = {
|
||||
'application/json': {
|
||||
supportedTypes: [...BASIC_TYPES.filter(t => t !== 'file'), ...ARRAY_ELEMENT_TYPES],
|
||||
description: 'JSON supports all types including arrays',
|
||||
},
|
||||
'text/plain': {
|
||||
supportedTypes: [VarType.string] as const,
|
||||
description: 'Plain text only supports string',
|
||||
},
|
||||
'application/x-www-form-urlencoded': {
|
||||
supportedTypes: [VarType.string, VarType.number, VarType.boolean] as const,
|
||||
description: 'Form data supports basic types',
|
||||
},
|
||||
'application/octet-stream': {
|
||||
supportedTypes: [VarType.file] as const,
|
||||
description: 'octet-stream supports only binary data',
|
||||
},
|
||||
'multipart/form-data': {
|
||||
supportedTypes: [VarType.string, VarType.number, VarType.boolean, VarType.file] as const,
|
||||
description: 'Multipart supports basic types plus files',
|
||||
},
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Type guard to check if a string is a valid parameter type
|
||||
*/
|
||||
export const isValidParameterType = (type: string): type is VarType => {
|
||||
return (VALID_PARAMETER_TYPES as readonly string[]).includes(type)
|
||||
}
|
||||
|
||||
export const normalizeParameterType = (input: string | undefined | null): VarType => {
|
||||
if (!input || typeof input !== 'string')
|
||||
return VarType.string
|
||||
|
||||
const trimmed = input.trim().toLowerCase()
|
||||
if (trimmed === 'array[string]')
|
||||
return VarType.arrayString
|
||||
else if (trimmed === 'array[number]')
|
||||
return VarType.arrayNumber
|
||||
else if (trimmed === 'array[boolean]')
|
||||
return VarType.arrayBoolean
|
||||
else if (trimmed === 'array[object]')
|
||||
return VarType.arrayObject
|
||||
else if (trimmed === 'array')
|
||||
// Migrate legacy 'array' type to 'array[string]'
|
||||
return VarType.arrayString
|
||||
else if (trimmed === 'number')
|
||||
return VarType.number
|
||||
else if (trimmed === 'boolean')
|
||||
return VarType.boolean
|
||||
else if (trimmed === 'object')
|
||||
return VarType.object
|
||||
else if (trimmed === 'file')
|
||||
return VarType.file
|
||||
|
||||
return VarType.string
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets display name for parameter types in UI components
|
||||
*/
|
||||
export const getParameterTypeDisplayName = (type: VarType): string => {
|
||||
return TYPE_DISPLAY_NAMES[type]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets available parameter types based on content type
|
||||
* Provides context-aware type filtering for different webhook content types
|
||||
*/
|
||||
export const getAvailableParameterTypes = (contentType?: string): VarType[] => {
|
||||
if (!contentType)
|
||||
return [VarType.string, VarType.number, VarType.boolean]
|
||||
|
||||
const normalizedContentType = (contentType || '').toLowerCase()
|
||||
const configKey = normalizedContentType in CONTENT_TYPE_CONFIGS
|
||||
? normalizedContentType as keyof typeof CONTENT_TYPE_CONFIGS
|
||||
: 'application/json'
|
||||
|
||||
const config = CONTENT_TYPE_CONFIGS[configKey]
|
||||
return [...config.supportedTypes]
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates type options for UI select components
|
||||
*/
|
||||
export const createParameterTypeOptions = (contentType?: string) => {
|
||||
const availableTypes = getAvailableParameterTypes(contentType)
|
||||
|
||||
return availableTypes.map(type => ({
|
||||
name: getParameterTypeDisplayName(type),
|
||||
value: type,
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { VarType, type Variable } from '@/app/components/workflow/types'
|
||||
|
||||
export const WEBHOOK_RAW_VARIABLE_NAME = '_webhook_raw'
|
||||
export const WEBHOOK_RAW_VARIABLE_LABEL = 'raw'
|
||||
|
||||
export const createWebhookRawVariable = (): Variable => ({
|
||||
variable: WEBHOOK_RAW_VARIABLE_NAME,
|
||||
label: WEBHOOK_RAW_VARIABLE_LABEL,
|
||||
value_type: VarType.object,
|
||||
value_selector: [],
|
||||
required: true,
|
||||
})
|
||||
@@ -0,0 +1,75 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import type { Variable } from '@/app/components/workflow/types'
|
||||
|
||||
type OutputVariablesContentProps = {
|
||||
variables?: Variable[]
|
||||
}
|
||||
|
||||
// Define the display order for variable labels to match the table order in the UI
|
||||
const LABEL_ORDER = { raw: 0, param: 1, header: 2, body: 3 } as const
|
||||
|
||||
const getLabelPrefix = (label: string): string => {
|
||||
const prefixMap: Record<string, string> = {
|
||||
raw: 'payload',
|
||||
param: 'query_params',
|
||||
header: 'header_params',
|
||||
body: 'req_body_params',
|
||||
}
|
||||
return prefixMap[label] || label
|
||||
}
|
||||
|
||||
type VarItemProps = {
|
||||
prefix: string
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
|
||||
const VarItem: FC<VarItemProps> = ({ prefix, name, type }) => {
|
||||
return (
|
||||
<div className='py-1'>
|
||||
<div className='flex items-center leading-[18px]'>
|
||||
<span className='code-sm-regular text-text-tertiary'>{prefix}.</span>
|
||||
<span className='code-sm-semibold text-text-secondary'>{name}</span>
|
||||
<span className='system-xs-regular ml-2 text-text-tertiary'>{type}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const OutputVariablesContent: FC<OutputVariablesContentProps> = ({ variables = [] }) => {
|
||||
if (!variables || variables.length === 0) {
|
||||
return (
|
||||
<div className="system-sm-regular py-2 text-text-tertiary">
|
||||
No output variables
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Sort variables by label to match the table display order: param → header → body
|
||||
// Unknown labels are placed at the end (order value 999)
|
||||
const sortedVariables = [...variables].sort((a, b) => {
|
||||
const labelA = typeof a.label === 'string' ? a.label : ''
|
||||
const labelB = typeof b.label === 'string' ? b.label : ''
|
||||
return (LABEL_ORDER[labelA as keyof typeof LABEL_ORDER] || 999)
|
||||
- (LABEL_ORDER[labelB as keyof typeof LABEL_ORDER] || 999)
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{sortedVariables.map((variable, index) => {
|
||||
const label = typeof variable.label === 'string' ? variable.label : ''
|
||||
const varName = typeof variable.variable === 'string' ? variable.variable : ''
|
||||
|
||||
return (
|
||||
<VarItem
|
||||
key={`${label}-${varName}-${index}`}
|
||||
prefix={getLabelPrefix(label)}
|
||||
name={varName}
|
||||
type={variable.value_type || 'string'}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user