From 12d2304d3d6bd84c9354eda48627d76a0ba4b567 Mon Sep 17 00:00:00 2001 From: CH3CHO Date: Wed, 25 Dec 2024 22:24:40 +0800 Subject: [PATCH] feat: Add AI dashboard page --- .../console/constant/UserConfigKey.java | 2 + .../console/controller/SystemController.java | 18 ++++++-- frontend/src/interfaces/dashboard.ts | 6 +++ frontend/src/locales/en-US/translation.json | 8 +++- frontend/src/locales/zh-CN/translation.json | 5 +- frontend/src/pages/_defaultProps.tsx | 4 +- frontend/src/pages/ai/dashboard.module.css | 3 ++ frontend/src/pages/ai/dashboard.tsx | 46 +++++++++++++++++++ frontend/src/pages/dashboard/index.tsx | 3 +- frontend/src/pages/layout.tsx | 15 +++++- frontend/src/services/dashboard.ts | 6 +-- 11 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 frontend/src/pages/ai/dashboard.module.css create mode 100644 frontend/src/pages/ai/dashboard.tsx diff --git a/backend/console/src/main/java/com/alibaba/higress/console/constant/UserConfigKey.java b/backend/console/src/main/java/com/alibaba/higress/console/constant/UserConfigKey.java index 6b9759ac..4a13d8d1 100644 --- a/backend/console/src/main/java/com/alibaba/higress/console/constant/UserConfigKey.java +++ b/backend/console/src/main/java/com/alibaba/higress/console/constant/UserConfigKey.java @@ -25,6 +25,7 @@ private UserConfigKey() {} public static final String LOGIN_PAGE_PROMPT_KEY = "login.prompt"; public static final String DASHBOARD_URL = "dashboard.url"; public static final String DASHBOARD_URL_PREFIX = "dashboard.url."; + public static final String DASHBOARD_BUILTIN = "dashboard.builtin"; public static final String CHAT_ENABLED = "chat.enabled"; public static final String ADMIN_PASSWORD_CHANGE_DISABLED = "admin.password-change.disabled"; @@ -35,6 +36,7 @@ private UserConfigKey() {} CONFIG_VALUE_TYPES.put(DASHBOARD_URL, String.class); CONFIG_VALUE_TYPES.put(CHAT_ENABLED, Boolean.class); CONFIG_VALUE_TYPES.put(ADMIN_PASSWORD_CHANGE_DISABLED, Boolean.class); + CONFIG_VALUE_TYPES.put(DASHBOARD_BUILTIN, Boolean.class); CONFIG_VALUE_TYPES.put(SYSTEM_INITIALIZED, Boolean.class); } diff --git a/backend/console/src/main/java/com/alibaba/higress/console/controller/SystemController.java b/backend/console/src/main/java/com/alibaba/higress/console/controller/SystemController.java index 9fb1dd7d..b2de6e69 100644 --- a/backend/console/src/main/java/com/alibaba/higress/console/controller/SystemController.java +++ b/backend/console/src/main/java/com/alibaba/higress/console/controller/SystemController.java @@ -17,6 +17,8 @@ import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; + import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -30,17 +32,18 @@ import org.springframework.web.bind.annotation.RestController; import com.alibaba.higress.console.constant.UserConfigKey; +import com.alibaba.higress.console.controller.dto.DashboardInfo; +import com.alibaba.higress.console.controller.dto.DashboardType; import com.alibaba.higress.console.controller.dto.Response; import com.alibaba.higress.console.controller.dto.SystemInfo; import com.alibaba.higress.console.controller.dto.SystemInitRequest; import com.alibaba.higress.console.controller.dto.User; -import com.alibaba.higress.sdk.exception.ValidationException; import com.alibaba.higress.console.controller.util.ControllerUtil; import com.alibaba.higress.console.service.ConfigService; +import com.alibaba.higress.console.service.DashboardService; import com.alibaba.higress.console.service.SessionService; import com.alibaba.higress.console.service.SystemService; - -import javax.annotation.PostConstruct; +import com.alibaba.higress.sdk.exception.ValidationException; /** * @author CH3CHO @@ -50,10 +53,16 @@ @Validated public class SystemController { + private DashboardService dashboardService; private SessionService sessionService; private ConfigService configService; private SystemService systemService; + @Autowired + public void setDashboardService(DashboardService dashboardService) { + this.dashboardService = dashboardService; + } + @Autowired public void setSessionService(SessionService sessionService) { this.sessionService = sessionService; @@ -72,6 +81,9 @@ public void setSystemService(SystemService systemService) { @PostConstruct public void syncSystemState() { configService.setConfig(UserConfigKey.SYSTEM_INITIALIZED, sessionService.isAdminInitialized()); + DashboardInfo dashboardInfo = dashboardService.getDashboardInfo(DashboardType.MAIN); + configService.setConfig(UserConfigKey.DASHBOARD_BUILTIN, + dashboardInfo != null && Boolean.TRUE.equals(dashboardInfo.getBuiltIn())); } @PostMapping("/init") diff --git a/frontend/src/interfaces/dashboard.ts b/frontend/src/interfaces/dashboard.ts index 8a2d0709..378e373c 100644 --- a/frontend/src/interfaces/dashboard.ts +++ b/frontend/src/interfaces/dashboard.ts @@ -2,3 +2,9 @@ export interface DashboardInfo { builtIn: boolean; url: string; } + +export enum DashboardType { + MAIN = "MAIN", + AI = "AI", + LOG = "LOG", +} diff --git a/frontend/src/locales/en-US/translation.json b/frontend/src/locales/en-US/translation.json index 337442b1..08feedb3 100644 --- a/frontend/src/locales/en-US/translation.json +++ b/frontend/src/locales/en-US/translation.json @@ -13,8 +13,13 @@ "serviceSources": "Service Sources", "serviceList": "Service List", "routeConfig": "Route Config", + "aiServiceManagement": "AI Service Config", + "aiRouteManagement": "AI Route Config", + "aiDashboard": "AI Dashboard", + "llmProviderManagement": "LLM Provider Management", "domainManagement": "Domain Management", "certManagement": "Certificate Management", + "consumerManagement": "Consumer Management", "pluginManagement": "Plugin Management" }, "index": { @@ -185,6 +190,7 @@ "placeholder": { "type": "Please select LLM vendor", "name": "Please enter a name", + "agreement": "Please select a protocol", "serviceName": "Please enter a service name", "tokens": "Please enter authentication token", "domain": "Please enter domain name", @@ -203,7 +209,7 @@ "howtouse": "How to use", "AirouterUse": "How to use AI routing" }, - "create": "Provide AI service providers", + "create": "Create AI service provider", "edit": "Edit AI service provider", "deleteConfirmation": "Are you sure you want to delete < 1 > {{currentLlmProviderName}} ?", "deleteRoute": "Are you sure you want to delete < 1 > {{currentRouteName}} ?", diff --git a/frontend/src/locales/zh-CN/translation.json b/frontend/src/locales/zh-CN/translation.json index 4347869a..7a0a6fd4 100644 --- a/frontend/src/locales/zh-CN/translation.json +++ b/frontend/src/locales/zh-CN/translation.json @@ -15,6 +15,7 @@ "routeConfig": "路由配置", "aiServiceManagement": "AI流量入口管理", "aiRouteManagement": "AI路由管理", + "aiDashboard": "AI监控面板", "llmProviderManagement": "AI服务提供者管理", "domainManagement": "域名管理", "certManagement": "证书管理", @@ -168,8 +169,8 @@ "type": "大模型供应商", "name": "名称", "serviceName": "服务名称", - "agreement": "协议", "domain": "域名", + "agreement": "协议", "modelPredicate": "是否启用基于模型的路由匹配规则", "extra": "启用后,若请求目标服务失败,网关会改为请求降级服务。", "modelPredicatePrefix": "模型名称匹配规则", @@ -208,7 +209,7 @@ "howtouse": "使用方法", "AirouterUse": "AI路由使用方法" }, - "create": "提供AI服务提供者", + "create": "创建AI服务提供者", "edit": "编辑AI服务提供者", "deleteConfirmation": "确定删除 <1>{{currentLlmProviderName}} 吗?", "deleteRoute": "确定删除 <1>{{currentRouteName}} 吗?", diff --git a/frontend/src/pages/_defaultProps.tsx b/frontend/src/pages/_defaultProps.tsx index bb27072c..ec6ad13a 100644 --- a/frontend/src/pages/_defaultProps.tsx +++ b/frontend/src/pages/_defaultProps.tsx @@ -70,7 +70,9 @@ export default { path: '/ai/route', }, { - path: '/ai/config', + name: 'menu.aiDashboard', + path: '/ai/dashboard', + visiblePredicate: (configData: any) => configData && configData['dashboard.builtin'], }, ], }, diff --git a/frontend/src/pages/ai/dashboard.module.css b/frontend/src/pages/ai/dashboard.module.css new file mode 100644 index 00000000..901d2b70 --- /dev/null +++ b/frontend/src/pages/ai/dashboard.module.css @@ -0,0 +1,3 @@ +.mb0 { + margin-bottom: 0; +} diff --git a/frontend/src/pages/ai/dashboard.tsx b/frontend/src/pages/ai/dashboard.tsx new file mode 100644 index 00000000..2287ceb9 --- /dev/null +++ b/frontend/src/pages/ai/dashboard.tsx @@ -0,0 +1,46 @@ +import { DashboardType } from '@/interfaces/dashboard'; +import { getDashboardInfo } from '@/services'; +import { useRequest } from 'ahooks'; +import { Col, Row, Spin } from 'antd'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const Dashboard: React.FC = () => { + const { t } = useTranslation(); + + const { data: dashboardInfo, error, loading } = useRequest(() => getDashboardInfo(DashboardType.AI)); + + if (loading) { + return ( +
+ +
+ ); + } + + if (error || !dashboardInfo || !dashboardInfo.url) { + return ( +
+

{t('dashboard.loadFailed')}

+
+ ); + } + + const frameUrl = dashboardInfo.builtIn ? location.origin + dashboardInfo.url : dashboardInfo.url; + return ( + <> + + + {t('dashboard.openInNewPage')} + + +