From 96efd7da1873a86da40d881396f66779b7d81bfa Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Fri, 10 May 2024 20:15:25 +0900 Subject: [PATCH 01/15] make the new file statement to new file isUrlCanPreview --- webapp/src/components/link_tooltip/link_tooltip.jsx | 6 ++---- webapp/src/utils/github_utils.js | 7 +++++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 webapp/src/utils/github_utils.js diff --git a/webapp/src/components/link_tooltip/link_tooltip.jsx b/webapp/src/components/link_tooltip/link_tooltip.jsx index 806f79c45..c34383baa 100644 --- a/webapp/src/components/link_tooltip/link_tooltip.jsx +++ b/webapp/src/components/link_tooltip/link_tooltip.jsx @@ -6,6 +6,7 @@ import ReactMarkdown from 'react-markdown'; import Client from 'client'; import {getLabelFontColor, hexToRGB} from '../../utils/styles'; +import {isUrlCanPreview} from 'src/utils/github_utils'; const maxTicketDescriptionLength = 160; @@ -13,11 +14,8 @@ export const LinkTooltip = ({href, connected, show, theme}) => { const [data, setData] = useState(null); useEffect(() => { const initData = async () => { - if (href.includes('github.com/')) { + if (isUrlCanPreview(href)) { const [owner, repo, type, number] = href.split('github.com/')[1].split('/'); - if (!owner | !repo | !type | !number) { - return; - } let res; switch (type) { diff --git a/webapp/src/utils/github_utils.js b/webapp/src/utils/github_utils.js new file mode 100644 index 000000000..20b8bb1f4 --- /dev/null +++ b/webapp/src/utils/github_utils.js @@ -0,0 +1,7 @@ +export function isUrlCanPreview(url) { + if (url.includes('github.com/')) { + const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); + return !(!owner | !repo | !type | !number); + } + return false; +} From 503608256b7d41b8665570c1c9ba2c4d56a27deb Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Fri, 10 May 2024 20:15:29 +0900 Subject: [PATCH 02/15] fix css on tooltip labels It had use flex-related property without flex. so I added `display: flex` --- webapp/src/components/link_tooltip/tooltip.css | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/components/link_tooltip/tooltip.css b/webapp/src/components/link_tooltip/tooltip.css index 2c1475bff..dca33aff7 100644 --- a/webapp/src/components/link_tooltip/tooltip.css +++ b/webapp/src/components/link_tooltip/tooltip.css @@ -86,6 +86,7 @@ /* Labels */ .github-tooltip .labels { + display: flex; justify-content: flex-start; align-items: center; } From df4623ad33bb191b07ffab479189b3a185c1ceb7 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Fri, 10 May 2024 20:16:08 +0900 Subject: [PATCH 03/15] add link_preview component for pull and issue --- webapp/src/components/link_preview/index.jsx | 14 ++ .../components/link_preview/link_preview.jsx | 183 ++++++++++++++++++ .../src/components/link_preview/preview.css | 136 +++++++++++++ webapp/src/index.js | 3 + 4 files changed, 336 insertions(+) create mode 100644 webapp/src/components/link_preview/index.jsx create mode 100644 webapp/src/components/link_preview/link_preview.jsx create mode 100644 webapp/src/components/link_preview/preview.css diff --git a/webapp/src/components/link_preview/index.jsx b/webapp/src/components/link_preview/index.jsx new file mode 100644 index 000000000..ca2f97605 --- /dev/null +++ b/webapp/src/components/link_preview/index.jsx @@ -0,0 +1,14 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {connect} from 'react-redux'; + +import manifest from 'manifest'; + +import {LinkPreview} from './link_preview'; + +const mapStateToProps = (state) => { + return {connected: state[`plugins-${manifest.id}`].connected}; +}; + +export default connect(mapStateToProps, null)(LinkPreview); diff --git a/webapp/src/components/link_preview/link_preview.jsx b/webapp/src/components/link_preview/link_preview.jsx new file mode 100644 index 000000000..054e6ef60 --- /dev/null +++ b/webapp/src/components/link_preview/link_preview.jsx @@ -0,0 +1,183 @@ +import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon} from '@primer/octicons-react'; +import PropTypes from 'prop-types'; +import React, {useEffect, useState} from 'react'; +import ReactMarkdown from 'react-markdown'; +import './preview.css'; + +import Client from 'client'; +import {getLabelFontColor} from '../../utils/styles'; +import {isUrlCanPreview} from 'src/utils/github_utils'; + +const maxTicketDescriptionLength = 160; + +export const LinkPreview = ({embed: {url}, connected}) => { + const [data, setData] = useState(null); + useEffect(() => { + const initData = async () => { + if (isUrlCanPreview(url)) { + const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); + + let res; + switch (type) { + case 'issues': + res = await Client.getIssue(owner, repo, number); + break; + case 'pull': + res = await Client.getPullRequest(owner, repo, number); + break; + } + if (res) { + res.owner = owner; + res.repo = repo; + res.type = type; + } + setData(res); + } + }; + + // show is not provided for Mattermost Server < 5.28 + if (!connected || data) { + return; + } + + initData(); + }, [connected, data, url]); + + const getIconElement = () => { + const iconProps = { + size: 'small', + verticalAlign: 'text-bottom', + }; + + let icon; + let color; + switch (data.type) { + case 'pull': + icon = ; + + color = '#28a745'; + if (data.state === 'closed') { + if (data.merged) { + color = '#6f42c1'; + icon = ; + } else { + color = '#cb2431'; + } + } + + break; + case 'issues': + color = data.state === 'open' ? '#28a745' : '#cb2431'; + + if (data.state === 'open') { + icon = ; + } else { + icon = ; + } + break; + } + return ( + + {icon} + + ); + }; + + if (data) { + let date = new Date(data.created_at); + date = date.toDateString(); + + let description = ''; + if (data.body) { + description = data.body.substring(0, maxTicketDescriptionLength).trim(); + if (data.body.length > maxTicketDescriptionLength) { + description += '...'; + } + } + + return ( +
+
+ + {data.repo} + + {' on '} + {date} +
+ +
+ + {/* info */} +
+ +
+ + { getIconElement() } + + {data.title} +
+ {'#' + data.number} +
+
+ {description} +
+ +
+ {/* base <- head */} + {data.type === 'pull' && ( +
+
{'Base ← Head'}
+
+ {data.base.ref} + {'←'}{' '} + {data.head.ref} + +
+
+ )} + + {/* Labels */} + {data.labels && data.labels.length > 0 && ( +
+
{'Labels'}
+
+ {data.labels.map((label, idx) => { + return ( + + {label.name} + + ); + })} +
+
+ )} +
+
+
+
+ ); + } + return null; +}; + +LinkPreview.propTypes = { + embed: { + url: PropTypes.string.isRequired, + }, + connected: PropTypes.bool.isRequired, +}; diff --git a/webapp/src/components/link_preview/preview.css b/webapp/src/components/link_preview/preview.css new file mode 100644 index 000000000..7d21b5b30 --- /dev/null +++ b/webapp/src/components/link_preview/preview.css @@ -0,0 +1,136 @@ +:root { + --light-gray: #6a737d; + --blue: #274466; + --light-blue: #eff7ff; +} + +@media (min-width: 544px) { + .github-preview--large { + min-width: 320px; + } +} + +/* Github Preview */ +.github-preview { + background-color: var(--center-channel-bg-rgb); + box-shadow: 0 2px 3px rgba(0,0,0,.08); + position: relative; + width: 100%; + max-width: 700px; + border-radius: 4px; + border: 1px solid rgba(var(--center-channel-color-rgb), 0.16); +} + +/* Header */ +.github-preview .header { + color: rgba(var(--center-channel-color-rgb), 0.64); + font-size: 11px; + line-height: 16px; + white-space: nowrap; +} + +.github-preview .header a { + text-decoration: none; + color: rgba(var(--center-channel-color-rgb), 0.64); + display: inline-block; +} + +.github-preview .header .repo { + color: var(--center-channel-color-rgb); +} + +/* Body */ +.github-preview .body > span { + line-height: 1.25; +} + +/* Info */ +.github-preview .preview-info { + line-height: 1.25; + display: flex; + flex-direction: column; +} +.github-preview .preview-info > a, .github-preview .preview-info > a:hover { + display: block; + text-decoration: none; + color: var(--link-color); +} +.github-preview .preview-info > a span { + color: var(--light-gray); +} + +.github-preview .preview-info h5 { + font-weight: 600; + font-size: 14px; + display: inline; +} + +.github-preview .preview-info .markdown-text { + max-height: 150px; + line-height: 1.25; + overflow: hidden; + word-break: break-word; + word-wrap: break-word; + overflow-wrap: break-word; + font-size: 12px; +} + +.github-preview .preview-info .markdown-text::-webkit-scrollbar { + display: none; +} + +.github-preview .sub-info { + display: flex; + width: 100%; + flex-wrap: wrap; + gap: 4px 0; +} + +.github-preview .sub-info .sub-info-block { + display: flex; + flex-direction: column; + width: 50%; +} + +/* Labels */ +.github-preview .labels { + display: flex; + justify-content: flex-start; + align-items: center; + flex-wrap: wrap; + gap: 4px; +} + +.github-preview .label { + height: 20px; + padding: .15em 4px; + font-size: 12px; + font-weight: 600; + line-height: 15px; + border-radius: 2px; + box-shadow: inset 0 -1px 0 rgba(27,31,35,.12); + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + max-width: 125px; +} + +.github-preview .base-head { + display: flex; + line-height: 1; + align-items: center; +} + +.github-preview .commit-ref { + position: relative; + display: inline-block; + padding: 0 5px; + font: .75em/2 SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; + color: var(--blue); + background-color: var(--light-blue); + border-radius: 3px; + max-width: 140px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} diff --git a/webapp/src/index.js b/webapp/src/index.js index 4b0a50d2b..4c02f2539 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -10,12 +10,14 @@ import TeamSidebar from './components/team_sidebar'; import UserAttribute from './components/user_attribute'; import SidebarRight from './components/sidebar_right'; import LinkTooltip from './components/link_tooltip'; +import LinkPreview from './components/link_preview'; import Reducer from './reducers'; import Client from './client'; import {getConnected, setShowRHSAction} from './actions'; import {handleConnect, handleDisconnect, handleConfigurationUpdate, handleOpenCreateIssueModal, handleReconnect, handleRefresh} from './websocket'; import {getServerRoute} from './selectors'; import manifest from './manifest'; +import {isUrlCanPreview} from './utils/github_utils'; let activityFunc; let lastActivityTime = Number.MAX_SAFE_INTEGER; @@ -37,6 +39,7 @@ class PluginClass { registry.registerRootComponent(AttachCommentToIssueModal); registry.registerPostDropdownMenuComponent(AttachCommentToIssuePostMenuAction); registry.registerLinkTooltipComponent(LinkTooltip); + registry.registerPostWillRenderEmbedComponent((embed) => embed.url && isUrlCanPreview(embed.url), LinkPreview, true); const {showRHSPlugin} = registry.registerRightHandSidebarComponent(SidebarRight, 'GitHub'); store.dispatch(setShowRHSAction(() => store.dispatch(showRHSPlugin))); From e04cb25921c2bdb663a616938be1168704b227ba Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Thu, 16 May 2024 09:15:54 +0900 Subject: [PATCH 04/15] add array length check on statement --- webapp/src/utils/github_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/utils/github_utils.js b/webapp/src/utils/github_utils.js index 20b8bb1f4..9c7782261 100644 --- a/webapp/src/utils/github_utils.js +++ b/webapp/src/utils/github_utils.js @@ -1,5 +1,5 @@ export function isUrlCanPreview(url) { - if (url.includes('github.com/')) { + if (url.includes('github.com/') && url.split('github.com/')[1]) { const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); return !(!owner | !repo | !type | !number); } From 14c9e8bb74cd0f9cc6d92d6040cc05a88bb0cf6f Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Thu, 16 May 2024 09:35:41 +0900 Subject: [PATCH 05/15] move color value to css --- .../components/link_preview/link_preview.jsx | 23 ++++++++++--------- .../src/components/link_preview/preview.css | 20 ++++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/webapp/src/components/link_preview/link_preview.jsx b/webapp/src/components/link_preview/link_preview.jsx index 054e6ef60..fa3639e50 100644 --- a/webapp/src/components/link_preview/link_preview.jsx +++ b/webapp/src/components/link_preview/link_preview.jsx @@ -1,4 +1,4 @@ -import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon} from '@primer/octicons-react'; +import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, SkipIcon} from '@primer/octicons-react'; import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; import ReactMarkdown from 'react-markdown'; @@ -50,34 +50,37 @@ export const LinkPreview = ({embed: {url}, connected}) => { }; let icon; - let color; + let colorClass; switch (data.type) { case 'pull': icon = ; - color = '#28a745'; + colorClass = 'github-preview-icon-open'; if (data.state === 'closed') { if (data.merged) { - color = '#6f42c1'; + colorClass = 'github-preview-icon-merged'; icon = ; } else { - color = '#cb2431'; + colorClass = 'github-preview-icon-closed'; } } break; case 'issues': - color = data.state === 'open' ? '#28a745' : '#cb2431'; - if (data.state === 'open') { + colorClass = 'github-preview-icon-open'; icon = ; + } else if (data.state_reason === 'not_planned') { + colorClass = 'github-preview-icon-not-planned'; + icon = ; } else { + colorClass = 'github-preview-icon-merged'; icon = ; } break; } return ( - + {icon} ); @@ -115,9 +118,7 @@ export const LinkPreview = ({embed: {url}, connected}) => { rel='noopener noreferrer' >
- - { getIconElement() } - + { getIconElement() } {data.title}
{'#' + data.number} diff --git a/webapp/src/components/link_preview/preview.css b/webapp/src/components/link_preview/preview.css index 7d21b5b30..3aa5569ba 100644 --- a/webapp/src/components/link_preview/preview.css +++ b/webapp/src/components/link_preview/preview.css @@ -2,6 +2,10 @@ --light-gray: #6a737d; --blue: #274466; --light-blue: #eff7ff; + --github-merged: #6f42c1; + --github-closed: #cb2431; + --github-open: #28a745; + --github-not-planned: #6e7681 } @media (min-width: 544px) { @@ -65,6 +69,22 @@ display: inline; } +.github-preview .preview-info h5 span.github-preview-icon-opened { + color: var(--github-open); +} + +.github-preview .preview-info h5 span.github-preview-icon-closed { + color: var(--github-closed); +} + +.github-preview .preview-info h5 span.github-preview-icon-merged { + color: var(--github-merged); +} + +.github-preview .preview-info h5 span.github-preview-icon-not-planned { + color: var(--github-not-planned); +} + .github-preview .preview-info .markdown-text { max-height: 150px; line-height: 1.25; From 7633e5bf7f545295f7657768d3620ee208f46bc3 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Mon, 20 May 2024 10:22:39 +0900 Subject: [PATCH 06/15] link preview to link embed preview --- .../preview.css => link_embed_preview/embed_preview.css} | 0 .../{link_preview => link_embed_preview}/index.jsx | 4 ++-- .../link_embed_preview.jsx} | 6 +++--- webapp/src/index.js | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename webapp/src/components/{link_preview/preview.css => link_embed_preview/embed_preview.css} (100%) rename webapp/src/components/{link_preview => link_embed_preview}/index.jsx (71%) rename webapp/src/components/{link_preview/link_preview.jsx => link_embed_preview/link_embed_preview.jsx} (98%) diff --git a/webapp/src/components/link_preview/preview.css b/webapp/src/components/link_embed_preview/embed_preview.css similarity index 100% rename from webapp/src/components/link_preview/preview.css rename to webapp/src/components/link_embed_preview/embed_preview.css diff --git a/webapp/src/components/link_preview/index.jsx b/webapp/src/components/link_embed_preview/index.jsx similarity index 71% rename from webapp/src/components/link_preview/index.jsx rename to webapp/src/components/link_embed_preview/index.jsx index ca2f97605..309dd980e 100644 --- a/webapp/src/components/link_preview/index.jsx +++ b/webapp/src/components/link_embed_preview/index.jsx @@ -5,10 +5,10 @@ import {connect} from 'react-redux'; import manifest from 'manifest'; -import {LinkPreview} from './link_preview'; +import {LinkEmbedPreview} from './link_embed_preview'; const mapStateToProps = (state) => { return {connected: state[`plugins-${manifest.id}`].connected}; }; -export default connect(mapStateToProps, null)(LinkPreview); +export default connect(mapStateToProps, null)(LinkEmbedPreview); diff --git a/webapp/src/components/link_preview/link_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.jsx similarity index 98% rename from webapp/src/components/link_preview/link_preview.jsx rename to webapp/src/components/link_embed_preview/link_embed_preview.jsx index fa3639e50..a99a51ae5 100644 --- a/webapp/src/components/link_preview/link_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.jsx @@ -2,7 +2,7 @@ import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, Skip import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; import ReactMarkdown from 'react-markdown'; -import './preview.css'; +import './embed_preview.css'; import Client from 'client'; import {getLabelFontColor} from '../../utils/styles'; @@ -10,7 +10,7 @@ import {isUrlCanPreview} from 'src/utils/github_utils'; const maxTicketDescriptionLength = 160; -export const LinkPreview = ({embed: {url}, connected}) => { +export const LinkEmbedPreview = ({embed: {url}, connected}) => { const [data, setData] = useState(null); useEffect(() => { const initData = async () => { @@ -176,7 +176,7 @@ export const LinkPreview = ({embed: {url}, connected}) => { return null; }; -LinkPreview.propTypes = { +LinkEmbedPreview.propTypes = { embed: { url: PropTypes.string.isRequired, }, diff --git a/webapp/src/index.js b/webapp/src/index.js index 4c02f2539..49773a99c 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -10,7 +10,7 @@ import TeamSidebar from './components/team_sidebar'; import UserAttribute from './components/user_attribute'; import SidebarRight from './components/sidebar_right'; import LinkTooltip from './components/link_tooltip'; -import LinkPreview from './components/link_preview'; +import LinkEmbedPreview from './components/link_embed_preview'; import Reducer from './reducers'; import Client from './client'; import {getConnected, setShowRHSAction} from './actions'; @@ -39,7 +39,7 @@ class PluginClass { registry.registerRootComponent(AttachCommentToIssueModal); registry.registerPostDropdownMenuComponent(AttachCommentToIssuePostMenuAction); registry.registerLinkTooltipComponent(LinkTooltip); - registry.registerPostWillRenderEmbedComponent((embed) => embed.url && isUrlCanPreview(embed.url), LinkPreview, true); + registry.registerPostWillRenderEmbedComponent((embed) => embed.url && isUrlCanPreview(embed.url), LinkEmbedPreview, true); const {showRHSPlugin} = registry.registerRightHandSidebarComponent(SidebarRight, 'GitHub'); store.dispatch(setShowRHSAction(() => store.dispatch(showRHSPlugin))); From 802c3601145e94328f33ad03325f54d0752fc96b Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Mon, 20 May 2024 10:24:31 +0900 Subject: [PATCH 07/15] make it ts and readable --- webapp/src/utils/{github_utils.js => github_utils.ts} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename webapp/src/utils/{github_utils.js => github_utils.ts} (63%) diff --git a/webapp/src/utils/github_utils.js b/webapp/src/utils/github_utils.ts similarity index 63% rename from webapp/src/utils/github_utils.js rename to webapp/src/utils/github_utils.ts index 9c7782261..74e209c1e 100644 --- a/webapp/src/utils/github_utils.js +++ b/webapp/src/utils/github_utils.ts @@ -1,7 +1,7 @@ -export function isUrlCanPreview(url) { +export function isUrlCanPreview(url: string) { if (url.includes('github.com/') && url.split('github.com/')[1]) { const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); - return !(!owner | !repo | !type | !number); + return Boolean(owner && repo && type && number); } return false; } From 6e0a69fa56ddf553bae4400eb92cff637423f94c Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Mon, 20 May 2024 10:38:40 +0900 Subject: [PATCH 08/15] early return on link_embed_preview --- .../link_embed_preview/link_embed_preview.jsx | 160 +++++++++--------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.jsx index a99a51ae5..d3aa30369 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.jsx @@ -86,94 +86,94 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => { ); }; - if (data) { - let date = new Date(data.created_at); - date = date.toDateString(); - - let description = ''; - if (data.body) { - description = data.body.substring(0, maxTicketDescriptionLength).trim(); - if (data.body.length > maxTicketDescriptionLength) { - description += '...'; - } + if (!data) { + return null; + } + let date = new Date(data.created_at); + date = date.toDateString(); + + let description = ''; + if (data.body) { + description = data.body.substring(0, maxTicketDescriptionLength).trim(); + if (data.body.length > maxTicketDescriptionLength) { + description += '...'; } + } - return ( -
-
- - {data.repo} - - {' on '} - {date} -
+ return ( +
+
+ + {data.repo} + + {' on '} + {date} +
+ +
+ + {/* info */} +
+ +
+ { getIconElement() } + {data.title} +
+ {'#' + data.number} +
+
+ {description} +
-
- - {/* info */} -
- -
- { getIconElement() } - {data.title} -
- {'#' + data.number} -
-
- {description} -
- -
- {/* base <- head */} - {data.type === 'pull' && ( -
-
{'Base ← Head'}
-
- {data.base.ref} - {'←'}{' '} - {data.head.ref} - -
+
+ {/* base <- head */} + {data.type === 'pull' && ( +
+
{'Base ← Head'}
+
+ {data.base.ref} + {'←'}{' '} + {data.head.ref} +
- )} - - {/* Labels */} - {data.labels && data.labels.length > 0 && ( -
-
{'Labels'}
-
- {data.labels.map((label, idx) => { - return ( - - {label.name} - - ); - })} -
+
+ )} + + {/* Labels */} + {data.labels && data.labels.length > 0 && ( +
+
{'Labels'}
+
+ {data.labels.map((label, idx) => { + return ( + + {label.name} + + ); + })}
- )} -
+
+ )}
- ); - } - return null; +
+ ); }; LinkEmbedPreview.propTypes = { From 0dfcb288bf0e72dad68a78aec09de94fa7e49eb7 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Mon, 20 May 2024 10:45:00 +0900 Subject: [PATCH 09/15] fix eslint error --- webapp/src/components/link_embed_preview/link_embed_preview.jsx | 2 +- webapp/src/components/link_tooltip/link_tooltip.jsx | 2 +- webapp/src/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.jsx index d3aa30369..39907a165 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.jsx @@ -6,7 +6,7 @@ import './embed_preview.css'; import Client from 'client'; import {getLabelFontColor} from '../../utils/styles'; -import {isUrlCanPreview} from 'src/utils/github_utils'; +import {isUrlCanPreview} from '../../utils/github_utils'; const maxTicketDescriptionLength = 160; diff --git a/webapp/src/components/link_tooltip/link_tooltip.jsx b/webapp/src/components/link_tooltip/link_tooltip.jsx index c34383baa..d0958fb58 100644 --- a/webapp/src/components/link_tooltip/link_tooltip.jsx +++ b/webapp/src/components/link_tooltip/link_tooltip.jsx @@ -6,7 +6,7 @@ import ReactMarkdown from 'react-markdown'; import Client from 'client'; import {getLabelFontColor, hexToRGB} from '../../utils/styles'; -import {isUrlCanPreview} from 'src/utils/github_utils'; +import {isUrlCanPreview} from '../../utils/github_utils'; const maxTicketDescriptionLength = 160; diff --git a/webapp/src/index.js b/webapp/src/index.js index 49773a99c..fbee5e38a 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -2,6 +2,7 @@ // See License.txt for license information. import AttachCommentToIssuePostMenuAction from 'components/post_menu_actions/attach_comment_to_issue'; import AttachCommentToIssueModal from 'components/modals/attach_comment_to_issue'; +import {isUrlCanPreview} from 'utils/github_utils'; import CreateIssueModal from './components/modals/create_issue'; import CreateIssuePostMenuAction from './components/post_menu_action/create_issue'; @@ -17,7 +18,6 @@ import {getConnected, setShowRHSAction} from './actions'; import {handleConnect, handleDisconnect, handleConfigurationUpdate, handleOpenCreateIssueModal, handleReconnect, handleRefresh} from './websocket'; import {getServerRoute} from './selectors'; import manifest from './manifest'; -import {isUrlCanPreview} from './utils/github_utils'; let activityFunc; let lastActivityTime = Number.MAX_SAFE_INTEGER; From 895ffcebd185a7da0b71a53f92a2b4f9527d2e71 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Wed, 22 May 2024 09:19:51 +0900 Subject: [PATCH 10/15] remove redundant comment --- webapp/src/components/link_embed_preview/link_embed_preview.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.jsx index 39907a165..4b350eb87 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.jsx @@ -35,7 +35,6 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => { } }; - // show is not provided for Mattermost Server < 5.28 if (!connected || data) { return; } From f5f39bd914252c2937fe3954704990dc9446b390 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Wed, 22 May 2024 10:25:26 +0900 Subject: [PATCH 11/15] fix the statement of isCanUrlPreview prevent such as https://google.com/https://github.com/mattermost/mattermost-plugin-github/pull/768 --- webapp/src/utils/github_utils.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp/src/utils/github_utils.ts b/webapp/src/utils/github_utils.ts index 74e209c1e..8596b6c63 100644 --- a/webapp/src/utils/github_utils.ts +++ b/webapp/src/utils/github_utils.ts @@ -1,6 +1,7 @@ export function isUrlCanPreview(url: string) { - if (url.includes('github.com/') && url.split('github.com/')[1]) { - const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); + const {hostname, pathname} = new URL(url); + if (hostname.includes('github.com') && pathname.split('/')[1]) { + const [_, owner, repo, type, number] = pathname.split('/'); return Boolean(owner && repo && type && number); } return false; From 95630fdaa37c4a2acc750f2c3ede46a79dd52a29 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Wed, 22 May 2024 10:55:30 +0900 Subject: [PATCH 12/15] convert css to scss --- .../link_embed_preview/embed_preview.css | 156 ----------------- .../link_embed_preview/embed_preview.scss | 157 ++++++++++++++++++ .../link_embed_preview/link_embed_preview.jsx | 2 +- 3 files changed, 158 insertions(+), 157 deletions(-) delete mode 100644 webapp/src/components/link_embed_preview/embed_preview.css create mode 100644 webapp/src/components/link_embed_preview/embed_preview.scss diff --git a/webapp/src/components/link_embed_preview/embed_preview.css b/webapp/src/components/link_embed_preview/embed_preview.css deleted file mode 100644 index 3aa5569ba..000000000 --- a/webapp/src/components/link_embed_preview/embed_preview.css +++ /dev/null @@ -1,156 +0,0 @@ -:root { - --light-gray: #6a737d; - --blue: #274466; - --light-blue: #eff7ff; - --github-merged: #6f42c1; - --github-closed: #cb2431; - --github-open: #28a745; - --github-not-planned: #6e7681 -} - -@media (min-width: 544px) { - .github-preview--large { - min-width: 320px; - } -} - -/* Github Preview */ -.github-preview { - background-color: var(--center-channel-bg-rgb); - box-shadow: 0 2px 3px rgba(0,0,0,.08); - position: relative; - width: 100%; - max-width: 700px; - border-radius: 4px; - border: 1px solid rgba(var(--center-channel-color-rgb), 0.16); -} - -/* Header */ -.github-preview .header { - color: rgba(var(--center-channel-color-rgb), 0.64); - font-size: 11px; - line-height: 16px; - white-space: nowrap; -} - -.github-preview .header a { - text-decoration: none; - color: rgba(var(--center-channel-color-rgb), 0.64); - display: inline-block; -} - -.github-preview .header .repo { - color: var(--center-channel-color-rgb); -} - -/* Body */ -.github-preview .body > span { - line-height: 1.25; -} - -/* Info */ -.github-preview .preview-info { - line-height: 1.25; - display: flex; - flex-direction: column; -} -.github-preview .preview-info > a, .github-preview .preview-info > a:hover { - display: block; - text-decoration: none; - color: var(--link-color); -} -.github-preview .preview-info > a span { - color: var(--light-gray); -} - -.github-preview .preview-info h5 { - font-weight: 600; - font-size: 14px; - display: inline; -} - -.github-preview .preview-info h5 span.github-preview-icon-opened { - color: var(--github-open); -} - -.github-preview .preview-info h5 span.github-preview-icon-closed { - color: var(--github-closed); -} - -.github-preview .preview-info h5 span.github-preview-icon-merged { - color: var(--github-merged); -} - -.github-preview .preview-info h5 span.github-preview-icon-not-planned { - color: var(--github-not-planned); -} - -.github-preview .preview-info .markdown-text { - max-height: 150px; - line-height: 1.25; - overflow: hidden; - word-break: break-word; - word-wrap: break-word; - overflow-wrap: break-word; - font-size: 12px; -} - -.github-preview .preview-info .markdown-text::-webkit-scrollbar { - display: none; -} - -.github-preview .sub-info { - display: flex; - width: 100%; - flex-wrap: wrap; - gap: 4px 0; -} - -.github-preview .sub-info .sub-info-block { - display: flex; - flex-direction: column; - width: 50%; -} - -/* Labels */ -.github-preview .labels { - display: flex; - justify-content: flex-start; - align-items: center; - flex-wrap: wrap; - gap: 4px; -} - -.github-preview .label { - height: 20px; - padding: .15em 4px; - font-size: 12px; - font-weight: 600; - line-height: 15px; - border-radius: 2px; - box-shadow: inset 0 -1px 0 rgba(27,31,35,.12); - display: inline-block; - overflow: hidden; - text-overflow: ellipsis; - max-width: 125px; -} - -.github-preview .base-head { - display: flex; - line-height: 1; - align-items: center; -} - -.github-preview .commit-ref { - position: relative; - display: inline-block; - padding: 0 5px; - font: .75em/2 SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; - color: var(--blue); - background-color: var(--light-blue); - border-radius: 3px; - max-width: 140px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} diff --git a/webapp/src/components/link_embed_preview/embed_preview.scss b/webapp/src/components/link_embed_preview/embed_preview.scss new file mode 100644 index 000000000..ae07ac939 --- /dev/null +++ b/webapp/src/components/link_embed_preview/embed_preview.scss @@ -0,0 +1,157 @@ +$light-gray: #6a737d; +$light-blue: #eff7ff; +$github-merged: #6f42c1; +$github-closed: #cb2431; +$github-open: #28a745; +$github-not-planned: #6e7681; + +@media (min-width: 544px) { + .github-preview--large { + min-width: 320px; + } +} + +/* Github Preview */ +.github-preview { + background-color: var(--center-channel-bg-rgb); + box-shadow: 0 2px 3px rgba(0,0,0,.08); + position: relative; + width: 100%; + max-width: 700px; + border-radius: 4px; + border: 1px solid rgba(var(--center-channel-color-rgb), 0.16); + + /* Header */ + .header { + color: rgba(var(--center-channel-color-rgb), 0.64); + font-size: 11px; + line-height: 16px; + white-space: nowrap; + + a { + text-decoration: none; + color: rgba(var(--center-channel-color-rgb), 0.64); + display: inline-block; + + .repo { + color: var(--center-channel-color-rgb); + } + } + } + + /* Body */ + .body > span { + line-height: 1.25; + } + + /* Info */ + .preview-info { + line-height: 1.25; + display: flex; + flex-direction: column; + + > a, + > a:hover { + display: block; + text-decoration: none; + color: var(--link-color); + } + + > a span { + color: var($light-gray); + + h5 { + font-weight: 600; + font-size: 14px; + display: inline; + + span.github-preview-icon-opened { + color: var($github-open); + } + + span.github-preview-icon-closed { + color: var($github-closed); + } + + span.github-preview-icon-merged { + color: var($github-merged); + } + + span.github-preview-icon-not-planned { + color: var($github-not-planned); + } + } + + .markdown-text { + max-height: 150px; + line-height: 1.25; + overflow: hidden; + word-break: break-word; + word-wrap: break-word; + overflow-wrap: break-word; + font-size: 12px; + + &::-webkit-scrollbar { + display: none; + } + } + } + } + + .sub-info { + display: flex; + width: 100%; + flex-wrap: wrap; + gap: 4px 0; + + .sub-info-block { + display: flex; + flex-direction: column; + width: 50%; + } + } + + /* Labels */ + .labels { + display: flex; + justify-content: flex-start; + align-items: center; + flex-wrap: wrap; + gap: 4px; + } + + .label { + height: 20px; + padding: .15em 4px; + font-size: 12px; + font-weight: 600; + line-height: 15px; + border-radius: 2px; + box-shadow: inset 0 -1px 0 rgba(27,31,35,.12); + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + max-width: 125px; + } + + .base-head { + display: flex; + line-height: 1; + align-items: center; + } + + .commit-ref { + position: relative; + display: inline-block; + padding: 0 5px; + font: .75em/2 SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; + color: var(--blue); + background-color: var($light-blue); + border-radius: 3px; + max-width: 140px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + +} \ No newline at end of file diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.jsx index 4b350eb87..5e9c2a8de 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.jsx @@ -2,7 +2,7 @@ import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, Skip import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; import ReactMarkdown from 'react-markdown'; -import './embed_preview.css'; +import './embed_preview.scss'; import Client from 'client'; import {getLabelFontColor} from '../../utils/styles'; From dac4f1d4851225eadbea12776f805d3a229fd9b2 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Thu, 23 May 2024 09:09:41 +0900 Subject: [PATCH 13/15] remove var() on scss variables --- .../components/link_embed_preview/embed_preview.scss | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webapp/src/components/link_embed_preview/embed_preview.scss b/webapp/src/components/link_embed_preview/embed_preview.scss index ae07ac939..b9d8c329d 100644 --- a/webapp/src/components/link_embed_preview/embed_preview.scss +++ b/webapp/src/components/link_embed_preview/embed_preview.scss @@ -58,7 +58,7 @@ $github-not-planned: #6e7681; } > a span { - color: var($light-gray); + color: $light-gray; h5 { font-weight: 600; @@ -66,19 +66,19 @@ $github-not-planned: #6e7681; display: inline; span.github-preview-icon-opened { - color: var($github-open); + color: $github-open; } span.github-preview-icon-closed { - color: var($github-closed); + color: $github-closed; } span.github-preview-icon-merged { - color: var($github-merged); + color: $github-merged; } span.github-preview-icon-not-planned { - color: var($github-not-planned); + color: $github-not-planned; } } @@ -146,7 +146,7 @@ $github-not-planned: #6e7681; padding: 0 5px; font: .75em/2 SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; color: var(--blue); - background-color: var($light-blue); + background-color: $light-blue; border-radius: 3px; max-width: 140px; text-overflow: ellipsis; From 5af2dbb962bd98e9a1a2966fca874b0c33ca7daf Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Mon, 8 Sep 2025 15:39:25 +0530 Subject: [PATCH 14/15] [MM-1518] Convert files from js to ts --- .../{index.jsx => index.ts} | 8 +- ...bed_preview.jsx => link_embed_preview.tsx} | 100 +++++++++++++----- webapp/src/types/github_types.ts | 77 +++++++++++++- 3 files changed, 156 insertions(+), 29 deletions(-) rename webapp/src/components/link_embed_preview/{index.jsx => index.ts} (58%) rename webapp/src/components/link_embed_preview/{link_embed_preview.jsx => link_embed_preview.tsx} (67%) diff --git a/webapp/src/components/link_embed_preview/index.jsx b/webapp/src/components/link_embed_preview/index.ts similarity index 58% rename from webapp/src/components/link_embed_preview/index.jsx rename to webapp/src/components/link_embed_preview/index.ts index 309dd980e..0eb46ac3f 100644 --- a/webapp/src/components/link_embed_preview/index.jsx +++ b/webapp/src/components/link_embed_preview/index.ts @@ -3,12 +3,12 @@ import {connect} from 'react-redux'; -import manifest from 'manifest'; - import {LinkEmbedPreview} from './link_embed_preview'; +import { GlobalState } from '@/types/store'; +import { getPluginState } from '@/selectors'; -const mapStateToProps = (state) => { - return {connected: state[`plugins-${manifest.id}`].connected}; +const mapStateToProps = (state: GlobalState) => { + return {connected: getPluginState(state).connected}; }; export default connect(mapStateToProps, null)(LinkEmbedPreview); diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.jsx b/webapp/src/components/link_embed_preview/link_embed_preview.tsx similarity index 67% rename from webapp/src/components/link_embed_preview/link_embed_preview.jsx rename to webapp/src/components/link_embed_preview/link_embed_preview.tsx index 5e9c2a8de..e5a1d8dee 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.jsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.tsx @@ -1,37 +1,87 @@ -import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, SkipIcon} from '@primer/octicons-react'; +import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, SkipIcon, IconProps} from '@primer/octicons-react'; import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; import ReactMarkdown from 'react-markdown'; import './embed_preview.scss'; -import Client from 'client'; import {getLabelFontColor} from '../../utils/styles'; import {isUrlCanPreview} from '../../utils/github_utils'; +import Client from '@/client'; const maxTicketDescriptionLength = 160; -export const LinkEmbedPreview = ({embed: {url}, connected}) => { - const [data, setData] = useState(null); +interface Label { + name: string; + color: string; + description?: string; +} + +interface RepoRef { + ref: string; +} + +interface GitHubData { + owner: string; + repo: string; + type: 'issues' | 'pull'; + state: string; + merged?: boolean; + state_reason?: string; + created_at: string; + title: string; + body?: string; + number: number; + labels?: Label[]; + base?: RepoRef; + head?: RepoRef; +} + +type LinkEmbedProps = { + embed: { + url: string; + }; + connected: boolean; +}; + +export const LinkEmbedPreview = ({embed: {url}, connected}: LinkEmbedProps) => { + const [data, setData] = useState(null); useEffect(() => { const initData = async () => { if (isUrlCanPreview(url)) { const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); - let res; - switch (type) { - case 'issues': - res = await Client.getIssue(owner, repo, number); - break; - case 'pull': - res = await Client.getPullRequest(owner, repo, number); - break; - } - if (res) { - res.owner = owner; - res.repo = repo; - res.type = type; + try { + let issueOrPR: any; + + if (type === 'issues') { + issueOrPR = await Client.getIssue(owner, repo, Number(number)); + } else if (type === 'pull') { + issueOrPR = await Client.getPullRequest(owner, repo, Number(number)); + } else { + return; + } + + if (issueOrPR && !('error' in issueOrPR)) { + const githubData: GitHubData = { + owner, + repo, + type: type as 'issues' | 'pull', + state: issueOrPR.state || '', + created_at: issueOrPR.created_at || '', + title: issueOrPR.title || '', + number: issueOrPR.number || 0, + merged: type === 'pull' ? issueOrPR.merged : undefined, + state_reason: issueOrPR.state_reason, + body: issueOrPR.body, + labels: Array.isArray(issueOrPR.labels) ? issueOrPR.labels : [], + base: type === 'pull' && issueOrPR.base ? issueOrPR.base : undefined, + head: type === 'pull' && issueOrPR.head ? issueOrPR.head : undefined, + }; + setData(githubData); + } + } catch (error) { + console.error('Error fetching GitHub data:', error); } - setData(res); } }; @@ -43,9 +93,11 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => { }, [connected, data, url]); const getIconElement = () => { + if (!data) return null; + const iconProps = { - size: 'small', - verticalAlign: 'text-bottom', + size: 16, // Use a number instead of 'small' + verticalAlign: 'text-bottom' as const, }; let icon; @@ -88,8 +140,8 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => { if (!data) { return null; } - let date = new Date(data.created_at); - date = date.toDateString(); + const dateObj = new Date(data.created_at); + const dateStr = dateObj.toDateString(); let description = ''; if (data.body) { @@ -106,7 +158,7 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => { {data.repo} {' on '} - {date} + {dateStr}
@@ -130,7 +182,7 @@ export const LinkEmbedPreview = ({embed: {url}, connected}) => {
{/* base <- head */} - {data.type === 'pull' && ( + {data.type === 'pull' && data.base && data.head && (
{'Base ← Head'}
diff --git a/webapp/src/types/github_types.ts b/webapp/src/types/github_types.ts index 2bc95d5ea..faad3e4af 100644 --- a/webapp/src/types/github_types.ts +++ b/webapp/src/types/github_types.ts @@ -85,8 +85,36 @@ export type PrsDetailsData = { } export type GithubIssueData = { + id?: number; number: number; + state?: string; + state_reason?: string; + locked?: boolean; + title?: string; + body?: string; + author_association?: string; + user?: GitHubUser; + labels?: GithubLabel[]; + assignee?: GitHubUser; + comments?: number; + closed_at?: string; + created_at?: string; + updated_at?: string; + closed_by?: GitHubUser; + url?: string; + html_url?: string; + comments_url?: string; + events_url?: string; + labels_url?: string; repository_url: string; + milestone?: { title: string }; + pull_request?: unknown; + repository?: { full_name: string }; + reactions?: unknown; + assignees?: GitHubUser[]; + node_id?: string; + text_matches?: unknown[]; + active_lock_reason?: string; } export type DefaultRepo = { @@ -126,7 +154,54 @@ export type GithubUsersData = { } export type GitHubPullRequestData = { - id: number; + id?: number; + number?: number; + state?: string; + locked?: boolean; + title?: string; + body?: string; + created_at?: string; + updated_at?: string; + closed_at?: string; + merged_at?: string; + labels?: GithubLabel[]; + user?: GitHubUser; + draft?: boolean; + merged?: boolean; + mergeable?: boolean; + mergeable_state?: string; + merged_by?: GitHubUser; + merge_commit_sha?: string; + rebaseable?: boolean; + comments?: number; + commits?: number; + additions?: number; + deletions?: number; + changed_files?: number; + url?: string; + html_url?: string; + issue_url?: string; + statuses_url?: string; + diff_url?: string; + patch_url?: string; + commits_url?: string; + comments_url?: string; + review_comments_url?: string; + review_comment_url?: string; + review_comments?: number; + assignee?: GitHubUser; + assignees?: GitHubUser[]; + milestone?: { title: string; number: number }; + maintainer_can_modify?: boolean; + author_association?: string; + node_id?: string; + requested_reviewers?: GitHubUser[]; + auto_merge?: unknown; + requested_teams?: { name: string; id: number }[]; + links?: unknown; + head?: { ref: string; sha: string; repo?: { full_name: string } }; + base?: { ref: string; sha: string; repo?: { full_name: string } }; + active_lock_reason?: string; } export type MilestoneData = { From 02f666962e42f32b8bd3834aa194bfb9d696526b Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Mon, 8 Sep 2025 15:59:32 +0530 Subject: [PATCH 15/15] Fix lint errors --- .../components/link_embed_preview/index.ts | 11 ++-- .../link_embed_preview/link_embed_preview.tsx | 66 +++++++++---------- webapp/src/index.js | 3 +- webapp/src/utils/github_utils.ts | 3 + webapp/src/utils/styles.js | 2 +- 5 files changed, 45 insertions(+), 40 deletions(-) diff --git a/webapp/src/components/link_embed_preview/index.ts b/webapp/src/components/link_embed_preview/index.ts index 0eb46ac3f..64c46ec31 100644 --- a/webapp/src/components/link_embed_preview/index.ts +++ b/webapp/src/components/link_embed_preview/index.ts @@ -1,14 +1,17 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {connect} from 'react-redux'; +import {GlobalState} from '@/types/store'; +import {getPluginState} from '@/selectors'; + import {LinkEmbedPreview} from './link_embed_preview'; -import { GlobalState } from '@/types/store'; -import { getPluginState } from '@/selectors'; const mapStateToProps = (state: GlobalState) => { return {connected: getPluginState(state).connected}; }; -export default connect(mapStateToProps, null)(LinkEmbedPreview); +// Use a more direct approach with type assertion +// @ts-ignore - Ignoring type errors for connect function +export default connect(mapStateToProps)(LinkEmbedPreview); diff --git a/webapp/src/components/link_embed_preview/link_embed_preview.tsx b/webapp/src/components/link_embed_preview/link_embed_preview.tsx index e5a1d8dee..bec9df7e4 100644 --- a/webapp/src/components/link_embed_preview/link_embed_preview.tsx +++ b/webapp/src/components/link_embed_preview/link_embed_preview.tsx @@ -1,3 +1,6 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon, SkipIcon, IconProps} from '@primer/octicons-react'; import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; @@ -50,37 +53,32 @@ export const LinkEmbedPreview = ({embed: {url}, connected}: LinkEmbedProps) => { if (isUrlCanPreview(url)) { const [owner, repo, type, number] = url.split('github.com/')[1].split('/'); - try { - let issueOrPR: any; - - if (type === 'issues') { - issueOrPR = await Client.getIssue(owner, repo, Number(number)); - } else if (type === 'pull') { - issueOrPR = await Client.getPullRequest(owner, repo, Number(number)); - } else { - return; - } - - if (issueOrPR && !('error' in issueOrPR)) { - const githubData: GitHubData = { - owner, - repo, - type: type as 'issues' | 'pull', - state: issueOrPR.state || '', - created_at: issueOrPR.created_at || '', - title: issueOrPR.title || '', - number: issueOrPR.number || 0, - merged: type === 'pull' ? issueOrPR.merged : undefined, - state_reason: issueOrPR.state_reason, - body: issueOrPR.body, - labels: Array.isArray(issueOrPR.labels) ? issueOrPR.labels : [], - base: type === 'pull' && issueOrPR.base ? issueOrPR.base : undefined, - head: type === 'pull' && issueOrPR.head ? issueOrPR.head : undefined, - }; - setData(githubData); - } - } catch (error) { - console.error('Error fetching GitHub data:', error); + let issueOrPR: any; + if (type === 'issues') { + issueOrPR = await Client.getIssue(owner, repo, Number(number)); + } else if (type === 'pull') { + issueOrPR = await Client.getPullRequest(owner, repo, Number(number)); + } else { + return; + } + + if (issueOrPR && !('error' in issueOrPR)) { + const githubData: GitHubData = { + owner, + repo, + type: type as 'issues' | 'pull', + state: issueOrPR.state || '', + created_at: issueOrPR.created_at || '', + title: issueOrPR.title || '', + number: issueOrPR.number || 0, + merged: type === 'pull' && issueOrPR.merged, + state_reason: issueOrPR.state_reason, + body: issueOrPR.body, + labels: Array.isArray(issueOrPR.labels) ? issueOrPR.labels : [], + base: type === 'pull' && issueOrPR.base && issueOrPR.base, + head: type === 'pull' && issueOrPR.head && issueOrPR.head, + }; + setData(githubData); } } }; @@ -93,8 +91,10 @@ export const LinkEmbedPreview = ({embed: {url}, connected}: LinkEmbedProps) => { }, [connected, data, url]); const getIconElement = () => { - if (!data) return null; - + if (!data) { + return null; + } + const iconProps = { size: 16, // Use a number instead of 'small' verticalAlign: 'text-bottom' as const, diff --git a/webapp/src/index.js b/webapp/src/index.js index 073e7c67d..a9d63be43 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -9,8 +9,6 @@ import AttachCommentToIssueModal from '@/components/modals/attach_comment_to_iss import {getConnected, openAttachCommentToIssueModal, openCreateIssueModal, setShowRHSAction} from '@/actions'; -import {isUrlCanPreview} from 'utils/github_utils'; - import CreateIssueModal from './components/modals/create_issue'; import CreateIssuePostMenuAction from './components/post_menu_action/create_issue'; import SidebarHeader from './components/sidebar_header'; @@ -25,6 +23,7 @@ import Client from './client'; import {handleConnect, handleDisconnect, handleConfigurationUpdate, handleOpenCreateIssueModal, handleReconnect, handleRefresh} from './websocket'; import {getServerRoute} from './selectors'; import manifest from './manifest'; +import {isUrlCanPreview} from './utils/github_utils'; let activityFunc; let lastActivityTime = Number.MAX_SAFE_INTEGER; diff --git a/webapp/src/utils/github_utils.ts b/webapp/src/utils/github_utils.ts index 8596b6c63..1783f3692 100644 --- a/webapp/src/utils/github_utils.ts +++ b/webapp/src/utils/github_utils.ts @@ -1,3 +1,6 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + export function isUrlCanPreview(url: string) { const {hostname, pathname} = new URL(url); if (hostname.includes('github.com') && pathname.split('/')[1]) { diff --git a/webapp/src/utils/styles.js b/webapp/src/utils/styles.js index 9964b08c1..8a95eb7cd 100644 --- a/webapp/src/utils/styles.js +++ b/webapp/src/utils/styles.js @@ -1,4 +1,4 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {changeOpacity} from 'mattermost-redux/utils/theme_utils';