mirror of https://github.com/langgenius/dify.git
feat: can show app detail modal
This commit is contained in:
parent
ab56b4a818
commit
b018f2b0a0
|
|
@ -8,7 +8,10 @@ import AppIcon from '@/app/components/base/app-icon'
|
|||
import { AppTypeIcon } from '../../app/type-selector'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
||||
import Link from 'next/link'
|
||||
import { useCallback } from 'react'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
|
||||
export type AppCardProps = {
|
||||
app: App
|
||||
canCreate: boolean
|
||||
|
|
@ -26,6 +29,12 @@ const AppCard = ({
|
|||
const { app: appBasicInfo } = app
|
||||
const { systemFeatures } = useGlobalPublicStore()
|
||||
const isTrialApp = app.can_trial && systemFeatures.enable_trial_app
|
||||
const setShowTryAppPanel = useContextSelector(ExploreContext, ctx => ctx.setShowTryAppPanel)
|
||||
const showTryAPPPanel = useCallback((appId: string) => {
|
||||
return () => {
|
||||
setShowTryAppPanel?.(true, { appId })
|
||||
}
|
||||
}, [setShowTryAppPanel])
|
||||
|
||||
return (
|
||||
<div className={cn('group relative col-span-1 flex cursor-pointer flex-col overflow-hidden rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-2 shadow-sm transition-all duration-200 ease-in-out hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-lg')}>
|
||||
|
|
@ -71,12 +80,11 @@ const AppCard = ({
|
|||
</Button>
|
||||
)}
|
||||
{isTrialApp && (
|
||||
<Link href={`/try/app/${app.app_id}`} target='_blank' rel='noreferrer'>
|
||||
<Button className='w-full'>
|
||||
<span>{t('explore.appCard.try')}</span>
|
||||
<RiArrowRightUpLine className='size-4' />
|
||||
</Button>
|
||||
</Link>
|
||||
// /try/app/${app.app_id}
|
||||
<Button className='w-full' onClick={showTryAPPPanel(app.app_id)}>
|
||||
<span>{t('explore.appCard.try')}</span>
|
||||
<RiArrowRightUpLine className='size-4' />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import DSLConfirmModal from '@/app/components/app/create-from-dsl-modal/dsl-conf
|
|||
import Banner from '@/app/components/explore/banner/banner'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import TryApp from '../try-app'
|
||||
|
||||
type AppsProps = {
|
||||
onSuccess?: () => void
|
||||
|
|
@ -141,6 +143,12 @@ const Apps = ({
|
|||
})
|
||||
}, [handleImportDSLConfirm, onSuccess])
|
||||
|
||||
const isShowTryAppPanel = useContextSelector(ExploreContext, ctx => ctx.isShowTryAppPanel)
|
||||
const setShowTryAppPanel = useContextSelector(ExploreContext, ctx => ctx.setShowTryAppPanel)
|
||||
const hideTryAppPanel = useCallback(() => {
|
||||
setShowTryAppPanel(false)
|
||||
}, [setShowTryAppPanel])
|
||||
const appId = useContextSelector(ExploreContext, ctx => ctx.currentApp?.appId) as string
|
||||
if (!categories || categories.length === 0) {
|
||||
return (
|
||||
<div className="flex h-full items-center">
|
||||
|
|
@ -235,6 +243,8 @@ const Apps = ({
|
|||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{isShowTryAppPanel && <TryApp appId={appId} onClose={hideTryAppPanel} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import type { CurrentTryAppParams } from '@/context/explore-context'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
import Sidebar from '@/app/components/explore/sidebar'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
|
@ -42,6 +43,16 @@ const Explore: FC<IExploreProps> = ({
|
|||
return router.replace('/datasets')
|
||||
}, [isCurrentWorkspaceDatasetOperator])
|
||||
|
||||
const [currentTryAppParams, setCurrentTryAppParams] = useState<CurrentTryAppParams | undefined>({ appId: '47b94c61-5b0d-402b-b5bb-482ee406bc68' })
|
||||
const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(true)
|
||||
const setShowTryAppPanel = (showTryAppPanel: boolean, params?: CurrentTryAppParams) => {
|
||||
if (showTryAppPanel)
|
||||
setCurrentTryAppParams(params)
|
||||
else
|
||||
setCurrentTryAppParams(undefined)
|
||||
setIsShowTryAppPanel(showTryAppPanel)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex h-full overflow-hidden border-t border-divider-regular bg-background-body'>
|
||||
<ExploreContext.Provider
|
||||
|
|
@ -54,6 +65,9 @@ const Explore: FC<IExploreProps> = ({
|
|||
setInstalledApps,
|
||||
isFetchingInstalledApps,
|
||||
setIsFetchingInstalledApps,
|
||||
currentApp: currentTryAppParams,
|
||||
isShowTryAppPanel,
|
||||
setShowTryAppPanel,
|
||||
}
|
||||
}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import Modal from '@/app/components/base/modal/index'
|
||||
import Tab, { TypeEnum } from './tab'
|
||||
|
||||
type Props = {
|
||||
appId: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const TryApp: FC<Props> = ({
|
||||
appId,
|
||||
onClose,
|
||||
}) => {
|
||||
const [type, setType] = useState<TypeEnum>(TypeEnum.TRY)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={onClose}
|
||||
className='h-[calc(100vh-32px)] max-w-[calc(100vw-32px)]'
|
||||
>
|
||||
<Tab
|
||||
value={type}
|
||||
onChange={setType}
|
||||
/>
|
||||
{appId}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default React.memo(TryApp)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import TabHeader from '../../base/tab-header'
|
||||
|
||||
export enum TypeEnum {
|
||||
TRY = 'try',
|
||||
DETAIL = 'detail',
|
||||
}
|
||||
|
||||
type Props = {
|
||||
value: TypeEnum
|
||||
onChange: (value: TypeEnum) => void
|
||||
}
|
||||
|
||||
const Tab: FC<Props> = ({
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
const tabs = [
|
||||
{ id: TypeEnum.TRY, name: 'Try App' },
|
||||
{ id: TypeEnum.DETAIL, name: 'App Details' },
|
||||
]
|
||||
return (
|
||||
<div>
|
||||
<TabHeader
|
||||
items={tabs}
|
||||
value={value}
|
||||
onChange={onChange as (value: string) => void}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(Tab)
|
||||
|
|
@ -2,6 +2,10 @@ import { createContext } from 'use-context-selector'
|
|||
import type { InstalledApp } from '@/models/explore'
|
||||
import { noop } from 'lodash-es'
|
||||
|
||||
export type CurrentTryAppParams = {
|
||||
appId: string
|
||||
}
|
||||
|
||||
type IExplore = {
|
||||
controlUpdateInstalledApps: number
|
||||
setControlUpdateInstalledApps: (controlUpdateInstalledApps: number) => void
|
||||
|
|
@ -10,6 +14,9 @@ type IExplore = {
|
|||
setInstalledApps: (installedApps: InstalledApp[]) => void
|
||||
isFetchingInstalledApps: boolean
|
||||
setIsFetchingInstalledApps: (isFetchingInstalledApps: boolean) => void
|
||||
currentApp?: CurrentTryAppParams
|
||||
isShowTryAppPanel: boolean
|
||||
setShowTryAppPanel: (showTryAppPanel: boolean, params?: CurrentTryAppParams) => void
|
||||
}
|
||||
|
||||
const ExploreContext = createContext<IExplore>({
|
||||
|
|
@ -20,6 +27,9 @@ const ExploreContext = createContext<IExplore>({
|
|||
setInstalledApps: noop,
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: noop,
|
||||
isShowTryAppPanel: false,
|
||||
setShowTryAppPanel: noop,
|
||||
currentApp: undefined,
|
||||
})
|
||||
|
||||
export default ExploreContext
|
||||
|
|
|
|||
Loading…
Reference in New Issue