mirror of https://github.com/langgenius/dify.git
app list modification
This commit is contained in:
parent
171dd5c737
commit
117b84116e
|
|
@ -13,7 +13,9 @@ import type { ConfigParams } from '@/app/components/app/overview/settings'
|
|||
import type { App } from '@/types/app'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
import { deleteApp, fetchAppDetail, updateAppSiteConfig } from '@/service/apps'
|
||||
import { createApp, deleteApp, fetchAppDetail, updateAppSiteConfig } from '@/service/apps'
|
||||
import DuplicateAppModal from '@/app/components/app/duplicate-modal'
|
||||
import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import AppsContext, { useAppContext } from '@/context/app-context'
|
||||
import type { HtmlContentProps } from '@/app/components/base/popover'
|
||||
|
|
@ -21,6 +23,7 @@ import CustomPopover from '@/app/components/base/popover'
|
|||
import Divider from '@/app/components/base/divider'
|
||||
import { asyncRunSafe } from '@/utils'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
|
||||
export type AppCardProps = {
|
||||
app: App
|
||||
|
|
@ -39,8 +42,9 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
state => state.mutateApps,
|
||||
)
|
||||
|
||||
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
|
||||
const [showSettingsModal, setShowSettingsModal] = useState(false)
|
||||
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
|
||||
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
|
||||
const [detailState, setDetailState] = useState<{
|
||||
loading: boolean
|
||||
detail?: App
|
||||
|
|
@ -69,11 +73,10 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
const [err, res] = await asyncRunSafe(
|
||||
fetchAppDetail({ url: '/apps', id: app.id }),
|
||||
)
|
||||
if (!err) {
|
||||
if (!err)
|
||||
setDetailState({ loading: false, detail: res })
|
||||
setShowSettingsModal(true)
|
||||
}
|
||||
else { setDetailState({ loading: false }) }
|
||||
else
|
||||
setDetailState({ loading: false })
|
||||
}
|
||||
|
||||
const onSaveSiteConfig = useCallback(
|
||||
|
|
@ -103,12 +106,49 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
[app.id],
|
||||
)
|
||||
|
||||
const onCreate: DuplicateAppModalProps['onConfirm'] = async ({ name, icon, icon_background }) => {
|
||||
const { app_model_config: model_config } = await fetchAppDetail({ url: '/apps', id: app.id })
|
||||
|
||||
try {
|
||||
const newApp = await createApp({
|
||||
name,
|
||||
icon,
|
||||
icon_background,
|
||||
mode: app.mode,
|
||||
config: model_config,
|
||||
})
|
||||
setShowDuplicateModal(false)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('app.newApp.appCreated'),
|
||||
})
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
push(`/app/${newApp.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`)
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
}
|
||||
|
||||
const Operations = (props: HtmlContentProps) => {
|
||||
const onClickSettings = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
props.onClick?.()
|
||||
e.preventDefault()
|
||||
await getAppDetail()
|
||||
setShowSettingsModal(true)
|
||||
}
|
||||
const onClickDuplicate = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
props.onClick?.()
|
||||
e.preventDefault()
|
||||
setShowDuplicateModal(true)
|
||||
}
|
||||
const onClickExport = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
props.onClick?.()
|
||||
e.preventDefault()
|
||||
// TODO export
|
||||
}
|
||||
const onClickDelete = async (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation()
|
||||
|
|
@ -121,7 +161,13 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
<button className={s.actionItem} onClick={onClickSettings} disabled={detailState.loading}>
|
||||
<span className={s.actionName}>{t('common.operation.settings')}</span>
|
||||
</button>
|
||||
|
||||
<Divider className="!my-1" />
|
||||
<button className={s.actionItem} onClick={onClickDuplicate} disabled={detailState.loading}>
|
||||
<span className={s.actionName}>{t('app.duplicate')}</span>
|
||||
</button>
|
||||
<button className={s.actionItem} onClick={onClickExport} disabled={detailState.loading}>
|
||||
<span className={s.actionName}>{t('app.export')}</span>
|
||||
</button>
|
||||
<Divider className="!my-1" />
|
||||
<div
|
||||
className={cn(s.actionItem, s.deleteActionItem, 'group')}
|
||||
|
|
@ -149,7 +195,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
>
|
||||
<div className={style.listItemTitle}>
|
||||
<AppIcon
|
||||
size="small"
|
||||
size="large"
|
||||
icon={app.icon}
|
||||
background={app.icon_background}
|
||||
/>
|
||||
|
|
@ -175,9 +221,26 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
{app.model_config?.pre_prompt}
|
||||
</div>
|
||||
<div className={style.listItemFooter}>
|
||||
<AppModeLabel mode={app.mode} isAgent={app.is_agent} />
|
||||
<AppModeLabel mode={app.mode} />
|
||||
</div>
|
||||
|
||||
{showSettingsModal && detailState.detail && (
|
||||
<SettingsModal
|
||||
appInfo={detailState.detail}
|
||||
isShow={showSettingsModal}
|
||||
onClose={() => setShowSettingsModal(false)}
|
||||
onSave={onSaveSiteConfig}
|
||||
/>
|
||||
)}
|
||||
{showDuplicateModal && (
|
||||
<DuplicateAppModal
|
||||
appName={app.name}
|
||||
icon={app.icon}
|
||||
icon_background={app.icon_background}
|
||||
show={showDuplicateModal}
|
||||
onConfirm={onCreate}
|
||||
onHide={() => setShowDuplicateModal(false)}
|
||||
/>
|
||||
)}
|
||||
{showConfirmDelete && (
|
||||
<Confirm
|
||||
title={t('app.deleteAppConfirmTitle')}
|
||||
|
|
@ -188,14 +251,6 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||
onCancel={() => setShowConfirmDelete(false)}
|
||||
/>
|
||||
)}
|
||||
{showSettingsModal && detailState.detail && (
|
||||
<SettingsModal
|
||||
appInfo={detailState.detail}
|
||||
isShow={showSettingsModal}
|
||||
onClose={() => setShowSettingsModal(false)}
|
||||
onSave={onSaveSiteConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,52 +2,40 @@
|
|||
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { type AppMode } from '@/types/app'
|
||||
import {
|
||||
AiText,
|
||||
CuteRobote,
|
||||
} from '@/app/components/base/icons/src/vender/solid/communication'
|
||||
import { CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication'
|
||||
import { BubbleText } from '@/app/components/base/icons/src/vender/solid/education'
|
||||
import { Route } from '@/app/components/base/icons/src/vender/line/mapsAndTravel'
|
||||
|
||||
export type AppModeLabelProps = {
|
||||
mode: AppMode
|
||||
isAgent?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
const AppModeLabel = ({
|
||||
mode,
|
||||
isAgent,
|
||||
className,
|
||||
}: AppModeLabelProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className={`inline-flex items-center px-2 h-6 rounded-md border border-gray-100 text-xs text-gray-500 ${className}`}>
|
||||
{
|
||||
mode === 'completion' && (
|
||||
<>
|
||||
<AiText className='mr-1 w-3 h-3 text-gray-400' />
|
||||
{t('app.newApp.completeApp')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
mode === 'chat' && !isAgent && (
|
||||
<>
|
||||
<BubbleText className='mr-1 w-3 h-3 text-gray-400' />
|
||||
{t('appDebug.assistantType.chatAssistant.name')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
mode === 'chat' && isAgent && (
|
||||
<>
|
||||
<CuteRobote className='mr-1 w-3 h-3 text-gray-400' />
|
||||
{t('appDebug.assistantType.agentAssistant.name')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<>
|
||||
{mode === 'chat' && (
|
||||
<div className='inline-flex items-center px-2 h-6 rounded-md bg-indigo-25 border border-indigo-100 text-xs text-indigo-600'>
|
||||
<BubbleText className='mr-1 w-3 h-3' />
|
||||
{t('app.types.chatbot')}
|
||||
</div>
|
||||
)}
|
||||
{mode === 'agent' && (
|
||||
<div className='inline-flex items-center px-2 h-6 rounded-md bg-indigo-25 border border-indigo-100 text-xs text-indigo-600'>
|
||||
<CuteRobote className='mr-1 w-3 h-3' />
|
||||
{t('app.types.agent')}
|
||||
</div>
|
||||
)}
|
||||
{mode === 'workflow' && (
|
||||
<div className='inline-flex items-center px-2 h-6 rounded-md bg-[#fffcf5] border border-[#fef0c7] text-xs text-[#f79009]'>
|
||||
<Route className='mr-1 w-3 h-3' />
|
||||
{t('app.types.workflow')}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { fetchAppList } from '@/service/apps'
|
|||
import { useAppContext } from '@/context/app-context'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import { CheckModal } from '@/hooks/use-pay'
|
||||
import TabSlider from '@/app/components/base/tab-slider'
|
||||
import TabSliderNew from '@/app/components/base/tab-slider-new'
|
||||
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
|
||||
|
||||
|
|
@ -48,8 +48,9 @@ const Apps = () => {
|
|||
const anchorRef = useRef<HTMLDivElement>(null)
|
||||
const options = [
|
||||
{ value: 'all', text: t('app.types.all') },
|
||||
{ value: 'chat', text: t('app.types.assistant') },
|
||||
{ value: 'completion', text: t('app.types.completion') },
|
||||
{ value: 'chat', text: t('app.types.chatbot') },
|
||||
{ value: 'agent', text: t('app.types.agent') },
|
||||
{ value: 'workflow', text: t('app.types.workflow') },
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -88,6 +89,11 @@ const Apps = () => {
|
|||
return (
|
||||
<>
|
||||
<div className='sticky top-0 flex justify-between items-center pt-4 px-12 pb-2 leading-[56px] bg-gray-100 z-10 flex-wrap gap-y-2'>
|
||||
<TabSliderNew
|
||||
value={activeTab}
|
||||
onChange={setActiveTab}
|
||||
options={options}
|
||||
/>
|
||||
<div className="flex items-center px-2 w-[200px] h-8 rounded-lg bg-gray-200">
|
||||
<div className="pointer-events-none shrink-0 flex items-center mr-1.5 justify-center w-4 h-4">
|
||||
<SearchLg className="h-3.5 w-3.5 text-gray-500" aria-hidden="true" />
|
||||
|
|
@ -114,12 +120,6 @@ const Apps = () => {
|
|||
)
|
||||
}
|
||||
</div>
|
||||
<TabSlider
|
||||
value={activeTab}
|
||||
onChange={setActiveTab}
|
||||
options={options}
|
||||
/>
|
||||
|
||||
</div>
|
||||
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
|
||||
{isCurrentWorkspaceManager
|
||||
|
|
|
|||
|
|
@ -1,32 +1,42 @@
|
|||
'use client'
|
||||
|
||||
import { forwardRef, useState } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import style from '../list.module.css'
|
||||
import NewAppDialog from './NewAppDialog'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
|
||||
export type CreateAppCardProps = {
|
||||
onSuccess?: () => void
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuccess }, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { onPlanInfoChanged } = useProviderContext()
|
||||
|
||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
||||
return (
|
||||
<a ref={ref} className={classNames(style.listItem, style.newItemCard)} onClick={() => setShowNewAppDialog(true)}>
|
||||
<div className={style.listItemTitle}>
|
||||
<span className={style.newItemIcon}>
|
||||
<span className={classNames(style.newItemIconImage, style.newItemIconAdd)} />
|
||||
</span>
|
||||
<div className={classNames(style.listItemHeading, style.newItemCardHeading)}>
|
||||
{t('app.createApp')}
|
||||
<a
|
||||
ref={ref}
|
||||
onClick={() => setShowNewAppDialog(true)}
|
||||
className='relative col-span-1 flex flex-col justify-between min-h-[160px] bg-gray-200 rounded-xl cursor-pointer duration-200 ease-in-out hover:bg-gray-50 hover:shadow-lg transition-colors'
|
||||
>
|
||||
<div className='grow rounded-t-xl group hover:bg-white'>
|
||||
<div className='flex pt-4 px-4 pb-3 h-[66px] items-center gap-3 grow-0 shrink-0'>
|
||||
<span className='w-10 h-10 p-3 bg-gray-100 rounded-lg border border-gray-200 group-hover:bg-primary-50 group-hover:border-primary-100'>
|
||||
<Plus className='w-4 h-4 text-gray-500 group-hover:text-primary-600'/>
|
||||
</span>
|
||||
<div className='relative grow h-8 text-sm font-medium leading-8 transition-colors duration-200 ease-in-out group-hover:text-primary-600'>
|
||||
{t('app.createApp')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className='text-xs text-gray-500'>{t('app.createFromConfigFile')}</div> */}
|
||||
<div className='flex items-center px-4 py-3 border-t-[0.5px] border-black/[.05] rounded-b-xl text-xs leading-[18px] text-gray-500 hover:bg-white hover:text-primary-600'>
|
||||
{t('app.createFromConfigFile')}
|
||||
<ArrowUpRight className='ml-1 w-3 h-3'/>
|
||||
</div>
|
||||
<NewAppDialog show={showNewAppDialog} onSuccess={
|
||||
() => {
|
||||
onPlanInfoChanged()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
mask-image: url(~@/assets/action.svg);
|
||||
}
|
||||
.actionItem {
|
||||
@apply h-9 py-2 px-3 mx-1 flex items-center gap-2 hover:bg-gray-100 rounded-lg cursor-pointer;
|
||||
@apply h-8 py-[6px] px-3 mx-1 flex items-center gap-2 hover:bg-gray-100 rounded-lg cursor-pointer;
|
||||
width: calc(100% - 0.5rem);
|
||||
}
|
||||
.deleteActionItem {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import Datasets from './Datasets'
|
|||
import DatasetFooter from './DatasetFooter'
|
||||
import ApiServer from './ApiServer'
|
||||
import Doc from './Doc'
|
||||
import TabSlider from '@/app/components/base/tab-slider'
|
||||
import TabSliderNew from '@/app/components/base/tab-slider-new'
|
||||
|
||||
// Services
|
||||
import { fetchDatasetApiBaseUrl } from '@/service/datasets'
|
||||
|
|
@ -30,7 +30,7 @@ const Container = () => {
|
|||
return (
|
||||
<div ref={containerRef} className='grow relative flex flex-col bg-gray-100 overflow-y-auto'>
|
||||
<div className='sticky top-0 flex justify-between pt-4 px-12 pb-2 leading-[56px] bg-gray-100 z-10 flex-wrap gap-y-2'>
|
||||
<TabSlider
|
||||
<TabSliderNew
|
||||
value={activeTab}
|
||||
onChange={newActiveTab => setActiveTab(newActiveTab)}
|
||||
options={options}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.listItem {
|
||||
@apply col-span-1 bg-white border-2 border-solid border-transparent rounded-lg shadow-xs min-h-[160px] flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg;
|
||||
@apply col-span-1 bg-white border-2 border-solid border-transparent rounded-xl shadow-xs min-h-[160px] flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg;
|
||||
}
|
||||
|
||||
.listItem.newItemCard {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import cn from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import s from './style.module.css'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import EmojiPicker from '@/app/components/base/emoji-picker'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||
export type DuplicateAppModalProps = {
|
||||
appName: string
|
||||
icon: string
|
||||
icon_background: string
|
||||
show: boolean
|
||||
onConfirm: (info: {
|
||||
name: string
|
||||
icon: string
|
||||
icon_background: string
|
||||
}) => Promise<void>
|
||||
onHide: () => void
|
||||
}
|
||||
|
||||
const DuplicateAppModal = ({
|
||||
appName,
|
||||
icon,
|
||||
icon_background,
|
||||
show = false,
|
||||
onConfirm,
|
||||
onHide,
|
||||
}: DuplicateAppModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [name, setName] = React.useState(appName)
|
||||
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false)
|
||||
const [emoji, setEmoji] = useState({ icon, icon_background })
|
||||
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||
|
||||
const submit = () => {
|
||||
if (!name.trim()) {
|
||||
Toast.notify({ type: 'error', message: t('explore.appCustomize.nameRequired') })
|
||||
return
|
||||
}
|
||||
onConfirm({
|
||||
name,
|
||||
...emoji,
|
||||
})
|
||||
onHide()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
isShow={show}
|
||||
onClose={() => { }}
|
||||
className={cn(s.modal, '!max-w-[480px]', 'px-8')}
|
||||
>
|
||||
<span className={s.close} onClick={onHide} />
|
||||
<div className={s.title}>{t('app.duplicateTitle')}</div>
|
||||
<div className={s.content}>
|
||||
<div className={s.subTitle}>{t('explore.appCustomize.subTitle')}</div>
|
||||
<div className='flex items-center justify-between space-x-3'>
|
||||
<AppIcon size='large' onClick={() => { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} />
|
||||
<input
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
className='h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg grow'
|
||||
/>
|
||||
</div>
|
||||
{/* TODO loc */}
|
||||
{isAppsFull && <AppsFull loc='app-duplicate-create' />}
|
||||
</div>
|
||||
<div className='flex flex-row-reverse'>
|
||||
<Button disabled={isAppsFull} className='w-24 ml-2' type='primary' onClick={submit}>{t('app.duplicate')}</Button>
|
||||
<Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
{showEmojiPicker && <EmojiPicker
|
||||
onSelect={(icon, icon_background) => {
|
||||
setEmoji({ icon, icon_background })
|
||||
setShowEmojiPicker(false)
|
||||
}}
|
||||
onClose={() => {
|
||||
setEmoji({ icon, icon_background })
|
||||
setShowEmojiPicker(false)
|
||||
}}
|
||||
/>}
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default DuplicateAppModal
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
.modal {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.modal .close {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 25px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
background: center no-repeat url(~@/app/components/datasets/create/assets/close.svg);
|
||||
background-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal .title {
|
||||
@apply mb-9;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.modal .content {
|
||||
@apply mb-9;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="route" clip-path="url(#clip0_664_8452)">
|
||||
<path id="Icon" d="M5.75 2.5H5.9672C7.49082 2.5 8.25263 2.5 8.54182 2.77364C8.79179 3.01018 8.90257 3.35864 8.83508 3.69611C8.75701 4.08651 8.13505 4.52643 6.89114 5.40627L4.85886 6.84373C3.61495 7.72357 2.99299 8.16349 2.91492 8.5539C2.84743 8.89136 2.95821 9.23982 3.20818 9.47636C3.49737 9.75 4.25918 9.75 5.7828 9.75H6.25M4 2.5C4 3.32843 3.32843 4 2.5 4C1.67157 4 1 3.32843 1 2.5C1 1.67157 1.67157 1 2.5 1C3.32843 1 4 1.67157 4 2.5ZM11 9.5C11 10.3284 10.3284 11 9.5 11C8.67157 11 8 10.3284 8 9.5C8 8.67157 8.67157 8 9.5 8C10.3284 8 11 8.67157 11 9.5Z" stroke="#F79009" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_664_8452">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 900 B |
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "12",
|
||||
"viewBox": "0 0 12 12",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "route",
|
||||
"clip-path": "url(#clip0_664_8452)"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"d": "M5.75 2.5H5.9672C7.49082 2.5 8.25263 2.5 8.54182 2.77364C8.79179 3.01018 8.90257 3.35864 8.83508 3.69611C8.75701 4.08651 8.13505 4.52643 6.89114 5.40627L4.85886 6.84373C3.61495 7.72357 2.99299 8.16349 2.91492 8.5539C2.84743 8.89136 2.95821 9.23982 3.20818 9.47636C3.49737 9.75 4.25918 9.75 5.7828 9.75H6.25M4 2.5C4 3.32843 3.32843 4 2.5 4C1.67157 4 1 3.32843 1 2.5C1 1.67157 1.67157 1 2.5 1C3.32843 1 4 1.67157 4 2.5ZM11 9.5C11 10.3284 10.3284 11 9.5 11C8.67157 11 8 10.3284 8 9.5C8 8.67157 8.67157 8 9.5 8C10.3284 8 11 8.67157 11 9.5Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.25",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "defs",
|
||||
"attributes": {},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "clipPath",
|
||||
"attributes": {
|
||||
"id": "clip0_664_8452"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "rect",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "12",
|
||||
"fill": "white"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Route"
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Route.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Route'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -1 +1,2 @@
|
|||
export { default as Globe01 } from './Globe01'
|
||||
export { default as Route } from './Route'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import type { FC } from 'react'
|
||||
import cn from 'classnames'
|
||||
|
||||
type Option = {
|
||||
value: string
|
||||
text: string
|
||||
}
|
||||
type TabSliderProps = {
|
||||
className?: string
|
||||
value: string
|
||||
onChange: (v: string) => void
|
||||
options: Option[]
|
||||
}
|
||||
const TabSliderNew: FC<TabSliderProps> = ({
|
||||
className,
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
}) => {
|
||||
return (
|
||||
<div className={cn(className, 'relative flex')}>
|
||||
{options.map(option => (
|
||||
<div
|
||||
key={option.value}
|
||||
onClick={() => onChange(option.value)}
|
||||
className={cn(
|
||||
'mr-1 px-3 py-[5px] h-[28px] rounded-lg border-[0.5px] border-transparent text-gray-700 text-[13px] font-medium leading-[18px] cursor-pointer hover:bg-gray-200',
|
||||
value === option.value && 'bg-white border-gray-200 shadow-xs text-primary-600 hover:bg-white',
|
||||
)}
|
||||
>
|
||||
{option.text}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabSliderNew
|
||||
|
|
@ -1,15 +1,19 @@
|
|||
const translation = {
|
||||
createApp: 'Create new App',
|
||||
createApp: 'Create App',
|
||||
types: {
|
||||
all: 'All',
|
||||
assistant: 'Assistant',
|
||||
completion: 'Completion',
|
||||
chatbot: 'Chatbot',
|
||||
agent: 'Agent',
|
||||
workflow: 'Workflow',
|
||||
},
|
||||
modes: {
|
||||
completion: 'Text Generator',
|
||||
chat: 'Basic Assistant',
|
||||
},
|
||||
createFromConfigFile: 'Create app from config file',
|
||||
duplicate: 'Duplicate',
|
||||
duplicateTitle: 'Duplicate App',
|
||||
export: 'Export DSL',
|
||||
createFromConfigFile: 'Create from DSL file',
|
||||
deleteAppConfirmTitle: 'Delete this app?',
|
||||
deleteAppConfirmContent:
|
||||
'Deleting the app is irreversible. Users will no longer be able to access your app, and all prompt configurations and logs will be permanently deleted.',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
const translation = {
|
||||
createApp: 'Criar novo aplicativo',
|
||||
createApp: 'Criar aplicativo',
|
||||
types: {
|
||||
all: 'Tudo',
|
||||
chatbot: 'Chatbot',
|
||||
agent: 'Agente',
|
||||
workflow: 'Fluxo de trabalho',
|
||||
},
|
||||
modes: {
|
||||
completion: 'Gerador de Texto',
|
||||
chat: 'Aplicativo de Chat',
|
||||
},
|
||||
createFromConfigFile: 'Criar aplicativo a partir do arquivo de configuração',
|
||||
duplicate: 'Duplicar',
|
||||
duplicateTitle: 'Duplicate aplicativo',
|
||||
export: 'Exportar DSL',
|
||||
createFromConfigFile: 'Criar através do arquivo DSL',
|
||||
deleteAppConfirmTitle: 'Excluir este aplicativo?',
|
||||
deleteAppConfirmContent:
|
||||
'A exclusão do aplicativo é irreversível. Os usuários não poderão mais acessar seu aplicativo e todas as configurações de prompt e logs serão excluídas permanentemente.',
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
const translation = { // Add the Ukrainian translation object
|
||||
createApp: 'Створити новий додаток',
|
||||
createApp: 'Створити додаток',
|
||||
types: {
|
||||
all: 'Всі',
|
||||
assistant: 'Асистент',
|
||||
completion: 'Автодоповнення',
|
||||
all: 'Все',
|
||||
chatbot: 'Чатбот',
|
||||
agent: 'Агент',
|
||||
workflow: 'Робочий Процес',
|
||||
},
|
||||
modes: {
|
||||
completion: 'Генератор тексту',
|
||||
chat: 'Базовий асистент',
|
||||
},
|
||||
createFromConfigFile: 'Створити додаток з файла конфігурації',
|
||||
duplicate: 'Дублювати',
|
||||
duplicateTitle: 'Дублювати додаток',
|
||||
export: 'Експортувати DSL',
|
||||
createFromConfigFile: 'Створити через файл DSL',
|
||||
deleteAppConfirmTitle: 'Видалити цей додаток?',
|
||||
deleteAppConfirmContent:
|
||||
'Видалення додатка є незворотнім. Користувачі більше не матимуть доступ до вашого додатка, всі конфігурації підказок та журнали будуть видалені назавжди.',
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@ const translation = {
|
|||
createApp: '创建应用',
|
||||
types: {
|
||||
all: '全部',
|
||||
assistant: '助手',
|
||||
completion: '文本生成',
|
||||
chatbot: '聊天助手',
|
||||
agent: 'Agent',
|
||||
workflow: '工作流',
|
||||
},
|
||||
modes: {
|
||||
completion: '文本生成型',
|
||||
chat: '基础助手',
|
||||
},
|
||||
createFromConfigFile: '通过导入应用配置文件创建',
|
||||
duplicate: '复制',
|
||||
duplicateTitle: '复制应用',
|
||||
export: '导出 DSL',
|
||||
createFromConfigFile: '通过 DSL 文件创建',
|
||||
deleteAppConfirmTitle: '确认删除应用?',
|
||||
deleteAppConfirmContent:
|
||||
'删除应用将无法撤销。用户将不能访问你的应用,所有 Prompt 编排配置和日志均将一并被删除。',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import type { App, AppTemplate, SiteConfig } from '@/types/app'
|
||||
|
||||
export type AppMode = 'chat' | 'completion'
|
||||
|
||||
/* export type App = {
|
||||
id: string
|
||||
name: string
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { AppMode } from './app'
|
||||
|
||||
import type { AppMode } from '@/types/app'
|
||||
export type AppBasicInfo = {
|
||||
id: string
|
||||
name: string
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export type VariableInput = {
|
|||
/**
|
||||
* App modes
|
||||
*/
|
||||
export const AppModes = ['completion', 'chat'] as const
|
||||
export const AppModes = ['agent', 'chat', 'workflow'] as const
|
||||
export type AppMode = typeof AppModes[number]
|
||||
|
||||
/**
|
||||
|
|
@ -286,7 +286,6 @@ export type App = {
|
|||
|
||||
/** Mode */
|
||||
mode: AppMode
|
||||
is_agent: boolean
|
||||
/** Enable web app */
|
||||
enable_site: boolean
|
||||
/** Enable web API */
|
||||
|
|
|
|||
Loading…
Reference in New Issue