diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py
index fda5a7d3bb..9bddbb4b4b 100644
--- a/api/controllers/console/workspace/plugin.py
+++ b/api/controllers/console/workspace/plugin.py
@@ -41,12 +41,16 @@ class PluginListApi(Resource):
@account_initialization_required
def get(self):
tenant_id = current_user.current_tenant_id
+ parser = reqparse.RequestParser()
+ parser.add_argument("page", type=int, required=False, location="args", default=1)
+ parser.add_argument("page_size", type=int, required=False, location="args", default=256)
+ args = parser.parse_args()
try:
- plugins = PluginService.list(tenant_id)
+ plugins_with_total = PluginService.list_with_total(tenant_id, args["page"], args["page_size"])
except PluginDaemonClientSideError as e:
raise ValueError(e)
- return jsonable_encoder({"plugins": plugins})
+ return jsonable_encoder({"plugins": plugins_with_total.list, "total": plugins_with_total.total})
class PluginListLatestVersionsApi(Resource):
diff --git a/api/core/plugin/entities/plugin_daemon.py b/api/core/plugin/entities/plugin_daemon.py
index 2bea07bea0..e9275c31cc 100644
--- a/api/core/plugin/entities/plugin_daemon.py
+++ b/api/core/plugin/entities/plugin_daemon.py
@@ -9,7 +9,7 @@ from core.agent.plugin_entities import AgentProviderEntityWithPlugin
from core.model_runtime.entities.model_entities import AIModelEntity
from core.model_runtime.entities.provider_entities import ProviderEntity
from core.plugin.entities.base import BasePluginEntity
-from core.plugin.entities.plugin import PluginDeclaration
+from core.plugin.entities.plugin import PluginDeclaration, PluginEntity
from core.tools.entities.common_entities import I18nObject
from core.tools.entities.tool_entities import ToolProviderEntityWithPlugin
@@ -167,3 +167,8 @@ class PluginOAuthAuthorizationUrlResponse(BaseModel):
class PluginOAuthCredentialsResponse(BaseModel):
credentials: Mapping[str, Any] = Field(description="The credentials of the OAuth.")
+
+
+class PluginListResponse(BaseModel):
+ list: list[PluginEntity]
+ total: int
diff --git a/api/core/plugin/impl/plugin.py b/api/core/plugin/impl/plugin.py
index 3349463ce5..1cd2dc1be7 100644
--- a/api/core/plugin/impl/plugin.py
+++ b/api/core/plugin/impl/plugin.py
@@ -9,7 +9,12 @@ from core.plugin.entities.plugin import (
PluginInstallation,
PluginInstallationSource,
)
-from core.plugin.entities.plugin_daemon import PluginInstallTask, PluginInstallTaskStartResponse, PluginUploadResponse
+from core.plugin.entities.plugin_daemon import (
+ PluginInstallTask,
+ PluginInstallTaskStartResponse,
+ PluginListResponse,
+ PluginUploadResponse,
+)
from core.plugin.impl.base import BasePluginClient
@@ -27,11 +32,20 @@ class PluginInstaller(BasePluginClient):
)
def list_plugins(self, tenant_id: str) -> list[PluginEntity]:
+ result = self._request_with_plugin_daemon_response(
+ "GET",
+ f"plugin/{tenant_id}/management/list",
+ PluginListResponse,
+ params={"page": 1, "page_size": 256},
+ )
+ return result.list
+
+ def list_plugins_with_total(self, tenant_id: str, page: int, page_size: int) -> PluginListResponse:
return self._request_with_plugin_daemon_response(
"GET",
f"plugin/{tenant_id}/management/list",
- list[PluginEntity],
- params={"page": 1, "page_size": 256},
+ PluginListResponse,
+ params={"page": page, "page_size": page_size},
)
def upload_pkg(
diff --git a/api/services/plugin/plugin_service.py b/api/services/plugin/plugin_service.py
index be722a59ad..a8b64f27db 100644
--- a/api/services/plugin/plugin_service.py
+++ b/api/services/plugin/plugin_service.py
@@ -17,7 +17,7 @@ from core.plugin.entities.plugin import (
PluginInstallation,
PluginInstallationSource,
)
-from core.plugin.entities.plugin_daemon import PluginInstallTask, PluginUploadResponse
+from core.plugin.entities.plugin_daemon import PluginInstallTask, PluginListResponse, PluginUploadResponse
from core.plugin.impl.asset import PluginAssetManager
from core.plugin.impl.debugging import PluginDebuggingClient
from core.plugin.impl.plugin import PluginInstaller
@@ -110,6 +110,15 @@ class PluginService:
plugins = manager.list_plugins(tenant_id)
return plugins
+ @staticmethod
+ def list_with_total(tenant_id: str, page: int, page_size: int) -> PluginListResponse:
+ """
+ list all plugins of the tenant
+ """
+ manager = PluginInstaller()
+ plugins = manager.list_plugins_with_total(tenant_id, page, page_size)
+ return plugins
+
@staticmethod
def list_installations_from_ids(tenant_id: str, ids: Sequence[str]) -> Sequence[PluginInstallation]:
"""
diff --git a/web/app/components/plugins/plugin-page/plugins-panel.tsx b/web/app/components/plugins/plugin-page/plugins-panel.tsx
index 125e6f0a70..513641f4b9 100644
--- a/web/app/components/plugins/plugin-page/plugins-panel.tsx
+++ b/web/app/components/plugins/plugin-page/plugins-panel.tsx
@@ -1,20 +1,23 @@
'use client'
import { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
import type { FilterState } from './filter-management'
import FilterManagement from './filter-management'
import List from './list'
-import { useInstalledLatestVersion, useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
+import { useInstalledLatestVersion, useInstalledPluginListWithPagination, useInvalidateInstalledPluginList } from '@/service/use-plugins'
import PluginDetailPanel from '@/app/components/plugins/plugin-detail-panel'
import { usePluginPageContext } from './context'
import { useDebounceFn } from 'ahooks'
+import Button from '@/app/components/base/button'
import Empty from './empty'
import Loading from '../../base/loading'
import { PluginSource } from '../types'
const PluginsPanel = () => {
+ const { t } = useTranslation()
const filters = usePluginPageContext(v => v.filters) as FilterState
const setFilters = usePluginPageContext(v => v.setFilters)
- const { data: pluginList, isLoading: isPluginListLoading } = useInstalledPluginList()
+ const { data: pluginList, isLoading: isPluginListLoading, isFetching, isLastPage, loadNextPage } = useInstalledPluginListWithPagination()
const { data: installedLatestVersion } = useInstalledLatestVersion(
pluginList?.plugins
.filter(plugin => plugin.source === PluginSource.marketplace)
@@ -64,10 +67,16 @@ const PluginsPanel = () => {
/>
{isPluginListLoading ?