diff --git a/api/controllers/console/explore/installed_app.py b/api/controllers/console/explore/installed_app.py index b60c4e176b3214..3de179164de91d 100644 --- a/api/controllers/console/explore/installed_app.py +++ b/api/controllers/console/explore/installed_app.py @@ -1,5 +1,6 @@ from datetime import UTC, datetime +from flask import request from flask_login import current_user from flask_restful import Resource, inputs, marshal_with, reqparse from sqlalchemy import and_ @@ -20,8 +21,17 @@ class InstalledAppsListApi(Resource): @account_initialization_required @marshal_with(installed_app_list_fields) def get(self): + app_id = request.args.get("app_id", default=None, type=str) current_tenant_id = current_user.current_tenant_id - installed_apps = db.session.query(InstalledApp).filter(InstalledApp.tenant_id == current_tenant_id).all() + + if app_id: + installed_apps = ( + db.session.query(InstalledApp) + .filter(and_(InstalledApp.tenant_id == current_tenant_id, InstalledApp.app_id == app_id)) + .all() + ) + else: + installed_apps = db.session.query(InstalledApp).filter(InstalledApp.tenant_id == current_tenant_id).all() current_user.role = TenantService.get_user_role(current_user, current_user.current_tenant) installed_apps = [ diff --git a/web/app/(commonLayout)/apps/AppCard.tsx b/web/app/(commonLayout)/apps/AppCard.tsx index 1ffb132cf8c186..4d1537d38dbccd 100644 --- a/web/app/(commonLayout)/apps/AppCard.tsx +++ b/web/app/(commonLayout)/apps/AppCard.tsx @@ -9,6 +9,7 @@ import s from './style.module.css' import cn from '@/utils/classnames' import type { App } from '@/types/app' import Confirm from '@/app/components/base/confirm' +import Toast from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast' import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' import DuplicateAppModal from '@/app/components/app/duplicate-modal' @@ -31,6 +32,7 @@ import TagSelector from '@/app/components/base/tag-management/selector' import type { EnvironmentVariable } from '@/app/components/workflow/types' import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' import { fetchWorkflowDraft } from '@/service/workflow' +import { fetchInstalledAppList } from '@/service/explore' export type AppCardProps = { app: App @@ -209,6 +211,21 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { e.preventDefault() setShowConfirmDelete(true) } + const onClickInstalledApp = async (e: React.MouseEvent) => { + e.stopPropagation() + props.onClick?.() + e.preventDefault() + try { + const { installed_apps }: any = await fetchInstalledAppList(app.id) || {} + if (installed_apps?.length > 0) + window.open(`/explore/installed/${installed_apps[0].id}`, '_blank') + else + throw new Error('No app found in Explore') + } + catch (e: any) { + Toast.notify({ type: 'error', message: `${e.message || e}` }) + } + } return (
+
{ } popupClassName={ (app.mode === 'completion' || app.mode === 'chat') - ? '!w-[238px] translate-x-[-110px]' - : '' + ? '!w-[256px] translate-x-[-224px]' + : '!w-[160px] translate-x-[-128px]' } - className={'!w-[128px] h-fit !z-20'} + className={'h-fit !z-20'} />
diff --git a/web/app/components/app/app-publisher/index.tsx b/web/app/components/app/app-publisher/index.tsx index 0558e299560396..3ba35a73369d37 100644 --- a/web/app/components/app/app-publisher/index.tsx +++ b/web/app/components/app/app-publisher/index.tsx @@ -5,7 +5,8 @@ import { } from 'react' import { useTranslation } from 'react-i18next' import dayjs from 'dayjs' -import { RiArrowDownSLine } from '@remixicon/react' +import { RiArrowDownSLine, RiPlanetLine } from '@remixicon/react' +import Toast from '../../base/toast' import type { ModelAndParameter } from '../configuration/debug/types' import SuggestedAction from './suggested-action' import PublishWithMultipleModel from './publish-with-multiple-model' @@ -15,6 +16,7 @@ import { PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' +import { fetchInstalledAppList } from '@/service/explore' import EmbeddedModal from '@/app/components/app/overview/embedded' import { useStore as useAppStore } from '@/app/components/app/store' import { useGetLanguage } from '@/context/i18n' @@ -105,6 +107,19 @@ const AppPublisher = ({ setPublished(false) }, [disabled, onToggle, open]) + const handleOpenInExplore = useCallback(async () => { + try { + const { installed_apps }: any = await fetchInstalledAppList(appDetail?.id) || {} + if (installed_apps?.length > 0) + window.open(`/explore/installed/${installed_apps[0].id}`, '_blank') + else + throw new Error('No app found in Explore') + } + catch (e: any) { + Toast.notify({ type: 'error', message: `${e.message || e}` }) + } + }, [appDetail?.id]) + const [embeddingModalOpen, setEmbeddingModalOpen] = useState(false) return ( @@ -205,6 +220,15 @@ const AppPublisher = ({ {t('workflow.common.embedIntoSite')} )} + { + handleOpenInExplore() + }} + disabled={!publishedAt} + icon={} + > + {t('workflow.common.openInExplore')} + }>{t('workflow.common.accessAPIReference')} {appDetail?.mode === 'workflow' && ( => { return get(`/explore/apps/${id}`) } -export const fetchInstalledAppList = () => { - return get('/installed-apps') +export const fetchInstalledAppList = (app_id?: string | null) => { + return get(`/installed-apps${app_id ? `?app_id=${app_id}` : ''}`) } export const installApp = (id: string) => {