diff --git a/web/docs/markdown.md b/web/docs/markdown.md
new file mode 100644
index 000000000..8e231ad19
--- /dev/null
+++ b/web/docs/markdown.md
@@ -0,0 +1,5 @@
+# Markdown Examples
+
+## Embed a video with a title
+
+https://user-images.githubusercontent.com/1680273/138299599-88547edd-859c-44c9-8b52-2cc06f7f2dd3.mov?!#title=Example%20Display
diff --git a/web/package.json b/web/package.json
index a59109d5f..566c8836d 100644
--- a/web/package.json
+++ b/web/package.json
@@ -1,21 +1,21 @@
{
- "name": "ui-template",
- "description": "Harness Inc",
+ "name": "codeui",
+ "description": "Harness Code UI",
"version": "0.0.1",
"author": "Harness Inc",
"license": "Harness Inc",
"private": true,
- "homepage": "http://harness.io/",
+ "homepage": "http://app.harness.io/",
"repository": {
"type": "git",
- "url": "https://github.com/wings-software/ui-template.git"
+ "url": "https://github.com/harness/gitness.git"
},
"bugs": {
- "url": "https://github.com/wings-software/ui-template/issues"
+ "url": "https://github.com/harness/gitness/issues"
},
"keywords": [],
"scripts": {
- "dev": "NODE_ENV=development webpack serve --config config/webpack.dev.js",
+ "dev": "webpack serve --config config/webpack.dev.js",
"test": "jest src --silent",
"test:watch": "jest --watch",
"lint": "eslint --rulesdir ./scripts/eslint-rules --ext .ts --ext .tsx src",
@@ -80,9 +80,11 @@
"react-split-pane": "^0.1.92",
"react-table": "^7.1.0",
"react-timeago": "^4.4.0",
+ "rehype-external-links": "^2.0.1",
"rehype-highlight": "^5.0.2",
"rehype-raw": "^6.1.1",
"rehype-sanitize": "^5.0.1",
+ "rehype-video": "^1.2.2",
"remark-gfm": "^3.0.1",
"restful-react": "15.6.0",
"webpack-retry-chunk-load-plugin": "^3.1.0",
diff --git a/web/src/components/SourceCodeViewer/SourceCodeViewer.module.scss b/web/src/components/SourceCodeViewer/SourceCodeViewer.module.scss
index 9f51b1099..a4b6caf10 100644
--- a/web/src/components/SourceCodeViewer/SourceCodeViewer.module.scss
+++ b/web/src/components/SourceCodeViewer/SourceCodeViewer.module.scss
@@ -4,6 +4,19 @@
pre {
position: relative;
}
+
+ // Customize https://wangchujiang.com/rehype-video/
+ details.octicon.octicon-video {
+ display: block;
+
+ > summary {
+ padding-bottom: var(--spacing-xsmall);
+
+ > svg {
+ margin: 0 var(--spacing-small);
+ }
+ }
+ }
}
}
}
diff --git a/web/src/components/SourceCodeViewer/SourceCodeViewer.tsx b/web/src/components/SourceCodeViewer/SourceCodeViewer.tsx
index 7d48da0de..df9b51339 100644
--- a/web/src/components/SourceCodeViewer/SourceCodeViewer.tsx
+++ b/web/src/components/SourceCodeViewer/SourceCodeViewer.tsx
@@ -1,6 +1,8 @@
-import React, { Suspense } from 'react'
+import React, { Suspense, useCallback } from 'react'
import { Container, Text } from '@harness/uicore'
import MarkdownEditor from '@uiw/react-markdown-editor'
+import rehypeVideo from 'rehype-video'
+import rehypeExternalLinks from 'rehype-external-links'
import { useStrings } from 'framework/strings'
import { SourceCodeEditor } from 'components/SourceCodeEditor/SourceCodeEditor'
import type { SourceCodeEditorProps } from 'utils/Utils'
@@ -8,27 +10,57 @@ import css from './SourceCodeViewer.module.scss'
interface MarkdownViewerProps {
source: string
+ navigateTo: (url: string) => void
}
-export function MarkdownViewer({ source }: MarkdownViewerProps) {
+export function MarkdownViewer({ source, navigateTo }: MarkdownViewerProps) {
const { getString } = useStrings()
+ const interceptClickEventOnViewerContainer = useCallback(
+ event => {
+ const { target } = event
+
+ if (target?.tagName?.toLowerCase() === 'a') {
+ const { href } = target
+
+ // Intercept click event on internal links and navigate to pages to avoid full page reload
+ if (href && !href.startsWith('#')) {
+ try {
+ const origin = new URL(href).origin
+
+ if (origin === window.location.origin) {
+ // For some reason, history.push(href) does not work in the context of @uiw/react-markdown-editor library.
+ navigateTo?.(href)
+ event.stopPropagation()
+ event.preventDefault()
+ }
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.error('MarkdownViewer/interceptClickEventOnViewerContainer', e)
+ }
+ }
+ }
+ },
+ [navigateTo]
+ )
return (
-
+
{getString('loading')}}>
{
- if (
- (node as unknown as HTMLDivElement).tagName === 'a' &&
- parent &&
- /^h(1|2|3|4|5|6)/.test((parent as unknown as HTMLDivElement).tagName)
- ) {
- parent.children = parent.children.slice(1)
+ if ((node as unknown as HTMLDivElement).tagName === 'a') {
+ if (parent && /^h(1|2|3|4|5|6)/.test((parent as unknown as HTMLDivElement).tagName)) {
+ parent.children = parent.children.slice(1)
+ }
}
}}
+ rehypePlugins={[
+ rehypeVideo,
+ [rehypeExternalLinks, { rel: ['nofollow noreferrer noopener'], target: '_blank' }]
+ ]}
/>
diff --git a/web/src/global.d.ts b/web/src/global.d.ts
index 3ef87fcc5..b6d006236 100644
--- a/web/src/global.d.ts
+++ b/web/src/global.d.ts
@@ -47,10 +47,11 @@ declare interface Window {
harnessNameSpace: string
bugsnagClient?: any
STRIP_CODE_PREFIX?: boolean
- __ENABLE_CDN__: string
- __webpack_public_path__: string
}
+declare const __ENABLE_CDN__: boolean
+declare let __webpack_public_path__: string
+
declare const monaco: any
declare module '*.scss'
diff --git a/web/src/pages/PullRequest/Conversation/Conversation.tsx b/web/src/pages/PullRequest/Conversation/Conversation.tsx
index c2a648508..d06720031 100644
--- a/web/src/pages/PullRequest/Conversation/Conversation.tsx
+++ b/web/src/pages/PullRequest/Conversation/Conversation.tsx
@@ -21,6 +21,7 @@ import cx from 'classnames'
import { useGet, useMutate } from 'restful-react'
import ReactTimeago from 'react-timeago'
import { orderBy } from 'lodash-es'
+import { useHistory } from 'react-router-dom'
import { Render } from 'react-jsx-match'
import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
import { MarkdownViewer } from 'components/SourceCodeViewer/SourceCodeViewer'
@@ -35,12 +36,12 @@ import {
CommentType,
PullRequestCodeCommentPayload
} from 'components/DiffViewer/DiffViewerUtils'
+import { ThreadSection } from 'components/ThreadSection/ThreadSection'
import { PullRequestTabContentWrapper } from '../PullRequestTabContentWrapper'
import { DescriptionBox } from './DescriptionBox'
import { PullRequestActionsBox } from './PullRequestActionsBox/PullRequestActionsBox'
import PullRequestSideBar from './PullRequestSideBar/PullRequestSideBar'
import css from './Conversation.module.scss'
-import { ThreadSection } from 'components/ThreadSection/ThreadSection'
export interface ConversationProps extends Pick {
onCommentUpdate: () => void
@@ -529,6 +530,7 @@ const generateReviewDecisionIcon = (
}
const SystemBox: React.FC = ({ pullRequestMetadata, commentItems }) => {
+ const history = useHistory()
const { getString } = useStrings()
const payload = commentItems[0].payload
const type = payload?.type
@@ -692,6 +694,7 @@ const SystemBox: React.FC = ({ pullRequestMetadata, commentItems
)
)
.join('\n')}
+ navigateTo={history.push}
/>
diff --git a/web/src/pages/PullRequest/Conversation/DescriptionBox.tsx b/web/src/pages/PullRequest/Conversation/DescriptionBox.tsx
index e7dff5a2e..1c506ce06 100644
--- a/web/src/pages/PullRequest/Conversation/DescriptionBox.tsx
+++ b/web/src/pages/PullRequest/Conversation/DescriptionBox.tsx
@@ -1,6 +1,7 @@
import React, { useState } from 'react'
import { Container, useToaster } from '@harness/uicore'
import cx from 'classnames'
+import { useHistory } from 'react-router-dom'
import { useMutate } from 'restful-react'
import { MarkdownViewer } from 'components/SourceCodeViewer/SourceCodeViewer'
import { useStrings } from 'framework/strings'
@@ -16,6 +17,7 @@ export const DescriptionBox: React.FC = ({
pullRequestMetadata,
onCommentUpdate: refreshPullRequestMetadata
}) => {
+ const history = useHistory()
const [edit, setEdit] = useState(false)
// const [updated, setUpdated] = useState(pullRequestMetadata.edited as number)
const [originalContent, setOriginalContent] = useState(pullRequestMetadata.description as string)
@@ -63,7 +65,7 @@ export const DescriptionBox: React.FC = ({
/>
)) || (
-
+
{
const history = useHistory()
-
const { routes } = useAppContext()
const { getString } = useStrings()
const { currentUserProfileURL } = useAppContext()
@@ -140,7 +139,7 @@ const EmptyRepositoryInfo: React.FC
{getString('emptyRepoHeader')}
-
+
diff --git a/web/src/pages/Repository/RepositoryContent/FolderContent/Readme.tsx b/web/src/pages/Repository/RepositoryContent/FolderContent/Readme.tsx
index 1d8fae471..e24adc8d9 100644
--- a/web/src/pages/Repository/RepositoryContent/FolderContent/Readme.tsx
+++ b/web/src/pages/Repository/RepositoryContent/FolderContent/Readme.tsx
@@ -61,7 +61,10 @@ function ReadmeViewer({ metadata, gitRef, readmeInfo, contentOnly, maxWidth }: F
-
+
diff --git a/web/yarn.lock b/web/yarn.lock
index c64c60cc3..4ede8c6c2 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -6262,7 +6262,7 @@ highlight.js@11.6.0, highlight.js@~11.6.0:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.6.0.tgz#a50e9da05763f1bb0c1322c8f4f755242cff3f5a"
integrity sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==
-history@^4.9.0:
+history@^4.10.1, history@^4.9.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
@@ -6722,6 +6722,11 @@ ipaddr.js@^2.0.1:
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0"
integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==
+is-absolute-url@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-4.0.1.tgz#16e4d487d4fded05cfe0685e53ec86804a5e94dc"
+ integrity sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==
+
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@@ -10905,6 +10910,18 @@ rehype-autolink-headings@~6.1.1:
unified "^10.0.0"
unist-util-visit "^4.0.0"
+rehype-external-links@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/rehype-external-links/-/rehype-external-links-2.0.1.tgz#fe54f9f227a1a2f8f6afe442ac4c9ee748f08756"
+ integrity sha512-u2dNypma+ps12SJWlS23zvbqwNx0Hl24t0YHXSM/6FCZj/pqWETCO3WyyrvALv4JYvRtuPjhiv2Lpen15ESqbA==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ extend "^3.0.0"
+ is-absolute-url "^4.0.0"
+ space-separated-tokens "^2.0.0"
+ unified "^10.0.0"
+ unist-util-visit "^4.0.0"
+
rehype-highlight@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/rehype-highlight/-/rehype-highlight-5.0.2.tgz#de952123cd4d9672f21a4a38d3b119b88a08eafa"
@@ -10987,6 +11004,14 @@ rehype-slug@~5.1.0:
unified "^10.0.0"
unist-util-visit "^4.0.0"
+rehype-video@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/rehype-video/-/rehype-video-1.2.2.tgz#a1dbd62c487e22b7282e9a23fa0b57f1f745ade9"
+ integrity sha512-p18JzIZiFSUqk21RHeJTU/7/7n9Moy0aQzFzbujVWb4vPrRZHQAN0ZfzTV8J32yDsZE5d6JDGWOzmMdvJrHq0w==
+ dependencies:
+ unified "~10.1.1"
+ unist-util-visit "~4.1.0"
+
relateurl@^0.2.7:
version "0.2.7"
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"