@@ -3,11 +3,12 @@ import {
33 CodeOutlined ,
44 CopyOutlined ,
55 DownloadOutlined ,
6+ GitlabOutlined ,
67 QuestionCircleOutlined ,
78 SettingOutlined ,
89 SyncOutlined ,
910} from '@ant-design/icons' ;
10- import { Button , Card , Empty , message , Spin , Tag , Tooltip , Typography } from 'antd' ;
11+ import { Button , Card , Empty , message , Space , Spin , Tag , Tooltip , Typography } from 'antd' ;
1112import moment from 'moment' ;
1213
1314import { API } from '@/api' ;
@@ -23,6 +24,23 @@ const { Paragraph, Text, Title } = Typography;
2324const { normalizeAgentCapabilities } = require ( './capability-utils' ) ;
2425const { buildAgentIntroBlocks } = require ( './intro-utils' ) ;
2526
27+ // 将 gitUrl 转换为可在浏览器中直接打开的 HTTP(S) 仓库页面地址
28+ const getRepoWebUrl = ( gitUrl ?: string ) : string => {
29+ if ( ! gitUrl ) return '' ;
30+ const trimmed = gitUrl . trim ( ) ;
31+ if ( ! trimmed ) return '' ;
32+ // 兼容 SSH 格式:git@gitlab.xxx:group/project.git
33+ const sshMatch = trimmed . match ( / ^ g i t @ ( [ ^ : ] + ) : ( .+ ?) ( \. g i t ) ? $ / i) ;
34+ if ( sshMatch ) {
35+ return `http://${ sshMatch [ 1 ] } /${ sshMatch [ 2 ] } ` ;
36+ }
37+ // 兼容 HTTP(S) 格式,去除末尾 .git 后缀方便直接访问网页
38+ if ( / ^ h t t p s ? : \/ \/ / i. test ( trimmed ) ) {
39+ return trimmed . replace ( / \. g i t $ / i, '' ) ;
40+ }
41+ return trimmed ;
42+ } ;
43+
2644const RelatedAgentCard : React . FC < {
2745 item : AgentItem ;
2846 history : { push : ( path : string ) => void } ;
@@ -77,6 +95,20 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ name, history }
7795 return m . isValid ( ) ? m . format ( 'YYYY-MM-DD HH:mm:ss' ) : '-' ;
7896 } , [ detail ?. lastGitSyncAt , detail ?. updatedAt ] ) ;
7997
98+ // 打开 GitLab 远端仓库网页地址
99+ const handleOpenGitLab = ( ) => {
100+ if ( ! detail ?. gitUrl ) {
101+ message . info ( '尚未配置 Git 仓库地址' ) ;
102+ return ;
103+ }
104+ const webUrl = getRepoWebUrl ( detail . gitUrl ) ;
105+ if ( webUrl ) {
106+ safeOpenUrl ( webUrl ) ;
107+ } else {
108+ message . warning ( '无效的 Git 仓库地址' ) ;
109+ }
110+ } ;
111+
80112 const handleOpenSetting = ( ) => {
81113 if ( ! detail ) return ;
82114 setSettingVisible ( true ) ;
@@ -474,15 +506,29 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ name, history }
474506 className = "agent-side-sync"
475507 title = "Git 仓库设置"
476508 extra = {
477- < Tooltip title = "Git 仓库设置" >
478- < Button
479- type = "text"
480- size = "small"
481- className = "agent-side-sync-setting-btn"
482- icon = { < SettingOutlined /> }
483- onClick = { handleOpenSetting }
484- />
485- </ Tooltip >
509+ < Space size = { 4 } >
510+ < Tooltip title = { detail ?. gitUrl ? '打开仓库地址' : '未配置仓库地址' } >
511+ < span >
512+ < Button
513+ type = "text"
514+ size = "small"
515+ disabled = { ! detail ?. gitUrl }
516+ className = "agent-side-sync-gitlab-btn"
517+ icon = { < GitlabOutlined /> }
518+ onClick = { handleOpenGitLab }
519+ />
520+ </ span >
521+ </ Tooltip >
522+ < Tooltip title = "Git 仓库设置" >
523+ < Button
524+ type = "text"
525+ size = "small"
526+ className = "agent-side-sync-setting-btn"
527+ icon = { < SettingOutlined /> }
528+ onClick = { handleOpenSetting }
529+ />
530+ </ Tooltip >
531+ </ Space >
486532 }
487533 >
488534 { detail . gitUrl ? (
0 commit comments