diff --git a/web/config/webpack.common.js b/web/config/webpack.common.js
index ffd01a146..b63b998a2 100644
--- a/web/config/webpack.common.js
+++ b/web/config/webpack.common.js
@@ -1,17 +1,17 @@
-const path = require('path');
+const path = require('path')
const webpack = require('webpack')
const {
container: { ModuleFederationPlugin },
DefinePlugin
-} = require('webpack');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
+} = require('webpack')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
const GenerateStringTypesPlugin = require('../scripts/webpack/GenerateStringTypesPlugin').GenerateStringTypesPlugin
const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin')
-
-const moduleFederationConfig = require('./moduleFederation.config');
-const CONTEXT = process.cwd();
+const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
+const moduleFederationConfig = require('./moduleFederation.config')
+const CONTEXT = process.cwd()
const DEV = process.env.NODE_ENV === 'development'
const ON_PREM = `${process.env.ON_PREM}` === 'true'
@@ -150,8 +150,7 @@ module.exports = {
},
resolve: {
extensions: ['.mjs', '.js', '.ts', '.tsx', '.json', '.ttf', '.scss'],
- plugins: [
- new TsconfigPathsPlugin()]
+ plugins: [new TsconfigPathsPlugin()]
},
plugins: [
new ModuleFederationPlugin(moduleFederationConfig),
@@ -164,5 +163,71 @@ module.exports = {
new RetryChunkLoadPlugin({
maxRetries: 2
}),
+ new MonacoWebpackPlugin({
+ // available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
+ languages: [
+ 'abap',
+ 'apex',
+ 'azcli',
+ 'bat',
+ 'cameligo',
+ 'clojure',
+ 'coffee',
+ 'cpp',
+ 'csharp',
+ 'csp',
+ 'css',
+ 'dockerfile',
+ 'fsharp',
+ 'go',
+ 'graphql',
+ 'handlebars',
+ 'html',
+ 'ini',
+ 'java',
+ 'javascript',
+ 'json',
+ 'kotlin',
+ 'less',
+ 'lua',
+ 'markdown',
+ 'mips',
+ 'msdax',
+ 'mysql',
+ 'objective-c',
+ 'pascal',
+ 'pascaligo',
+ 'perl',
+ 'pgsql',
+ 'php',
+ 'postiats',
+ 'powerquery',
+ 'powershell',
+ 'pug',
+ 'python',
+ 'r',
+ 'razor',
+ 'redis',
+ 'redshift',
+ 'restructuredtext',
+ 'ruby',
+ 'rust',
+ 'sb',
+ 'scheme',
+ 'scss',
+ 'shell',
+ 'solidity',
+ 'sophia',
+ 'sql',
+ 'st',
+ 'swift',
+ 'tcl',
+ 'twig',
+ 'typescript',
+ 'vb',
+ 'xml',
+ 'yaml'
+ ]
+ })
]
-};
\ No newline at end of file
+}
diff --git a/web/config/webpack.dev.js b/web/config/webpack.dev.js
index 5be0658a4..95dc73a75 100644
--- a/web/config/webpack.dev.js
+++ b/web/config/webpack.dev.js
@@ -12,7 +12,6 @@ const {
WatchIgnorePlugin,
container: { ModuleFederationPlugin }
} = require('webpack')
-const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const commonConfig = require('./webpack.common')
const baseUrl = process.env.BASE_URL ?? 'https://qa.harness.io/gateway'
@@ -61,72 +60,6 @@ const devConfig = {
new DefinePlugin({
'process.env': '{}', // required for @blueprintjs/core
__DEV__: DEV
- }),
- new MonacoWebpackPlugin({
- // available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
- languages: [
- 'abap',
- 'apex',
- 'azcli',
- 'bat',
- 'cameligo',
- 'clojure',
- 'coffee',
- 'cpp',
- 'csharp',
- 'csp',
- 'css',
- 'dockerfile',
- 'fsharp',
- 'go',
- 'graphql',
- 'handlebars',
- 'html',
- 'ini',
- 'java',
- 'javascript',
- 'json',
- 'kotlin',
- 'less',
- 'lua',
- 'markdown',
- 'mips',
- 'msdax',
- 'mysql',
- 'objective-c',
- 'pascal',
- 'pascaligo',
- 'perl',
- 'pgsql',
- 'php',
- 'postiats',
- 'powerquery',
- 'powershell',
- 'pug',
- 'python',
- 'r',
- 'razor',
- 'redis',
- 'redshift',
- 'restructuredtext',
- 'ruby',
- 'rust',
- 'sb',
- 'scheme',
- 'scss',
- 'shell',
- 'solidity',
- 'sophia',
- 'sql',
- 'st',
- 'swift',
- 'tcl',
- 'twig',
- 'typescript',
- 'vb',
- 'xml',
- 'yaml'
- ]
})
// new ForkTsCheckerWebpackPlugin()
// new WatchIgnorePlugin({
diff --git a/web/src/components/SourceCodeEditor/MonacoSourceCodeEditor.tsx b/web/src/components/SourceCodeEditor/MonacoSourceCodeEditor.tsx
new file mode 100644
index 000000000..504b6c5d6
--- /dev/null
+++ b/web/src/components/SourceCodeEditor/MonacoSourceCodeEditor.tsx
@@ -0,0 +1,102 @@
+import React, { useEffect } from 'react'
+import { Container } from '@harness/uicore'
+import type monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'
+import MonacoEditor from 'react-monaco-editor'
+import { noop } from 'lodash-es'
+import type { SourceCodeEditorProps } from 'utils/Utils'
+
+export const MonacoEditorOptions = {
+ ignoreTrimWhitespace: true,
+ minimap: { enabled: false },
+ codeLens: false,
+ scrollBeyondLastLine: false,
+ smartSelect: false,
+ tabSize: 2,
+ insertSpaces: true,
+ overviewRulerBorder: false,
+ automaticLayout: true
+}
+
+const diagnosticsOptions = {
+ noSemanticValidation: true,
+ noSyntaxValidation: true
+}
+
+const compilerOptions = {
+ jsx: 'react',
+ noLib: true,
+ allowNonTsExtensions: true
+}
+
+function autoAdjustEditorHeight(editor: monacoEditor.editor.IStandaloneCodeEditor) {
+ // Adjust editor height based on its content
+ // https://github.com/microsoft/monaco-editor/issues/794#issuecomment-427092969
+ const LINE_HEIGHT = 18
+ const CONTAINER_GUTTER = 10
+ const editorNode = editor.getDomNode() as HTMLElement
+ const codeContainer = editorNode.getElementsByClassName('view-lines')[0]
+ let prevLineCount = 0
+ const adjustHeight = (): void => {
+ const _height =
+ codeContainer.childElementCount > prevLineCount
+ ? (codeContainer as HTMLElement).offsetHeight // unfold
+ : codeContainer.childElementCount * LINE_HEIGHT + CONTAINER_GUTTER // fold
+ prevLineCount = codeContainer.childElementCount
+
+ editorNode.style.height = Math.max(_height, 100) + 'px'
+ editor.layout()
+ }
+
+ setTimeout(adjustHeight, 0)
+ editor.onDidChangeModelDecorations(() => setTimeout(adjustHeight, 0))
+}
+
+const toOnOff = (flag: boolean) => (flag ? 'on' : 'off')
+
+export default function MonacoSourceCodeEditor({
+ source,
+ language = 'plaintext',
+ lineNumbers = true,
+ readOnly = false,
+ className,
+ height,
+ autoHeight,
+ wordWrap = true,
+ onChange = noop
+}: SourceCodeEditorProps) {
+ const scrollbar = autoHeight ? 'hidden' : 'auto'
+
+ useEffect(() => {
+ monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions?.(diagnosticsOptions)
+ monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions?.(diagnosticsOptions)
+ monaco.languages.typescript.typescriptDefaults.setCompilerOptions(compilerOptions)
+ }, [])
+
+ return (
+
+ {
+ if (autoHeight) {
+ autoAdjustEditorHeight(editor)
+ }
+ }}
+ onChange={onChange}
+ />
+
+ )
+}
diff --git a/web/src/components/SourceCodeEditor/SourceCodeEditor.tsx b/web/src/components/SourceCodeEditor/SourceCodeEditor.tsx
index 3a9e2b1be..0a384e817 100644
--- a/web/src/components/SourceCodeEditor/SourceCodeEditor.tsx
+++ b/web/src/components/SourceCodeEditor/SourceCodeEditor.tsx
@@ -1,79 +1,17 @@
-import React, { useRef } from 'react'
-import { Container } from '@harness/uicore'
-import MonacoEditor from 'react-monaco-editor'
-import { MonacoEditorOptions } from 'utils/Utils'
+import React, { lazy, Suspense } from 'react'
+import { Text } from '@harness/uicore'
+import type { SourceCodeEditorProps } from 'utils/Utils'
+import { useStrings } from 'framework/strings'
-export interface SourceCodeEditorProps {
- source: string
- language?: string
- lineNumbers?: boolean
- readOnly?: boolean
- highlightLines?: string // i.e: {1,3-4}, TODO: not yet supported
- className?: string
- height?: number | string
- autoHeight?: boolean
-}
+function Editor(props: SourceCodeEditorProps) {
+ const { getString } = useStrings()
+ const MonacoSourceCodeEditor = lazy(() => import('./MonacoSourceCodeEditor'))
-function MonacoSourceCodeEditor({
- source,
- language = 'plaintext',
- lineNumbers = true,
- readOnly = false,
- className,
- height,
- autoHeight
-}: SourceCodeEditorProps) {
- const inputContainerRef = useRef(null)
- const scrollbar = autoHeight ? 'hidden' : 'auto'
-
- // return
return (
-
- {
- if (autoHeight) {
- // Aadjust editor height based on content
- // https://github.com/microsoft/monaco-editor/issues/794#issuecomment-427092969
- const LINE_HEIGHT = 18
- const CONTAINER_GUTTER = 10
- const editorNode = editor.getDomNode() as HTMLElement
- const codeContainer = editorNode.getElementsByClassName('view-lines')[0]
- let prevLineCount = 0
- const adjustHeight = (): void => {
- const _height =
- codeContainer.childElementCount > prevLineCount
- ? (codeContainer as HTMLElement).offsetHeight // unfold
- : codeContainer.childElementCount * LINE_HEIGHT + CONTAINER_GUTTER // fold
- prevLineCount = codeContainer.childElementCount
-
- editorNode.style.height = Math.max(_height, 100) + 'px'
- editor.layout()
- }
-
- setTimeout(adjustHeight, 0)
- editor.onDidChangeModelDecorations(() => setTimeout(adjustHeight, 0))
- }
- }}
- />
-
+ {getString('loading')}}>
+
+
)
}
-export const SourceCodeEditor = React.memo(MonacoSourceCodeEditor)
+export const SourceCodeEditor = React.memo(Editor)
diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts
index 706d0d15d..6d9e8f8ee 100644
--- a/web/src/framework/strings/stringTypes.ts
+++ b/web/src/framework/strings/stringTypes.ts
@@ -36,9 +36,12 @@ export interface StringsMap {
failedToCreateRepo: string
files: string
history: string
+ identifier: string
+ in: string
inactiveBranches: string
loading: string
name: string
+ nameYourFile: string
newFile: string
newFolder: string
newRepo: string
diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml
index 6c62cc3e0..fc211748f 100644
--- a/web/src/i18n/strings.en.yaml
+++ b/web/src/i18n/strings.en.yaml
@@ -32,6 +32,7 @@ create: Create
clone: Clone
copy: Copy
defaultBranch: Default
+in: in
ok: OK
loading: Loading...
addGitIgnore: Add a .gitignore
@@ -51,6 +52,7 @@ createBranch: + Create Branch
searchBranches: Search branches
updated: Updated
cloneHTTPS: Clone with HTTPS
+nameYourFile: Name your file...
repos:
name: Repo Name
data: Repo Data
diff --git a/web/src/pages/Repository/RepositoryContent/ContentHeader/ContentHeader.tsx b/web/src/pages/Repository/RepositoryContent/ContentHeader/ContentHeader.tsx
index fcfc863d7..1011c6a7b 100644
--- a/web/src/pages/Repository/RepositoryContent/ContentHeader/ContentHeader.tsx
+++ b/web/src/pages/Repository/RepositoryContent/ContentHeader/ContentHeader.tsx
@@ -129,9 +129,7 @@ export function ContentHeader({ repoMetadata, gitRef, resourcePath = '' }: Conte
variation={ButtonVariation.SECONDARY}
icon="main-clone"
iconProps={{ size: 10 }}
- tooltip={
-
- }
+ tooltip={}
tooltipProps={{
interactionKind: 'click',
minimal: true,
diff --git a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss
index 99553fd62..8cfe44be8 100644
--- a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss
+++ b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss
@@ -7,13 +7,28 @@
overflow: hidden;
.heading {
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
+ // border-top-left-radius: 4px;
+ // border-top-right-radius: 4px;
align-items: center;
padding: 0 var(--spacing-xlarge) !important;
height: 52px;
background-color: var(--grey-100);
box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.08), 0px 0.5px 2px rgba(96, 97, 112, 0.16);
+ border-bottom: 1px solid var(--grey-200);
+
+ .path {
+ align-items: center;
+
+ .inputContainer {
+ margin-left: var(--spacing-small) !important;
+ margin-bottom: 0;
+
+ input {
+ padding: var(--spacing-xsmall) var(--spacing-small);
+ height: 28px;
+ }
+ }
+ }
}
.content {
@@ -21,8 +36,7 @@
overflow: hidden;
.editorContainer {
- height: calc(100vh - 95px - 52px);
- background-color: red;
+ height: calc(100vh - 96px - 52px);
overflow: hidden;
}
}
diff --git a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss.d.ts b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss.d.ts
index 0481e443b..0ba005f4d 100644
--- a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss.d.ts
+++ b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.module.scss.d.ts
@@ -3,6 +3,8 @@
declare const styles: {
readonly container: string
readonly heading: string
+ readonly path: string
+ readonly inputContainer: string
readonly content: string
readonly editorContainer: string
}
diff --git a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.tsx b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.tsx
index 5a5e24b43..1ae465322 100644
--- a/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.tsx
+++ b/web/src/pages/RepositoryFileEdit/FileEditor/FileEditor.tsx
@@ -8,10 +8,12 @@ import {
FlexExpander,
Icon,
Layout,
- Text
+ Text,
+ TextInput
} from '@harness/uicore'
import { Link } from 'react-router-dom'
import ReactJoin from 'react-join'
+import cx from 'classnames'
import { SourceCodeEditor } from 'components/SourceCodeEditor/SourceCodeEditor'
import type { OpenapiGetContentOutput, RepoFileContent, TypesRepository } from 'services/scm'
import { useAppContext } from 'AppContext'
@@ -22,7 +24,7 @@ import css from './FileEditor.module.scss'
interface FileEditorProps {
repoMetadata: TypesRepository
- gitRef?: string
+ gitRef: string
resourcePath?: string
contentInfo: OpenapiGetContentOutput
}
@@ -30,12 +32,13 @@ interface FileEditorProps {
export function FileEditor({ contentInfo, repoMetadata, gitRef, resourcePath = '' }: FileEditorProps) {
const { getString } = useStrings()
const { routes } = useAppContext()
+ const language = filenameToLanguage(contentInfo?.name)
return (
-
+
@@ -44,7 +47,7 @@ export function FileEditor({ contentInfo, repoMetadata, gitRef, resourcePath = '
{resourcePath.split('/').map((_path, index, paths) => {
const pathAtIndex = paths.slice(0, index + 1).join('/')
- return (
+ return index < paths.length - 1 ? (
)
})}
+ {getString('in')}
+
+ {gitRef}
+
@@ -69,16 +88,14 @@ export function FileEditor({ contentInfo, repoMetadata, gitRef, resourcePath = '
/>
- {(contentInfo?.content as RepoFileContent)?.data && (
-
-
-
- )}
+
+
+
)
}
diff --git a/web/src/pages/RepositoryFileEdit/RepositoryFileEditContent/RepositoryFileEditContent.tsx b/web/src/pages/RepositoryFileEdit/RepositoryFileEditContent/RepositoryFileEditContent.tsx
index fd08c4197..c46f8243d 100644
--- a/web/src/pages/RepositoryFileEdit/RepositoryFileEditContent/RepositoryFileEditContent.tsx
+++ b/web/src/pages/RepositoryFileEdit/RepositoryFileEditContent/RepositoryFileEditContent.tsx
@@ -1,7 +1,6 @@
import React from 'react'
import { Container } from '@harness/uicore'
import type { TypesRepository } from 'services/scm'
-import { isFile } from 'utils/GitUtils'
import { useGetResourceContent } from 'hooks/useGetResourceContent'
import { FileEditor } from '../FileEditor/FileEditor'
import css from './RepositoryFileEditContent.module.scss'
@@ -19,10 +18,10 @@ export function RepositoryFileEditContent({ repoMetadata, gitRef, resourcePath }
return (
- {data && isFile(data) && (
+ {data && (
diff --git a/web/src/utils/Utils.ts b/web/src/utils/Utils.ts
index db70b8710..ff8f5634a 100644
--- a/web/src/utils/Utils.ts
+++ b/web/src/utils/Utils.ts
@@ -26,15 +26,17 @@ export function showToaster(message: string, props?: Partial): IToa
export const getErrorMessage = (error: Unknown): string =>
get(error, 'data.error', get(error, 'data.message', error?.message))
-export const MonacoEditorOptions = {
- ignoreTrimWhitespace: true,
- minimap: { enabled: false },
- codeLens: false,
- scrollBeyondLastLine: false,
- smartSelect: false,
- tabSize: 2,
- insertSpaces: true,
- overviewRulerBorder: false
+export interface SourceCodeEditorProps {
+ source: string
+ language?: string
+ lineNumbers?: boolean
+ readOnly?: boolean
+ highlightLines?: string // i.e: {1,3-4}, TODO: not yet supported
+ className?: string
+ height?: number | string
+ autoHeight?: boolean
+ wordWrap?: boolean
+ onChange?: (value: string) => void
}
// Monaco editor has a bug where when its value is set, the value
@@ -157,10 +159,16 @@ const MONACO_SUPPORTED_LANGUAGES = [
'yaml'
]
+const EXTENSION_TO_LANG: Record = {
+ tsx: 'typescript',
+ jsx: 'typescript'
+}
+
export const filenameToLanguage = (name?: string): string | undefined => {
- const map = langMap.languages(name?.split('.').pop() || '')
+ const extension = name?.split('.').pop() || ''
+ const map = langMap.languages(extension)
if (map?.length) {
- return MONACO_SUPPORTED_LANGUAGES.find(lang => map.includes(lang))
+ return MONACO_SUPPORTED_LANGUAGES.find(lang => map.includes(lang)) || EXTENSION_TO_LANG[extension]
}
}