123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- 'use client'
- import type { FC } from 'react'
- import React, { useCallback, useMemo } from 'react'
- import produce from 'immer'
- 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 { 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
- payload: Body
- onChange: (payload: Body) => void
- }
- const allTypes = [
- BodyType.none,
- BodyType.formData,
- BodyType.xWwwFormUrlencoded,
- BodyType.json,
- BodyType.rawText,
- BodyType.binary,
- ]
- const bodyTextMap = {
- [BodyType.none]: 'none',
- [BodyType.formData]: 'form-data',
- [BodyType.xWwwFormUrlencoded]: 'x-www-form-urlencoded',
- [BodyType.rawText]: 'raw',
- [BodyType.json]: 'JSON',
- [BodyType.binary]: 'binary',
- }
- const EditBody: FC<Props> = ({
- readonly,
- nodeId,
- payload,
- onChange,
- }) => {
- 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) => {
- return [VarType.string, VarType.number, VarType.secret, VarType.arrayNumber, VarType.arrayString].includes(varPayload.type)
- },
- })
- 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: hasKeyValue
- ? [
- {
- id: uniqueId(UNIQUE_ID_PREFIX),
- type: BodyPayloadValueType.text,
- key: '',
- value: '',
- },
- ]
- : [],
- })
- }, [onChange])
- const handleAddBody = useCallback(() => {
- const newPayload = produce(payload, (draft) => {
- (draft.data as BodyPayload).push({
- id: uniqueId(UNIQUE_ID_PREFIX),
- type: BodyPayloadValueType.text,
- key: '',
- value: '',
- })
- })
- onChange(newPayload)
- }, [onChange, payload])
- const handleBodyPayloadChange = useCallback((newList: KeyValueType[]) => {
- const newPayload = produce(payload, (draft) => {
- draft.data = newList as BodyPayload
- })
- 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) => {
- 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])
- return (
- <div>
- {/* body type */}
- <div className='flex flex-wrap'>
- {allTypes.map(t => (
- <label key={t} htmlFor={`body-type-${t}`} className='mr-4 flex h-7 items-center space-x-2'>
- <input
- type="radio"
- id={`body-type-${t}`}
- value={t}
- checked={type === t}
- onChange={handleTypeChange}
- disabled={readonly}
- />
- <div className='text-[13px] font-normal leading-[18px] text-gray-700'>{bodyTextMap[t]}</div>
- </label>
- ))}
- </div>
- {/* body value */}
- <div className={cn(type !== BodyType.none && 'mt-1')}>
- {type === BodyType.none && null}
- {(type === BodyType.formData || type === BodyType.xWwwFormUrlencoded) && (
- <KeyValue
- readonly={readonly}
- nodeId={nodeId}
- list={bodyPayload as KeyValueType[]}
- onChange={handleBodyPayloadChange}
- onAdd={handleAddBody}
- isSupportFile={type === BodyType.formData}
- />
- )}
- {type === BodyType.rawText && (
- <InputWithVar
- instanceId={'http-body-raw'}
- title={<div className='uppercase'>Raw text</div>}
- onChange={handleBodyValueChange}
- value={stringValue}
- justVar
- nodesOutputVars={availableVars}
- availableNodes={availableNodes}
- readOnly={readonly}
- />
- )}
- {type === BodyType.json && (
- <InputWithVar
- instanceId={'http-body-json'}
- title='JSON'
- value={stringValue}
- onChange={handleBodyValueChange}
- justVar
- nodesOutputVars={availableVars}
- availableNodes={availableNodes}
- readOnly={readonly}
- />
- )}
- {type === BodyType.binary && (
- <VarReferencePicker
- nodeId={nodeId}
- readonly={readonly}
- value={bodyPayload[0]?.file || []}
- onChange={handleFileChange}
- filterVar={filterOnlyFileVariable}
- />
- )}
- </div>
- </div>
- )
- }
- export default React.memo(EditBody)
|