mirror of https://github.com/langgenius/dify.git
feat: auth struct
This commit is contained in:
parent
b08327cb4b
commit
076fe8ca3a
|
|
@ -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 (
|
||||
<div>
|
||||
<div className='leading-8 text-[13px] font-medium text-gray-700'>{title}</div>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Authorization: FC<Props> = ({
|
||||
payload,
|
||||
onChange,
|
||||
isShow,
|
||||
onHide,
|
||||
}) => {
|
||||
const [tempPayload, setTempPayload] = React.useState<AuthorizationPayloadType>(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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<Modal
|
||||
title='Authorization'
|
||||
wrapperClassName='z-50 w-400'
|
||||
isShow={isShow}
|
||||
onClose={onHide}
|
||||
>
|
||||
<div>
|
||||
<div className='space-y-2'>
|
||||
<Field title='Type'>
|
||||
<RadioGroup
|
||||
options={[
|
||||
{ value: AuthorizationType.none, label: 'Basic' },
|
||||
{ value: AuthorizationType.apiKey, label: 'Bearer' },
|
||||
]}
|
||||
value={tempPayload.type}
|
||||
onChange={handleAuthTypeChange}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
{tempPayload.type === AuthorizationType.apiKey && (
|
||||
<>
|
||||
<Field title='Auth type'>
|
||||
<RadioGroup
|
||||
options={[
|
||||
{ value: APIType.basic, label: 'Basic' },
|
||||
{ value: APIType.bearer, label: 'Bearer' },
|
||||
{ value: APIType.custom, label: 'Custom' },
|
||||
]}
|
||||
value={tempPayload.config?.type || APIType.basic}
|
||||
onChange={handleAuthAPITypeChange}
|
||||
/>
|
||||
</Field>
|
||||
{tempPayload.config?.type === APIType.custom && (
|
||||
<Field title='header'>
|
||||
<input
|
||||
type='text'
|
||||
className='w-full h-8 leading-8 px-2.5 rounded-lg border-0 bg-gray-100 text-gray-900 text-[13px] placeholder:text-gray-400 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
|
||||
value={tempPayload.config?.header || ''}
|
||||
onChange={handleAPIKeyOrHeaderChange('header')}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
<Field title='API Key'>
|
||||
<input
|
||||
type='text'
|
||||
className='w-full h-8 leading-8 px-2.5 rounded-lg border-0 bg-gray-100 text-gray-900 text-[13px] placeholder:text-gray-400 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
|
||||
value={tempPayload.config?.api_key || ''}
|
||||
onChange={handleAPIKeyOrHeaderChange('api_key')}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className='mt-6 flex justify-end space-x-2'>
|
||||
<Button onClick={onHide} className='flex items-center !h-8 leading-[18px] !text-[13px] !font-medium'>Cancel</Button>
|
||||
<Button type='primary' onClick={handleConfirm} className='flex items-center !h-8 leading-[18px] !text-[13px] !font-medium'>Confirm</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default React.memo(Authorization)
|
||||
|
|
@ -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<ItemProps> = ({
|
||||
title,
|
||||
onClick,
|
||||
isSelected,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
isSelected ? 'border-[2px] border-primary-400 bg-white shadow-xs' : 'border border-gray-100 bg-gray-25',
|
||||
'w-0 grow flex items-center justify-center h-8 cursor-pointer rounded-lg text-[13px] font-normal text-gray-900')
|
||||
}
|
||||
onClick={onClick}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type Props = {
|
||||
options: Option[]
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
|
||||
const RadioGroup: FC<Props> = ({
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
const handleChange = useCallback((value: string) => {
|
||||
return () => onChange(value)
|
||||
}, [onChange])
|
||||
return (
|
||||
<div className='flex space-x-2'>
|
||||
{options.map(option => (
|
||||
<Item
|
||||
key={option.value}
|
||||
title={option.label}
|
||||
onClick={handleChange(option.value)}
|
||||
isSelected={option.value === value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(RadioGroup)
|
||||
|
|
@ -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',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
|||
</Field>
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.api`)}
|
||||
operations={
|
||||
<div
|
||||
onClick={showAuthorization}
|
||||
className='flex '
|
||||
>
|
||||
API-KEY
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<ApiInput
|
||||
readonly={readOnly}
|
||||
|
|
@ -95,6 +108,14 @@ const Panel: FC = () => {
|
|||
/>
|
||||
</Field>
|
||||
</div>
|
||||
{isShowAuthorization && (
|
||||
<AuthorizationModal
|
||||
isShow
|
||||
onHide={hideAuthorization}
|
||||
payload={inputs.authorization}
|
||||
onChange={setAuthorization}
|
||||
/>
|
||||
)}
|
||||
<Split />
|
||||
<div className='px-4 pt-4 pb-2'>
|
||||
<OutputVars>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<HttpNodeType>(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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue