From ae906126e9e032fc1feab8ceb6419f4380487a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Ctan-nhu=E2=80=9D?= <“tan@harness.io”> Date: Sun, 2 Apr 2023 22:50:52 -0700 Subject: [PATCH] Add Git Blame UI + API integration --- web/package.json | 3 + web/src/App.module.scss | 59 +++ web/src/App.module.scss.d.ts | 6 + web/src/App.scss | 59 --- web/src/App.tsx | 66 ++-- .../MarkdownEditorWithPreview.module.scss | 5 +- web/src/framework/strings/stringTypes.ts | 1 + web/src/i18n/strings.en.yaml | 1 + .../Conversation/Conversation.module.scss | 4 +- .../PullRequestSideBar/PullRequestSideBar.tsx | 2 +- .../FileContent/FileContent.tsx | 56 ++- .../FileContent/GitBlame.module.scss | 83 +++++ .../FileContent/GitBlame.module.scss.d.ts | 13 + .../FileContent/GitBlame.tsx | 340 ++++++++++++++++++ .../FileContent/lineWidget.ts | 59 +++ web/src/services/code/index.tsx | 50 +++ web/src/services/code/swagger.yaml | 74 ++++ web/src/utils/types.ts | 25 ++ web/src/utils/utils.scss | 4 + web/yarn.lock | 229 ++++++++++++ 20 files changed, 1029 insertions(+), 110 deletions(-) create mode 100644 web/src/App.module.scss create mode 100644 web/src/App.module.scss.d.ts delete mode 100644 web/src/App.scss create mode 100644 web/src/pages/Repository/RepositoryContent/FileContent/GitBlame.module.scss create mode 100644 web/src/pages/Repository/RepositoryContent/FileContent/GitBlame.module.scss.d.ts create mode 100644 web/src/pages/Repository/RepositoryContent/FileContent/GitBlame.tsx create mode 100644 web/src/pages/Repository/RepositoryContent/FileContent/lineWidget.ts create mode 100644 web/src/utils/utils.scss diff --git a/web/package.json b/web/package.json index 9d4ef356a..b724b68ff 100644 --- a/web/package.json +++ b/web/package.json @@ -44,6 +44,9 @@ "@harness/uicore": "3.106.3", "@harness/use-modal": "1.1.0", "@popperjs/core": "^2.4.2", + "@uiw/codemirror-extensions-color": "^4.19.9", + "@uiw/codemirror-extensions-hyper-link": "^4.19.9", + "@uiw/codemirror-themes-all": "^4.19.9", "@uiw/react-markdown-editor": "^5.10.1", "anser": "2.0.1", "classnames": "^2.2.6", diff --git a/web/src/App.module.scss b/web/src/App.module.scss new file mode 100644 index 000000000..c6ad7e7d7 --- /dev/null +++ b/web/src/App.module.scss @@ -0,0 +1,59 @@ +/* + * NOTE: Styles in this file are loaded in both standalone and embedded + * versions. Be careful! Don't introduce global states that could be conflict + * with Harness Platform and other modules. + */ + +.main { + --code-editor-font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', + monospace; + --code-editor-font-size: 13px; + --code-editor-border-color: var(--grey-200); + + :global { + .Resizer { + background-color: var(--grey-300); + opacity: 0.2; + z-index: 1; + box-sizing: border-box; + background-clip: padding-box; + } + + .Resizer:hover { + transition: all 2s ease; + } + + .Resizer.horizontal { + margin: -5px 0; + border-top: 5px solid rgba(255, 255, 255, 0); + border-bottom: 5px solid rgba(255, 255, 255, 0); + cursor: row-resize; + } + + .Resizer.horizontal:hover { + border-top: 5px solid rgba(0, 0, 0, 0.5); + border-bottom: 5px solid rgba(0, 0, 0, 0.5); + } + + .Resizer.vertical { + width: 11px; + margin: 0 -5px; + border-left: 5px solid rgba(255, 255, 255, 0); + border-right: 5px solid rgba(255, 255, 255, 0); + cursor: col-resize; + } + + .Resizer.vertical:hover { + border-left: 5px solid rgba(0, 0, 0, 0.5); + border-right: 5px solid rgba(0, 0, 0, 0.5); + } + + .Resizer.disabled { + cursor: not-allowed; + } + + .Resizer.disabled:hover { + border-color: transparent; + } + } +} diff --git a/web/src/App.module.scss.d.ts b/web/src/App.module.scss.d.ts new file mode 100644 index 000000000..9e614bf2d --- /dev/null +++ b/web/src/App.module.scss.d.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +// this is an auto-generated file +declare const styles: { + readonly main: string +} +export default styles diff --git a/web/src/App.scss b/web/src/App.scss deleted file mode 100644 index 0acbb6bb6..000000000 --- a/web/src/App.scss +++ /dev/null @@ -1,59 +0,0 @@ -/* - * NOTE: Styles in this file are loaded in both standalone and embedded - * versions. Be careful! Don't introduce global states that could be conflict - * with Harness Platform and other modules. - */ - -.Resizer { - background: var(--grey-300); - opacity: 0.2; - z-index: 1; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - -moz-background-clip: padding; - -webkit-background-clip: padding; - background-clip: padding-box; -} - -.Resizer:hover { - -webkit-transition: all 2s ease; - transition: all 2s ease; -} - -.Resizer.horizontal { - margin: -5px 0; - border-top: 5px solid rgba(255, 255, 255, 0); - border-bottom: 5px solid rgba(255, 255, 255, 0); - cursor: row-resize; -} - -.Resizer.horizontal:hover { - border-top: 5px solid rgba(0, 0, 0, 0.5); - border-bottom: 5px solid rgba(0, 0, 0, 0.5); -} - -.Resizer.vertical { - width: 11px; - margin: 0 -5px; - border-left: 5px solid rgba(255, 255, 255, 0); - border-right: 5px solid rgba(255, 255, 255, 0); - cursor: col-resize; -} - -.Resizer.vertical:hover { - border-left: 5px solid rgba(0, 0, 0, 0.5); - border-right: 5px solid rgba(0, 0, 0, 0.5); -} - -.Resizer.disabled { - cursor: not-allowed; -} - -.Resizer.disabled:hover { - border-color: transparent; -} - -.wmde-markdown { - font-size: 14px !important; -} diff --git a/web/src/App.tsx b/web/src/App.tsx index e788a2ae5..493110d86 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState, useCallback, useMemo } from 'react' import { RestfulProvider } from 'restful-react' -import { TooltipContextProvider } from '@harness/uicore' +import { Container, TooltipContextProvider } from '@harness/uicore' import { ModalProvider } from '@harness/use-modal' import { FocusStyleManager } from '@blueprintjs/core' import { tooltipDictionary } from '@harness/ng-tooltip' @@ -17,7 +17,7 @@ import type { LanguageRecord } from './framework/strings/languageLoader' import { StringsContextProvider } from './framework/strings/StringsContextProvider' import 'highlight.js/styles/github.css' import 'diff2html/bundles/css/diff2html.min.css' -import './App.scss' +import css from './App.module.scss' FocusStyleManager.onlyShowFocusOnTabs() @@ -43,40 +43,42 @@ const App: React.FC = React.memo(function App({ languageLoader(lang).then(setStrings) }, [lang, setStrings]) - // Workaround to disable editor dark mode (https://github.com/uiwjs/react-markdown-editor#support-dark-modenight-mode) + // TODO: Workaround to disable editor dark mode (https://github.com/uiwjs/react-markdown-editor#support-dark-modenight-mode) document.documentElement.setAttribute('data-color-mode', 'light') return strings ? ( - - - { - if (!response.ok && response.status === 401) { - on401() - } - }}> - + + + { + if (!response.ok && response.status === 401) { + on401() + } }}> - - {children ? children : } - - - - - + + + {children ? children : } + + + + + + ) : null }) diff --git a/web/src/components/MarkdownEditorWithPreview/MarkdownEditorWithPreview.module.scss b/web/src/components/MarkdownEditorWithPreview/MarkdownEditorWithPreview.module.scss index 753578e63..2619028e2 100644 --- a/web/src/components/MarkdownEditorWithPreview/MarkdownEditorWithPreview.module.scss +++ b/web/src/components/MarkdownEditorWithPreview/MarkdownEditorWithPreview.module.scss @@ -1,3 +1,5 @@ +@import 'src/utils/utils'; + .main { --color-border: var(--grey-200); --box-radius: 5px; @@ -102,8 +104,7 @@ .cm-editor .cm-line { &, * { - font-family: var(--font-family); - font-size: 13px; + @include mono-font; } } diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts index 033f7c7d6..143746d99 100644 --- a/web/src/framework/strings/stringTypes.ts +++ b/web/src/framework/strings/stringTypes.ts @@ -17,6 +17,7 @@ export interface StringsMap { and: string approve: string ascending: string + blameCommitLine: string botAlerts: string branch: string branchCreated: string diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml index fdb84628f..2670dd2c7 100644 --- a/web/src/i18n/strings.en.yaml +++ b/web/src/i18n/strings.en.yaml @@ -349,3 +349,4 @@ resetZoom: Reset Zoom zoomIn: Zoom In zoomOut: Zoom Out checks: Checks +blameCommitLine: '{author} committed {timestamp}' diff --git a/web/src/pages/PullRequest/Conversation/Conversation.module.scss b/web/src/pages/PullRequest/Conversation/Conversation.module.scss index 4ff140e13..113cd6ef2 100644 --- a/web/src/pages/PullRequest/Conversation/Conversation.module.scss +++ b/web/src/pages/PullRequest/Conversation/Conversation.module.scss @@ -63,8 +63,8 @@ } .mergedBox { - padding-top: var(--spacing-small) !important; - padding-bottom: var(--spacing-small) !important; + padding-top: var(--spacing-xsmall) !important; + padding-bottom: var(--spacing-xsmall) !important; } .mergeContainer { diff --git a/web/src/pages/PullRequest/Conversation/PullRequestSideBar/PullRequestSideBar.tsx b/web/src/pages/PullRequest/Conversation/PullRequestSideBar/PullRequestSideBar.tsx index e4a587db9..a7670cebf 100644 --- a/web/src/pages/PullRequest/Conversation/PullRequestSideBar/PullRequestSideBar.tsx +++ b/web/src/pages/PullRequest/Conversation/PullRequestSideBar/PullRequestSideBar.tsx @@ -60,7 +60,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => { } //TODO add actions when you click the options menu button and also api integration return ( - + diff --git a/web/src/pages/Repository/RepositoryContent/FileContent/FileContent.tsx b/web/src/pages/Repository/RepositoryContent/FileContent/FileContent.tsx index 2e6cb0122..991078e65 100644 --- a/web/src/pages/Repository/RepositoryContent/FileContent/FileContent.tsx +++ b/web/src/pages/Repository/RepositoryContent/FileContent/FileContent.tsx @@ -1,6 +1,16 @@ import React, { useMemo } from 'react' -import { Button, ButtonVariation, Color, Container, FlexExpander, Heading, Layout, Utils } from '@harness/uicore' -import { Render } from 'react-jsx-match' +import { + Button, + ButtonVariation, + Color, + Container, + FlexExpander, + Heading, + Layout, + useToggle, + Utils +} from '@harness/uicore' +import { Else, Match, Render, Truthy } from 'react-jsx-match' import { useHistory } from 'react-router-dom' import { SourceCodeViewer } from 'components/SourceCodeViewer/SourceCodeViewer' import type { OpenapiContentInfo, RepoFileContent } from 'services/code' @@ -16,9 +26,11 @@ import { import { filenameToLanguage } from 'utils/Utils' import { useAppContext } from 'AppContext' import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit' +import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' import { CommitModalButton } from 'components/CommitModalButton/CommitModalButton' import { useStrings } from 'framework/strings' import { Readme } from '../FolderContent/Readme' +import { GitBlame } from './GitBlame' import css from './FileContent.module.scss' export function FileContent({ @@ -30,6 +42,7 @@ export function FileContent({ const { routes } = useAppContext() const { getString } = useStrings() const history = useHistory() + const [showGitBlame, toggleGitBlame] = useToggle(false) const content = useMemo( () => decodeGitContent((resourceContent?.content as RepoFileContent)?.data), [resourceContent?.content] @@ -98,23 +111,38 @@ export function FileContent({ } }} /> + + +