mirror of
https://github.com/harness/drone.git
synced 2025-05-31 11:43:15 +00:00
Merge branch 'gitblame' of _OKE5H2PQKOUfzFFDuD4FA/default/CODE/gitness (#15)
This commit is contained in:
commit
c2975da1e6
@ -44,6 +44,9 @@
|
|||||||
"@harness/uicore": "3.106.3",
|
"@harness/uicore": "3.106.3",
|
||||||
"@harness/use-modal": "1.1.0",
|
"@harness/use-modal": "1.1.0",
|
||||||
"@popperjs/core": "^2.4.2",
|
"@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",
|
"@uiw/react-markdown-editor": "^5.10.1",
|
||||||
"anser": "2.0.1",
|
"anser": "2.0.1",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
59
web/src/App.module.scss
Normal file
59
web/src/App.module.scss
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
web/src/App.module.scss.d.ts
vendored
Normal file
6
web/src/App.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// this is an auto-generated file
|
||||||
|
declare const styles: {
|
||||||
|
readonly main: string
|
||||||
|
}
|
||||||
|
export default styles
|
@ -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;
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState, useCallback, useMemo } from 'react'
|
import React, { useEffect, useState, useCallback, useMemo } from 'react'
|
||||||
import { RestfulProvider } from 'restful-react'
|
import { RestfulProvider } from 'restful-react'
|
||||||
import { TooltipContextProvider } from '@harness/uicore'
|
import { Container, TooltipContextProvider } from '@harness/uicore'
|
||||||
import { ModalProvider } from '@harness/use-modal'
|
import { ModalProvider } from '@harness/use-modal'
|
||||||
import { FocusStyleManager } from '@blueprintjs/core'
|
import { FocusStyleManager } from '@blueprintjs/core'
|
||||||
import { tooltipDictionary } from '@harness/ng-tooltip'
|
import { tooltipDictionary } from '@harness/ng-tooltip'
|
||||||
@ -17,7 +17,7 @@ import type { LanguageRecord } from './framework/strings/languageLoader'
|
|||||||
import { StringsContextProvider } from './framework/strings/StringsContextProvider'
|
import { StringsContextProvider } from './framework/strings/StringsContextProvider'
|
||||||
import 'highlight.js/styles/github.css'
|
import 'highlight.js/styles/github.css'
|
||||||
import 'diff2html/bundles/css/diff2html.min.css'
|
import 'diff2html/bundles/css/diff2html.min.css'
|
||||||
import './App.scss'
|
import css from './App.module.scss'
|
||||||
|
|
||||||
FocusStyleManager.onlyShowFocusOnTabs()
|
FocusStyleManager.onlyShowFocusOnTabs()
|
||||||
|
|
||||||
@ -43,40 +43,42 @@ const App: React.FC<AppProps> = React.memo(function App({
|
|||||||
languageLoader(lang).then(setStrings)
|
languageLoader(lang).then(setStrings)
|
||||||
}, [lang, 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')
|
document.documentElement.setAttribute('data-color-mode', 'light')
|
||||||
|
|
||||||
return strings ? (
|
return strings ? (
|
||||||
<StringsContextProvider initialStrings={strings}>
|
<Container className={css.main}>
|
||||||
<AppErrorBoundary>
|
<StringsContextProvider initialStrings={strings}>
|
||||||
<RestfulProvider
|
<AppErrorBoundary>
|
||||||
base={standalone ? '/' : getConfig('code')}
|
<RestfulProvider
|
||||||
requestOptions={getRequestOptions}
|
base={standalone ? '/' : getConfig('code')}
|
||||||
queryParams={queryParams}
|
requestOptions={getRequestOptions}
|
||||||
queryParamStringifyOptions={{ skipNulls: true }}
|
queryParams={queryParams}
|
||||||
onResponse={response => {
|
queryParamStringifyOptions={{ skipNulls: true }}
|
||||||
if (!response.ok && response.status === 401) {
|
onResponse={response => {
|
||||||
on401()
|
if (!response.ok && response.status === 401) {
|
||||||
}
|
on401()
|
||||||
}}>
|
}
|
||||||
<AppContextProvider
|
|
||||||
value={{
|
|
||||||
standalone,
|
|
||||||
space,
|
|
||||||
routes,
|
|
||||||
lang,
|
|
||||||
on401,
|
|
||||||
hooks,
|
|
||||||
currentUser: defaultCurrentUser,
|
|
||||||
currentUserProfileURL
|
|
||||||
}}>
|
}}>
|
||||||
<TooltipContextProvider initialTooltipDictionary={tooltipDictionary}>
|
<AppContextProvider
|
||||||
<ModalProvider>{children ? children : <RouteDestinations />}</ModalProvider>
|
value={{
|
||||||
</TooltipContextProvider>
|
standalone,
|
||||||
</AppContextProvider>
|
space,
|
||||||
</RestfulProvider>
|
routes,
|
||||||
</AppErrorBoundary>
|
lang,
|
||||||
</StringsContextProvider>
|
on401,
|
||||||
|
hooks,
|
||||||
|
currentUser: defaultCurrentUser,
|
||||||
|
currentUserProfileURL
|
||||||
|
}}>
|
||||||
|
<TooltipContextProvider initialTooltipDictionary={tooltipDictionary}>
|
||||||
|
<ModalProvider>{children ? children : <RouteDestinations />}</ModalProvider>
|
||||||
|
</TooltipContextProvider>
|
||||||
|
</AppContextProvider>
|
||||||
|
</RestfulProvider>
|
||||||
|
</AppErrorBoundary>
|
||||||
|
</StringsContextProvider>
|
||||||
|
</Container>
|
||||||
) : null
|
) : null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
@import 'src/utils/utils';
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
--color-border: var(--grey-200);
|
--color-border: var(--grey-200);
|
||||||
--box-radius: 5px;
|
--box-radius: 5px;
|
||||||
@ -102,8 +104,7 @@
|
|||||||
.cm-editor .cm-line {
|
.cm-editor .cm-line {
|
||||||
&,
|
&,
|
||||||
* {
|
* {
|
||||||
font-family: var(--font-family);
|
@include mono-font;
|
||||||
font-size: 13px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ export interface StringsMap {
|
|||||||
and: string
|
and: string
|
||||||
approve: string
|
approve: string
|
||||||
ascending: string
|
ascending: string
|
||||||
|
blameCommitLine: string
|
||||||
botAlerts: string
|
botAlerts: string
|
||||||
branch: string
|
branch: string
|
||||||
branchCreated: string
|
branchCreated: string
|
||||||
|
@ -349,3 +349,4 @@ resetZoom: Reset Zoom
|
|||||||
zoomIn: Zoom In
|
zoomIn: Zoom In
|
||||||
zoomOut: Zoom Out
|
zoomOut: Zoom Out
|
||||||
checks: Checks
|
checks: Checks
|
||||||
|
blameCommitLine: '{author} committed {timestamp}'
|
||||||
|
@ -63,8 +63,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mergedBox {
|
.mergedBox {
|
||||||
padding-top: var(--spacing-small) !important;
|
padding-top: var(--spacing-xsmall) !important;
|
||||||
padding-bottom: var(--spacing-small) !important;
|
padding-bottom: var(--spacing-xsmall) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mergeContainer {
|
.mergeContainer {
|
||||||
|
@ -60,7 +60,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
}
|
}
|
||||||
//TODO add actions when you click the options menu button and also api integration
|
//TODO add actions when you click the options menu button and also api integration
|
||||||
return (
|
return (
|
||||||
<Container width={`30%`} padding={{ left: 'xxlarge', right: 'xxlarge' }}>
|
<Container width={`30%`}>
|
||||||
<Container padding={{ left: 'xxlarge' }}>
|
<Container padding={{ left: 'xxlarge' }}>
|
||||||
<Layout.Vertical>
|
<Layout.Vertical>
|
||||||
<Layout.Horizontal>
|
<Layout.Horizontal>
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { Button, ButtonVariation, Color, Container, FlexExpander, Heading, Layout, Utils } from '@harness/uicore'
|
import {
|
||||||
import { Render } from 'react-jsx-match'
|
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 { useHistory } from 'react-router-dom'
|
||||||
import { SourceCodeViewer } from 'components/SourceCodeViewer/SourceCodeViewer'
|
import { SourceCodeViewer } from 'components/SourceCodeViewer/SourceCodeViewer'
|
||||||
import type { OpenapiContentInfo, RepoFileContent } from 'services/code'
|
import type { OpenapiContentInfo, RepoFileContent } from 'services/code'
|
||||||
@ -16,9 +26,11 @@ import {
|
|||||||
import { filenameToLanguage } from 'utils/Utils'
|
import { filenameToLanguage } from 'utils/Utils'
|
||||||
import { useAppContext } from 'AppContext'
|
import { useAppContext } from 'AppContext'
|
||||||
import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit'
|
import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit'
|
||||||
|
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
|
||||||
import { CommitModalButton } from 'components/CommitModalButton/CommitModalButton'
|
import { CommitModalButton } from 'components/CommitModalButton/CommitModalButton'
|
||||||
import { useStrings } from 'framework/strings'
|
import { useStrings } from 'framework/strings'
|
||||||
import { Readme } from '../FolderContent/Readme'
|
import { Readme } from '../FolderContent/Readme'
|
||||||
|
import { GitBlame } from './GitBlame'
|
||||||
import css from './FileContent.module.scss'
|
import css from './FileContent.module.scss'
|
||||||
|
|
||||||
export function FileContent({
|
export function FileContent({
|
||||||
@ -30,6 +42,7 @@ export function FileContent({
|
|||||||
const { routes } = useAppContext()
|
const { routes } = useAppContext()
|
||||||
const { getString } = useStrings()
|
const { getString } = useStrings()
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
|
const [showGitBlame, toggleGitBlame] = useToggle(false)
|
||||||
const content = useMemo(
|
const content = useMemo(
|
||||||
() => decodeGitContent((resourceContent?.content as RepoFileContent)?.data),
|
() => decodeGitContent((resourceContent?.content as RepoFileContent)?.data),
|
||||||
[resourceContent?.content]
|
[resourceContent?.content]
|
||||||
@ -98,23 +111,38 @@ export function FileContent({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<PipeSeparator />
|
||||||
|
<Container padding={{ left: 'small', right: 'xsmall' }}>
|
||||||
|
<Button
|
||||||
|
variation={ButtonVariation.SECONDARY}
|
||||||
|
text={showGitBlame ? 'View File' : 'Blame'}
|
||||||
|
onClick={toggleGitBlame}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
</Layout.Horizontal>
|
</Layout.Horizontal>
|
||||||
</Layout.Horizontal>
|
</Layout.Horizontal>
|
||||||
|
|
||||||
<Render when={(resourceContent?.content as RepoFileContent)?.data}>
|
<Render when={(resourceContent?.content as RepoFileContent)?.data}>
|
||||||
<Container className={css.content}>
|
<Container className={css.content}>
|
||||||
<Render when={!markdownInfo}>
|
<Match expr={showGitBlame}>
|
||||||
<SourceCodeViewer language={filenameToLanguage(resourceContent?.name)} source={content} />
|
<Truthy>
|
||||||
</Render>
|
<GitBlame repoMetadata={repoMetadata} resourcePath={resourcePath} />
|
||||||
<Render when={markdownInfo}>
|
</Truthy>
|
||||||
<Readme
|
<Else>
|
||||||
metadata={repoMetadata}
|
<Render when={!markdownInfo}>
|
||||||
readmeInfo={markdownInfo as OpenapiContentInfo}
|
<SourceCodeViewer language={filenameToLanguage(resourceContent?.name)} source={content} />
|
||||||
contentOnly
|
</Render>
|
||||||
maxWidth="calc(100vw - 346px)"
|
<Render when={markdownInfo}>
|
||||||
gitRef={gitRef}
|
<Readme
|
||||||
/>
|
metadata={repoMetadata}
|
||||||
</Render>
|
readmeInfo={markdownInfo as OpenapiContentInfo}
|
||||||
|
contentOnly
|
||||||
|
maxWidth="calc(100vw - 346px)"
|
||||||
|
gitRef={gitRef}
|
||||||
|
/>
|
||||||
|
</Render>
|
||||||
|
</Else>
|
||||||
|
</Match>
|
||||||
</Container>
|
</Container>
|
||||||
</Render>
|
</Render>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
@import 'src/utils/utils';
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.cm-editor {
|
||||||
|
.cm-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cm-line {
|
||||||
|
&,
|
||||||
|
* {
|
||||||
|
@include mono-font;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineNo {
|
||||||
|
min-width: 70px !important;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 10px;
|
||||||
|
height: 100%;
|
||||||
|
color: var(--grey-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitBlame {
|
||||||
|
padding: 0 var(--spacing-xlarge) 0 var(--spacing-small) !important;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.cm-gutter {
|
||||||
|
background-color: var(--grey-50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--code-editor-border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.blameColumn {
|
||||||
|
width: 400px;
|
||||||
|
background: var(--grey-50);
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
border-right: 1px solid var(--code-editor-border-color);
|
||||||
|
|
||||||
|
.blameBox {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
content: '';
|
||||||
|
width: 100vw;
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--code-editor-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-of-type::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blameBoxLayout {
|
||||||
|
padding: var(--spacing-medium);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blameCommitPortalClass {
|
||||||
|
:global {
|
||||||
|
.bp3-popover-content {
|
||||||
|
padding: var(--spacing-large);
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
web/src/pages/Repository/RepositoryContent/FileContent/GitBlame.module.scss.d.ts
vendored
Normal file
13
web/src/pages/Repository/RepositoryContent/FileContent/GitBlame.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// this is an auto-generated file
|
||||||
|
declare const styles: {
|
||||||
|
readonly main: string
|
||||||
|
readonly lineNo: string
|
||||||
|
readonly gitBlame: string
|
||||||
|
readonly layout: string
|
||||||
|
readonly blameColumn: string
|
||||||
|
readonly blameBox: string
|
||||||
|
readonly blameBoxLayout: string
|
||||||
|
readonly blameCommitPortalClass: string
|
||||||
|
}
|
||||||
|
export default styles
|
@ -0,0 +1,340 @@
|
|||||||
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import { throttle } from 'lodash-es'
|
||||||
|
import { Avatar, Container, FontVariation, Layout, StringSubstitute, Text } from '@harness/uicore'
|
||||||
|
import { LanguageDescription } from '@codemirror/language'
|
||||||
|
import { indentWithTab } from '@codemirror/commands'
|
||||||
|
import { ViewPlugin, ViewUpdate } from '@codemirror/view'
|
||||||
|
import { languages } from '@codemirror/language-data'
|
||||||
|
import { EditorView, gutter, GutterMarker, keymap, WidgetType } from '@codemirror/view'
|
||||||
|
import { Compartment, EditorState } from '@codemirror/state'
|
||||||
|
import ReactTimeago from 'react-timeago'
|
||||||
|
import { color } from '@uiw/codemirror-extensions-color'
|
||||||
|
import { hyperLink } from '@uiw/codemirror-extensions-hyper-link'
|
||||||
|
import { githubLight as theme } from '@uiw/codemirror-themes-all'
|
||||||
|
import { useGet } from 'restful-react'
|
||||||
|
import { Render } from 'react-jsx-match'
|
||||||
|
import type { GitBlameEntry, GitBlameResponse } from 'utils/types'
|
||||||
|
import type { GitInfoProps } from 'utils/GitUtils'
|
||||||
|
import { useStrings } from 'framework/strings'
|
||||||
|
import { getErrorMessage } from 'utils/Utils'
|
||||||
|
import { lineWidget, LineWidgetPosition, LineWidgetSpec } from './lineWidget'
|
||||||
|
import css from './GitBlame.module.scss'
|
||||||
|
|
||||||
|
interface BlameBlock {
|
||||||
|
fromLineNumber: number
|
||||||
|
toLineNumber: number
|
||||||
|
topPosition: number
|
||||||
|
heights: Record<number, number>
|
||||||
|
commitInfo: GitBlameEntry['Commit']
|
||||||
|
lines: GitBlameEntry['Lines']
|
||||||
|
numberOfLines: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlameBlockRecord = Record<number, BlameBlock>
|
||||||
|
|
||||||
|
const BLAME_BLOCK_NOT_YET_CALCULATED_TOP_POSITION = -1
|
||||||
|
|
||||||
|
export const GitBlame: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'resourcePath'>> = ({
|
||||||
|
repoMetadata,
|
||||||
|
resourcePath
|
||||||
|
}) => {
|
||||||
|
const { getString } = useStrings()
|
||||||
|
const [blameBlocks, setBlameBlocks] = useState<BlameBlockRecord>({})
|
||||||
|
const { data, error, loading } = useGet<GitBlameResponse>({
|
||||||
|
path: `/api/v1/repos/${repoMetadata?.path}/+/blame/${resourcePath}`,
|
||||||
|
lazy: !repoMetadata || !resourcePath
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
let fromLineNumber = 1
|
||||||
|
|
||||||
|
data.forEach(({ Commit, Lines }) => {
|
||||||
|
const toLineNumber = fromLineNumber + Lines.length - 1
|
||||||
|
|
||||||
|
blameBlocks[fromLineNumber] = {
|
||||||
|
fromLineNumber,
|
||||||
|
toLineNumber,
|
||||||
|
topPosition: BLAME_BLOCK_NOT_YET_CALCULATED_TOP_POSITION, // Not yet calculated
|
||||||
|
heights: {}, // Not yet calculated
|
||||||
|
commitInfo: Commit,
|
||||||
|
lines: Lines,
|
||||||
|
numberOfLines: Lines.length
|
||||||
|
}
|
||||||
|
|
||||||
|
fromLineNumber = toLineNumber + 1
|
||||||
|
})
|
||||||
|
|
||||||
|
setBlameBlocks({ ...blameBlocks })
|
||||||
|
}
|
||||||
|
}, [data]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
const findBlockForLineNumber = useCallback(
|
||||||
|
lineNumber => {
|
||||||
|
let startLine = lineNumber
|
||||||
|
while (!blameBlocks[startLine] && startLine > 0) {
|
||||||
|
startLine--
|
||||||
|
}
|
||||||
|
return blameBlocks[startLine]
|
||||||
|
},
|
||||||
|
[blameBlocks]
|
||||||
|
)
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
const onViewUpdate = useCallback(
|
||||||
|
throttle(({ view, geometryChanged }: ViewUpdate) => {
|
||||||
|
if (geometryChanged) {
|
||||||
|
view.viewportLineBlocks.forEach(lineBlock => {
|
||||||
|
const { from, top, height } = lineBlock
|
||||||
|
const lineNumber = view.state.doc.lineAt(from).number
|
||||||
|
const blameBlockAtLineNumber = findBlockForLineNumber(lineNumber)
|
||||||
|
|
||||||
|
if (!blameBlockAtLineNumber) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('Bad math! Cannot find a block at line', lineNumber)
|
||||||
|
} else {
|
||||||
|
if (blameBlockAtLineNumber.topPosition === BLAME_BLOCK_NOT_YET_CALCULATED_TOP_POSITION) {
|
||||||
|
blameBlockAtLineNumber.topPosition = top
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeMirror reports top position of a block incorrectly sometimes, so we need to normalize it
|
||||||
|
// using the previous block.
|
||||||
|
if (lineNumber > 1) {
|
||||||
|
const previousBlock = findBlockForLineNumber(lineNumber - 1)
|
||||||
|
|
||||||
|
if (previousBlock.fromLineNumber !== blameBlockAtLineNumber.fromLineNumber) {
|
||||||
|
const normalizedTop =
|
||||||
|
previousBlock.topPosition + Object.values(previousBlock.heights).reduce((a, b) => a + b, 0)
|
||||||
|
|
||||||
|
blameBlockAtLineNumber.topPosition = normalizedTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blameBlockAtLineNumber.heights[lineNumber] = height
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setBlameBlocks({ ...blameBlocks })
|
||||||
|
}
|
||||||
|
}, 50),
|
||||||
|
[blameBlocks]
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Normalize loading and error rendering when implementing new Design layout
|
||||||
|
// that have Blame in a separate tab.
|
||||||
|
if (loading) {
|
||||||
|
return <Container padding="xlarge">{getString('loading')}</Container>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <Container padding="xlarge">{getErrorMessage(error)}</Container>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className={css.gitBlame}>
|
||||||
|
<Layout.Horizontal className={css.layout}>
|
||||||
|
<Container className={css.blameColumn}>
|
||||||
|
{Object.values(blameBlocks)
|
||||||
|
.filter(({ topPosition }) => topPosition !== BLAME_BLOCK_NOT_YET_CALCULATED_TOP_POSITION)
|
||||||
|
.map(({ fromLineNumber, topPosition: top, heights, commitInfo }) => {
|
||||||
|
const height = Object.values(heights).reduce((a, b) => a + b, 0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className={css.blameBox} key={fromLineNumber} height={height} style={{ top }}>
|
||||||
|
<Layout.Horizontal spacing="small" className={css.blameBoxLayout}>
|
||||||
|
<Container>
|
||||||
|
<Avatar name={commitInfo.Author.Identity.Name} size="normal" hoverCard={false} />
|
||||||
|
</Container>
|
||||||
|
<Container style={{ flexGrow: 1 }}>
|
||||||
|
<Layout.Vertical spacing="xsmall">
|
||||||
|
<Text
|
||||||
|
font={{ variation: FontVariation.BODY }}
|
||||||
|
lineClamp={2}
|
||||||
|
tooltipProps={{
|
||||||
|
portalClassName: css.blameCommitPortalClass
|
||||||
|
}}>
|
||||||
|
{commitInfo.Title}
|
||||||
|
</Text>
|
||||||
|
<Text font={{ variation: FontVariation.BODY }} lineClamp={1}>
|
||||||
|
<StringSubstitute
|
||||||
|
str={getString('blameCommitLine')}
|
||||||
|
vars={{
|
||||||
|
author: <strong>{commitInfo.Author.Identity.Name}</strong>,
|
||||||
|
timestamp: <ReactTimeago date={commitInfo.Author.When} />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</Layout.Vertical>
|
||||||
|
</Container>
|
||||||
|
</Layout.Horizontal>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Container>
|
||||||
|
<Render when={Object.values(blameBlocks).length}>
|
||||||
|
<GitBlameSourceViewer
|
||||||
|
source={data?.map(({ Lines }) => Lines.join('\n')).join('\n') || ''}
|
||||||
|
filename={resourcePath}
|
||||||
|
onViewUpdate={onViewUpdate}
|
||||||
|
blameBlocks={blameBlocks}
|
||||||
|
/>
|
||||||
|
</Render>
|
||||||
|
</Layout.Horizontal>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomLineNumber extends GutterMarker {
|
||||||
|
lineNumber: number
|
||||||
|
|
||||||
|
constructor(lineNumber: number) {
|
||||||
|
super()
|
||||||
|
this.lineNumber = lineNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
toDOM() {
|
||||||
|
const element = document.createElement('div')
|
||||||
|
element.textContent = this.lineNumber.toString()
|
||||||
|
element.classList.add(css.lineNo)
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GitBlameSourceViewerProps {
|
||||||
|
filename: string
|
||||||
|
source: string
|
||||||
|
onViewUpdate?: (update: ViewUpdate) => void
|
||||||
|
blameBlocks: BlameBlockRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EditorLinePaddingWidgetSpec extends LineWidgetSpec {
|
||||||
|
blockLines: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function GitBlameSourceViewer({ source, filename, onViewUpdate, blameBlocks }: GitBlameSourceViewerProps) {
|
||||||
|
const [view, setView] = useState<EditorView>()
|
||||||
|
const ref = useRef<HTMLDivElement>()
|
||||||
|
const languageConfig = useMemo(() => new Compartment(), [])
|
||||||
|
const lineWidgetSpec = useMemo(() => {
|
||||||
|
const spec: EditorLinePaddingWidgetSpec[] = []
|
||||||
|
|
||||||
|
Object.values(blameBlocks).forEach(block => {
|
||||||
|
const blockLines = block.numberOfLines
|
||||||
|
|
||||||
|
spec.push({
|
||||||
|
lineNumber: block.fromLineNumber,
|
||||||
|
position: LineWidgetPosition.TOP,
|
||||||
|
blockLines
|
||||||
|
})
|
||||||
|
|
||||||
|
spec.push({
|
||||||
|
lineNumber: block.toLineNumber,
|
||||||
|
position: LineWidgetPosition.BOTTOM,
|
||||||
|
blockLines
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return spec
|
||||||
|
}, [blameBlocks])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const customLineNumberGutter = gutter({
|
||||||
|
lineMarker(_view, line) {
|
||||||
|
const lineNumber: number = _view.state.doc.lineAt(line.from).number
|
||||||
|
return new CustomLineNumber(lineNumber)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const editorView = new EditorView({
|
||||||
|
doc: source,
|
||||||
|
extensions: [
|
||||||
|
customLineNumberGutter,
|
||||||
|
|
||||||
|
ViewPlugin.fromClass(
|
||||||
|
class {
|
||||||
|
update(update: ViewUpdate) {
|
||||||
|
onViewUpdate?.(update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
color,
|
||||||
|
hyperLink, // works pretty well in a markdown file
|
||||||
|
theme,
|
||||||
|
|
||||||
|
EditorView.lineWrapping,
|
||||||
|
keymap.of([indentWithTab]),
|
||||||
|
|
||||||
|
EditorState.readOnly.of(true),
|
||||||
|
EditorView.editable.of(false),
|
||||||
|
|
||||||
|
lineWidget({
|
||||||
|
spec: lineWidgetSpec,
|
||||||
|
widgetFor: spec => new EditorLinePaddingWidget(spec)
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
languageConfig is a compartment that defaults to an empty array (no language support)
|
||||||
|
at first, when a language is detected, languageConfig is used to reconfigure dynamically.
|
||||||
|
@see https://codemirror.net/examples/config/
|
||||||
|
*/
|
||||||
|
languageConfig.of([])
|
||||||
|
],
|
||||||
|
parent: ref.current
|
||||||
|
})
|
||||||
|
|
||||||
|
setView(editorView)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
editorView.destroy()
|
||||||
|
}
|
||||||
|
}, []) // eslint-disable-line
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (view && filename) {
|
||||||
|
languageDescriptionFrom(filename)
|
||||||
|
?.load()
|
||||||
|
.then(languageSupport => {
|
||||||
|
view.dispatch({ effects: languageConfig.reconfigure(languageSupport) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [filename, view, languageConfig])
|
||||||
|
|
||||||
|
return <Container ref={ref} className={css.main} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function languageDescriptionFrom(filename: string) {
|
||||||
|
return LanguageDescription.matchFilename(languages, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditorLinePaddingWidget extends WidgetType {
|
||||||
|
constructor(readonly spec: EditorLinePaddingWidgetSpec) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
toDOM() {
|
||||||
|
const { blockLines, position, lineNumber } = this.spec
|
||||||
|
let height = 8
|
||||||
|
|
||||||
|
if (position === LineWidgetPosition.BOTTOM && blockLines <= 4) {
|
||||||
|
height += (5 - blockLines) * 15
|
||||||
|
}
|
||||||
|
|
||||||
|
const div = document.createElement('div')
|
||||||
|
|
||||||
|
div.setAttribute('aria-hidden', 'true')
|
||||||
|
div.setAttribute('data-line-number', String(lineNumber))
|
||||||
|
div.setAttribute('data-position', position)
|
||||||
|
|
||||||
|
div.style.height = `${height}px`
|
||||||
|
|
||||||
|
return div
|
||||||
|
}
|
||||||
|
|
||||||
|
eq() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreEvent() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
import { StateField, Range, Text } from '@codemirror/state'
|
||||||
|
import { EditorView, Decoration, WidgetType } from '@codemirror/view'
|
||||||
|
|
||||||
|
export enum LineWidgetPosition {
|
||||||
|
TOP = 'top',
|
||||||
|
BOTTOM = 'bottom'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LineWidgetSpec {
|
||||||
|
lineNumber: number
|
||||||
|
position: LineWidgetPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LineWidgetGeneration<T extends LineWidgetSpec> = (args: T) => WidgetType
|
||||||
|
|
||||||
|
function buildLineDecorations<T extends LineWidgetSpec = LineWidgetSpec>(
|
||||||
|
doc: Text,
|
||||||
|
widgetFor: LineWidgetGeneration<T>,
|
||||||
|
spec: T[]
|
||||||
|
) {
|
||||||
|
const decorations: Range<Decoration>[] = []
|
||||||
|
|
||||||
|
spec.forEach(_spec => {
|
||||||
|
const { lineNumber, position } = _spec
|
||||||
|
const lines = doc.lines
|
||||||
|
const lineInfo = doc.line(lineNumber)
|
||||||
|
|
||||||
|
if (lineNumber <= lines) {
|
||||||
|
const decoration = Decoration.widget({
|
||||||
|
widget: widgetFor(_spec),
|
||||||
|
block: true,
|
||||||
|
side: position === LineWidgetPosition.TOP ? -1 : 1
|
||||||
|
})
|
||||||
|
|
||||||
|
decorations.push(decoration.range(position === LineWidgetPosition.TOP ? lineInfo.from : lineInfo.to))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Decoration.set(decorations)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LineWidgetParams<T extends LineWidgetSpec = LineWidgetSpec> {
|
||||||
|
spec: T[]
|
||||||
|
widgetFor: LineWidgetGeneration<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function lineWidget<T extends LineWidgetSpec = LineWidgetSpec>({ spec, widgetFor }: LineWidgetParams<T>) {
|
||||||
|
return StateField.define({
|
||||||
|
create: state => {
|
||||||
|
return buildLineDecorations(state.doc, widgetFor, spec)
|
||||||
|
},
|
||||||
|
|
||||||
|
update(decorations, transation) {
|
||||||
|
return transation.docChanged ? buildLineDecorations(transation.newDoc, widgetFor, spec) : decorations
|
||||||
|
},
|
||||||
|
|
||||||
|
provide: f => EditorView.decorations.from(f)
|
||||||
|
})
|
||||||
|
}
|
@ -62,6 +62,10 @@ export interface FormDataOpenapiRegisterRequest {
|
|||||||
username?: string
|
username?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GitrpcBlamePart {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
export type GitrpcFileAction = 'CREATE' | 'UPDATE' | 'DELETE' | 'MOVE'
|
export type GitrpcFileAction = 'CREATE' | 'UPDATE' | 'DELETE' | 'MOVE'
|
||||||
|
|
||||||
export interface OpenapiAdminUsersCreateRequest {
|
export interface OpenapiAdminUsersCreateRequest {
|
||||||
@ -832,6 +836,52 @@ export const useUpdateRepository = ({ repo_ref, ...props }: UseUpdateRepositoryP
|
|||||||
{ base: getConfig('code'), pathParams: { repo_ref }, ...props }
|
{ base: getConfig('code'), pathParams: { repo_ref }, ...props }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export interface GetBlameQueryParams {
|
||||||
|
/**
|
||||||
|
* The git reference (branch / tag / commitID) that will be used to retrieve the data. If no value is provided the default branch of the repository is used.
|
||||||
|
*/
|
||||||
|
git_ref?: string
|
||||||
|
/**
|
||||||
|
* Line number from which the file data is considered
|
||||||
|
*/
|
||||||
|
line_from?: number
|
||||||
|
/**
|
||||||
|
* Line number to which the file data is considered
|
||||||
|
*/
|
||||||
|
line_to?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetBlamePathParams {
|
||||||
|
repo_ref: string
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetBlameProps = Omit<
|
||||||
|
GetProps<GitrpcBlamePart[], UsererrorError, GetBlameQueryParams, GetBlamePathParams>,
|
||||||
|
'path'
|
||||||
|
> &
|
||||||
|
GetBlamePathParams
|
||||||
|
|
||||||
|
export const GetBlame = ({ repo_ref, path, ...props }: GetBlameProps) => (
|
||||||
|
<Get<GitrpcBlamePart[], UsererrorError, GetBlameQueryParams, GetBlamePathParams>
|
||||||
|
path={`/repos/${repo_ref}/blame/${path}`}
|
||||||
|
base={getConfig('code')}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
export type UseGetBlameProps = Omit<
|
||||||
|
UseGetProps<GitrpcBlamePart[], UsererrorError, GetBlameQueryParams, GetBlamePathParams>,
|
||||||
|
'path'
|
||||||
|
> &
|
||||||
|
GetBlamePathParams
|
||||||
|
|
||||||
|
export const useGetBlame = ({ repo_ref, path, ...props }: UseGetBlameProps) =>
|
||||||
|
useGet<GitrpcBlamePart[], UsererrorError, GetBlameQueryParams, GetBlamePathParams>(
|
||||||
|
(paramsInPath: GetBlamePathParams) => `/repos/${paramsInPath.repo_ref}/blame/${paramsInPath.path}`,
|
||||||
|
{ base: getConfig('code'), pathParams: { repo_ref, path }, ...props }
|
||||||
|
)
|
||||||
|
|
||||||
export interface ListBranchesQueryParams {
|
export interface ListBranchesQueryParams {
|
||||||
/**
|
/**
|
||||||
* Indicates whether optional commit information should be included in the response.
|
* Indicates whether optional commit information should be included in the response.
|
||||||
|
@ -481,6 +481,78 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
tags:
|
tags:
|
||||||
- repository
|
- repository
|
||||||
|
/repos/{repo_ref}/blame/{path}:
|
||||||
|
get:
|
||||||
|
operationId: getBlame
|
||||||
|
parameters:
|
||||||
|
- description: The git reference (branch / tag / commitID) that will be used
|
||||||
|
to retrieve the data. If no value is provided the default branch of the
|
||||||
|
repository is used.
|
||||||
|
in: query
|
||||||
|
name: git_ref
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
default: '{Repository Default Branch}'
|
||||||
|
type: string
|
||||||
|
- description: Line number from which the file data is considered
|
||||||
|
in: query
|
||||||
|
name: line_from
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
- description: Line number to which the file data is considered
|
||||||
|
in: query
|
||||||
|
name: line_to
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
- in: path
|
||||||
|
name: repo_ref
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: path
|
||||||
|
name: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/GitrpcBlamePart'
|
||||||
|
type: array
|
||||||
|
description: OK
|
||||||
|
'401':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UsererrorError'
|
||||||
|
description: Unauthorized
|
||||||
|
'403':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UsererrorError'
|
||||||
|
description: Forbidden
|
||||||
|
'404':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UsererrorError'
|
||||||
|
description: Not Found
|
||||||
|
'500':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UsererrorError'
|
||||||
|
description: Internal Server Error
|
||||||
|
tags:
|
||||||
|
- repository
|
||||||
/repos/{repo_ref}/branches:
|
/repos/{repo_ref}/branches:
|
||||||
get:
|
get:
|
||||||
operationId: listBranches
|
operationId: listBranches
|
||||||
@ -3643,6 +3715,8 @@ components:
|
|||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
GitrpcBlamePart:
|
||||||
|
type: object
|
||||||
GitrpcFileAction:
|
GitrpcFileAction:
|
||||||
enum:
|
enum:
|
||||||
- CREATE
|
- CREATE
|
||||||
|
@ -9,3 +9,28 @@ export interface DiffFileEntry extends DiffFile {
|
|||||||
fileActivities?: TypesPullReqActivity[]
|
fileActivities?: TypesPullReqActivity[]
|
||||||
activities?: TypesPullReqActivity[]
|
activities?: TypesPullReqActivity[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GitBlameEntry {
|
||||||
|
Commit: {
|
||||||
|
SHA: string
|
||||||
|
Title: string
|
||||||
|
Message: string
|
||||||
|
Author: {
|
||||||
|
Identity: {
|
||||||
|
Name: string
|
||||||
|
Email: string
|
||||||
|
}
|
||||||
|
When: string
|
||||||
|
}
|
||||||
|
Committer: {
|
||||||
|
Identity: {
|
||||||
|
Name: string
|
||||||
|
Email: string
|
||||||
|
}
|
||||||
|
When: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lines: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GitBlameResponse = GitBlameEntry[]
|
||||||
|
4
web/src/utils/utils.scss
Normal file
4
web/src/utils/utils.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@mixin mono-font {
|
||||||
|
font-family: var(--code-editor-font-family) !important;
|
||||||
|
font-size: var(--code-editor-font-size) !important;
|
||||||
|
}
|
229
web/yarn.lock
229
web/yarn.lock
@ -1949,11 +1949,225 @@
|
|||||||
"@codemirror/state" "^6.0.0"
|
"@codemirror/state" "^6.0.0"
|
||||||
"@codemirror/view" "^6.0.0"
|
"@codemirror/view" "^6.0.0"
|
||||||
|
|
||||||
|
"@uiw/codemirror-extensions-color@^4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-color/-/codemirror-extensions-color-4.19.9.tgz#2391a7c86d51aab195931f003d2df6386ed0877b"
|
||||||
|
integrity sha512-MHDELaVSplGbPBvNvBnkv/bsEvZbgG+DETZCDU/I7up2j2Bo8Z2cYIzlwjsN8Ap2Zq5aBdT9fN3NTKNdjRxueg==
|
||||||
|
dependencies:
|
||||||
|
colors-named "^1.0.0"
|
||||||
|
colors-named-hex "^1.0.0"
|
||||||
|
hsl-matcher "^1.2.3"
|
||||||
|
|
||||||
"@uiw/codemirror-extensions-events@^4.12.3":
|
"@uiw/codemirror-extensions-events@^4.12.3":
|
||||||
version "4.19.4"
|
version "4.19.4"
|
||||||
resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-events/-/codemirror-extensions-events-4.19.4.tgz#44b59a267752aaab62e94b06f07cd59e6c93f05e"
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-events/-/codemirror-extensions-events-4.19.4.tgz#44b59a267752aaab62e94b06f07cd59e6c93f05e"
|
||||||
integrity sha512-m2aAnR4K+yN8RX/yTKDw2mheNOq9xdVPYiawynroSkKF/6coFQcRa4j6DDDGkL4p0NxXG5vgzYRcCaQGVkQILA==
|
integrity sha512-m2aAnR4K+yN8RX/yTKDw2mheNOq9xdVPYiawynroSkKF/6coFQcRa4j6DDDGkL4p0NxXG5vgzYRcCaQGVkQILA==
|
||||||
|
|
||||||
|
"@uiw/codemirror-extensions-hyper-link@^4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-hyper-link/-/codemirror-extensions-hyper-link-4.19.9.tgz#4e0d66e8ff277af47293602fe3355eeaf53a66b6"
|
||||||
|
integrity sha512-epxMNrCoTXcgGeiZSGw3sqJ+rHP8YuiMCHvb4gZbBHj5vQ4M8GzErqPZBv0eDXZ7jB9wthv8GFBEEw/N1WYrww==
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-abcdef@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-abcdef/-/codemirror-theme-abcdef-4.19.9.tgz#10eac4542997d1064c83061a1e3668bb0f7bd646"
|
||||||
|
integrity sha512-F2ChAT9+ryD3hhzoHmVUmINxJKl6n+A/I2LTH4Gf9i0VFLvGRpBUGRmPqct3csIK34eG/LyPikoQremVb+p5sg==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-androidstudio@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-androidstudio/-/codemirror-theme-androidstudio-4.19.9.tgz#2c38488867b6820186428f3955c263e705a90e9d"
|
||||||
|
integrity sha512-Kaf425J4q7+dy0HhDzGlXNEm4AYE+PofWpPWyek45xlKRn0fFfEqdtfwQR+7qBwF4+CazOBawT5Jx6S2uDnr6A==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-atomone@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-atomone/-/codemirror-theme-atomone-4.19.9.tgz#3e2405542aafca92b3a072f3a7e56b52bf327ac9"
|
||||||
|
integrity sha512-eNDEkB+GDeQ3gAH3R/WXiqFkgcNR8EC/WviZC5Nj+b/2V7AeRinjrWundgST/wYCxdqvu+s3mZ7QN1kpgqCUrQ==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-aura@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-aura/-/codemirror-theme-aura-4.19.9.tgz#f8df2e3216a1a58b0ddaece9421acbd6c47e37a0"
|
||||||
|
integrity sha512-ISU7xmN1pfjDG1pxpxii7trcmEyuEUCWT1kjAPqBCCCqkofLWPyK+ly83Xl1Xnga+zJ2eNDgh2qXUp58MC1EhQ==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-bbedit@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-bbedit/-/codemirror-theme-bbedit-4.19.9.tgz#7a22f0e0fc96b73a1550b3f10a1e5d5f2e39257e"
|
||||||
|
integrity sha512-fAXX8umrS8RNUimTL0QVtytX0nujpUSxqmr7X89tJddp89nNfFPIHOzQxLRwNOudCJF4/kjN15cyOseBy2dy8g==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-bespin@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-bespin/-/codemirror-theme-bespin-4.19.9.tgz#e850a8eb331d9b00219f1ccde7368d911c254e69"
|
||||||
|
integrity sha512-HsReyL2sgW+VdiGNgVV7rxpK0a4jC28lYCjJfLWt1tZSP/XlazTY1o77Yug3L/jYVIgC+FZjaAGyc4NAYQZv8Q==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-darcula@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-darcula/-/codemirror-theme-darcula-4.19.9.tgz#010f04b1a42dab0c8a13aa9cb25a4318274ce88e"
|
||||||
|
integrity sha512-4s17IOvoOvOdlmbQZ1syO5BGv0D4POYUIZzOFeMyInpcjtYvBgKgng2KSFDdIFJMj/h/nWuusQCGivNUpRc4Iw==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-dracula@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-dracula/-/codemirror-theme-dracula-4.19.9.tgz#681e892d17ff1ca5cb9a2fbe7d0a50ebd9513a62"
|
||||||
|
integrity sha512-ZOU4WnxrRxFnH1UFK7pQS72OcSL7nY1c3nufVhwSmkQh2ZY8lEsyjAPvQxWS+4oNKFBg2VB2SuNiCO/hPxmmcA==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-duotone@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-duotone/-/codemirror-theme-duotone-4.19.9.tgz#85c88801fa6a97b0b0ba9c17f21b1bc373a77a6e"
|
||||||
|
integrity sha512-UbC1jZRYZaWFbw5UDUfU57Emvtc3ZXpI6t0Uw7GiqZH0WKfJA1Y7mZtrZNaJxV9ua/78SHL4CflidVajwZcdmQ==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-eclipse@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-eclipse/-/codemirror-theme-eclipse-4.19.9.tgz#7a3dbcbd94b82de41d1c2880402a323452a62329"
|
||||||
|
integrity sha512-9h9aNd8TnIUxGgzJx5sraEvCEfX5RV/xwigTGoI4gVyYQxhTKKcQn1l2mOvweKYFM0Lw7tmT9+gSv0rA7x/I+Q==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-github@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.19.9.tgz#eecc75527e56e1278680335f1163eb2a92a11e5d"
|
||||||
|
integrity sha512-TxAJu7eFrIWUvekJ/jbev8fGx4fAYRH3FCxS21rm8B1OzF/aRcJM28zlC1rgKxMV5uG4KjWHOdvT3rNIVs1Meg==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-gruvbox-dark@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-gruvbox-dark/-/codemirror-theme-gruvbox-dark-4.19.9.tgz#7c0fec29c462a73d0ab703f764a3fc07c3b6f776"
|
||||||
|
integrity sha512-bMGxo3fqwa0RxYnLX+gsK3E3MWzfdz3rVFu/8SvO2BEZugbknRa5eRiodQkVf8r63L5vpcjeZtVgIUsa6It81g==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-material@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-material/-/codemirror-theme-material-4.19.9.tgz#fc140b5085841100daa42fef4d1fc8ac92b2628f"
|
||||||
|
integrity sha512-0KzOgywKEs+p3/V38u8VW8eu2m8vAkbCVcxvupnTnv0MG5pf8JaS/gVWCQqRv7lSDtwlfVB9UdGmDR2NHEZNew==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-noctis-lilac@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-noctis-lilac/-/codemirror-theme-noctis-lilac-4.19.9.tgz#ba1ed1bfefc4424c250ae0e1887ff67d949e9c70"
|
||||||
|
integrity sha512-qDIOenJpSizfC+ZNdUnxZbjA4LIvdIMaw+EVFk+d7J5L74ak4HObK4oDVFN8nEUgdPf1FJ0G3yLk8wwVr35yAg==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-nord@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-nord/-/codemirror-theme-nord-4.19.9.tgz#a20d4e16288bf246a68eaa03bcce139daa82c5d3"
|
||||||
|
integrity sha512-RQLOTYVzauO2BAvE9/21ZurtCxnVO3vbfF7Y1CExEr4vCJr7+TA/KQ/eWJwhk45C+mFbZJ8/VgBev0iqyQ8XVQ==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-okaidia@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-okaidia/-/codemirror-theme-okaidia-4.19.9.tgz#2459dd3b6a4fc63967a8579f2f4aa7bc73adef5e"
|
||||||
|
integrity sha512-8NWKVbxQrBZc8jA5urwuzkdtotmCo60vvtRzjuq1jyVO+Rh2hyjE2oPbE+7H8qdZRsU+JqGZgEe9Y4Vm/3hlSA==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-solarized@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-solarized/-/codemirror-theme-solarized-4.19.9.tgz#c3703489e04bf2334bdad6c8972e6641b3c573a6"
|
||||||
|
integrity sha512-Z7uAxxDK0ZICnQmjoMvAqTAhdALG5v8CNmpNsvZZ5qr3bgtPw7N97fvCXXCqzjINOYZIETNVmps/+YwUd0lyyg==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-sublime@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-sublime/-/codemirror-theme-sublime-4.19.9.tgz#a8504dfceff5b833dca27c3de774a71b7284f959"
|
||||||
|
integrity sha512-u6BtA0jt1bsIK2tBAHr7YF4ZbkW7sEkoHAGgNqjnkYUsSyyvtKliv3AERRKM5WYFJ5npw1mxytpYQ61piUns5Q==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-tokyo-night-day@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-tokyo-night-day/-/codemirror-theme-tokyo-night-day-4.19.9.tgz#4134bd93bc6d44ce3ac70331a55e423b6bd38649"
|
||||||
|
integrity sha512-6I/+M31SeNHAh1sAQvyUFKH0NbWI7GKQ1ng8Hm9DQJ/t654tUtYtdZlAF4Mn+mwdRLJjkYhok5fxVBgs40NXTA==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-tokyo-night-storm@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-tokyo-night-storm/-/codemirror-theme-tokyo-night-storm-4.19.9.tgz#c0ef96ca87c6c00adc809980c2b2cfade0b575c3"
|
||||||
|
integrity sha512-iBim76h4VgnwIbGWssJnMrfTlPCjXh/BqgMm/mc3GmSu2z+SXcAEzW7NC4Iui85obpMVRo7G/8AvkBF5EVUFmg==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-tokyo-night@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-tokyo-night/-/codemirror-theme-tokyo-night-4.19.9.tgz#529b0af8cb06aeae4a43caad6425eb9d9404aba2"
|
||||||
|
integrity sha512-AWxY2dIJSwXGSu/kgnb5/kDyjX6fYgJrt6e8FKszGf7V/ctgE/eA1lJhDAXqbErC9tx25XDkS+oE7dyoOtZ9Ag==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-vscode@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.19.9.tgz#c426054e328ffc9515323acc92672f24100255e3"
|
||||||
|
integrity sha512-cpj40KO+O3mqIe8GmkWGlfo+ltA/72v+kWVZA4QoOK/DfuNGL4mAXZWFjxSvbSI6BmJZISKpKL23mIOpRmy1Zw==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-xcode@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-xcode/-/codemirror-theme-xcode-4.19.9.tgz#866ff78ea7c2987a06821f135955d57aa2d3f250"
|
||||||
|
integrity sha512-3oF2nrC9ef2Um/9yLSRDM9YTco58kePhiTtyaOt+Ly6SzEnGLfughRk1Aam4JLMqwXYRIhu0cLiqK0OIJZDLkw==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-themes-all@^4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes-all/-/codemirror-themes-all-4.19.9.tgz#ffb4327c3cc97362aedd7c77754c21e352370499"
|
||||||
|
integrity sha512-/Id11RqhYEz40W3skdcQvgJsZgO6mJc27cwjL2I+EC4jtSSo9MrJruYlN+wRDt/+jASMSWbw/Z4oJsgueAm3dA==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-theme-abcdef" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-androidstudio" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-atomone" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-aura" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-bbedit" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-bespin" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-darcula" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-dracula" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-duotone" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-eclipse" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-github" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-gruvbox-dark" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-material" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-noctis-lilac" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-nord" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-okaidia" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-solarized" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-sublime" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-tokyo-night" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-tokyo-night-day" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-tokyo-night-storm" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-vscode" "4.19.9"
|
||||||
|
"@uiw/codemirror-theme-xcode" "4.19.9"
|
||||||
|
"@uiw/codemirror-themes" "4.19.9"
|
||||||
|
|
||||||
|
"@uiw/codemirror-themes@4.19.9":
|
||||||
|
version "4.19.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes/-/codemirror-themes-4.19.9.tgz#988876213a2e350244ac2a0d479ebb792afbe94d"
|
||||||
|
integrity sha512-PH3hl1w42z7GXe/zoD9gSadOGBWyKPl7vHm/8V1PUuHXT21+neyfRc7v0xPwb05pGP6ExfbmPi78y4+g6cHopg==
|
||||||
|
dependencies:
|
||||||
|
"@codemirror/language" "^6.0.0"
|
||||||
|
"@codemirror/state" "^6.0.0"
|
||||||
|
"@codemirror/view" "^6.0.0"
|
||||||
|
|
||||||
"@uiw/codemirror-themes@^4.12.3":
|
"@uiw/codemirror-themes@^4.12.3":
|
||||||
version "4.19.4"
|
version "4.19.4"
|
||||||
resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes/-/codemirror-themes-4.19.4.tgz#78a443d98ec8261134349163efd01e939e4a3f22"
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes/-/codemirror-themes-4.19.4.tgz#78a443d98ec8261134349163efd01e939e4a3f22"
|
||||||
@ -3685,6 +3899,16 @@ colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.16:
|
|||||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
|
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
|
||||||
integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
|
integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
|
||||||
|
|
||||||
|
colors-named-hex@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/colors-named-hex/-/colors-named-hex-1.0.1.tgz#efbecaae99ac0793c7e6d34341845c5d54b0f460"
|
||||||
|
integrity sha512-2uoNWhxAPRn3GVpbuaQ2p5LAMhsjd9r/ZqQNJTUcEr1XQCkMFWh9zPLJLjg1l51xYApdDCMIEjkDNpoAXK2vMw==
|
||||||
|
|
||||||
|
colors-named@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/colors-named/-/colors-named-1.0.1.tgz#addea53c6fcf2661b7fae07553f8a396b615adb9"
|
||||||
|
integrity sha512-MGhZwJ6SPSdrg5qsr3YB3sD4zB2bfm3bPj9iIdkjxruUYNQakiBBWL+kFM3SXnyfkZClj3Bq7vofBKbgeJRJ/Q==
|
||||||
|
|
||||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
@ -6318,6 +6542,11 @@ hpack.js@^2.1.6:
|
|||||||
readable-stream "^2.0.1"
|
readable-stream "^2.0.1"
|
||||||
wbuf "^1.1.0"
|
wbuf "^1.1.0"
|
||||||
|
|
||||||
|
hsl-matcher@^1.2.3:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/hsl-matcher/-/hsl-matcher-1.2.3.tgz#a398ecef6ef592df9f636082f0ba0584ecc68825"
|
||||||
|
integrity sha512-irW1socbRjPPAtX/jdl2AWntFB2cCv5W0BGoeZW4uFURCWzupsyAqnw0wPB1qh5wKjdrEYVRV++IuLko+P31OA==
|
||||||
|
|
||||||
html-encoding-sniffer@^2.0.1:
|
html-encoding-sniffer@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
|
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user