mirror of https://github.com/langgenius/dify.git
feat: update chat app publishing
This commit is contained in:
parent
aca395b97d
commit
52a1c4580c
|
|
@ -5,55 +5,68 @@ import {
|
|||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import dayjs from 'dayjs'
|
||||
import classNames from 'classnames'
|
||||
import type { ModelAndParameter } from '../configuration/debug/types'
|
||||
import SuggestedAction from './suggested-action'
|
||||
import PublishWithMultipleModel from './publish-with-multiple-model'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import EmbeddedModal from '@/app/components/app/overview/embedded'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { PlayCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import { CodeBrowser } from '@/app/components/base/icons/src/vender/line/development'
|
||||
import { LeftIndent02 } from '@/app/components/base/icons/src/vender/line/editor'
|
||||
import { FileText } from '@/app/components/base/icons/src/vender/line/files'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
|
||||
export type AppPublisherProps = {
|
||||
disabled?: boolean
|
||||
publishDisabled?: boolean
|
||||
publishedAt?: number
|
||||
/** only needed in workflow / chatflow mode */
|
||||
draftUpdatedAt?: number
|
||||
onPublish?: () => Promise<void> | void
|
||||
onRestore?: () => Promise<void> | void
|
||||
debugWithMultipleModel?: boolean
|
||||
multipleModelConfigs?: ModelAndParameter[]
|
||||
/** modelAndParameter is passed when debugWithMultipleModel is true */
|
||||
onPublish?: (modelAndParameter?: ModelAndParameter) => Promise<any> | any
|
||||
onRestore?: () => Promise<any> | any
|
||||
onToggle?: (state: boolean) => void
|
||||
crossAxisOffset?: number
|
||||
}
|
||||
|
||||
const AppPublisher = ({
|
||||
disabled = false,
|
||||
publishDisabled = false,
|
||||
publishedAt,
|
||||
draftUpdatedAt,
|
||||
debugWithMultipleModel = false,
|
||||
multipleModelConfigs = [],
|
||||
onPublish,
|
||||
onRestore,
|
||||
onToggle,
|
||||
crossAxisOffset = 0,
|
||||
}: AppPublisherProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [published, setPublished] = useState(false)
|
||||
const [open, setOpen] = useState(false)
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const { app_base_url: appBaseURL, access_token } = appDetail?.site ?? {}
|
||||
const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {}
|
||||
const appMode = (appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow') ? 'chat' : appDetail.mode
|
||||
const appURL = `${appBaseURL}/${appMode}/${access_token}`
|
||||
const appURL = `${appBaseURL}/${appMode}/${accessToken}`
|
||||
|
||||
const language = useGetLanguage()
|
||||
const formatTimeFromNow = useCallback((time: number) => {
|
||||
return dayjs(time).locale(language === 'zh_Hans' ? 'zh-cn' : language.replace('_', '-')).fromNow()
|
||||
}, [language])
|
||||
|
||||
const handlePublish = async () => {
|
||||
const handlePublish = async (modelAndParameter?: ModelAndParameter) => {
|
||||
try {
|
||||
await onPublish?.()
|
||||
await onPublish?.(modelAndParameter)
|
||||
setPublished(true)
|
||||
}
|
||||
catch (e) {
|
||||
|
|
@ -70,22 +83,22 @@ const AppPublisher = ({
|
|||
}, [onRestore])
|
||||
|
||||
const handleTrigger = useCallback(() => {
|
||||
const state = !open
|
||||
|
||||
if (disabled) {
|
||||
setOpen(false)
|
||||
return
|
||||
}
|
||||
|
||||
onToggle?.(!open)
|
||||
onToggle?.(state)
|
||||
setOpen(state)
|
||||
|
||||
if (open) {
|
||||
setOpen(false)
|
||||
}
|
||||
else {
|
||||
setOpen(true)
|
||||
if (state)
|
||||
setPublished(false)
|
||||
}
|
||||
}, [disabled, onToggle, open])
|
||||
|
||||
const [embeddingModalOpen, setEmbeddingModalOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
|
|
@ -93,7 +106,7 @@ const AppPublisher = ({
|
|||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: -5,
|
||||
crossAxis: crossAxisOffset,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
||||
|
|
@ -137,35 +150,68 @@ const AppPublisher = ({
|
|||
{t('workflow.common.autoSaved')} · {Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
type='primary'
|
||||
className={`
|
||||
mt-3 px-3 py-0 w-full h-8 border-[0.5px] border-primary-700 rounded-lg text-[13px] font-medium
|
||||
${published && 'border-transparent'}
|
||||
`}
|
||||
onClick={handlePublish}
|
||||
disabled={published}
|
||||
>
|
||||
{
|
||||
published
|
||||
? t('workflow.common.published')
|
||||
: publishedAt ? t('workflow.common.update') : t('workflow.common.publish')
|
||||
}
|
||||
</Button>
|
||||
{debugWithMultipleModel
|
||||
? (
|
||||
<PublishWithMultipleModel
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onSelect={item => handlePublish(item)}
|
||||
// textGenerationModelList={textGenerationModelList}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<Button
|
||||
type='primary'
|
||||
className={classNames(
|
||||
'mt-3 px-3 py-0 w-full h-8 border-[0.5px] border-primary-700 rounded-lg text-[13px] font-medium',
|
||||
(publishDisabled || published) && 'border-transparent',
|
||||
)}
|
||||
onClick={() => handlePublish()}
|
||||
disabled={publishDisabled || published}
|
||||
>
|
||||
{
|
||||
published
|
||||
? t('workflow.common.published')
|
||||
: publishedAt ? t('workflow.common.update') : t('workflow.common.publish')
|
||||
}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='p-4 pt-3 border-t-[0.5px] border-t-black/5'>
|
||||
<SuggestedAction disabled={!publishedAt} link={appURL} icon={<PlayCircle />}>{t('workflow.common.runApp')}</SuggestedAction>
|
||||
{appMode === 'chat'
|
||||
{appDetail?.mode === 'workflow'
|
||||
? (
|
||||
<SuggestedAction disabled={!publishedAt} link={appURL} icon={<CodeBrowser className='w-4 h-4' />}>{t('workflow.common.embedIntoSite')}</SuggestedAction>
|
||||
<SuggestedAction
|
||||
disabled={!publishedAt}
|
||||
link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
|
||||
icon={<LeftIndent02 className='w-4 h-4' />}
|
||||
>
|
||||
{t('workflow.common.batchRunApp')}
|
||||
</SuggestedAction>
|
||||
)
|
||||
: (
|
||||
<SuggestedAction disabled={!publishedAt} link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`} icon={<LeftIndent02 className='w-4 h-4' />}>{t('workflow.common.batchRunApp')}</SuggestedAction>
|
||||
<SuggestedAction
|
||||
onClick={() => {
|
||||
setEmbeddingModalOpen(true)
|
||||
handleTrigger()
|
||||
}}
|
||||
disabled={!publishedAt}
|
||||
icon={<CodeBrowser className='w-4 h-4' />}
|
||||
>
|
||||
{t('workflow.common.embedIntoSite')}
|
||||
</SuggestedAction>
|
||||
)}
|
||||
<SuggestedAction disabled={!publishedAt} link='./develop' icon={<FileText className='w-4 h-4' />}>{t('workflow.common.accessAPIReference')}</SuggestedAction>
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
<EmbeddedModal
|
||||
isShow={embeddingModalOpen}
|
||||
onClose={() => setEmbeddingModalOpen(false)}
|
||||
appBaseUrl={appBaseURL}
|
||||
accessToken={accessToken}
|
||||
className='z-50'
|
||||
/>
|
||||
</PortalToFollowElem >
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ModelAndParameter } from '../types'
|
||||
import type { ModelAndParameter } from '../configuration/debug/types'
|
||||
import ModelIcon from '../../header/account-setting/model-provider-page/model-icon'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
|
|
@ -10,15 +11,17 @@ import {
|
|||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import type { ModelItem } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Model, ModelItem } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
|
||||
type PublishWithMultipleModelProps = {
|
||||
multipleModelConfigs: ModelAndParameter[]
|
||||
// textGenerationModelList?: Model[]
|
||||
onSelect: (v: ModelAndParameter) => void
|
||||
}
|
||||
const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
||||
multipleModelConfigs,
|
||||
// textGenerationModelList = [],
|
||||
onSelect,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -26,7 +29,7 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
|||
const { textGenerationModelList } = useProviderContext()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const validModelConfigs: (ModelAndParameter & { modelItem: ModelItem })[] = []
|
||||
const validModelConfigs: (ModelAndParameter & { modelItem: ModelItem; providerItem: Model })[] = []
|
||||
|
||||
multipleModelConfigs.forEach((item) => {
|
||||
const provider = textGenerationModelList.find(model => model.provider === item.provider)
|
||||
|
|
@ -40,6 +43,7 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
|||
model: item.model,
|
||||
provider: item.provider,
|
||||
modelItem: model,
|
||||
providerItem: provider,
|
||||
parameters: item.parameters,
|
||||
})
|
||||
}
|
||||
|
|
@ -62,18 +66,18 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
|||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleToggle}>
|
||||
<PortalToFollowElemTrigger className='w-full' onClick={handleToggle}>
|
||||
<Button
|
||||
type='primary'
|
||||
disabled={!validModelConfigs.length}
|
||||
className='pl-3 pr-2 h-8 text-[13px]'
|
||||
className='mt-3 px-3 py-0 w-full h-8 border-[0.5px] border-primary-700 rounded-lg text-[13px] font-medium'
|
||||
>
|
||||
{t('appDebug.operation.applyConfig')}
|
||||
<ChevronDown className='ml-0.5 w-3 h-3' />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent>
|
||||
<div className='p-1 w-[168px] rounded-lg border-[0.5px] border-gray-200 shadow-lg bg-white'>
|
||||
<PortalToFollowElemContent className='mt-1 w-[288px] z-50'>
|
||||
<div className='p-1 rounded-lg border-[0.5px] border-gray-200 shadow-lg bg-white'>
|
||||
<div className='flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'>
|
||||
{t('appDebug.publishAs')}
|
||||
</div>
|
||||
|
|
@ -81,10 +85,11 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
|||
validModelConfigs.map((item, index) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className='flex items-center px-3 h-8 rounded-lg hover:bg-gray-100 cursor-pointer text-sm text-gray-500'
|
||||
className='flex items-center h-8 px-3 text-sm text-gray-500 rounded-lg cursor-pointer hover:bg-gray-100'
|
||||
onClick={() => handleSelect(item)}
|
||||
>
|
||||
#{index + 1}
|
||||
<span className='italic min-w-[18px]'>#{index + 1}</span>
|
||||
<ModelIcon modelName={item.model} provider={item.providerItem} className='ml-2' />
|
||||
<div
|
||||
className='ml-1 text-gray-700 truncate'
|
||||
title={item.modelItem.label[language]}
|
||||
|
|
@ -1,15 +1,25 @@
|
|||
import type { PropsWithChildren } from 'react'
|
||||
import type { HTMLProps, PropsWithChildren } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
|
||||
export type SuggestedActionProps = PropsWithChildren<{
|
||||
export type SuggestedActionProps = PropsWithChildren<HTMLProps<HTMLAnchorElement> & {
|
||||
icon?: React.ReactNode
|
||||
link?: string
|
||||
disabled?: boolean
|
||||
}>
|
||||
|
||||
const SuggestedAction = ({ icon, link, disabled, children }: SuggestedActionProps) => (
|
||||
<a href={disabled ? undefined : link} target='_blank' rel='noreferrer' className={classNames('flex justify-start items-center gap-2 h-[34px] px-2.5 bg-gray-100 rounded-lg transition-colors [&:not(:first-child)]:mt-1', disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'hover:bg-primary-50 hover:text-primary-600 cursor-pointer')}>
|
||||
const SuggestedAction = ({ icon, link, disabled, children, className, ...props }: SuggestedActionProps) => (
|
||||
<a
|
||||
href={disabled ? undefined : link}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
className={classNames(
|
||||
'flex justify-start items-center gap-2 h-[34px] px-2.5 bg-gray-100 rounded-lg transition-colors [&:not(:first-child)]:mt-1',
|
||||
disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'hover:bg-primary-50 hover:text-primary-600 cursor-pointer',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className='relative w-4 h-4'>{icon}</div>
|
||||
<div className='grow shrink basis-0 text-[13px] font-medium leading-[18px]'>{children}</div>
|
||||
<ArrowUpRight />
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import produce from 'immer'
|
||||
import { useBoolean, useGetState } from 'ahooks'
|
||||
import cn from 'classnames'
|
||||
import { clone, isEqual } from 'lodash-es'
|
||||
import { CodeBracketIcon } from '@heroicons/react/20/solid'
|
||||
import Button from '../../base/button'
|
||||
import Loading from '../../base/loading'
|
||||
import AppPublisher from '../app-publisher'
|
||||
import AgentSettingButton from './config/agent-setting-button'
|
||||
import useAdvancedPromptConfig from './hooks/use-advanced-prompt-config'
|
||||
import EditHistoryModal from './config-prompt/conversation-histroy/edit-modal'
|
||||
|
|
@ -19,7 +19,6 @@ import {
|
|||
useFormattingChangedDispatcher,
|
||||
} from './debug/hooks'
|
||||
import type { ModelAndParameter } from './debug/types'
|
||||
import PublishWithMultipleModel from './debug/debug-with-multiple-model/publish-with-multiple-model'
|
||||
import type {
|
||||
AnnotationReplyConfig,
|
||||
DatasetConfigs,
|
||||
|
|
@ -66,7 +65,7 @@ type PublichConfig = {
|
|||
const Configuration: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const { setAppSiderbarExpand } = useAppStore()
|
||||
const { appDetail, setAppSiderbarExpand } = useAppStore()
|
||||
const [formattingChanged, setFormattingChanged] = useState(false)
|
||||
const { setShowAccountSettingModal } = useModalContext()
|
||||
const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
|
||||
|
|
@ -77,6 +76,7 @@ const Configuration: FC = () => {
|
|||
const [mode, setMode] = useState('')
|
||||
const [publishedConfig, setPublishedConfig] = useState<PublichConfig | null>(null)
|
||||
|
||||
const modalConfig = useMemo(() => appDetail?.model_config || {} as BackendModelConfig, [appDetail])
|
||||
const [conversationId, setConversationId] = useState<string | null>('')
|
||||
|
||||
const media = useBreakpoints()
|
||||
|
|
@ -130,7 +130,7 @@ const Configuration: FC = () => {
|
|||
const [inputs, setInputs] = useState<Inputs>({})
|
||||
const [query, setQuery] = useState('')
|
||||
const [completionParams, doSetCompletionParams] = useState<FormValue>({})
|
||||
const [tempStop, setTempStop, getTempStop] = useGetState<string[]>([])
|
||||
const [_, setTempStop, getTempStop] = useGetState<string[]>([])
|
||||
const setCompletionParams = (value: FormValue) => {
|
||||
const params = { ...value }
|
||||
|
||||
|
|
@ -508,6 +508,7 @@ const Configuration: FC = () => {
|
|||
setHasFetchedDetail(true)
|
||||
})
|
||||
})()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appId])
|
||||
|
||||
const promptEmpty = (() => {
|
||||
|
|
@ -541,7 +542,7 @@ const Configuration: FC = () => {
|
|||
else { return promptEmpty }
|
||||
})()
|
||||
const contextVarEmpty = mode === AppType.completion && dataSets.length > 0 && !hasSetContextVar
|
||||
const handlePublish = async (isSilence?: boolean, modelAndParameter?: ModelAndParameter) => {
|
||||
const onPublish = async (modelAndParameter?: ModelAndParameter) => {
|
||||
const modelId = modelAndParameter?.model || modelConfig.model_id
|
||||
const promptTemplate = modelConfig.configs.prompt_template
|
||||
const promptVariables = modelConfig.configs.prompt_variables
|
||||
|
|
@ -630,17 +631,16 @@ const Configuration: FC = () => {
|
|||
modelConfig: newModelConfig,
|
||||
completionParams,
|
||||
})
|
||||
if (!isSilence)
|
||||
notify({ type: 'success', message: t('common.api.success'), duration: 3000 })
|
||||
notify({ type: 'success', message: t('common.api.success'), duration: 3000 })
|
||||
|
||||
setCanReturnToSimpleMode(false)
|
||||
return true
|
||||
}
|
||||
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
const [restoreConfirmOpen, setRestoreConfirmOpen] = useState(false)
|
||||
const resetAppConfig = () => {
|
||||
syncToPublishedConfig(publishedConfig!)
|
||||
setShowConfirm(false)
|
||||
setRestoreConfirmOpen(false)
|
||||
}
|
||||
|
||||
const [showUseGPT4Confirm, setShowUseGPT4Confirm] = useState(false)
|
||||
|
|
@ -788,26 +788,20 @@ const Configuration: FC = () => {
|
|||
<div className='mx-2 w-[1px] h-[14px] bg-gray-200'></div>
|
||||
</>
|
||||
)}
|
||||
<Button onClick={() => setShowConfirm(true)} className='shrink-0 mr-2 w-[70px] !h-8 !text-[13px] font-medium text-gray-900'>{t('appDebug.operation.resetConfig')}</Button>
|
||||
{isMobile && (
|
||||
<Button className='!h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
|
||||
<span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
|
||||
<CodeBracketIcon className="w-4 h-4 text-gray-500" />
|
||||
</Button>
|
||||
)}
|
||||
{debugWithMultipleModel
|
||||
? (<PublishWithMultipleModel
|
||||
multipleModelConfigs={multipleModelConfigs}
|
||||
onSelect={item => handlePublish(false, item)}
|
||||
/>)
|
||||
: (<Button
|
||||
type='primary'
|
||||
onClick={() => handlePublish(false)}
|
||||
className={cn(cannotPublish && '!bg-primary-200 !cursor-not-allowed', 'shrink-0 w-[70px] !h-8 !text-[13px] font-medium')}
|
||||
>
|
||||
{t('appDebug.operation.applyConfig')}
|
||||
</Button>)}
|
||||
{/* <Publish /> */}
|
||||
<AppPublisher {...{
|
||||
publishDisabled: cannotPublish,
|
||||
publishedAt: (modalConfig.created_at || 0) * 1000,
|
||||
debugWithMultipleModel,
|
||||
multipleModelConfigs,
|
||||
onPublish,
|
||||
onRestore: () => setRestoreConfirmOpen(true),
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -832,14 +826,14 @@ const Configuration: FC = () => {
|
|||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
{showConfirm && (
|
||||
{restoreConfirmOpen && (
|
||||
<Confirm
|
||||
title={t('appDebug.resetConfig.title')}
|
||||
content={t('appDebug.resetConfig.message')}
|
||||
isShow={showConfirm}
|
||||
onClose={() => setShowConfirm(false)}
|
||||
isShow={restoreConfirmOpen}
|
||||
onClose={() => setRestoreConfirmOpen(false)}
|
||||
onConfirm={resetAppConfig}
|
||||
onCancel={() => setShowConfirm(false)}
|
||||
onCancel={() => setRestoreConfirmOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{showUseGPT4Confirm && (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type Props = {
|
|||
onClose: () => void
|
||||
accessToken: string
|
||||
appBaseUrl: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const OPTION_MAP = {
|
||||
|
|
@ -22,19 +23,19 @@ const OPTION_MAP = {
|
|||
`<iframe
|
||||
src="${url}/chatbot/${token}"
|
||||
style="width: 100%; height: 100%; min-height: 700px"
|
||||
frameborder="0"
|
||||
frameborder="0"
|
||||
allow="microphone">
|
||||
</iframe>`,
|
||||
},
|
||||
scripts: {
|
||||
getContent: (url: string, token: string, isTestEnv?: boolean) =>
|
||||
`<script>
|
||||
window.difyChatbotConfig = {
|
||||
window.difyChatbotConfig = {
|
||||
token: '${token}'${isTestEnv
|
||||
? `,
|
||||
? `,
|
||||
isDev: true`
|
||||
: ''}${IS_CE_EDITION
|
||||
? `,
|
||||
? `,
|
||||
baseUrl: '${url}'`
|
||||
: ''}
|
||||
}
|
||||
|
|
@ -59,7 +60,7 @@ type OptionStatus = {
|
|||
chromePlugin: boolean
|
||||
}
|
||||
|
||||
const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
|
||||
const Embedded = ({ isShow, onClose, appBaseUrl, accessToken, className }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const [option, setOption] = useState<Option>('iframe')
|
||||
const [isCopied, setIsCopied] = useState<OptionStatus>({ iframe: false, scripts: false, chromePlugin: false })
|
||||
|
|
@ -101,12 +102,13 @@ const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
|
|||
isShow={isShow}
|
||||
onClose={onClose}
|
||||
className="!max-w-2xl w-[640px]"
|
||||
wrapperClassName={className}
|
||||
closable={true}
|
||||
>
|
||||
<div className="mb-4 mt-8 text-gray-900 text-[14px] font-medium leading-tight">
|
||||
{t(`${prefixEmbedded}.explanation`)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between flex-wrap gap-y-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-y-2">
|
||||
{Object.keys(OPTION_MAP).map((v, index) => {
|
||||
return (
|
||||
<div
|
||||
|
|
@ -125,7 +127,7 @@ const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
|
|||
})}
|
||||
</div>
|
||||
{option === 'chromePlugin' && (
|
||||
<div className="mt-6 w-full">
|
||||
<div className="w-full mt-6">
|
||||
<div className={cn('gap-2 py-3 justify-center items-center inline-flex w-full rounded-lg',
|
||||
'bg-primary-600 hover:bg-primary-600/75 hover:shadow-md cursor-pointer text-white hover:shadow-sm flex-shrink-0')}>
|
||||
<div className={`w-4 h-4 relative ${style.pluginInstallIcon}`}></div>
|
||||
|
|
@ -135,22 +137,22 @@ const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
|
|||
)}
|
||||
<div className={cn('w-full bg-gray-100 rounded-lg flex-col justify-start items-start inline-flex',
|
||||
'mt-6')}>
|
||||
<div className="self-stretch pl-3 pr-1 py-1 bg-gray-50 rounded-tl-lg rounded-tr-lg border border-black border-opacity-5 justify-start items-center gap-2 inline-flex">
|
||||
<div className="inline-flex items-center self-stretch justify-start gap-2 py-1 pl-3 pr-1 border border-black rounded-tl-lg rounded-tr-lg bg-gray-50 border-opacity-5">
|
||||
<div className="grow shrink basis-0 text-slate-700 text-[13px] font-medium leading-none">
|
||||
{t(`${prefixEmbedded}.${option}`)}
|
||||
</div>
|
||||
<div className="p-2 rounded-lg justify-center items-center gap-1 flex">
|
||||
<div className="flex items-center justify-center gap-1 p-2 rounded-lg">
|
||||
<Tooltip
|
||||
selector={'code-copy-feedback'}
|
||||
content={(isCopied[option] ? t(`${prefixEmbedded}.copied`) : t(`${prefixEmbedded}.copy`)) || ''}
|
||||
>
|
||||
<div className="w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg">
|
||||
<div className="w-8 h-8 rounded-lg cursor-pointer hover:bg-gray-100">
|
||||
<div onClick={onClickCopy} className={`w-full h-full ${copyStyle.copyIcon} ${isCopied[option] ? copyStyle.copied : ''}`}></div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 justify-start items-start gap-2 flex overflow-x-auto w-full">
|
||||
<div className="flex items-start justify-start w-full gap-2 p-3 overflow-x-auto">
|
||||
<div className="grow shrink basis-0 text-slate-700 text-[13px] leading-tight font-mono">
|
||||
<pre className='select-text'>{OPTION_MAP[option].getContent(appBaseUrl, accessToken, isTestEnv)}</pre>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ const Header: FC = () => {
|
|||
onPublish,
|
||||
onRestore: onStartRestoring,
|
||||
onToggle: onPublisherToggle,
|
||||
crossAxisOffset: 53,
|
||||
}}
|
||||
/>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ export type ModelConfig = {
|
|||
image: VisionSettings
|
||||
}
|
||||
files?: VisionFile[]
|
||||
created_at?: number
|
||||
}
|
||||
|
||||
export type Language = typeof LanguagesSupported[number]
|
||||
|
|
|
|||
Loading…
Reference in New Issue