merge main

This commit is contained in:
Joel
2024-02-29 10:59:21 +08:00
147 changed files with 1883 additions and 2514 deletions

View File

@ -12,6 +12,7 @@ import { useAppContext } from '@/context/app-context'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { CheckModal } from '@/hooks/use-pay'
import TabSliderNew from '@/app/components/base/tab-slider-new'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
@ -35,7 +36,9 @@ const getKey = (
const Apps = () => {
const { t } = useTranslation()
const { isCurrentWorkspaceManager } = useAppContext()
const [activeTab, setActiveTab] = useState('all')
const [activeTab, setActiveTab] = useTabSearchParams({
defaultTab: 'all',
})
const [keywords, setKeywords] = useState('')
const [searchKeywords, setSearchKeywords] = useState('')

View File

@ -1,7 +1,7 @@
'use client'
// Libraries
import { useRef, useState } from 'react'
import { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import useSWR from 'swr'
@ -15,6 +15,9 @@ import TabSliderNew from '@/app/components/base/tab-slider-new'
// Services
import { fetchDatasetApiBaseUrl } from '@/service/datasets'
// Hooks
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
const Container = () => {
const { t } = useTranslation()
@ -23,7 +26,9 @@ const Container = () => {
{ value: 'api', text: t('dataset.datasetsApi') },
]
const [activeTab, setActiveTab] = useState('dataset')
const [activeTab, setActiveTab] = useTabSearchParams({
defaultTab: 'dataset',
})
const containerRef = useRef<HTMLDivElement>(null)
const { data } = useSWR(activeTab === 'dataset' ? null : '/datasets/api-base-info', fetchDatasetApiBaseUrl)

View File

@ -42,6 +42,7 @@ const HeaderOptions: FC<Props> = ({
const { locale } = useContext(I18n)
const { CSVDownloader, Type } = useCSVDownloader()
const [list, setList] = useState<AnnotationItemBasic[]>([])
const annotationUnavailable = list.length === 0
const listTransformer = (list: AnnotationItemBasic[]) => list.map(
(item: AnnotationItemBasic) => {
@ -116,11 +117,11 @@ const HeaderOptions: FC<Props> = ({
...list.map(item => [item.question, item.answer]),
]}
>
<button className={s.actionItem}>
<button disabled={annotationUnavailable} className={s.actionItem}>
<span className={s.actionName}>CSV</span>
</button>
</CSVDownloader>
<button className={cn(s.actionItem, '!border-0')} onClick={JSONLOutput}>
<button disabled={annotationUnavailable} className={cn(s.actionItem, '!border-0')} onClick={JSONLOutput}>
<span className={s.actionName}>JSONL</span>
</button>
</Menu.Items>

View File

@ -19,7 +19,7 @@
}
.actionItem {
@apply h-9 py-2 px-3 mx-1 flex items-center space-x-2 hover:bg-gray-100 rounded-lg cursor-pointer;
@apply h-9 py-2 px-3 mx-1 flex items-center space-x-2 hover:bg-gray-100 rounded-lg cursor-pointer disabled:opacity-50;
width: calc(100% - 0.5rem);
}
@ -35,4 +35,4 @@
left: 4px;
transform: translateX(-100%);
box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
}
}

View File

@ -18,7 +18,7 @@ import { getNewVar } from '@/utils/var'
import { varHighlightHTML } from '@/app/components/app/configuration/base/var-highlight'
import { Plus, Trash03 } from '@/app/components/base/icons/src/vender/line/general'
const MAX_QUESTION_NUM = 3
const MAX_QUESTION_NUM = 5
export type IOpeningStatementProps = {
value: string

View File

@ -1,15 +1,17 @@
import type { FC } from 'react'
import classNames from 'classnames'
type LogoSiteProps = {
className?: string
}
const LogoSite: FC<LogoSiteProps> = ({
className,
}) => {
return (
<img
src='/logo/logo-site.png'
className={`block w-auto h-10 ${className}`}
className={classNames('block w-auto h-10', className)}
alt='logo'
/>
)

View File

@ -1,7 +1,8 @@
'use client'
import type { FC } from 'react'
import React, { useEffect } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import useSWR from 'swr'
import PlanComp from '../plan'
import { ReceiptList } from '../../base/icons/src/vender/line/financeAndECommerce'
import { LinkExternal01 } from '../../base/icons/src/vender/line/general'
@ -12,17 +13,11 @@ import { useProviderContext } from '@/context/provider-context'
const Billing: FC = () => {
const { t } = useTranslation()
const { isCurrentWorkspaceManager } = useAppContext()
const [billingUrl, setBillingUrl] = React.useState('')
const { enableBilling } = useProviderContext()
useEffect(() => {
if (!enableBilling || !isCurrentWorkspaceManager)
return
(async () => {
const { url } = await fetchBillingUrl()
setBillingUrl(url)
})()
}, [isCurrentWorkspaceManager])
const { data: billingUrl } = useSWR(
(!enableBilling || !isCurrentWorkspaceManager) ? null : ['/billing/invoices'],
() => fetchBillingUrl().then(data => data.url),
)
return (
<div>
@ -39,4 +34,5 @@ const Billing: FC = () => {
</div>
)
}
export default React.memo(Billing)

View File

@ -16,8 +16,6 @@ import {
updateCurrentWorkspace,
} from '@/service/common'
import { useAppContext } from '@/context/app-context'
import { API_PREFIX } from '@/config'
import { getPurifyHref } from '@/utils'
const ALLOW_FILE_EXTENSIONS = ['svg', 'png']
@ -123,7 +121,7 @@ const CustomWebAppBrand = () => {
POWERED BY
{
webappLogo
? <img key={webappLogo} src={`${getPurifyHref(API_PREFIX.slice(0, -12))}/files/workspaces/${currentWorkspace.id}/webapp-logo`} alt='logo' className='ml-2 block w-auto h-5' />
? <img key={webappLogo} src={webappLogo} alt='logo' className='ml-2 block w-auto h-5' />
: <LogoSite className='ml-2 !h-5' />
}
</div>

View File

@ -289,9 +289,9 @@ The text generation application offers non-session support and is ideal for tran
</Col>
<Col sticky>
### Request Example
<CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST 'https://cloud.dify.ai/v1/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
<CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
```bash {{ title: 'cURL' }}
curl -X POST 'https://cloud.dify.ai/v1/completion-messages/:task_id/stop' \
curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \
-H 'Authorization: Bearer {api_key}' \
-H 'Content-Type: application/json' \
--data-raw '{

View File

@ -266,9 +266,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- `result` (string) 固定返回 success
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST 'https://cloud.dify.ai/v1/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
<CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
```bash {{ title: 'cURL' }}
curl -X POST 'https://cloud.dify.ai/v1/completion-messages/:task_id/stop' \
curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \
-H 'Authorization: Bearer {api_key}' \
-H 'Content-Type: application/json' \
--data-raw '{

View File

@ -344,9 +344,9 @@ Chat applications support session persistence, allowing previous chat history to
</Col>
<Col sticky>
### Request Example
<CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST 'https://cloud.dify.ai/v1/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
<CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
```bash {{ title: 'cURL' }}
curl -X POST 'https://cloud.dify.ai/v1/chat-messages/:task_id/stop' \
curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
-H 'Authorization: Bearer {api_key}' \
-H 'Content-Type: application/json' \
--data-raw '{
@ -1025,9 +1025,9 @@ Chat applications support session persistence, allowing previous chat history to
- (string) url of icon
</Col>
<Col>
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET 'https://cloud.dify.ai/v1/meta?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
<CodeGroup title="Request" tag="GET" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
```bash {{ title: 'cURL' }}
curl -X GET 'https://cloud.dify.ai/v1/meta?user=abc-123' \
curl -X GET '${props.appDetail.api_base_url}/meta?user=abc-123' \
-H 'Authorization: Bearer {api_key}'
```

View File

@ -360,9 +360,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- `result` (string) 固定返回 success
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST 'https://cloud.dify.ai/v1/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
<CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
```bash {{ title: 'cURL' }}
curl -X POST 'https://cloud.dify.ai/v1/chat-messages/:task_id/stop' \
curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
-H 'Authorization: Bearer {api_key}' \
-H 'Content-Type: application/json' \
--data-raw '{
@ -1022,9 +1022,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- (string) 图标URL
</Col>
<Col>
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET 'https://cloud.dify.ai/v1/meta?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
```bash {{ title: 'cURL' }}
curl -X GET 'https://cloud.dify.ai/v1/meta?user=abc-123' \
curl -X GET '${props.appDetail.api_base_url}/meta?user=abc-123' \
-H 'Authorization: Bearer {api_key}'
```

View File

@ -1,18 +1,20 @@
'use client'
import React, { useEffect } from 'react'
import React from 'react'
import cn from 'classnames'
import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import useSWR from 'swr'
import Toast from '../../base/toast'
import s from './style.module.css'
import ExploreContext from '@/context/explore-context'
import type { App, AppCategory } from '@/models/explore'
import type { App } from '@/models/explore'
import Category from '@/app/components/explore/category'
import AppCard from '@/app/components/explore/app-card'
import { fetchAppDetail, fetchAppList } from '@/service/explore'
import { createApp } from '@/service/apps'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import CreateAppModal from '@/app/components/explore/create-app-modal'
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
import Loading from '@/app/components/base/loading'
@ -36,32 +38,43 @@ const Apps = ({
const { isCurrentWorkspaceManager } = useAppContext()
const router = useRouter()
const { hasEditPermission } = useContext(ExploreContext)
const [currCategory, setCurrCategory] = React.useState<AppCategory | ''>('')
const [allList, setAllList] = React.useState<App[]>([])
const [isLoaded, setIsLoaded] = React.useState(false)
const allCategoriesEn = t('explore.apps.allCategories')
const [currCategory, setCurrCategory] = useTabSearchParams({
defaultTab: allCategoriesEn,
})
const {
data: { categories, allList },
} = useSWR(
['/explore/apps'],
() =>
fetchAppList().then(({ categories, recommended_apps }) => ({
categories,
allList: recommended_apps.sort((a, b) => a.position - b.position),
})),
{
fallbackData: {
categories: [],
allList: [],
},
},
)
const currList = (() => {
if (currCategory === '')
if (currCategory === allCategoriesEn)
return allList
return allList.filter(item => item.category === currCategory)
})()
const [categories, setCategories] = React.useState<AppCategory[]>([])
useEffect(() => {
(async () => {
const { categories, recommended_apps }: any = await fetchAppList()
const sortedRecommendedApps = [...recommended_apps]
sortedRecommendedApps.sort((a, b) => a.position - b.position) // position from small to big
setCategories(categories)
setAllList(sortedRecommendedApps)
setIsLoaded(true)
})()
}, [])
const [currApp, setCurrApp] = React.useState<App | null>(null)
const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
const onCreate: CreateAppModalProps['onConfirm'] = async ({ name, icon, icon_background, description }) => {
const { app_model_config: model_config } = await fetchAppDetail(currApp?.app.id as string)
const onCreate: CreateAppModalProps['onConfirm'] = async ({
name,
icon,
icon_background,
}) => {
const { app_model_config: model_config } = await fetchAppDetail(
currApp?.app.id as string,
)
try {
const app = await createApp({
@ -78,17 +91,20 @@ const Apps = ({
message: t('app.newApp.appCreated'),
})
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
router.push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`)
router.push(
`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'
}`,
)
}
catch (e) {
Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
}
}
if (!isLoaded) {
if (!categories) {
return (
<div className='flex h-full items-center'>
<Loading type='area' />
<div className="flex h-full items-center">
<Loading type="area" />
</div>
)
}

View File

@ -138,16 +138,12 @@ export default function AccountSetting({
]
const scrollRef = useRef<HTMLDivElement>(null)
const [scrolled, setScrolled] = useState(false)
const scrollHandle = (e: Event) => {
if ((e.target as HTMLDivElement).scrollTop > 0)
setScrolled(true)
else
setScrolled(false)
}
useEffect(() => {
const targetElement = scrollRef.current
const scrollHandle = (e: Event) => {
const userScrolled = (e.target as HTMLDivElement).scrollTop > 0
setScrolled(userScrolled)
}
targetElement?.addEventListener('scroll', scrollHandle)
return () => {
targetElement?.removeEventListener('scroll', scrollHandle)

View File

@ -54,7 +54,7 @@ const Header = () => {
</div>}
{!isMobile && <>
<Link href="/apps" className='flex items-center mr-4'>
<LogoSite />
<LogoSite className='object-contain' />
</Link>
<GithubStar />
</>}

View File

@ -3,11 +3,13 @@ import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import Tooltip from '../../base/tooltip'
import { HelpCircle } from '../../base/icons/src/vender/line/general'
import type { Credential } from '@/app/components/tools/types'
import Drawer from '@/app/components/base/drawer-plus'
import Button from '@/app/components/base/button'
import Radio from '@/app/components/base/radio/ui'
import { AuthType } from '@/app/components/tools/types'
import { AuthHeaderPrefix, AuthType } from '@/app/components/tools/types'
type Props = {
credential: Credential
@ -18,9 +20,9 @@ const keyClassNames = 'py-2 leading-5 text-sm font-medium text-gray-900'
type ItemProps = {
text: string
value: AuthType
value: AuthType | AuthHeaderPrefix
isChecked: boolean
onClick: (value: AuthType) => void
onClick: (value: AuthType | AuthHeaderPrefix) => void
}
const SelectItem: FC<ItemProps> = ({ text, value, isChecked, onClick }) => {
@ -31,7 +33,6 @@ const SelectItem: FC<ItemProps> = ({ text, value, isChecked, onClick }) => {
>
<Radio isChecked={isChecked} />
<div className='text-sm font-normal text-gray-900'>{text}</div>
</div>
)
}
@ -43,6 +44,7 @@ const ConfigCredential: FC<Props> = ({
}) => {
const { t } = useTranslation()
const [tempCredential, setTempCredential] = React.useState<Credential>(credential)
return (
<Drawer
isShow
@ -62,20 +64,59 @@ const ConfigCredential: FC<Props> = ({
text={t('tools.createTool.authMethod.types.none')}
value={AuthType.none}
isChecked={tempCredential.auth_type === AuthType.none}
onClick={value => setTempCredential({ ...tempCredential, auth_type: value })}
onClick={value => setTempCredential({ ...tempCredential, auth_type: value as AuthType })}
/>
<SelectItem
text={t('tools.createTool.authMethod.types.api_key')}
value={AuthType.apiKey}
isChecked={tempCredential.auth_type === AuthType.apiKey}
onClick={value => setTempCredential({ ...tempCredential, auth_type: value })}
onClick={value => setTempCredential({
...tempCredential,
auth_type: value as AuthType,
api_key_header: tempCredential.api_key_header || 'Authorization',
api_key_value: tempCredential.api_key_value || '',
api_key_header_prefix: tempCredential.api_key_header_prefix || AuthHeaderPrefix.custom,
})}
/>
</div>
</div>
{tempCredential.auth_type === AuthType.apiKey && (
<>
<div className={keyClassNames}>{t('tools.createTool.authHeaderPrefix.title')}</div>
<div className='flex space-x-3'>
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.basic')}
value={AuthHeaderPrefix.basic}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.basic}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
/>
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.bearer')}
value={AuthHeaderPrefix.bearer}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.bearer}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
/>
<SelectItem
text={t('tools.createTool.authHeaderPrefix.types.custom')}
value={AuthHeaderPrefix.custom}
isChecked={tempCredential.api_key_header_prefix === AuthHeaderPrefix.custom}
onClick={value => setTempCredential({ ...tempCredential, api_key_header_prefix: value as AuthHeaderPrefix })}
/>
</div>
<div>
<div className={keyClassNames}>{t('tools.createTool.authMethod.key')}</div>
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('tools.createTool.authMethod.key')}
<Tooltip
selector='model-page-system-reasoning-model-tip'
htmlContent={
<div className='w-[261px] text-gray-500'>
{t('tools.createTool.authMethod.keyTooltip')}
</div>
}
>
<HelpCircle className='ml-0.5 w-[14px] h-[14px] text-gray-400'/>
</Tooltip>
</div>
<input
value={tempCredential.api_key_header}
onChange={e => setTempCredential({ ...tempCredential, api_key_header: e.target.value })}
@ -83,7 +124,6 @@ const ConfigCredential: FC<Props> = ({
placeholder={t('tools.createTool.authMethod.types.apiKeyPlaceholder')!}
/>
</div>
<div>
<div className={keyClassNames}>{t('tools.createTool.authMethod.value')}</div>
<input

View File

@ -8,7 +8,7 @@ import { clone } from 'lodash-es'
import cn from 'classnames'
import { LinkExternal02, Settings01 } from '../../base/icons/src/vender/line/general'
import type { Credential, CustomCollectionBackend, CustomParamSchema, Emoji } from '../types'
import { AuthType } from '../types'
import { AuthHeaderPrefix, AuthType } from '../types'
import GetSchema from './get-schema'
import ConfigCredentials from './config-credentials'
import TestApi from './test-api'
@ -37,6 +37,7 @@ const EditCustomCollectionModal: FC<Props> = ({
const { t } = useTranslation()
const isAdd = !payload
const isEdit = !!payload
const [editFirst, setEditFirst] = useState(!isAdd)
const [paramsSchemas, setParamsSchemas] = useState<CustomParamSchema[]>(payload?.tools || [])
const [customCollection, setCustomCollection, getCustomCollection] = useGetState<CustomCollectionBackend>(isAdd
@ -44,6 +45,8 @@ const EditCustomCollectionModal: FC<Props> = ({
provider: '',
credentials: {
auth_type: AuthType.none,
api_key_header: 'Authorization',
api_key_header_prefix: AuthHeaderPrefix.basic,
},
icon: {
content: '🕵️',

View File

@ -16,6 +16,7 @@ import EditCustomToolModal from './edit-custom-collection-modal'
import NoCustomTool from './info/no-custom-tool'
import NoSearchRes from './info/no-search-res'
import NoCustomToolPlaceholder from './no-custom-tool-placeholder'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import TabSlider from '@/app/components/base/tab-slider'
import { createCustomCollection, fetchCollectionList as doFetchCollectionList, fetchBuiltInToolList, fetchCustomToolList } from '@/service/tools'
import type { AgentTool } from '@/types/app'
@ -68,7 +69,9 @@ const Tools: FC<Props> = ({
})()
const [query, setQuery] = useState('')
const [collectionType, setCollectionType] = useState<CollectionType>(collectionTypeOptions[0].value)
const [collectionType, setCollectionType] = useTabSearchParams({
defaultTab: collectionTypeOptions[0].value,
})
const showCollectionList = (() => {
let typeFilteredList: Collection[] = []

View File

@ -3,7 +3,7 @@ import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import { CollectionType, LOC } from '../types'
import { AuthHeaderPrefix, AuthType, CollectionType, LOC } from '../types'
import type { Collection, CustomCollectionBackend, Tool } from '../types'
import Loading from '../../base/loading'
import { ArrowNarrowRight } from '../../base/icons/src/vender/line/arrows'
@ -53,6 +53,10 @@ const ToolList: FC<Props> = ({
(async () => {
if (collection.type === CollectionType.custom) {
const res = await fetchCustomCollection(collection.name)
if (res.credentials.auth_type === AuthType.apiKey && !res.credentials.api_key_header_prefix) {
if (res.credentials.api_key_value)
res.credentials.api_key_header_prefix = AuthHeaderPrefix.custom
}
setCustomCollection({
...res,
provider: collection.name,

View File

@ -9,10 +9,17 @@ export enum AuthType {
apiKey = 'api_key',
}
export enum AuthHeaderPrefix {
basic = 'basic',
bearer = 'bearer',
custom = 'custom',
}
export type Credential = {
'auth_type': AuthType
'api_key_header'?: string
'api_key_value'?: string
'api_key_header_prefix'?: AuthHeaderPrefix
}
export enum CollectionType {