'use client' import type { HTMLProps } from 'react' import React, { useMemo, useState } from 'react' import { Cog8ToothIcon, DocumentTextIcon, PaintBrushIcon, RocketLaunchIcon, } from '@heroicons/react/24/outline' import { usePathname, useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' import SettingsModal from './settings' import EmbeddedModal from './embedded' import CustomizeModal from './customize' import style from './style.module.css' import type { ConfigParams } from './settings' import Tooltip from '@/app/components/base/tooltip' import AppBasic from '@/app/components/app-sidebar/basic' import { asyncRunSafe, randomString } from '@/utils' import Button from '@/app/components/base/button' import Tag from '@/app/components/base/tag' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import CopyFeedback from '@/app/components/base/copy-feedback' import Confirm from '@/app/components/base/confirm' import ShareQRCode from '@/app/components/base/qrcode' import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button' import type { AppDetailResponse } from '@/models/app' import { useAppContext } from '@/context/app-context' export type IAppCardProps = { className?: string appInfo: AppDetailResponse cardType?: 'api' | 'webapp' customBgColor?: string onChangeStatus: (val: boolean) => Promise onSaveSiteConfig?: (params: ConfigParams) => Promise onGenerateCode?: () => Promise } const EmbedIcon = ({ className = '' }: HTMLProps) => { return
} function AppCard({ appInfo, cardType = 'webapp', customBgColor, onChangeStatus, onSaveSiteConfig, onGenerateCode, className, }: IAppCardProps) { const router = useRouter() const pathname = usePathname() const { currentWorkspace, isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext() const [showSettingsModal, setShowSettingsModal] = useState(false) const [showEmbedded, setShowEmbedded] = useState(false) const [showCustomizeModal, setShowCustomizeModal] = useState(false) const [genLoading, setGenLoading] = useState(false) const [showConfirmDelete, setShowConfirmDelete] = useState(false) const { t } = useTranslation() const OPERATIONS_MAP = useMemo(() => { const operationsMap = { webapp: [ { opName: t('appOverview.overview.appInfo.preview'), opIcon: RocketLaunchIcon }, { opName: t('appOverview.overview.appInfo.customize.entry'), opIcon: PaintBrushIcon }, ] as { opName: string; opIcon: any }[], api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: DocumentTextIcon }], app: [], } if (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: EmbedIcon }) if (isCurrentWorkspaceEditor) operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: Cog8ToothIcon }) return operationsMap }, [isCurrentWorkspaceEditor, appInfo, t]) const isApp = cardType === 'webapp' const basicName = isApp ? appInfo?.site?.title : t('appOverview.overview.apiInfo.title') const toggleDisabled = isApp ? !isCurrentWorkspaceEditor : !isCurrentWorkspaceManager const runningStatus = isApp ? appInfo.enable_site : appInfo.enable_api const { app_base_url, access_token } = appInfo.site ?? {} const appMode = (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') ? 'chat' : appInfo.mode const appUrl = `${app_base_url}/${appMode}/${access_token}` const apiUrl = appInfo?.api_base_url let bgColor = 'bg-primary-50 bg-opacity-40' if (cardType === 'api') bgColor = 'bg-purple-50' const genClickFuncByName = (opName: string) => { switch (opName) { case t('appOverview.overview.appInfo.preview'): return () => { window.open(appUrl, '_blank') } case t('appOverview.overview.appInfo.customize.entry'): return () => { setShowCustomizeModal(true) } case t('appOverview.overview.appInfo.settings.entry'): return () => { setShowSettingsModal(true) } case t('appOverview.overview.appInfo.embedded.entry'): return () => { setShowEmbedded(true) } default: // jump to page develop return () => { const pathSegments = pathname.split('/') pathSegments.pop() router.push(`${pathSegments.join('/')}/develop`) } } } const onGenCode = async () => { if (onGenerateCode) { setGenLoading(true) await asyncRunSafe(onGenerateCode()) setGenLoading(false) } } return (
{runningStatus ? t('appOverview.overview.status.running') : t('appOverview.overview.status.disable')}
{isApp ? t('appOverview.overview.appInfo.accessibleAddress') : t('appOverview.overview.apiInfo.accessibleAddress')}
{isApp ? appUrl : apiUrl}
{isApp && } {/* button copy link/ button regenerate */} {showConfirmDelete && ( setShowConfirmDelete(false)} onConfirm={() => { onGenCode() setShowConfirmDelete(false) }} onCancel={() => setShowConfirmDelete(false)} /> )} {isApp && isCurrentWorkspaceManager && (
setShowConfirmDelete(true)} >
)}
{!isApp && } {OPERATIONS_MAP[cardType].map((op) => { const disabled = op.opName === t('appOverview.overview.appInfo.settings.entry') ? false : !runningStatus return ( ) })}
{isApp ? ( <> setShowSettingsModal(false)} onSave={onSaveSiteConfig} /> setShowEmbedded(false)} appBaseUrl={app_base_url} accessToken={access_token} /> setShowCustomizeModal(false)} appId={appInfo.id} api_base_url={appInfo.api_base_url} mode={appInfo.mode} /> ) : null}
) } export default AppCard