'use client' import type { AppMode } from '@dify/contracts/api/console/installed-apps/types.gen' import type { AppData } from '@/models/share' import { useQuery, useSuspenseQuery } from '@tanstack/react-query' import * as React from 'react' import { useEffect } from 'react' import Loading from '@/app/components/base/loading' import TextGenerationApp from '@/app/components/share/text-generation' import { useWebAppStore } from '@/context/web-app-context' import { systemFeaturesQueryOptions } from '@/features/system-features/client' import { AccessMode } from '@/models/access-control' import dynamic from '@/next/dynamic' import { useGetUserCanAccessApp } from '@/service/access-control/use-app-access-control' import { consoleQuery } from '@/service/client' import AppUnavailable from '../../base/app-unavailable' import { toInstalledAppAccessMode, toInstalledAppMeta, toInstalledAppParameters } from './runtime' const ChatWithHistory = dynamic(() => import('@/app/components/base/chat/chat-with-history'), { ssr: false, }) const InstalledAppFrame = ({ children }: { children: React.ReactNode }) => (
{children}
) const installedAppSurfaceClassName = 'rounded-tr-none rounded-bl-none border-t-4 border-l-4 border-components-chat-input-border' const InstalledTextGenerationSurface = ({ children }: { children: React.ReactNode }) => (
{children}
) const getInstalledAppSurface = ( mode: AppMode, ): 'chat' | 'completion' | 'unsupported' | 'workflow' => { switch (mode) { case 'chat': case 'advanced-chat': case 'agent-chat': return 'chat' case 'completion': return 'completion' case 'workflow': return 'workflow' case 'agent': case 'channel': case 'rag-pipeline': return 'unsupported' } } const InstalledApp = ({ id }: { id: string }) => { const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) const webappAuthEnabled = systemFeatures.webapp_auth.enabled const { data: installedApp, isPending: isPendingInstalledApp, error: installedAppError, } = useQuery({ ...consoleQuery.installedApps.byInstalledAppId.get.queryOptions({ input: { params: { installed_app_id: id, }, }, }), }) const updateAppInfo = useWebAppStore((s) => s.updateAppInfo) const updateWebAppAccessMode = useWebAppStore((s) => s.updateWebAppAccessMode) const updateAppParams = useWebAppStore((s) => s.updateAppParams) const updateWebAppMeta = useWebAppStore((s) => s.updateWebAppMeta) const updateUserCanAccessApp = useWebAppStore((s) => s.updateUserCanAccessApp) const { isPending: isPendingWebAppAccessMode, data: webAppAccessMode, error: webAppAccessModeError, } = useQuery({ ...consoleQuery.enterprise.webAppAuth.getWebAppAccessMode.queryOptions({ input: { query: { appId: id } }, }), enabled: webappAuthEnabled, select: toInstalledAppAccessMode, }) const { isPending: isPendingAppParams, data: appParams, error: appParamsError, } = useQuery({ ...consoleQuery.installedApps.byInstalledAppId.parameters.get.queryOptions({ input: { params: { installed_app_id: id } }, }), select: toInstalledAppParameters, }) const { isPending: isPendingAppMeta, data: appMeta, error: appMetaError, } = useQuery({ ...consoleQuery.installedApps.byInstalledAppId.meta.get.queryOptions({ input: { params: { installed_app_id: id } }, }), select: toInstalledAppMeta, }) const resolvedWebAppAccessMode = webappAuthEnabled ? webAppAccessMode?.accessMode : AccessMode.PUBLIC const { data: userCanAccessApp, error: useCanAccessAppError, isPending: isPendingUserCanAccessApp, } = useGetUserCanAccessApp({ appId: installedApp?.app.id, isInstalledApp: true, }) useEffect(() => { if (!installedApp) { updateAppInfo(null) } else { const { id, app } = installedApp updateAppInfo({ app_id: id, site: { title: app.name, description: app.description, icon_type: app.icon_type, icon: app.icon ?? undefined, icon_background: app.icon_background, icon_url: app.icon_url, prompt_public: false, copyright: '', show_workflow_steps: true, use_icon_as_answer_icon: app.use_icon_as_answer_icon, }, custom_config: null, } satisfies AppData) } if (appParams) updateAppParams(appParams) if (appMeta) updateWebAppMeta(appMeta) if (resolvedWebAppAccessMode) updateWebAppAccessMode(resolvedWebAppAccessMode) updateUserCanAccessApp(Boolean(userCanAccessApp?.result)) }, [ installedApp, appMeta, appParams, updateAppInfo, updateAppParams, updateUserCanAccessApp, updateWebAppMeta, userCanAccessApp, resolvedWebAppAccessMode, updateWebAppAccessMode, ]) if (appParamsError) { return (
) } if (appMetaError) { return (
) } if (useCanAccessAppError) { return (
) } if (webAppAccessModeError) { return (
) } if (installedAppError) { const isNotFound = installedAppError instanceof Response && installedAppError.status === 404 return (
{isNotFound ? ( ) : ( )}
) } if (userCanAccessApp && !userCanAccessApp.result) { return (
) } if ( isPendingInstalledApp || isPendingAppParams || isPendingAppMeta || (webappAuthEnabled && isPendingWebAppAccessMode) || isPendingUserCanAccessApp ) { return (
) } if (!installedApp) { return (
) } const surface = getInstalledAppSurface(installedApp.app.mode) if (surface === 'unsupported') { return (
) } return ( {surface === 'chat' && ( )} {surface === 'completion' && ( )} {surface === 'workflow' && ( )} ) } export default React.memo(InstalledApp)