mirror of
https://github.com/langgenius/dify.git
synced 2026-04-24 17:16:37 +08:00
212 lines
7.3 KiB
TypeScript
212 lines
7.3 KiB
TypeScript
'use client'
|
|
import React, { useState } from 'react'
|
|
import {
|
|
Cog8ToothIcon,
|
|
DocumentTextIcon,
|
|
RocketLaunchIcon,
|
|
ShareIcon,
|
|
} from '@heroicons/react/24/outline'
|
|
import { SparklesIcon } from '@heroicons/react/24/solid'
|
|
import { usePathname, useRouter } from 'next/navigation'
|
|
import { useTranslation } from 'react-i18next'
|
|
import SettingsModal from './settings'
|
|
import ShareLink from './share-link'
|
|
import CustomizeModal from './customize'
|
|
import Tooltip from '@/app/components/base/tooltip'
|
|
import AppBasic, { randomString } from '@/app/components/app-sidebar/basic'
|
|
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'
|
|
|
|
export type IAppCardProps = {
|
|
className?: string
|
|
appInfo: AppDetailResponse
|
|
cardType?: 'app' | 'api'
|
|
customBgColor?: string
|
|
onChangeStatus: (val: boolean) => Promise<any>
|
|
onSaveSiteConfig?: (params: any) => Promise<any>
|
|
onGenerateCode?: () => Promise<any>
|
|
}
|
|
|
|
// todo: get image url from appInfo
|
|
const defaultUrl = 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
|
|
|
|
function AppCard({
|
|
appInfo,
|
|
cardType = 'app',
|
|
customBgColor,
|
|
onChangeStatus,
|
|
onSaveSiteConfig,
|
|
onGenerateCode,
|
|
className,
|
|
}: IAppCardProps) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
const [showSettingsModal, setShowSettingsModal] = useState(false)
|
|
const [showShareModal, setShowShareModal] = useState(false)
|
|
const [showCustomizeModal, setShowCustomizeModal] = useState(false)
|
|
const { t } = useTranslation()
|
|
|
|
const OPERATIONS_MAP = {
|
|
app: [
|
|
{ opName: t('appOverview.overview.appInfo.preview'), opIcon: RocketLaunchIcon },
|
|
{ opName: t('appOverview.overview.appInfo.share.entry'), opIcon: ShareIcon },
|
|
{ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: Cog8ToothIcon },
|
|
],
|
|
api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: DocumentTextIcon }],
|
|
}
|
|
|
|
const isApp = cardType === 'app'
|
|
const basicName = isApp ? appInfo?.site?.title : t('appOverview.overview.apiInfo.title')
|
|
const runningStatus = isApp ? appInfo.enable_site : appInfo.enable_api
|
|
const { app_base_url, access_token } = appInfo.site ?? {}
|
|
const appUrl = `${app_base_url}/${appInfo.mode}/${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.share.entry'):
|
|
return () => {
|
|
setShowShareModal(true)
|
|
}
|
|
case t('appOverview.overview.appInfo.settings.entry'):
|
|
return () => {
|
|
setShowSettingsModal(true)
|
|
}
|
|
default:
|
|
// jump to page develop
|
|
return () => {
|
|
const pathSegments = pathname.split('/')
|
|
pathSegments.pop()
|
|
router.push(`${pathSegments.join('/')}/develop`)
|
|
}
|
|
}
|
|
}
|
|
|
|
const onClickCustomize = () => {
|
|
setShowCustomizeModal(true)
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={`flex flex-col w-full shadow-sm border-[0.5px] rounded-lg border-gray-200 ${className ?? ''}`}
|
|
>
|
|
<div className={`px-6 py-4 ${customBgColor ?? bgColor} rounded-lg`}>
|
|
<div className="mb-2.5 flex flex-row items-start justify-between">
|
|
<AppBasic
|
|
iconType={isApp ? 'app' : 'api'}
|
|
iconUrl={defaultUrl}
|
|
name={basicName}
|
|
type={
|
|
isApp
|
|
? t('appOverview.overview.appInfo.explanation')
|
|
: t('appOverview.overview.apiInfo.explanation')
|
|
}
|
|
/>
|
|
<div className="flex flex-row items-center h-9">
|
|
<Tag className="mr-2" color={runningStatus ? 'green' : 'yellow'}>
|
|
{runningStatus ? t('appOverview.overview.status.running') : t('appOverview.overview.status.disable')}
|
|
</Tag>
|
|
<Switch defaultValue={runningStatus} onChange={onChangeStatus} />
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col justify-center py-2">
|
|
<div className="py-1">
|
|
<div className="pb-1 text-xs text-gray-500">
|
|
{isApp ? t('appOverview.overview.appInfo.accessibleAddress') : t('appOverview.overview.apiInfo.accessibleAddress')}
|
|
</div>
|
|
<div className="text-sm text-gray-800">
|
|
{isApp ? appUrl : apiUrl}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
className={`pt-2 flex flex-row items-center ${!isApp ? 'mb-[calc(2rem_+_1px)]' : ''
|
|
}`}
|
|
>
|
|
{OPERATIONS_MAP[cardType].map((op) => {
|
|
return (
|
|
<Button
|
|
className="mr-2 text-gray-800"
|
|
key={op.opName}
|
|
onClick={genClickFuncByName(op.opName)}
|
|
disabled={
|
|
[t('appOverview.overview.appInfo.preview'), t('appOverview.overview.appInfo.share.entry')].includes(op.opName) && !runningStatus
|
|
}
|
|
>
|
|
<Tooltip
|
|
content={t('appOverview.overview.appInfo.preUseReminder') ?? ''}
|
|
selector={`op-btn-${randomString(16)}`}
|
|
className={
|
|
([t('appOverview.overview.appInfo.preview'), t('appOverview.overview.appInfo.share.entry')].includes(op.opName) && !runningStatus)
|
|
? 'mt-[-8px]'
|
|
: '!hidden'
|
|
}
|
|
>
|
|
<div className="flex flex-row items-center">
|
|
<op.opIcon className="h-4 w-4 mr-1.5" />
|
|
<span className="text-xs">{op.opName}</span>
|
|
</div>
|
|
</Tooltip>
|
|
</Button>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
{isApp
|
|
? (
|
|
<div
|
|
className={
|
|
'flex items-center px-6 py-2 box-border text-xs text-gray-500 bg-opacity-50 bg-white border-t-[0.5px] border-primary-50'
|
|
}
|
|
>
|
|
<div
|
|
className="flex items-center hover:text-primary-600 hover:cursor-pointer"
|
|
onClick={onClickCustomize}
|
|
>
|
|
<SparklesIcon className="w-4 h-4 mr-1" />
|
|
{t('appOverview.overview.appInfo.customize.entry')}
|
|
</div>
|
|
</div>
|
|
)
|
|
: null}
|
|
{isApp
|
|
? (
|
|
<div>
|
|
<ShareLink
|
|
isShow={showShareModal}
|
|
onClose={() => setShowShareModal(false)}
|
|
linkUrl={appUrl}
|
|
onGenerateCode={onGenerateCode}
|
|
/>
|
|
<SettingsModal
|
|
appInfo={appInfo}
|
|
isShow={showSettingsModal}
|
|
onClose={() => setShowSettingsModal(false)}
|
|
onSave={onSaveSiteConfig}
|
|
/>
|
|
<CustomizeModal
|
|
isShow={showCustomizeModal}
|
|
linkUrl=""
|
|
onClose={() => setShowCustomizeModal(false)}
|
|
appId={appInfo.id}
|
|
mode={appInfo.mode}
|
|
/>
|
|
</div>
|
|
)
|
|
: null}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default AppCard
|