Feat/attachments (#9526)
Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import produce from 'immer'
|
||||
import type { Body } from '../../types'
|
||||
import { BodyType } from '../../types'
|
||||
import useKeyValueList from '../../hooks/use-key-value-list'
|
||||
import { uniqueId } from 'lodash-es'
|
||||
import type { Body, BodyPayload, KeyValue as KeyValueType } from '../../types'
|
||||
import { BodyPayloadValueType, BodyType } from '../../types'
|
||||
import KeyValue from '../key-value'
|
||||
import useAvailableVarList from '../../../_base/hooks/use-available-var-list'
|
||||
import VarReferencePicker from '../../../_base/components/variable/var-reference-picker'
|
||||
import cn from '@/utils/classnames'
|
||||
import InputWithVar from '@/app/components/workflow/nodes/_base/components/prompt/editor'
|
||||
import type { Var } from '@/app/components/workflow/types'
|
||||
import type { ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
|
||||
const UNIQUE_ID_PREFIX = 'key-value-'
|
||||
|
||||
type Props = {
|
||||
readonly: boolean
|
||||
nodeId: string
|
||||
@@ -23,15 +26,17 @@ const allTypes = [
|
||||
BodyType.none,
|
||||
BodyType.formData,
|
||||
BodyType.xWwwFormUrlencoded,
|
||||
BodyType.rawText,
|
||||
BodyType.json,
|
||||
BodyType.rawText,
|
||||
BodyType.binary,
|
||||
]
|
||||
const bodyTextMap = {
|
||||
[BodyType.none]: 'none',
|
||||
[BodyType.formData]: 'form-data',
|
||||
[BodyType.xWwwFormUrlencoded]: 'x-www-form-urlencoded',
|
||||
[BodyType.rawText]: 'raw text',
|
||||
[BodyType.rawText]: 'raw',
|
||||
[BodyType.json]: 'JSON',
|
||||
[BodyType.binary]: 'binary',
|
||||
}
|
||||
|
||||
const EditBody: FC<Props> = ({
|
||||
@@ -40,7 +45,15 @@ const EditBody: FC<Props> = ({
|
||||
payload,
|
||||
onChange,
|
||||
}) => {
|
||||
const { type } = payload
|
||||
const { type, data } = payload
|
||||
const bodyPayload = useMemo(() => {
|
||||
if (typeof data === 'string') { // old data
|
||||
return []
|
||||
}
|
||||
return data
|
||||
}, [data])
|
||||
const stringValue = [BodyType.formData, BodyType.xWwwFormUrlencoded].includes(type) ? '' : (bodyPayload[0]?.value || '')
|
||||
|
||||
const { availableVars, availableNodes } = useAvailableVarList(nodeId, {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar: (varPayload: Var) => {
|
||||
@@ -50,49 +63,69 @@ const EditBody: FC<Props> = ({
|
||||
|
||||
const handleTypeChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newType = e.target.value as BodyType
|
||||
const hasKeyValue = [BodyType.formData, BodyType.xWwwFormUrlencoded].includes(newType)
|
||||
onChange({
|
||||
type: newType,
|
||||
data: '',
|
||||
data: hasKeyValue
|
||||
? [
|
||||
{
|
||||
id: uniqueId(UNIQUE_ID_PREFIX),
|
||||
type: BodyPayloadValueType.text,
|
||||
key: '',
|
||||
value: '',
|
||||
},
|
||||
]
|
||||
: [],
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
setBody([])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [onChange])
|
||||
|
||||
const isCurrentKeyValue = type === BodyType.formData || type === BodyType.xWwwFormUrlencoded
|
||||
|
||||
const {
|
||||
list: body,
|
||||
setList: setBody,
|
||||
addItem: addBody,
|
||||
} = useKeyValueList(payload.data, (value) => {
|
||||
if (!isCurrentKeyValue)
|
||||
return
|
||||
|
||||
const newBody = produce(payload, (draft: Body) => {
|
||||
draft.data = value
|
||||
const handleAddBody = useCallback(() => {
|
||||
const newPayload = produce(payload, (draft) => {
|
||||
(draft.data as BodyPayload).push({
|
||||
id: uniqueId(UNIQUE_ID_PREFIX),
|
||||
type: BodyPayloadValueType.text,
|
||||
key: '',
|
||||
value: '',
|
||||
})
|
||||
})
|
||||
onChange(newBody)
|
||||
}, type === BodyType.json)
|
||||
onChange(newPayload)
|
||||
}, [onChange, payload])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCurrentKeyValue)
|
||||
return
|
||||
|
||||
const newBody = produce(payload, (draft: Body) => {
|
||||
draft.data = body.map((item) => {
|
||||
if (!item.key && !item.value)
|
||||
return ''
|
||||
return `${item.key}:${item.value}`
|
||||
}).join('\n')
|
||||
const handleBodyPayloadChange = useCallback((newList: KeyValueType[]) => {
|
||||
const newPayload = produce(payload, (draft) => {
|
||||
draft.data = newList as BodyPayload
|
||||
})
|
||||
onChange(newBody)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isCurrentKeyValue])
|
||||
onChange(newPayload)
|
||||
}, [onChange, payload])
|
||||
|
||||
const filterOnlyFileVariable = (varPayload: Var) => {
|
||||
return [VarType.file, VarType.arrayFile].includes(varPayload.type)
|
||||
}
|
||||
|
||||
const handleBodyValueChange = useCallback((value: string) => {
|
||||
const newBody = produce(payload, (draft: Body) => {
|
||||
draft.data = value
|
||||
if ((draft.data as BodyPayload).length === 0) {
|
||||
(draft.data as BodyPayload).push({
|
||||
id: uniqueId(UNIQUE_ID_PREFIX),
|
||||
type: BodyPayloadValueType.text,
|
||||
key: '',
|
||||
value: '',
|
||||
})
|
||||
}
|
||||
(draft.data as BodyPayload)[0].value = value
|
||||
})
|
||||
onChange(newBody)
|
||||
}, [onChange, payload])
|
||||
|
||||
const handleFileChange = useCallback((value: ValueSelector | string) => {
|
||||
const newBody = produce(payload, (draft: Body) => {
|
||||
if ((draft.data as BodyPayload).length === 0) {
|
||||
(draft.data as BodyPayload).push({
|
||||
id: uniqueId(UNIQUE_ID_PREFIX),
|
||||
type: BodyPayloadValueType.file,
|
||||
})
|
||||
}
|
||||
(draft.data as BodyPayload)[0].file = value as ValueSelector
|
||||
})
|
||||
onChange(newBody)
|
||||
}, [onChange, payload])
|
||||
@@ -122,9 +155,10 @@ const EditBody: FC<Props> = ({
|
||||
<KeyValue
|
||||
readonly={readonly}
|
||||
nodeId={nodeId}
|
||||
list={body}
|
||||
onChange={setBody}
|
||||
onAdd={addBody}
|
||||
list={bodyPayload as KeyValueType[]}
|
||||
onChange={handleBodyPayloadChange}
|
||||
onAdd={handleAddBody}
|
||||
isSupportFile={type === BodyType.formData}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -133,7 +167,7 @@ const EditBody: FC<Props> = ({
|
||||
instanceId={'http-body-raw'}
|
||||
title={<div className='uppercase'>Raw text</div>}
|
||||
onChange={handleBodyValueChange}
|
||||
value={payload.data}
|
||||
value={stringValue}
|
||||
justVar
|
||||
nodesOutputVars={availableVars}
|
||||
availableNodes={availableNodes}
|
||||
@@ -145,7 +179,7 @@ const EditBody: FC<Props> = ({
|
||||
<InputWithVar
|
||||
instanceId={'http-body-json'}
|
||||
title='JSON'
|
||||
value={payload.data}
|
||||
value={stringValue}
|
||||
onChange={handleBodyValueChange}
|
||||
justVar
|
||||
nodesOutputVars={availableVars}
|
||||
@@ -153,6 +187,16 @@ const EditBody: FC<Props> = ({
|
||||
readOnly={readonly}
|
||||
/>
|
||||
)}
|
||||
|
||||
{type === BodyType.binary && (
|
||||
<VarReferencePicker
|
||||
nodeId={nodeId}
|
||||
readonly={readonly}
|
||||
value={bodyPayload[0]?.file || []}
|
||||
onChange={handleFileChange}
|
||||
filterVar={filterOnlyFileVariable}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user