Commit 4edaa95c authored by JzoNg's avatar JzoNg

app menu

parent 067e6b5a
...@@ -31,19 +31,6 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => { ...@@ -31,19 +31,6 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
const { appDetail, setAppDetail } = useStore() const { appDetail, setAppDetail } = useStore()
const { data: response } = useSWR(detailParams, fetchAppDetail) const { data: response } = useSWR(detailParams, fetchAppDetail)
const appModeName = (() => {
if (response?.mode === 'chat' || response?.mode === 'advanced-chat')
return t('app.types.chatbot')
if (response?.mode === 'agent-chat')
return t('app.types.agent')
if (response?.mode === 'completion')
return t('app.types.completion')
return t('app.types.workflow')
})()
const navigation = useMemo(() => { const navigation = useMemo(() => {
const navs = [ const navs = [
...(isCurrentWorkspaceManager ...(isCurrentWorkspaceManager
...@@ -97,7 +84,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => { ...@@ -97,7 +84,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
return ( return (
<div className={cn(s.app, 'flex', 'overflow-hidden')}> <div className={cn(s.app, 'flex', 'overflow-hidden')}>
<AppSideBar title={response.name} icon={response.icon} icon_background={response.icon_background} desc={appModeName} navigation={navigation} /> <AppSideBar title={response.name} icon={response.icon} icon_background={response.icon_background} desc={response.mode} navigation={navigation} />
<div className="bg-white grow overflow-hidden"> <div className="bg-white grow overflow-hidden">
{children} {children}
</div> </div>
......
...@@ -122,6 +122,8 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { ...@@ -122,6 +122,8 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
message: t('app.newApp.appCreated'), message: t('app.newApp.appCreated'),
}) })
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
mutateApps()
onPlanInfoChanged()
getRedirection(isCurrentWorkspaceManager, newApp, push) getRedirection(isCurrentWorkspaceManager, newApp, push)
} }
catch (e) { catch (e) {
...@@ -175,13 +177,17 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { ...@@ -175,13 +177,17 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
<span className={s.actionName}>{t('common.operation.settings')}</span> <span className={s.actionName}>{t('common.operation.settings')}</span>
</button> </button>
<Divider className="!my-1" /> <Divider className="!my-1" />
<button className={s.actionItem} onClick={onClickDuplicate} disabled={detailState.loading}> {app.mode !== 'completion' && (
<span className={s.actionName}>{t('app.duplicate')}</span> <>
</button> <button className={s.actionItem} onClick={onClickDuplicate} disabled={detailState.loading}>
<button className={s.actionItem} onClick={onClickExport} disabled={detailState.loading}> <span className={s.actionName}>{t('app.duplicate')}</span>
<span className={s.actionName}>{t('app.export')}</span> </button>
</button> <button className={s.actionItem} onClick={onClickExport} disabled={detailState.loading}>
<Divider className="!my-1" /> <span className={s.actionName}>{t('app.export')}</span>
</button>
<Divider className="!my-1" />
</>
)}
<div <div
className={cn(s.actionItem, s.deleteActionItem, 'group')} className={cn(s.actionItem, s.deleteActionItem, 'group')}
onClick={onClickDelete} onClick={onClickDelete}
......
...@@ -49,11 +49,10 @@ const Apps = () => { ...@@ -49,11 +49,10 @@ const Apps = () => {
) )
const anchorRef = useRef<HTMLDivElement>(null) const anchorRef = useRef<HTMLDivElement>(null)
// #TODO# query key ???
const options = [ const options = [
{ value: 'all', text: t('app.types.all') }, { value: 'all', text: t('app.types.all') },
{ value: 'chat', text: t('app.types.chatbot') }, { value: 'chat', text: t('app.types.chatbot') },
{ value: 'agent-chat', text: t('app.types.agent') }, { value: 'agent', text: t('app.types.agent') },
{ value: 'workflow', text: t('app.types.workflow') }, { value: 'workflow', text: t('app.types.workflow') },
] ]
......
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/navigation'
import { useContext, useContextSelector } from 'use-context-selector'
import cn from 'classnames'
import React, { useCallback, useState } from 'react'
import AppIcon from '../base/app-icon'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
import Divider from '@/app/components/base/divider'
import Confirm from '@/app/components/base/confirm'
import { useStore as useAppStore } from '@/app/components/app/store'
import { ToastContext } from '@/app/components/base/toast'
import AppsContext from '@/context/app-context'
import { useProviderContext } from '@/context/provider-context'
import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps'
import DuplicateAppModal from '@/app/components/app/duplicate-modal'
import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal'
import CreateAppModal from '@/app/components/explore/create-app-modal'
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection'
export type IAppInfoProps = {
expand: boolean
}
const AppInfo = ({ expand }: IAppInfoProps) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const { replace } = useRouter()
const { onPlanInfoChanged } = useProviderContext()
const appDetail = useAppStore(state => state.appDetail)
const setAppDetail = useAppStore(state => state.setAppDetail)
const [open, setOpen] = useState(false)
const [showEditModal, setShowEditModal] = useState(false)
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
const mutateApps = useContextSelector(
AppsContext,
state => state.mutateApps,
)
const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({
name,
icon,
icon_background,
description,
}) => {
if (!appDetail)
return
try {
const app = await updateAppInfo({
appID: appDetail.id,
name,
icon,
icon_background,
description,
})
setShowEditModal(false)
notify({
type: 'success',
message: t('app.editDone'),
})
console.log(app.description)
setAppDetail(app)
mutateApps()
}
catch (e) {
notify({ type: 'error', message: t('app.editFailed') })
}
}, [appDetail, mutateApps, notify, setAppDetail, t])
const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon, icon_background }) => {
if (!appDetail)
return
try {
const newApp = await copyApp({
appID: appDetail.id,
name,
icon,
icon_background,
mode: appDetail.mode,
})
setShowDuplicateModal(false)
notify({
type: 'success',
message: t('app.newApp.appCreated'),
})
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
mutateApps()
onPlanInfoChanged()
getRedirection(true, newApp, replace)
}
catch (e) {
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
}
}
const onExport = async () => {
if (!appDetail)
return
try {
const { data } = await exportAppConfig(appDetail.id)
const a = document.createElement('a')
const file = new Blob([data], { type: 'application/yaml' })
a.href = URL.createObjectURL(file)
a.download = `${appDetail.name}.yml`
a.click()
}
catch (e) {
notify({ type: 'error', message: t('app.exportFailed') })
}
}
const onConfirmDelete = useCallback(async () => {
if (!appDetail)
return
try {
await deleteApp(appDetail.id)
notify({ type: 'success', message: t('app.appDeleted') })
mutateApps()
onPlanInfoChanged()
replace('/apps')
}
catch (e: any) {
notify({
type: 'error',
message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,
})
}
setShowConfirmDelete(false)
}, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, t])
if (!appDetail)
return null
return (
<PortalToFollowElem
open={open}
onOpenChange={setOpen}
placement='bottom-start'
offset={4}
>
<div className='relative'>
<PortalToFollowElemTrigger
onClick={() => setOpen(v => !v)}
className='block'
>
<div className='flex cursor-pointer'>
<div className='shrink-0 mr-2'>
<AppIcon icon={appDetail.icon} background={appDetail.icon_background} />
</div>
{expand && (
<div className="grow w-0 pt-[2px]">
<div className='flex justify-between items-center text-sm leading-4 font-medium text-gray-900'>
<div className='truncate' title={appDetail.name}>{appDetail.name}</div>
<ChevronDown className='shrink-0 ml-[2px] w-3 h-3 text-gray-500' />
</div>
<div className='flex items-center text-xs leading-[18px] font-medium text-gray-500 gap-1'>
{appDetail.mode === 'advanced-chat' && (
<>
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div>
<div title={t('app.newApp.advanced') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.newApp.advanced').toUpperCase()}</div>
</>
)}
{appDetail.mode === 'agent-chat' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.agent').toUpperCase()}</div>
)}
{appDetail.mode === 'chat' && (
<>
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div>
<div title={t('app.newApp.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.newApp.basic').toUpperCase())}</div>
</>
)}
{appDetail.mode === 'completion' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.completion').toUpperCase()}</div>
)}
{appDetail.mode === 'workflow' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.workflow').toUpperCase()}</div>
)}
</div>
</div>
)}
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-[1002]'>
<div className='w-[320px] bg-white rounded-2xl shadow-xl'>
{/* header */}
<div className={cn('flex pl-4 pt-3 pr-3', !appDetail.description && 'pb-2')}>
<div className='shrink-0 mr-2'>
<AppIcon icon={appDetail.icon} background={appDetail.icon_background} />
</div>
<div className='grow w-0 pt-[2px]'>
<div title={appDetail.name} className='flex justify-between items-center text-sm leading-4 font-medium text-gray-900 truncate'>{appDetail.name}</div>
<div className='flex items-center text-xs leading-[18px] font-medium text-gray-500 gap-1'>
{appDetail.mode === 'advanced-chat' && (
<>
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div>
<div title={t('app.newApp.advanced') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.newApp.advanced').toUpperCase()}</div>
</>
)}
{appDetail.mode === 'agent-chat' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.agent').toUpperCase()}</div>
)}
{appDetail.mode === 'chat' && (
<>
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div>
<div title={t('app.newApp.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.newApp.basic').toUpperCase())}</div>
</>
)}
{appDetail.mode === 'completion' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.completion').toUpperCase()}</div>
)}
{appDetail.mode === 'workflow' && (
<div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.workflow').toUpperCase()}</div>
)}
</div>
</div>
</div>
{/* desscription */}
{appDetail.description && (
<div className='px-4 py-2 text-gray-500 text-xs leading-[18px]'>{appDetail.description}</div>
)}
{/* operations */}
<div></div>
<Divider className="!my-1" />
<div className="w-full py-1">
<div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={() => {
setOpen(false)
setShowEditModal(true)
}}>
<span className='text-gray-700 text-sm leading-5'>{t('app.editApp')}</span>
</div>
{appDetail.mode !== 'completion' && (
<>
<div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={() => {
setOpen(false)
setShowDuplicateModal(true)
}}>
<span className='text-gray-700 text-sm leading-5'>{t('app.duplicate')}</span>
</div>
<div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={onExport}>
<span className='text-gray-700 text-sm leading-5'>{t('app.export')}</span>
</div>
</>
)}
<Divider className="!my-1" />
<div className='group h-9 py-2 px-3 mx-1 flex items-center hover:bg-red-50 rounded-lg cursor-pointer' onClick={() => {
setOpen(false)
setShowConfirmDelete(true)
}}>
<span className='text-gray-700 text-sm leading-5 group-hover:text-red-500'>
{t('common.operation.delete')}
</span>
</div>
</div>
</div>
</PortalToFollowElemContent>
{showEditModal && (
<CreateAppModal
isEditModal
appIcon={appDetail.icon}
appIconBackground={appDetail.icon_background}
appName={appDetail.name}
appDescription={appDetail.description}
show={showEditModal}
onConfirm={onEdit}
onHide={() => setShowEditModal(false)}
/>
)}
{showDuplicateModal && (
<DuplicateAppModal
appName={appDetail.name}
icon={appDetail.icon}
icon_background={appDetail.icon_background}
show={showDuplicateModal}
onConfirm={onCopy}
onHide={() => setShowDuplicateModal(false)}
/>
)}
{showConfirmDelete && (
<Confirm
title={t('app.deleteAppConfirmTitle')}
content={t('app.deleteAppConfirmContent')}
isShow={showConfirmDelete}
onClose={() => setShowConfirmDelete(false)}
onConfirm={onConfirmDelete}
onCancel={() => setShowConfirmDelete(false)}
/>
)}
</div>
</PortalToFollowElem>
)
}
export default React.memo(AppInfo)
...@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react' ...@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react'
import NavLink from './navLink' import NavLink from './navLink'
import type { NavIcon } from './navLink' import type { NavIcon } from './navLink'
import AppBasic from './basic' import AppBasic from './basic'
import AppInfo from './app-info'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { import {
AlignLeft01, AlignLeft01,
...@@ -62,14 +63,19 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf ...@@ -62,14 +63,19 @@ const AppDetailNav = ({ title, desc, icon, icon_background, navigation, extraInf
${expand ? 'p-4' : 'p-2'} ${expand ? 'p-4' : 'p-2'}
`} `}
> >
<AppBasic {iconType === 'app' && (
mode={modeState} <AppInfo expand={expand}/>
iconType={iconType} )}
icon={icon} {iconType !== 'app' && (
icon_background={icon_background} <AppBasic
name={title} mode={modeState}
type={desc} iconType={iconType}
/> icon={icon}
icon_background={icon_background}
name={title}
type={desc}
/>
)}
</div> </div>
<nav <nav
className={` className={`
......
...@@ -149,7 +149,10 @@ const Apps = ({ ...@@ -149,7 +149,10 @@ const Apps = ({
</div> </div>
{isShowCreateModal && ( {isShowCreateModal && (
<CreateAppModal <CreateAppModal
appIcon={currApp?.app.icon || ''}
appIconBackground={currApp?.app.icon_background || ''}
appName={currApp?.app.name || ''} appName={currApp?.app.name || ''}
appDescription={currApp?.app.description || ''}
show={isShowCreateModal} show={isShowCreateModal}
onConfirm={onCreate} onConfirm={onCreate}
onHide={() => setIsShowCreateModal(false)} onHide={() => setIsShowCreateModal(false)}
......
...@@ -11,9 +11,12 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog' ...@@ -11,9 +11,12 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { XClose } from '@/app/components/base/icons/src/vender/line/general' import { XClose } from '@/app/components/base/icons/src/vender/line/general'
export type CreateAppModalProps = { export type CreateAppModalProps = {
appName: string
appDescription?: string
show: boolean show: boolean
isEditModal?: boolean
appName: string
appDescription: string
appIcon: string
appIconBackground: string
onConfirm: (info: { onConfirm: (info: {
name: string name: string
icon: string icon: string
...@@ -24,9 +27,12 @@ export type CreateAppModalProps = { ...@@ -24,9 +27,12 @@ export type CreateAppModalProps = {
} }
const CreateAppModal = ({ const CreateAppModal = ({
show = false,
isEditModal = false,
appIcon,
appIconBackground,
appName, appName,
appDescription, appDescription,
show = false,
onConfirm, onConfirm,
onHide, onHide,
}: CreateAppModalProps) => { }: CreateAppModalProps) => {
...@@ -34,7 +40,7 @@ const CreateAppModal = ({ ...@@ -34,7 +40,7 @@ const CreateAppModal = ({
const [name, setName] = React.useState(appName) const [name, setName] = React.useState(appName)
const [showEmojiPicker, setShowEmojiPicker] = useState(false) const [showEmojiPicker, setShowEmojiPicker] = useState(false)
const [emoji, setEmoji] = useState({ icon: '🤖', icon_background: '#FFEAD5' }) const [emoji, setEmoji] = useState({ icon: appIcon, icon_background: appIconBackground })
const [description, setDescription] = useState(appDescription || '') const [description, setDescription] = useState(appDescription || '')
const { plan, enableBilling } = useProviderContext() const { plan, enableBilling } = useProviderContext()
...@@ -64,7 +70,12 @@ const CreateAppModal = ({ ...@@ -64,7 +70,12 @@ const CreateAppModal = ({
<div className='absolute right-4 top-4 p-2 cursor-pointer' onClick={onHide}> <div className='absolute right-4 top-4 p-2 cursor-pointer' onClick={onHide}>
<XClose className='w-4 h-4 text-gray-500' /> <XClose className='w-4 h-4 text-gray-500' />
</div> </div>
<div className='mb-9 font-semibold text-xl leading-[30px] text-gray-900'>{t('explore.appCustomize.title', { name: appName })}</div> {isEditModal && (
<div className='mb-9 font-semibold text-xl leading-[30px] text-gray-900'>{t('app.editAppTitle')}</div>
)}
{!isEditModal && (
<div className='mb-9 font-semibold text-xl leading-[30px] text-gray-900'>{t('explore.appCustomize.title', { name: appName })}</div>
)}
<div className='mb-9'> <div className='mb-9'>
{/* icon & name */} {/* icon & name */}
<div className='pt-2'> <div className='pt-2'>
...@@ -78,16 +89,6 @@ const CreateAppModal = ({ ...@@ -78,16 +89,6 @@ const CreateAppModal = ({
className='grow h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg border border-transparent outline-none appearance-none caret-primary-600 placeholder:text-gray-400 hover:bg-gray-50 hover:border hover:border-gray-300 focus:bg-gray-50 focus:border focus:border-gray-300 focus:shadow-xs' className='grow h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg border border-transparent outline-none appearance-none caret-primary-600 placeholder:text-gray-400 hover:bg-gray-50 hover:border hover:border-gray-300 focus:bg-gray-50 focus:border focus:border-gray-300 focus:shadow-xs'
/> />
</div> </div>
{showEmojiPicker && <EmojiPicker
onSelect={(icon, icon_background) => {
setEmoji({ icon, icon_background })
setShowEmojiPicker(false)
}}
onClose={() => {
setEmoji({ icon: '🤖', icon_background: '#FFEAD5' })
setShowEmojiPicker(false)
}}
/>}
</div> </div>
{/* description */} {/* description */}
<div className='pt-2'> <div className='pt-2'>
...@@ -99,10 +100,10 @@ const CreateAppModal = ({ ...@@ -99,10 +100,10 @@ const CreateAppModal = ({
onChange={e => setDescription(e.target.value)} onChange={e => setDescription(e.target.value)}
/> />
</div> </div>
{isAppsFull && <AppsFull loc='app-explore-create' />} {!isEditModal && isAppsFull && <AppsFull loc='app-explore-create' />}
</div> </div>
<div className='flex flex-row-reverse'> <div className='flex flex-row-reverse'>
<Button disabled={isAppsFull} className='w-24 ml-2' type='primary' onClick={submit}>{t('common.operation.create')}</Button> <Button disabled={!isEditModal && isAppsFull} className='w-24 ml-2' type='primary' onClick={submit}>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</Button>
<Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button> <Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
</div> </div>
</Modal> </Modal>
...@@ -112,7 +113,7 @@ const CreateAppModal = ({ ...@@ -112,7 +113,7 @@ const CreateAppModal = ({
setShowEmojiPicker(false) setShowEmojiPicker(false)
}} }}
onClose={() => { onClose={() => {
setEmoji({ icon: '🤖', icon_background: '#FFEAD5' }) setEmoji({ icon: appIcon, icon_background: appIconBackground })
setShowEmojiPicker(false) setShowEmojiPicker(false)
}} }}
/>} />}
......
...@@ -58,9 +58,10 @@ const translation = { ...@@ -58,9 +58,10 @@ const translation = {
appCreated: 'App created', appCreated: 'App created',
appCreateFailed: 'Failed to create app', appCreateFailed: 'Failed to create app',
}, },
editApp: { editApp: 'Edit Info',
startToEdit: 'Edit App', editAppTitle: 'Edit App Info',
}, editDone: 'App info updated',
editFailed: 'Failed to update app info',
emoji: { emoji: {
ok: 'OK', ok: 'OK',
cancel: 'Cancel', cancel: 'Cancel',
......
...@@ -57,9 +57,10 @@ const translation = { ...@@ -57,9 +57,10 @@ const translation = {
appCreated: '应用已创建', appCreated: '应用已创建',
appCreateFailed: '应用创建失败', appCreateFailed: '应用创建失败',
}, },
editApp: { editApp: '编辑信息',
startToEdit: '编辑应用', editAppTitle: '编辑应用信息',
}, editDone: '应用信息已更新',
editFailed: '更新应用信息失败',
emoji: { emoji: {
ok: '确认', ok: '确认',
cancel: '取消', cancel: '取消',
......
import type { AppMode } from '@/types/app' import type { AppMode } from '@/types/app'
export type AppBasicInfo = { export type AppBasicInfo = {
id: string id: string
name: string
mode: AppMode mode: AppMode
icon: string icon: string
icon_background: string icon_background: string
is_agent: boolean name: string
description: string
} }
export type AppCategory = 'Writing' | 'Translate' | 'HR' | 'Programming' | 'Assistant' export type AppCategory = 'Writing' | 'Translate' | 'HR' | 'Programming' | 'Assistant'
......
import type { Fetcher } from 'swr' import type { Fetcher } from 'swr'
import { del, get, post } from './base' import { del, get, post, put } from './base'
import type { ApikeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDetailResponse, AppListResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, GenerationIntroductionResponse, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse } from '@/models/app' import type { ApikeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDetailResponse, AppListResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, GenerationIntroductionResponse, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse } from '@/models/app'
import type { CommonResponse } from '@/models/common' import type { CommonResponse } from '@/models/common'
import type { AppMode, ModelConfig } from '@/types/app' import type { AppMode, ModelConfig } from '@/types/app'
...@@ -20,6 +20,10 @@ export const createApp: Fetcher<AppDetailResponse, { name: string; icon: string; ...@@ -20,6 +20,10 @@ export const createApp: Fetcher<AppDetailResponse, { name: string; icon: string;
return post<AppDetailResponse>('apps', { body: { name, icon, icon_background, mode, description, model_config: config } }) return post<AppDetailResponse>('apps', { body: { name, icon, icon_background, mode, description, model_config: config } })
} }
export const updateAppInfo: Fetcher<AppDetailResponse, { appID: string; name: string; icon: string; icon_background: string; description: string }> = ({ appID, name, icon, icon_background, description }) => {
return put<AppDetailResponse>(`apps/${appID}`, { body: { name, icon, icon_background, description } })
}
export const copyApp: Fetcher<AppDetailResponse, { appID: string; name: string; icon: string; icon_background: string; mode: AppMode; description?: string }> = ({ appID, name, icon, icon_background, mode, description }) => { export const copyApp: Fetcher<AppDetailResponse, { appID: string; name: string; icon: string; icon_background: string; mode: AppMode; description?: string }> = ({ appID, name, icon, icon_background, mode, description }) => {
return post<AppDetailResponse>(`apps/${appID}/copy`, { body: { name, icon, icon_background, mode, description } }) return post<AppDetailResponse>(`apps/${appID}/copy`, { body: { name, icon, icon_background, mode, description } })
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment