diff --git a/web/app/components/workflow/nodes/http/components/authorization/index.tsx b/web/app/components/workflow/nodes/http/components/authorization/index.tsx new file mode 100644 index 0000000000..dd00077dab --- /dev/null +++ b/web/app/components/workflow/nodes/http/components/authorization/index.tsx @@ -0,0 +1,141 @@ +'use client' +import type { FC } from 'react' +import React, { useCallback } from 'react' +import produce from 'immer' +import type { Authorization as AuthorizationPayloadType } from '../../types' +import { APIType, AuthorizationType } from '../../types' +import RadioGroup from './radio-group' +import Modal from '@/app/components/base/modal' +import Button from '@/app/components/base/button' +type Props = { + payload: AuthorizationPayloadType + onChange: (newPayload: AuthorizationPayloadType) => void + isShow: boolean + onHide: () => void +} + +const Field = ({ title, children }: { title: string; children: JSX.Element }) => { + return ( +
+
{title}
+
{children}
+
+ ) +} + +const Authorization: FC = ({ + payload, + onChange, + isShow, + onHide, +}) => { + const [tempPayload, setTempPayload] = React.useState(payload) + const handleAuthTypeChange = useCallback((type: string) => { + const newPayload = produce(tempPayload, (draft: AuthorizationPayloadType) => { + draft.type = type as AuthorizationType + if (draft.type === AuthorizationType.apiKey && !draft.config) { + draft.config = { + type: APIType.basic, + api_key: '', + } + } + }) + setTempPayload(newPayload) + }, [tempPayload, setTempPayload]) + + const handleAuthAPITypeChange = useCallback((type: string) => { + const newPayload = produce(tempPayload, (draft: AuthorizationPayloadType) => { + if (!draft.config) { + draft.config = { + type: APIType.basic, + api_key: '', + } + } + draft.config.type = type as APIType + }) + setTempPayload(newPayload) + }, [tempPayload, setTempPayload]) + + const handleAPIKeyOrHeaderChange = useCallback((type: 'api_key' | 'header') => { + return (e: React.ChangeEvent) => { + const newPayload = produce(tempPayload, (draft: AuthorizationPayloadType) => { + if (!draft.config) { + draft.config = { + type: APIType.basic, + api_key: '', + } + } + draft.config[type] = e.target.value + }) + setTempPayload(newPayload) + } + }, [tempPayload, setTempPayload]) + + const handleConfirm = useCallback(() => { + onChange(tempPayload) + onHide() + }, [tempPayload, onChange, onHide]) + return ( + +
+
+ + + + + {tempPayload.type === AuthorizationType.apiKey && ( + <> + + + + {tempPayload.config?.type === APIType.custom && ( + + + + )} + + + + + + )} +
+
+ + +
+
+
+ ) +} +export default React.memo(Authorization) diff --git a/web/app/components/workflow/nodes/http/components/authorization/radio-group.tsx b/web/app/components/workflow/nodes/http/components/authorization/radio-group.tsx new file mode 100644 index 0000000000..470ceab236 --- /dev/null +++ b/web/app/components/workflow/nodes/http/components/authorization/radio-group.tsx @@ -0,0 +1,61 @@ +'use client' +import type { FC } from 'react' +import React, { useCallback } from 'react' +import cn from 'classnames' + +type Option = { + value: string + label: string +} + +type ItemProps = { + title: string + onClick: () => void + isSelected: boolean +} +const Item: FC = ({ + title, + onClick, + isSelected, +}) => { + return ( +
+ {title} +
+ ) +} + +type Props = { + options: Option[] + value: string + onChange: (value: string) => void +} + +const RadioGroup: FC = ({ + options, + value, + onChange, +}) => { + const handleChange = useCallback((value: string) => { + return () => onChange(value) + }, [onChange]) + return ( +
+ {options.map(option => ( + + ))} +
+ ) +} +export default React.memo(RadioGroup) diff --git a/web/app/components/workflow/nodes/http/mock.ts b/web/app/components/workflow/nodes/http/mock.ts index 6a4c712498..15aa6ab0f1 100644 --- a/web/app/components/workflow/nodes/http/mock.ts +++ b/web/app/components/workflow/nodes/http/mock.ts @@ -1,5 +1,5 @@ import { BlockEnum } from '../../types' -import { BodyType, Method } from './types' +import { APIType, AuthorizationType, BodyType, Method } from './types' import type { HttpNodeType } from './types' export const mockData: HttpNodeType = { @@ -24,4 +24,12 @@ export const mockData: HttpNodeType = { type: BodyType.none, data: '', }, + authorization: { + type: AuthorizationType.apiKey, + config: { + type: APIType.custom, + api_key: 'abc', + header: 'x-Authorization', + }, + }, } diff --git a/web/app/components/workflow/nodes/http/panel.tsx b/web/app/components/workflow/nodes/http/panel.tsx index a1d46cfc7f..073f8a3a28 100644 --- a/web/app/components/workflow/nodes/http/panel.tsx +++ b/web/app/components/workflow/nodes/http/panel.tsx @@ -5,6 +5,7 @@ import { mockData } from './mock' import ApiInput from './components/api-input' import KeyValue from './components/key-value' import EditBody from './components/edit-body' +import AuthorizationModal from './components/authorization' import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list' import Field from '@/app/components/workflow/nodes/_base/components/field' import AddButton from '@/app/components/base/button/add-button' @@ -33,6 +34,10 @@ const Panel: FC = () => { isParamKeyValueEdit, toggleIsParamKeyValueEdit, setBody, + isShowAuthorization, + showAuthorization, + hideAuthorization, + setAuthorization, } = useConfig(mockData) return ( @@ -52,6 +57,14 @@ const Panel: FC = () => { + API-KEY + + } > { /> + {isShowAuthorization && ( + + )}
diff --git a/web/app/components/workflow/nodes/http/types.ts b/web/app/components/workflow/nodes/http/types.ts index 06194c434e..c8b0251320 100644 --- a/web/app/components/workflow/nodes/http/types.ts +++ b/web/app/components/workflow/nodes/http/types.ts @@ -27,6 +27,26 @@ export type Body = { data: string } +export enum AuthorizationType { + none = 'no-auth', + apiKey = 'api-key', +} + +export enum APIType { + basic = 'basic', + bearer = 'bearer', + custom = 'custom', +} + +export type Authorization = { + type: AuthorizationType + config?: { + type: APIType + api_key: string + header?: string + } +} + export type HttpNodeType = CommonNodeType & { variables: Variable[] method: Method @@ -34,4 +54,5 @@ export type HttpNodeType = CommonNodeType & { headers: string params: string body: Body + authorization: Authorization } diff --git a/web/app/components/workflow/nodes/http/use-config.ts b/web/app/components/workflow/nodes/http/use-config.ts index 29aa203464..060392b182 100644 --- a/web/app/components/workflow/nodes/http/use-config.ts +++ b/web/app/components/workflow/nodes/http/use-config.ts @@ -1,7 +1,8 @@ import { useCallback, useState } from 'react' import produce from 'immer' +import { useBoolean } from 'ahooks' import useVarList from '../_base/hooks/use-var-list' -import type { Body, HttpNodeType, Method } from './types' +import type { Authorization, Body, HttpNodeType, Method } from './types' import useKeyValueList from './hooks/use-key-value-list' const useConfig = (initInputs: HttpNodeType) => { const [inputs, setInputs] = useState(initInputs) @@ -48,6 +49,19 @@ const useConfig = (initInputs: HttpNodeType) => { setInputs(newInputs) }, [inputs, setInputs]) + // authorization + const [isShowAuthorization, { + setTrue: showAuthorization, + setFalse: hideAuthorization, + }] = useBoolean(true) + + const setAuthorization = useCallback((authorization: Authorization) => { + const newInputs = produce(inputs, (draft: HttpNodeType) => { + draft.authorization = authorization + }) + setInputs(newInputs) + }, [inputs, setInputs]) + return { inputs, handleVarListChange, @@ -68,6 +82,11 @@ const useConfig = (initInputs: HttpNodeType) => { toggleIsParamKeyValueEdit, // body setBody, + // authorization + isShowAuthorization, + showAuthorization, + hideAuthorization, + setAuthorization, } }