Feat/attachments (#9526)

Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
zxhlyh
2024-10-21 10:32:37 +08:00
committed by GitHub
parent 4fd2743efa
commit 7a1d6fe509
445 changed files with 11759 additions and 6922 deletions

View File

@@ -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>
)