Skip to content

Commit

Permalink
Merge branch 'ui/markdown-editor-slowness' of _OKE5H2PQKOUfzFFDuD4FA/…
Browse files Browse the repository at this point in the history
…default/CODE/gitness (#39)
  • Loading branch information
tan-nhu authored and Harness committed Apr 24, 2023
2 parents 5b038a9 + 1873bf5 commit e091e06
Show file tree
Hide file tree
Showing 21 changed files with 2,210 additions and 1,714 deletions.
7 changes: 6 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
"@blueprintjs/core": "3.26.1",
"@blueprintjs/datetime": "3.13.0",
"@blueprintjs/select": "3.12.3",
"@codemirror/commands": "^6.2.3",
"@codemirror/lang-markdown": "^6.1.1",
"@codemirror/language-data": "^6.3.0",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.6",
"@harness/design-system": "1.4.0",
"@harness/icons": "1.110.2",
"@harness/ng-tooltip": ">=1.31.25",
Expand All @@ -47,7 +52,7 @@
"@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-preview": "^4.1.12",
"anser": "2.0.1",
"classnames": "^2.2.6",
"clipboard-copy": "^3.1.0",
Expand Down
5 changes: 0 additions & 5 deletions web/src/App.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
*/

.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);
Expand Down
3 changes: 1 addition & 2 deletions web/src/components/CommentBox/CommentBox.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@
}

.editCommentContainer {
background-color: var(--grey-50) !important;
padding: var(--spacing-large) !important;
padding: var(--spacing-small) !important;
border-radius: var(--box-radius);
}

Expand Down
23 changes: 13 additions & 10 deletions web/src/components/CommentBox/CommentBox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useCallback, useRef, useState } from 'react'
import { useResizeDetector } from 'react-resize-detector'
import type { EditorView } from '@codemirror/view'
import { Render, Match, Truthy, Falsy, Else } from 'react-jsx-match'
import {
Container,
Expand All @@ -22,10 +23,7 @@ import { ThreadSection } from 'components/ThreadSection/ThreadSection'
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
import { useAppContext } from 'AppContext'
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
import {
MarkdownEditorWithPreview,
MarkdownEditorWithPreviewResetProps
} from 'components/MarkdownEditorWithPreview/MarkdownEditorWithPreview'
import { MarkdownEditorWithPreview } from 'components/MarkdownEditorWithPreview/MarkdownEditorWithPreview'
import { MarkdownViewer } from 'components/MarkdownViewer/MarkdownViewer'
import css from './CommentBox.module.scss'

Expand Down Expand Up @@ -118,7 +116,7 @@ export const CommentBox = <T = unknown,>({
.join(CRLF)
)
}, [])
const editorRef = useRef<MarkdownEditorWithPreviewResetProps>()
const viewRef = useRef<EditorView>()

