From fec607db81d300b36ea6477087449d0bd35ed9ab Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Wed, 12 Jul 2023 17:27:50 +0800 Subject: [PATCH] Feat/embedding (#553) Co-authored-by: Gillian97 Co-authored-by: Joel --- .../(shareLayout)/chatbot/[token]/page.tsx | 13 + web/app/components/app/chat/index.tsx | 4 +- web/app/components/app/overview/appCard.tsx | 28 +- .../app/overview/assets/code-browser.svg | 3 + .../app/overview/assets/iframe-option.svg | 102 +++ .../app/overview/assets/scripts-option.svg | 160 +++++ .../app/overview/embedded/index.tsx | 111 +++ .../app/overview/embedded/style.module.css | 14 + web/app/components/app/overview/style.css | 5 + .../share/chatbot/config-scence/index.tsx | 13 + .../share/chatbot/hooks/use-conversation.ts | 70 ++ web/app/components/share/chatbot/index.tsx | 647 ++++++++++++++++++ .../share/chatbot/sidebar/app-info/index.tsx | 28 + .../share/chatbot/sidebar/card.module.css | 3 + .../components/share/chatbot/sidebar/card.tsx | 19 + .../share/chatbot/sidebar/index.tsx | 151 ++++ .../share/chatbot/sidebar/list/index.tsx | 115 ++++ .../chatbot/sidebar/list/style.module.css | 7 + .../components/share/chatbot/style.module.css | 3 + .../share/chatbot/value-panel/index.tsx | 79 +++ .../chatbot/value-panel/style.module.css | 3 + .../share/chatbot/welcome/icons/logo.png | Bin 0 -> 3921 bytes .../share/chatbot/welcome/index.tsx | 356 ++++++++++ .../chatbot/welcome/massive-component.tsx | 74 ++ .../share/chatbot/welcome/style.module.css | 29 + web/app/components/share/header.tsx | 50 +- web/bin/uglify-embed.js | 9 + web/i18n/lang/app-debug.en.ts | 8 +- web/i18n/lang/app-overview.en.ts | 9 + web/i18n/lang/app-overview.zh.ts | 9 + web/package.json | 8 +- web/public/embed.js | 89 +++ web/public/embed.min.js | 30 + 33 files changed, 2208 insertions(+), 41 deletions(-) create mode 100644 web/app/(shareLayout)/chatbot/[token]/page.tsx create mode 100644 web/app/components/app/overview/assets/code-browser.svg create mode 100644 web/app/components/app/overview/assets/iframe-option.svg create mode 100644 web/app/components/app/overview/assets/scripts-option.svg create mode 100644 web/app/components/app/overview/embedded/index.tsx create mode 100644 web/app/components/app/overview/embedded/style.module.css create mode 100644 web/app/components/share/chatbot/config-scence/index.tsx create mode 100644 web/app/components/share/chatbot/hooks/use-conversation.ts create mode 100644 web/app/components/share/chatbot/index.tsx create mode 100644 web/app/components/share/chatbot/sidebar/app-info/index.tsx create mode 100644 web/app/components/share/chatbot/sidebar/card.module.css create mode 100644 web/app/components/share/chatbot/sidebar/card.tsx create mode 100644 web/app/components/share/chatbot/sidebar/index.tsx create mode 100644 web/app/components/share/chatbot/sidebar/list/index.tsx create mode 100644 web/app/components/share/chatbot/sidebar/list/style.module.css create mode 100644 web/app/components/share/chatbot/style.module.css create mode 100644 web/app/components/share/chatbot/value-panel/index.tsx create mode 100644 web/app/components/share/chatbot/value-panel/style.module.css create mode 100644 web/app/components/share/chatbot/welcome/icons/logo.png create mode 100644 web/app/components/share/chatbot/welcome/index.tsx create mode 100644 web/app/components/share/chatbot/welcome/massive-component.tsx create mode 100644 web/app/components/share/chatbot/welcome/style.module.css create mode 100644 web/bin/uglify-embed.js create mode 100644 web/public/embed.js create mode 100644 web/public/embed.min.js diff --git a/web/app/(shareLayout)/chatbot/[token]/page.tsx b/web/app/(shareLayout)/chatbot/[token]/page.tsx new file mode 100644 index 0000000000..8aa182893a --- /dev/null +++ b/web/app/(shareLayout)/chatbot/[token]/page.tsx @@ -0,0 +1,13 @@ +import type { FC } from 'react' +import React from 'react' + +import type { IMainProps } from '@/app/components/share/chat' +import Main from '@/app/components/share/chatbot' + +const Chatbot: FC = () => { + return ( +
+ ) +} + +export default React.memo(Chatbot) diff --git a/web/app/components/app/chat/index.tsx b/web/app/components/app/chat/index.tsx index f67805cbf4..9dcf37399d 100644 --- a/web/app/components/app/chat/index.tsx +++ b/web/app/components/app/chat/index.tsx @@ -473,7 +473,7 @@ const Chat: FC = ({ } } - const haneleKeyDown = (e: any) => { + const handleKeyDown = (e: any) => { isUseInputMethod.current = e.nativeEvent.isComposing if (e.code === 'Enter' && !e.shiftKey) { setQuery(query.replace(/\n$/, '')) @@ -573,7 +573,7 @@ const Chat: FC = ({ value={query} onChange={handleContentChange} onKeyUp={handleKeyUp} - onKeyDown={haneleKeyDown} + onKeyDown={handleKeyDown} minHeight={48} autoFocus controlFocus={controlFocus} diff --git a/web/app/components/app/overview/appCard.tsx b/web/app/components/app/overview/appCard.tsx index f6358d27df..0a2f8e73f9 100644 --- a/web/app/components/app/overview/appCard.tsx +++ b/web/app/components/app/overview/appCard.tsx @@ -1,4 +1,5 @@ 'use client' +import type { FC } from 'react' import React, { useState } from 'react' import { Cog8ToothIcon, @@ -11,6 +12,7 @@ import { usePathname, useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' import SettingsModal from './settings' import ShareLink from './share-link' +import EmbeddedModal from './embedded' import CustomizeModal from './customize' import Tooltip from '@/app/components/base/tooltip' import AppBasic, { randomString } from '@/app/components/app-sidebar/basic' @@ -18,6 +20,8 @@ import Button from '@/app/components/base/button' import Tag from '@/app/components/base/tag' import Switch from '@/app/components/base/switch' import type { AppDetailResponse } from '@/models/app' +import './style.css' +import { AppType } from '@/types/app' export type IAppCardProps = { className?: string @@ -29,6 +33,10 @@ export type IAppCardProps = { onGenerateCode?: () => Promise } +const EmbedIcon: FC<{ className?: string }> = ({ className = '' }) => { + return
+} + function AppCard({ appInfo, cardType = 'app', @@ -42,6 +50,7 @@ function AppCard({ const pathname = usePathname() const [showSettingsModal, setShowSettingsModal] = useState(false) const [showShareModal, setShowShareModal] = useState(false) + const [showEmbedded, setShowEmbedded] = useState(false) const [showCustomizeModal, setShowCustomizeModal] = useState(false) const { t } = useTranslation() @@ -49,8 +58,9 @@ function AppCard({ webapp: [ { opName: t('appOverview.overview.appInfo.preview'), opIcon: RocketLaunchIcon }, { opName: t('appOverview.overview.appInfo.share.entry'), opIcon: ShareIcon }, + appInfo.mode === AppType.chat ? { opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: EmbedIcon } : false, { opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: Cog8ToothIcon }, - ], + ].filter(item => !!item), api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: DocumentTextIcon }], app: [], } @@ -80,6 +90,10 @@ function AppCard({ return () => { setShowSettingsModal(true) } + case t('appOverview.overview.appInfo.embedded.entry'): + return () => { + setShowEmbedded(true) + } default: // jump to page develop return () => { @@ -139,20 +153,20 @@ function AppCard({ key={op.opName} onClick={genClickFuncByName(op.opName)} disabled={ - [t('appOverview.overview.appInfo.preview'), t('appOverview.overview.appInfo.share.entry')].includes(op.opName) && !runningStatus + [t('appOverview.overview.appInfo.preview'), t('appOverview.overview.appInfo.share.entry'), t('appOverview.overview.appInfo.embedded.entry')].includes(op.opName) && !runningStatus } >
- + {op.opName}
@@ -193,6 +207,12 @@ function AppCard({ onClose={() => setShowSettingsModal(false)} onSave={onSaveSiteConfig} /> + setShowEmbedded(false)} + appBaseUrl={app_base_url} + accessToken={access_token} + /> + + diff --git a/web/app/components/app/overview/assets/iframe-option.svg b/web/app/components/app/overview/assets/iframe-option.svg new file mode 100644 index 0000000000..d9ffc024aa --- /dev/null +++ b/web/app/components/app/overview/assets/iframe-option.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/app/components/app/overview/assets/scripts-option.svg b/web/app/components/app/overview/assets/scripts-option.svg new file mode 100644 index 0000000000..fee40407b6 --- /dev/null +++ b/web/app/components/app/overview/assets/scripts-option.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx new file mode 100644 index 0000000000..225ab9667f --- /dev/null +++ b/web/app/components/app/overview/embedded/index.tsx @@ -0,0 +1,111 @@ +import React, { useState } from 'react' +import { useTranslation } from 'react-i18next' +import cn from 'classnames' +import style from './style.module.css' +import Modal from '@/app/components/base/modal' +import useCopyToClipboard from '@/hooks/use-copy-to-clipboard' +import copyStyle from '@/app/components/app/chat/copy-btn/style.module.css' +import Tooltip from '@/app/components/base/tooltip' +import { useAppContext } from '@/context/app-context' + +// const isDevelopment = process.env.NODE_ENV === 'development' + +type Props = { + isShow: boolean + onClose: () => void + accessToken: string + appBaseUrl: string +} + +const OPTION_MAP = { + iframe: { + getContent: (url: string, token: string) => + ``, + }, + scripts: { + getContent: (url: string, token: string, isTestEnv?: boolean) => + ` +`, + }, +} +const prefixEmbedded = 'appOverview.overview.appInfo.embedded' + +type Option = keyof typeof OPTION_MAP + +const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => { + const { t } = useTranslation() + const [option, setOption] = useState