11// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
22// See LICENSE.txt for license information.
33
4- import React , { useEffect , useState } from 'react' ;
4+ import React , { useEffect , useMemo , useState } from 'react' ;
55import PropTypes from 'prop-types' ;
66import './tooltip.css' ;
7- import { GitMergeIcon , GitPullRequestIcon , IssueClosedIcon , IssueOpenedIcon } from '@primer/octicons-react' ;
7+ import { GitMergeIcon , GitPullRequestIcon , IssueClosedIcon , IssueOpenedIcon } from '@primer/octicons-react' ;
88import ReactMarkdown from 'react-markdown' ;
99
1010import Client from '@/client' ;
1111
12- import { getLabelFontColor , hexToRGB } from '../../utils/styles' ;
12+ import { getLabelFontColor , hexToRGB } from '../../utils/styles' ;
1313
1414const maxTicketDescriptionLength = 160 ;
1515
16- export const LinkTooltip = ( { href, connected, show, theme} ) => {
16+ export const LinkTooltip = ( { href, connected, show, theme, enterpriseURL } ) => {
1717 const [ data , setData ] = useState ( null ) ;
1818 useEffect ( ( ) => {
1919 const initData = async ( ) => {
20- if ( href . includes ( 'github.com/' ) ) {
21- const [ owner , repo , type , number ] = href . split ( 'github.com/' ) [ 1 ] . split ( '/' ) ;
22- if ( ! owner | ! repo | ! type | ! number ) {
23- return ;
20+ let owner ;
21+ let repo ;
22+ let type ;
23+ let number ;
24+
25+ if ( enterpriseURL ) {
26+ const entURL = enterpriseURL . endsWith ( '/' ) ? enterpriseURL : enterpriseURL + '/' ;
27+ if ( href . startsWith ( entURL ) ) {
28+ [ owner , repo , type , number ] = href . substring ( entURL . length ) . split ( '/' ) ;
2429 }
30+ } else if ( href . includes ( 'github.com/' ) ) {
31+ [ owner , repo , type , number ] = href . split ( 'github.com/' ) [ 1 ] . split ( '/' ) ;
32+ }
33+
34+ if ( ! owner || ! repo || ! type || ! number ) {
35+ return ;
36+ }
2537
26- let res ;
27- switch ( type ) {
38+ let res ;
39+ switch ( type ) {
2840 case 'issues' :
2941 res = await Client . getIssue ( owner , repo , number ) ;
3042 break ;
3143 case 'pull' :
3244 res = await Client . getPullRequest ( owner , repo , number ) ;
3345 break ;
34- }
35- if ( res ) {
36- res . owner = owner ;
37- res . repo = repo ;
38- res . type = type ;
39- }
40- setData ( res ) ;
4146 }
47+ if ( res ) {
48+ res . owner = owner ;
49+ res . repo = repo ;
50+ res . type = type ;
51+ }
52+ setData ( res ) ;
4253 } ;
4354
4455 // show is not provided for Mattermost Server < 5.28
@@ -47,7 +58,26 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
4758 }
4859
4960 initData ( ) ;
50- } , [ connected , data , href , show ] ) ;
61+ } , [ connected , data , href , show , enterpriseURL ] ) ;
62+
63+ const openedByLink = useMemo ( ( ) => {
64+ if ( ! data ?. user ?. login ) {
65+ return null ;
66+ }
67+ // Immediately map the html_url value when present (which should work for both Enterprise and Cloud)
68+ if ( data . user . html_url ) {
69+ return data . user . html_url ;
70+ }
71+
72+ // Fallback to a generic enterprise URL when appropriate, handling possible trailing slashes
73+ if ( enterpriseURL ) {
74+ const entURL = enterpriseURL . endsWith ( '/' ) ? enterpriseURL : enterpriseURL + '/' ;
75+ return `${ entURL } ${ data . user . login } ` ;
76+ }
77+
78+ // Assume it's GitHub cloud and fallback to the original path (unlikely to ever run unless there are breaking changes in GitHub's API
79+ return `https://github.com/${ data . user . login } ` ;
80+ } , [ data , enterpriseURL ] ) ;
5181
5282 const getIconElement = ( ) => {
5383 const iconProps = {
@@ -58,32 +88,32 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
5888 let icon ;
5989 let color ;
6090 switch ( data . type ) {
61- case 'pull' :
62- icon = < GitPullRequestIcon { ...iconProps } /> ;
63-
64- color = '#28a745' ;
65- if ( data . state === 'closed' ) {
66- if ( data . merged ) {
67- color = '#6f42c1' ;
68- icon = < GitMergeIcon { ...iconProps } /> ;
69- } else {
70- color = '#cb2431' ;
91+ case 'pull' :
92+ icon = < GitPullRequestIcon { ...iconProps } /> ;
93+
94+ color = '#28a745' ;
95+ if ( data . state === 'closed' ) {
96+ if ( data . merged ) {
97+ color = '#6f42c1' ;
98+ icon = < GitMergeIcon { ...iconProps } /> ;
99+ } else {
100+ color = '#cb2431' ;
101+ }
71102 }
72- }
73103
74- break ;
75- case 'issues' :
76- color = data . state === 'open' ? '#28a745' : '#cb2431' ;
104+ break ;
105+ case 'issues' :
106+ color = data . state === 'open' ? '#28a745' : '#cb2431' ;
77107
78- if ( data . state === 'open' ) {
79- icon = < IssueOpenedIcon { ...iconProps } /> ;
80- } else {
81- icon = < IssueClosedIcon { ...iconProps } /> ;
82- }
83- break ;
108+ if ( data . state === 'open' ) {
109+ icon = < IssueOpenedIcon { ...iconProps } /> ;
110+ } else {
111+ icon = < IssueClosedIcon { ...iconProps } /> ;
112+ }
113+ break ;
84114 }
85115 return (
86- < span style = { { color} } >
116+ < span style = { { color } } >
87117 { icon }
88118 </ span >
89119 ) ;
@@ -105,10 +135,10 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
105135 < div className = 'github-tooltip' >
106136 < div
107137 className = 'github-tooltip box github-tooltip--large github-tooltip--bottom-left p-4'
108- style = { { backgroundColor : theme . centerChannelBg , border : `1px solid ${ hexToRGB ( theme . centerChannelColor , '0.16' ) } ` } }
138+ style = { { backgroundColor : theme . centerChannelBg , border : `1px solid ${ hexToRGB ( theme . centerChannelColor , '0.16' ) } ` } }
109139 >
110140 < div className = 'header mb-1' >
111- < span style = { { color : theme . centerChannelColor } } >
141+ < span style = { { color : theme . centerChannelColor } } >
112142 { data . repo }
113143 </ span >
114144 { ' on ' }
@@ -117,7 +147,7 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
117147
118148 < div className = 'body d-flex mt-2' >
119149 < span className = 'pt-1 pb-1 pr-2' >
120- { getIconElement ( ) }
150+ { getIconElement ( ) }
121151 </ span >
122152
123153 { /* info */ }
@@ -126,7 +156,7 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
126156 href = { href }
127157 target = '_blank'
128158 rel = 'noopener noreferrer'
129- style = { { color : theme . centerChannelColor } }
159+ style = { { color : theme . centerChannelColor } }
130160 >
131161 < h5 className = 'mr-1' > { data . title } </ h5 >
132162 < span > { '#' + data . number } </ span >
@@ -135,7 +165,7 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
135165 < p className = 'opened-by' >
136166 { 'Opened by ' }
137167 < a
138- href = { `https://github.com/ ${ data . user . login } ` }
168+ href = { openedByLink }
139169 target = '_blank'
140170 rel = 'noopener noreferrer'
141171 >
@@ -172,7 +202,7 @@ export const LinkTooltip = ({href, connected, show, theme}) => {
172202 key = { idx }
173203 className = 'label mr-1'
174204 title = { label . description }
175- style = { { backgroundColor : '#' + label . color , color : getLabelFontColor ( label . color ) } }
205+ style = { { backgroundColor : '#' + label . color , color : getLabelFontColor ( label . color ) } }
176206 >
177207 < span > { label . name } </ span >
178208 </ span >
@@ -193,4 +223,5 @@ LinkTooltip.propTypes = {
193223 connected : PropTypes . bool . isRequired ,
194224 theme : PropTypes . object . isRequired ,
195225 show : PropTypes . bool ,
226+ enterpriseURL : PropTypes . string ,
196227} ;
0 commit comments