return (
<Container
Expand Down Expand Up @@ -160,11 +158,10 @@ export const CommentBox = <T = unknown,>({
</Container>
</Truthy>
<Falsy>
<Container
padding="xlarge"
className={cx(css.newCommentContainer, { [css.hasThread]: !!comments.length })}>
<Container className={cx(css.newCommentContainer, { [css.hasThread]: !!comments.length })}>
<MarkdownEditorWithPreview
editorRef={editorRef as React.MutableRefObject<MarkdownEditorWithPreviewResetProps>}
viewRef={viewRef}
noBorder
i18n={{
placeHolder: getString(comments.length ? 'replyHere' : 'leaveAComment'),
tabEdit: getString('write'),
Expand All @@ -186,7 +183,13 @@ export const CommentBox = <T = unknown,>({
setMarkdown('')

if (resetOnSave) {
editorRef.current?.resetEditor?.()
viewRef.current?.dispatch({
changes: {
from: 0,
to: viewRef.current.state.doc.length,
insert: ''
}
})
} else {
setComments([...comments, updatedItem as CommentItem<T>])
setShowReplyPlaceHolder(true)
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/CommitModalButton/CommitModalButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export const CommitModalButton: React.FC<CommitModalButtonProps> = ({
disabled={disableBranchCreation}
label=""
onChange={e => {
setTargetBranchOption(get(e.target, 'defaultValue'))
setTargetBranchOption(get(e.target, 'defaultValue') as unknown as CommitToGitRefOption)
}}
items={[
{
Expand Down
30 changes: 30 additions & 0 deletions web/src/components/Editor/Editor.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@import 'src/utils/utils';

.editor {
:global {
.cm-editor {
outline: none;
border: 1px solid var(--grey-200);
border-radius: 4px;
min-height: var(--editor-min-height, 60px);
max-height: var(--editor-max-height, 600px);

&.cm-focused {
border-color: var(--primary-7);
outline: none;
}

.cm-scroller {
overflow: auto;
padding: var(--spacing-small);

.cm-line {
&,
* {
@include markdown-font;
}
}
}
}
}
}
6 changes: 6 additions & 0 deletions web/src/components/Editor/Editor.module.scss.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable */
// this is an auto-generated file
declare const styles: {
readonly editor: string
}
export default styles
85 changes: 64 additions & 21 deletions web/src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,64 @@ import React, { useEffect, useMemo, useRef } from 'react'
import { Container } from '@harness/uicore'
import { LanguageDescription } from '@codemirror/language'
import { indentWithTab } from '@codemirror/commands'
import cx from 'classnames'
import type { ViewUpdate } from '@codemirror/view'
import type { Text } from '@codemirror/state'
import { languages } from '@codemirror/language-data'
import { EditorView, keymap } from '@codemirror/view'
import { noop } from 'lodash-es'
import { markdown } from '@codemirror/lang-markdown'
import { EditorView, keymap, placeholder as placeholderExtension } from '@codemirror/view'
import { Compartment, EditorState, Extension } from '@codemirror/state'
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 css from './Editor.module.scss'

interface EditorProps {
filename: string
source: string
onViewUpdate?: (update: ViewUpdate) => void
export interface EditorProps {
content: string
filename?: string
forMarkdown?: boolean
placeholder?: string
readonly?: boolean
autoFocus?: boolean
className?: string
extensions?: Extension
maxHeight?: string | number
viewRef?: React.MutableRefObject<EditorView | undefined>
setDirty?: React.Dispatch<React.SetStateAction<boolean>>
onChange?: (doc: Text, viewUpdate: ViewUpdate) => void
onViewUpdate?: (viewUpdate: ViewUpdate) => void
}

export const Editor = React.memo(function CodeMirrorReactEditor({
source,
content,
filename,
onViewUpdate = noop,
forMarkdown,
placeholder,
readonly = false,
autoFocus,
className,
extensions = new Compartment().of([]),
viewRef
maxHeight,
viewRef,
setDirty,
onChange,
onViewUpdate
}: EditorProps) {
const view = useRef<EditorView>()
const ref = useRef<HTMLDivElement>()
const languageConfig = useMemo(() => new Compartment(), [])
const markdownLanguageSupport = useMemo(() => markdown({ codeLanguages: languages }), [])
const style = useMemo(() => {
if (maxHeight) {
return {
'--editor-max-height': Number.isInteger(maxHeight) ? `${maxHeight}px` : maxHeight
} as React.CSSProperties
}
}, [maxHeight])

useEffect(() => {
const editorView = new EditorView({
doc: source,
doc: content,
extensions: [
extensions,

Expand All @@ -45,11 +68,21 @@ export const Editor = React.memo(function CodeMirrorReactEditor({
theme,

EditorView.lineWrapping,

...(placeholder ? [placeholderExtension(placeholder)] : []),

keymap.of([indentWithTab]),

...(readonly ? [EditorState.readOnly.of(true), EditorView.editable.of(false)] : []),

EditorView.updateListener.of(onViewUpdate),
EditorView.updateListener.of(viewUpdate => {
setDirty?.(!cleanDoc.eq(viewUpdate.state.doc))
onViewUpdate?.(viewUpdate)

if (viewUpdate.docChanged) {
onChange?.(viewUpdate.state.doc, viewUpdate)
}
}),

/**
languageConfig is a compartment that defaults to an empty array (no language support)
Expand All @@ -67,25 +100,35 @@ export const Editor = React.memo(function CodeMirrorReactEditor({
viewRef.current = editorView
}

const cleanDoc = editorView.state.doc

if (autoFocus) {
editorView.focus()
}

return () => {
editorView.destroy()
}
}, []) // eslint-disable-line react-hooks/exhaustive-deps

// Dynamically load language support based on filename
// Dynamically load language support based on filename. Note that
// we need to configure languageSupport for Markdown separately to
// enable syntax highlighting for all code blocks (multi-lang).
useEffect(() => {
if (filename) {
languageDescriptionFrom(filename)
if (forMarkdown) {
view.current?.dispatch({ effects: languageConfig.reconfigure(markdownLanguageSupport) })
} else if (filename) {
LanguageDescription.matchFilename(languages, filename)
?.load()
.then(languageSupport => {
view.current?.dispatch({ effects: languageConfig.reconfigure(languageSupport) })
view.current?.dispatch({
effects: languageConfig.reconfigure(
languageSupport.language.name === 'markdown' ? markdownLanguageSupport : languageSupport
)
})
})
}
}, [filename, view, languageConfig])
}, [filename, forMarkdown, view, languageConfig, markdownLanguageSupport])

return <Container ref={ref} className={className} />
return <Container ref={ref} className={cx(css.editor, className)} style={style} />
})

function languageDescriptionFrom(filename: string) {
return LanguageDescription.matchFilename(languages, filename)
}
17 changes: 12 additions & 5 deletions web/src/components/ImageCarousel/ImageCarousel.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import React, { useState } from 'react'
import { ButtonGroup, ButtonVariation, Button, Container, Dialog, Carousel } from '@harness/uicore'
import { ZOOM_INC_DEC_LEVEL } from 'utils/Utils'
import type { UseStringsReturn } from 'framework/strings'
import css from './ImageCarousel.module.scss'

interface ImageCarouselProps {
isOpen: boolean
setIsOpen: (value: boolean) => void
setZoomLevel: (value: number) => void
zoomLevel: number
imgEvent: string[]
getString: UseStringsReturn['getString']
i18n: {
zoomIn: string
zoomOut: string
}
}

const ImageCarousel = (props: ImageCarouselProps) => {
const { getString, isOpen, setIsOpen, setZoomLevel, zoomLevel, imgEvent } = props
const { isOpen, setIsOpen, setZoomLevel, zoomLevel, imgEvent, i18n } = props
const [imgTitle, setImageTitle] = useState(imgEvent[0])

return (
<Dialog
portalClassName={css.portalContainer}
Expand Down Expand Up @@ -55,7 +59,7 @@ const ImageCarousel = (props: ImageCarouselProps) => {
variation={ButtonVariation.TERTIARY}
icon="zoom-in"
data-testid="zoomInButton"
tooltip={getString('zoomIn')}
tooltip={i18n.zoomIn}
onClick={() => {
Number(zoomLevel.toFixed(1)) < 2 && setZoomLevel(zoomLevel + ZOOM_INC_DEC_LEVEL)
}}
Expand All @@ -71,7 +75,7 @@ const ImageCarousel = (props: ImageCarouselProps) => {
variation={ButtonVariation.TERTIARY}
icon="zoom-out"
data-testid="zoomOutButton"
tooltip={getString('zoomOut')}
tooltip={i18n.zoomOut}
onClick={() => {
Number(zoomLevel.toFixed(1)) > 0.3 && setZoomLevel(zoomLevel - ZOOM_INC_DEC_LEVEL)
}}
Expand All @@ -83,3 +87,6 @@ const ImageCarousel = (props: ImageCarouselProps) => {
}

export default ImageCarousel

// TODO: Dialog does not have i18n context when mounted inside CommentBox/different React root
// Hence getString can't get proper translations
Loading

0 comments on commit e091e06

Please sign in to comment.