mirror of
https://github.com/langgenius/dify.git
synced 2026-04-27 19:27:23 +08:00
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 { AppTypeIcon } from '../../app/type-selector'
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
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 = {
|
export type AppCardProps = {
|
||||||
app: App
|
app: App
|
||||||
canCreate: boolean
|
canCreate: boolean
|
||||||
@ -26,6 +29,12 @@ const AppCard = ({
|
|||||||
const { app: appBasicInfo } = app
|
const { app: appBasicInfo } = app
|
||||||
const { systemFeatures } = useGlobalPublicStore()
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const isTrialApp = app.can_trial && systemFeatures.enable_trial_app
|
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 (
|
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')}>
|
<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>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{isTrialApp && (
|
{isTrialApp && (
|
||||||
<Link href={`/try/app/${app.app_id}`} target='_blank' rel='noreferrer'>
|
// /try/app/${app.app_id}
|
||||||
<Button className='w-full'>
|
<Button className='w-full' onClick={showTryAPPPanel(app.app_id)}>
|
||||||
<span>{t('explore.appCard.try')}</span>
|
<span>{t('explore.appCard.try')}</span>
|
||||||
<RiArrowRightUpLine className='size-4' />
|
<RiArrowRightUpLine className='size-4' />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</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 Banner from '@/app/components/explore/banner/banner'
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
import { useContextSelector } from 'use-context-selector'
|
||||||
|
import TryApp from '../try-app'
|
||||||
|
|
||||||
type AppsProps = {
|
type AppsProps = {
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
@ -141,6 +143,12 @@ const Apps = ({
|
|||||||
})
|
})
|
||||||
}, [handleImportDSLConfirm, onSuccess])
|
}, [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) {
|
if (!categories || categories.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center">
|
<div className="flex h-full items-center">
|
||||||
@ -235,6 +243,8 @@ const Apps = ({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{isShowTryAppPanel && <TryApp appId={appId} onClose={hideTryAppPanel} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
|
import type { CurrentTryAppParams } from '@/context/explore-context'
|
||||||
import ExploreContext from '@/context/explore-context'
|
import ExploreContext from '@/context/explore-context'
|
||||||
import Sidebar from '@/app/components/explore/sidebar'
|
import Sidebar from '@/app/components/explore/sidebar'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
@ -42,6 +43,16 @@ const Explore: FC<IExploreProps> = ({
|
|||||||
return router.replace('/datasets')
|
return router.replace('/datasets')
|
||||||
}, [isCurrentWorkspaceDatasetOperator])
|
}, [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 (
|
return (
|
||||||
<div className='flex h-full overflow-hidden border-t border-divider-regular bg-background-body'>
|
<div className='flex h-full overflow-hidden border-t border-divider-regular bg-background-body'>
|
||||||
<ExploreContext.Provider
|
<ExploreContext.Provider
|
||||||
@ -54,6 +65,9 @@ const Explore: FC<IExploreProps> = ({
|
|||||||
setInstalledApps,
|
setInstalledApps,
|
||||||
isFetchingInstalledApps,
|
isFetchingInstalledApps,
|
||||||
setIsFetchingInstalledApps,
|
setIsFetchingInstalledApps,
|
||||||
|
currentApp: currentTryAppParams,
|
||||||
|
isShowTryAppPanel,
|
||||||
|
setShowTryAppPanel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
32
web/app/components/explore/try-app/index.tsx
Normal file
32
web/app/components/explore/try-app/index.tsx
Normal file
@ -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)
|
||||||
34
web/app/components/explore/try-app/tab.tsx
Normal file
34
web/app/components/explore/try-app/tab.tsx
Normal file
@ -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 type { InstalledApp } from '@/models/explore'
|
||||||
import { noop } from 'lodash-es'
|
import { noop } from 'lodash-es'
|
||||||
|
|
||||||
|
export type CurrentTryAppParams = {
|
||||||
|
appId: string
|
||||||
|
}
|
||||||
|
|
||||||
type IExplore = {
|
type IExplore = {
|
||||||
controlUpdateInstalledApps: number
|
controlUpdateInstalledApps: number
|
||||||
setControlUpdateInstalledApps: (controlUpdateInstalledApps: number) => void
|
setControlUpdateInstalledApps: (controlUpdateInstalledApps: number) => void
|
||||||
@ -10,6 +14,9 @@ type IExplore = {
|
|||||||
setInstalledApps: (installedApps: InstalledApp[]) => void
|
setInstalledApps: (installedApps: InstalledApp[]) => void
|
||||||
isFetchingInstalledApps: boolean
|
isFetchingInstalledApps: boolean
|
||||||
setIsFetchingInstalledApps: (isFetchingInstalledApps: boolean) => void
|
setIsFetchingInstalledApps: (isFetchingInstalledApps: boolean) => void
|
||||||
|
currentApp?: CurrentTryAppParams
|
||||||
|
isShowTryAppPanel: boolean
|
||||||
|
setShowTryAppPanel: (showTryAppPanel: boolean, params?: CurrentTryAppParams) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExploreContext = createContext<IExplore>({
|
const ExploreContext = createContext<IExplore>({
|
||||||
@ -20,6 +27,9 @@ const ExploreContext = createContext<IExplore>({
|
|||||||
setInstalledApps: noop,
|
setInstalledApps: noop,
|
||||||
isFetchingInstalledApps: false,
|
isFetchingInstalledApps: false,
|
||||||
setIsFetchingInstalledApps: noop,
|
setIsFetchingInstalledApps: noop,
|
||||||
|
isShowTryAppPanel: false,
|
||||||
|
setShowTryAppPanel: noop,
|
||||||
|
currentApp: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ExploreContext
|
export default ExploreContext
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user