diff options
Diffstat (limited to 'app/assets/javascripts/ide')
72 files changed, 421 insertions, 358 deletions
diff --git a/app/assets/javascripts/ide/commit_icon.js b/app/assets/javascripts/ide/commit_icon.js index 4984b5bb91d..70ee9cff22b 100644 --- a/app/assets/javascripts/ide/commit_icon.js +++ b/app/assets/javascripts/ide/commit_icon.js @@ -1,6 +1,6 @@ import { commitItemIconMap } from './constants'; -export default file => { +export default (file) => { if (file.deleted) { return commitItemIconMap.deleted; } else if (file.tempFile && !file.prevPath) { diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue index 123e0aba959..4192a002486 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue @@ -63,7 +63,7 @@ export default { return this.openPendingTab({ file: this.file, keyPrefix: this.keyPrefix, - }).then(changeViewer => { + }).then((changeViewer) => { if (changeViewer) { this.updateViewer(viewerTypes.diff); } diff --git a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue index aed7b792902..91cce44382c 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue @@ -74,6 +74,7 @@ export default { <input :placeholder="placeholderBranchName" :value="newBranchName" + data-testid="ide-new-branch-name" type="text" class="form-control monospace" @input="updateBranchName($event.target.value)" diff --git a/app/assets/javascripts/ide/components/file_templates/bar.vue b/app/assets/javascripts/ide/components/file_templates/bar.vue index 88dca2f0556..bd4c4f18141 100644 --- a/app/assets/javascripts/ide/components/file_templates/bar.vue +++ b/app/assets/javascripts/ide/components/file_templates/bar.vue @@ -29,7 +29,7 @@ export default { 'undoFileTemplate', ]), setInitialType() { - const initialTemplateType = this.templateTypes.find(t => t.name === this.activeFile.name); + const initialTemplateType = this.templateTypes.find((t) => t.name === this.activeFile.name); if (initialTemplateType) { this.setSelectedTemplateType(initialTemplateType); diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue index 5d5b66a6444..772dab3fed3 100644 --- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue +++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue @@ -44,7 +44,7 @@ export default { computed: { ...mapState('fileTemplates', ['templates', 'isLoading']), outputData() { - return (this.isAsyncData ? this.templates : this.data).filter(t => { + return (this.isAsyncData ? this.templates : this.data).filter((t) => { if (!this.searchable) return true; return t.name.toLowerCase().indexOf(this.search.toLowerCase()) >= 0; diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index f8568f46cd6..aac899fde0d 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -73,7 +73,7 @@ export default { }, }, mounted() { - window.onbeforeunload = e => this.onBeforeUnload(e); + window.onbeforeunload = (e) => this.onBeforeUnload(e); if (this.themeName) document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`); diff --git a/app/assets/javascripts/ide/components/ide_sidebar_nav.vue b/app/assets/javascripts/ide/components/ide_sidebar_nav.vue index 966c36d6e71..9dbed0ace40 100644 --- a/app/assets/javascripts/ide/components/ide_sidebar_nav.vue +++ b/app/assets/javascripts/ide/components/ide_sidebar_nav.vue @@ -37,7 +37,7 @@ export default { }, methods: { isActiveTab(tab) { - return this.isOpen && tab.views.some(view => view.name === this.currentView); + return this.isOpen && tab.views.some((view) => view.name === this.currentView); }, buttonClasses(tab) { return [ diff --git a/app/assets/javascripts/ide/components/nav_dropdown.vue b/app/assets/javascripts/ide/components/nav_dropdown.vue index 8cea8655461..6ff77e556c0 100644 --- a/app/assets/javascripts/ide/components/nav_dropdown.vue +++ b/app/assets/javascripts/ide/components/nav_dropdown.vue @@ -31,9 +31,7 @@ export default { }, removeDropdownListeners() { // eslint-disable-next-line @gitlab/no-global-event-off - $(this.$refs.dropdown) - .off('show.bs.dropdown') - .off('hide.bs.dropdown'); + $(this.$refs.dropdown).off('show.bs.dropdown').off('hide.bs.dropdown'); }, showDropdown() { this.isVisibleDropdown = true; diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue index 4a9a2a57acd..5704129c10f 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue @@ -25,23 +25,24 @@ export default { }, methods: { createFile(target, file) { - const { name } = file; + const { name, type: mimeType } = file; const encodedContent = target.result.split('base64,')[1]; const rawContent = encodedContent ? atob(encodedContent) : ''; - const isText = isTextFile({ content: rawContent, mimeType: file.type, name }); + const isText = isTextFile({ content: rawContent, mimeType, name }); - const emitCreateEvent = content => + const emitCreateEvent = (content) => this.$emit('create', { name: `${this.path ? `${this.path}/` : ''}${name}`, type: 'blob', content, rawPath: !isText ? URL.createObjectURL(file) : '', + mimeType, }); if (isText) { const reader = new FileReader(); - reader.addEventListener('load', e => emitCreateEvent(e.target.result), { once: true }); + reader.addEventListener('load', (e) => emitCreateEvent(e.target.result), { once: true }); reader.readAsText(file); } else { emitCreateEvent(rawContent); @@ -50,11 +51,11 @@ export default { readFile(file) { const reader = new FileReader(); - reader.addEventListener('load', e => this.createFile(e.target, file), { once: true }); + reader.addEventListener('load', (e) => this.createFile(e.target, file), { once: true }); reader.readAsDataURL(file); }, openFile() { - Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file)); + Array.from(this.$refs.fileUpload.files).forEach((file) => this.readFile(file)); }, startFileUpload() { this.$refs.fileUpload.click(); @@ -80,6 +81,7 @@ export default { type="file" class="hidden" multiple + data-qa-selector="file_upload_field" @change="openFile" /> </div> diff --git a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue index 87019c3b2a5..6f42ae48cc9 100644 --- a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue +++ b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue @@ -35,13 +35,13 @@ export default { return `${this.side}Pane`; }, tabs() { - return this.extensionTabs.filter(tab => tab.show); + return this.extensionTabs.filter((tab) => tab.show); }, tabViews() { - return this.tabs.map(tab => tab.views).flat(); + return this.tabs.map((tab) => tab.views).flat(); }, aliveTabViews() { - return this.tabViews.filter(view => this.isAliveView(view.name)); + return this.tabViews.filter((view) => this.isAliveView(view.name)); }, }, methods: { diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue index f65b1201d94..4c2a369226e 100644 --- a/app/assets/javascripts/ide/components/preview/clientside.vue +++ b/app/assets/javascripts/ide/components/preview/clientside.vue @@ -1,12 +1,13 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import { isEmpty } from 'lodash'; +import { isEmpty, debounce } from 'lodash'; import { Manager } from 'smooshpack'; import { listen } from 'codesandbox-api'; import { GlLoadingIcon } from '@gitlab/ui'; import Navigator from './navigator.vue'; -import { packageJsonPath } from '../../constants'; +import { packageJsonPath, LIVE_PREVIEW_DEBOUNCE } from '../../constants'; import { createPathWithExt } from '../../utils'; +import eventHub from '../../eventhub'; export default { components: { @@ -61,13 +62,10 @@ export default { }; }, }, - watch: { - entries: { - deep: true, - handler: 'update', - }, - }, mounted() { + this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE); + eventHub.$on('ide.files.change', this.onFilesChangeCallback); + this.loading = true; return this.loadFileContent(packageJsonPath) @@ -78,17 +76,19 @@ export default { .then(() => this.initPreview()); }, beforeDestroy() { + // Setting sandpackReady = false protects us form a phantom `update()` being called when `debounce` finishes. + this.sandpackReady = false; + eventHub.$off('ide.files.change', this.onFilesChangeCallback); + if (!isEmpty(this.manager)) { this.manager.listener(); } + this.manager = {}; if (this.listener) { this.listener(); } - - clearTimeout(this.timeout); - this.timeout = null; }, methods: { ...mapActions(['getFileData', 'getRawFileData']), @@ -108,7 +108,7 @@ export default { .then(() => { this.initManager(); - this.listener = listen(e => { + this.listener = listen((e) => { switch (e.type) { case 'done': this.sandpackReady = true; @@ -122,25 +122,21 @@ export default { update() { if (!this.sandpackReady) return; - clearTimeout(this.timeout); - - this.timeout = setTimeout(() => { - if (isEmpty(this.manager)) { - this.initPreview(); + if (isEmpty(this.manager)) { + this.initPreview(); - return; - } + return; + } - this.manager.updatePreview(this.sandboxOpts); - }, 250); + this.manager.updatePreview(this.sandboxOpts); }, initManager() { const { codesandboxBundlerUrl: bundlerURL } = this; const settings = { fileResolver: { - isFile: p => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])), - readFile: p => this.loadFileContent(createPathWithExt(p)).then(content => content), + isFile: (p) => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])), + readFile: (p) => this.loadFileContent(createPathWithExt(p)).then((content) => content), }, ...(bundlerURL ? { bundlerURL } : {}), }; diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index 60710251fef..8986359427f 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -31,7 +31,7 @@ export default { }, }, mounted() { - this.listener = listen(e => { + this.listener = listen((e) => { switch (e.type) { case 'urlchange': this.onUrlChange(e); diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue index dfd25feed08..8092ef3bce6 100644 --- a/app/assets/javascripts/ide/components/repo_commit_section.vue +++ b/app/assets/javascripts/ide/components/repo_commit_section.vue @@ -41,12 +41,12 @@ export default { file, keyPrefix: file.staged ? stageKeys.staged : stageKeys.unstaged, }) - .then(changeViewer => { + .then((changeViewer) => { if (changeViewer) { this.updateViewer('diff'); } }) - .catch(e => { + .catch((e) => { throw e; }); }, diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 1f029612c29..a9c05f2e1ac 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -74,8 +74,11 @@ export default { fileEditor() { return getFileEditorOrDefault(this.fileEditors, this.file.path); }, + isBinaryFile() { + return !isTextFile(this.file); + }, shouldHideEditor() { - return this.file && !this.file.loading && !isTextFile(this.file); + return this.file && !this.file.loading && this.isBinaryFile; }, showContentViewer() { return ( @@ -216,7 +219,7 @@ export default { .then(() => { this.createEditorInstance(); }) - .catch(err => { + .catch((err) => { flash( __('Error setting up editor. Please try again.'), 'alert', @@ -244,6 +247,10 @@ export default { ); }, createEditorInstance() { + if (this.isBinaryFile) { + return; + } + this.editor.dispose(); this.$nextTick(() => { @@ -274,7 +281,7 @@ export default { this.model.updateOptions(this.rules); - this.model.onChange(model => { + this.model.onChange((model) => { const { file } = model; if (!file.active) return; @@ -322,7 +329,7 @@ export default { } }, fetchEditorconfigRules() { - return getRulesWithTraversal(this.file.path, path => { + return getRulesWithTraversal(this.file.path, (path) => { const entry = this.entries[path]; if (!entry) return Promise.resolve(null); @@ -332,7 +339,7 @@ export default { return this.getFileData({ path: entry.path, makeFileActive: false }).then(() => this.getRawFileData({ path: entry.path }), ); - }).then(rules => { + }).then((rules) => { this.rules = mapRulesToMonaco(rules); }); }, @@ -346,7 +353,7 @@ export default { event.preventDefault(); event.stopImmediatePropagation(); - return readFileAsDataURL(file).then(content => { + return readFileAsDataURL(file).then((content) => { const parentPath = getPathParent(this.file.path); const path = `${parentPath ? `${parentPath}/` : ''}${file.name}`; diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index bdb11e6b004..e5618466395 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -97,3 +97,6 @@ export const packageJsonPath = 'package.json'; export const SIDE_LEFT = 'left'; export const SIDE_RIGHT = 'right'; + +// Live Preview feature +export const LIVE_PREVIEW_DEBOUNCE = 2000; diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index b9ebacef7e1..0e6775d87f1 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -39,7 +39,7 @@ const EmptyRouterComponent = { }, }; -export const createRouter = store => { +export const createRouter = (store) => { const router = new IdeRouter({ mode: 'history', base: joinPaths(gon.relative_url_root || '', '/-/ide/'), @@ -54,11 +54,11 @@ export const createRouter = store => { }, { path: ':targetmode(edit|tree|blob)/:branchid+/', - redirect: to => joinPaths(to.path, '/-/'), + redirect: (to) => joinPaths(to.path, '/-/'), }, { path: ':targetmode(edit|tree|blob)', - redirect: to => joinPaths(to.path, '/master/-/'), + redirect: (to) => joinPaths(to.path, '/master/-/'), }, { path: 'merge_requests/:mrid', @@ -66,7 +66,7 @@ export const createRouter = store => { }, { path: '', - redirect: to => joinPaths(to.path, '/edit/master/-/'), + redirect: (to) => joinPaths(to.path, '/edit/master/-/'), }, ], }, @@ -110,7 +110,7 @@ export const createRouter = store => { }); } }) - .catch(e => { + .catch((e) => { flash( __('Error while loading the project data. Please try again.'), 'alert', diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js index 62f49ba56b1..af408c06556 100644 --- a/app/assets/javascripts/ide/index.js +++ b/app/assets/javascripts/ide/index.js @@ -63,6 +63,10 @@ export function initIde(el, options = {}) { codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl, }); }, + beforeDestroy() { + // This helps tests do Singleton cleanups which we don't really have responsibility to know about here. + this.$emit('destroy'); + }, methods: { ...mapActions(['setEmptyStateSvgs', 'setLinks', 'setInitialData']), }, diff --git a/app/assets/javascripts/ide/lib/common/disposable.js b/app/assets/javascripts/ide/lib/common/disposable.js index 84b29bdb600..c5d0773c9a2 100644 --- a/app/assets/javascripts/ide/lib/common/disposable.js +++ b/app/assets/javascripts/ide/lib/common/disposable.js @@ -4,11 +4,11 @@ export default class Disposable { } add(...disposers) { - disposers.forEach(disposer => this.disposers.add(disposer)); + disposers.forEach((disposer) => this.disposers.add(disposer)); } dispose() { - this.disposers.forEach(disposer => disposer.dispose()); + this.disposers.forEach((disposer) => disposer.dispose()); this.disposers.clear(); } } diff --git a/app/assets/javascripts/ide/lib/common/model.js b/app/assets/javascripts/ide/lib/common/model.js index 2471b3627ce..4969875439e 100644 --- a/app/assets/javascripts/ide/lib/common/model.js +++ b/app/assets/javascripts/ide/lib/common/model.js @@ -75,7 +75,7 @@ export default class Model { } onChange(cb) { - this.events.add(this.disposable.add(this.model.onDidChangeContent(e => cb(this, e)))); + this.events.add(this.disposable.add(this.model.onDidChangeContent((e) => cb(this, e)))); } onDispose(cb) { @@ -121,7 +121,7 @@ export default class Model { dispose() { if (!this.model.isDisposed()) this.applyCustomOptions(); - this.events.forEach(cb => { + this.events.forEach((cb) => { if (typeof cb === 'function') cb(); }); diff --git a/app/assets/javascripts/ide/lib/create_diff.js b/app/assets/javascripts/ide/lib/create_diff.js index 3e915afdbcb..51d4967fb23 100644 --- a/app/assets/javascripts/ide/lib/create_diff.js +++ b/app/assets/javascripts/ide/lib/create_diff.js @@ -32,8 +32,8 @@ const filesWithChanges = ({ stagedFiles = [], changedFiles = [], entries = {} }) // We need to clean "move" actions, because we can only support 100% similarity moves at the moment. // This is because the previous file's content might not be loaded. Object.values(changes) - .filter(change => change.action === commitActionTypes.move) - .forEach(change => { + .filter((change) => change.action === commitActionTypes.move) + .forEach((change) => { const prev = changes[change.file.prevPath]; if (!prev) { @@ -51,14 +51,14 @@ const filesWithChanges = ({ stagedFiles = [], changedFiles = [], entries = {} }) // Next, we need to add deleted directories by looking at the parents Object.values(changes) - .filter(change => change.action === commitActionTypes.delete && change.file.parentPath) + .filter((change) => change.action === commitActionTypes.delete && change.file.parentPath) .forEach(({ file }) => { // Do nothing if we've already visited this directory. if (changes[file.parentPath]) { return; } - getDeletedParents(entries, file).forEach(parent => { + getDeletedParents(entries, file).forEach((parent) => { changes[parent.path] = { action: commitActionTypes.delete, file: parent }; }); }); @@ -66,13 +66,15 @@ const filesWithChanges = ({ stagedFiles = [], changedFiles = [], entries = {} }) return Object.values(changes); }; -const createDiff = state => { +const createDiff = (state) => { const changes = filesWithChanges(state); - const toDelete = changes.filter(x => x.action === commitActionTypes.delete).map(x => x.file.path); + const toDelete = changes + .filter((x) => x.action === commitActionTypes.delete) + .map((x) => x.file.path); const patch = changes - .filter(x => x.action !== commitActionTypes.delete) + .filter((x) => x.action !== commitActionTypes.delete) .map(({ file, action }) => createFileDiff(file, action)) .join(''); diff --git a/app/assets/javascripts/ide/lib/create_file_diff.js b/app/assets/javascripts/ide/lib/create_file_diff.js index 5ae4993321c..b417b4765d8 100644 --- a/app/assets/javascripts/ide/lib/create_file_diff.js +++ b/app/assets/javascripts/ide/lib/create_file_diff.js @@ -12,13 +12,13 @@ const NEW_LINE = '\n'; * * - Removes "=======" separator added at the beginning */ -const cleanTwoFilesPatch = text => text.replace(/^(=+\s*)/, ''); +const cleanTwoFilesPatch = (text) => text.replace(/^(=+\s*)/, ''); -const endsWithNewLine = val => !val || val[val.length - 1] === NEW_LINE; +const endsWithNewLine = (val) => !val || val[val.length - 1] === NEW_LINE; -const addEndingNewLine = val => (endsWithNewLine(val) ? val : val + NEW_LINE); +const addEndingNewLine = (val) => (endsWithNewLine(val) ? val : val + NEW_LINE); -const removeEndingNewLine = val => (endsWithNewLine(val) ? val.substr(0, val.length - 1) : val); +const removeEndingNewLine = (val) => (endsWithNewLine(val) ? val.substr(0, val.length - 1) : val); const diffHead = (prevPath, newPath = '') => `diff --git "a/${prevPath}" "b/${newPath || prevPath}"`; @@ -37,7 +37,7 @@ const createDiffBody = (path, content, isCreate) => { const chunkHead = isCreate ? `@@ -0,0 +1,${lines.length} @@` : `@@ -1,${lines.length} +0,0 @@`; const chunk = lines - .map(line => `${prefix}${line}`) + .map((line) => `${prefix}${line}`) .concat(!hasNewLine ? [NO_NEW_LINE] : []) .join(NEW_LINE); diff --git a/app/assets/javascripts/ide/lib/decorations/controller.js b/app/assets/javascripts/ide/lib/decorations/controller.js index 13d477bb2cf..b5d3eb10952 100644 --- a/app/assets/javascripts/ide/lib/decorations/controller.js +++ b/app/assets/javascripts/ide/lib/decorations/controller.js @@ -11,7 +11,7 @@ export default class DecorationsController { const modelDecorations = this.decorations.get(model.url); const decorations = []; - modelDecorations.forEach(val => decorations.push(...val)); + modelDecorations.forEach((val) => decorations.push(...val)); return decorations; } diff --git a/app/assets/javascripts/ide/lib/diff/controller.js b/app/assets/javascripts/ide/lib/diff/controller.js index 35fcda6a6c5..3efe692be13 100644 --- a/app/assets/javascripts/ide/lib/diff/controller.js +++ b/app/assets/javascripts/ide/lib/diff/controller.js @@ -3,7 +3,7 @@ import { throttle } from 'lodash'; import DirtyDiffWorker from './diff_worker'; import Disposable from '../common/disposable'; -export const getDiffChangeType = change => { +export const getDiffChangeType = (change) => { if (change.modified) { return 'modified'; } else if (change.added) { @@ -15,7 +15,7 @@ export const getDiffChangeType = change => { return ''; }; -export const getDecorator = change => ({ +export const getDecorator = (change) => ({ range: new Range(change.lineNumber, 1, change.endLineNumber, 1), options: { isWholeLine: true, @@ -71,7 +71,7 @@ export default class DirtyDiffController { } decorate({ data }) { - const decorations = data.changes.map(change => getDecorator(change)); + const decorations = data.changes.map((change) => getDecorator(change)); const model = this.modelManager.getModel(data.path); this.decorationsController.addDecorations(model, 'dirtyDiff', decorations); } diff --git a/app/assets/javascripts/ide/lib/diff/diff.js b/app/assets/javascripts/ide/lib/diff/diff.js index 62ec798b372..5a6401f56ec 100644 --- a/app/assets/javascripts/ide/lib/diff/diff.js +++ b/app/assets/javascripts/ide/lib/diff/diff.js @@ -11,7 +11,7 @@ export const computeDiff = (originalContent, newContent) => { let lineNumber = 1; return changes.reduce((acc, change) => { - const findOnLine = acc.find(c => c.lineNumber === lineNumber); + const findOnLine = acc.find((c) => c.lineNumber === lineNumber); if (findOnLine) { Object.assign(findOnLine, change, { diff --git a/app/assets/javascripts/ide/lib/diff/diff_worker.js b/app/assets/javascripts/ide/lib/diff/diff_worker.js index 77416a8de9d..78b2eab6399 100644 --- a/app/assets/javascripts/ide/lib/diff/diff_worker.js +++ b/app/assets/javascripts/ide/lib/diff/diff_worker.js @@ -1,7 +1,7 @@ import { computeDiff } from './diff'; // eslint-disable-next-line no-restricted-globals -self.addEventListener('message', e => { +self.addEventListener('message', (e) => { const { data } = e; // eslint-disable-next-line no-restricted-globals diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index 493dedcd89a..4fad0c09ce7 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -12,7 +12,7 @@ import { clearDomElement } from '~/editor/utils'; import { registerLanguages } from '../utils'; function setupThemes() { - themes.forEach(theme => { + themes.forEach((theme) => { monacoEditor.defineTheme(theme.name, theme.data); }); } @@ -108,7 +108,7 @@ export default class Editor { this.instance.updateOptions( editorOptions.reduce((acc, obj) => { - Object.keys(obj).forEach(key => { + Object.keys(obj).forEach((key) => { Object.assign(acc, { [key]: obj[key](model), }); @@ -177,7 +177,7 @@ export default class Editor { onPositionChange(cb) { if (!this.instance.onDidChangeCursorPosition) return; - this.disposable.add(this.instance.onDidChangeCursorPosition(e => cb(this.instance, e))); + this.disposable.add(this.instance.onDidChangeCursorPosition((e) => cb(this.instance, e))); } updateDiffView() { @@ -213,14 +213,14 @@ export default class Editor { addCommands() { const { store } = this; - const getKeyCode = key => { + const getKeyCode = (key) => { const monacoKeyMod = key.indexOf('KEY_') === 0; return monacoKeyMod ? KeyCode[key] : KeyMod[key]; }; - keymap.forEach(command => { - const keybindings = command.bindings.map(binding => { + keymap.forEach((command) => { + const keybindings = command.bindings.map((binding) => { const keys = binding.split('+'); // eslint-disable-next-line no-bitwise diff --git a/app/assets/javascripts/ide/lib/editor_options.js b/app/assets/javascripts/ide/lib/editor_options.js index f182a1ec50e..9f2a9a8cf4a 100644 --- a/app/assets/javascripts/ide/lib/editor_options.js +++ b/app/assets/javascripts/ide/lib/editor_options.js @@ -31,7 +31,7 @@ export const defaultModelOptions = { export const editorOptions = [ { - readOnly: model => Boolean(model.file.file_lock), - quickSuggestions: model => !(model.language === 'markdown'), + readOnly: (model) => Boolean(model.file.file_lock), + quickSuggestions: (model) => !(model.language === 'markdown'), }, ]; diff --git a/app/assets/javascripts/ide/lib/editorconfig/parser.js b/app/assets/javascripts/ide/lib/editorconfig/parser.js index 1597e4a8bfa..2adc643a15b 100644 --- a/app/assets/javascripts/ide/lib/editorconfig/parser.js +++ b/app/assets/javascripts/ide/lib/editorconfig/parser.js @@ -2,7 +2,7 @@ import { parseString } from 'editorconfig/src/lib/ini'; import minimatch from 'minimatch'; import { getPathParents } from '../../utils'; -const dirname = path => path.replace(/\.editorconfig$/, ''); +const dirname = (path) => path.replace(/\.editorconfig$/, ''); function isRootConfig(config) { return config.some(([pattern, rules]) => !pattern && rules?.root === 'true'); @@ -44,11 +44,16 @@ function getRulesWithConfigs(filePath, configFiles = [], rules = {}) { export function getRulesWithTraversal(filePath, getFileContent) { const editorconfigPaths = [ - ...getPathParents(filePath).map(x => `${x}/.editorconfig`), + ...getPathParents(filePath).map((x) => `${x}/.editorconfig`), '.editorconfig', ]; return Promise.all( - editorconfigPaths.map(path => getFileContent(path).then(content => ({ path, content }))), - ).then(results => getRulesWithConfigs(filePath, results.filter(x => x.content))); + editorconfigPaths.map((path) => getFileContent(path).then((content) => ({ path, content }))), + ).then((results) => + getRulesWithConfigs( + filePath, + results.filter((x) => x.content), + ), + ); } diff --git a/app/assets/javascripts/ide/lib/editorconfig/rules_mapper.js b/app/assets/javascripts/ide/lib/editorconfig/rules_mapper.js index f9d5579511a..25ffa9a15be 100644 --- a/app/assets/javascripts/ide/lib/editorconfig/rules_mapper.js +++ b/app/assets/javascripts/ide/lib/editorconfig/rules_mapper.js @@ -1,23 +1,23 @@ import { isBoolean, isNumber } from 'lodash'; -const map = (key, validValues) => value => +const map = (key, validValues) => (value) => value in validValues ? { [key]: validValues[value] } : {}; -const bool = key => value => (isBoolean(value) ? { [key]: value } : {}); +const bool = (key) => (value) => (isBoolean(value) ? { [key]: value } : {}); -const int = (key, isValid) => value => +const int = (key, isValid) => (value) => isNumber(value) && isValid(value) ? { [key]: Math.trunc(value) } : {}; const rulesMapper = { indent_style: map('insertSpaces', { tab: false, space: true }), - indent_size: int('tabSize', n => n > 0), - tab_width: int('tabSize', n => n > 0), + indent_size: int('tabSize', (n) => n > 0), + tab_width: int('tabSize', (n) => n > 0), trim_trailing_whitespace: bool('trimTrailingWhitespace'), end_of_line: map('endOfLine', { crlf: 1, lf: 0 }), insert_final_newline: bool('insertFinalNewline'), }; -const parseValue = x => { +const parseValue = (x) => { let value = typeof x === 'string' ? x.toLowerCase() : x; if (/^[0-9.-]+$/.test(value)) value = Number(value); if (value === 'true') value = true; diff --git a/app/assets/javascripts/ide/lib/errors.js b/app/assets/javascripts/ide/lib/errors.js index e62d9d1e77f..f975034a872 100644 --- a/app/assets/javascripts/ide/lib/errors.js +++ b/app/assets/javascripts/ide/lib/errors.js @@ -6,17 +6,17 @@ const CODEOWNERS_REGEX = /Push.*protected branches.*CODEOWNERS/; const BRANCH_CHANGED_REGEX = /changed.*since.*start.*edit/; const BRANCH_ALREADY_EXISTS = /branch.*already.*exists/; -const createNewBranchAndCommit = store => +const createNewBranchAndCommit = (store) => store .dispatch('commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH) .then(() => store.dispatch('commit/commitChanges')); -export const createUnexpectedCommitError = message => ({ +export const createUnexpectedCommitError = (message) => ({ title: __('Unexpected error'), messageHTML: escape(message) || __('Could not commit. An unexpected error occurred.'), }); -export const createCodeownersCommitError = message => ({ +export const createCodeownersCommitError = (message) => ({ title: __('CODEOWNERS rule violation'), messageHTML: escape(message), primaryAction: { @@ -25,7 +25,7 @@ export const createCodeownersCommitError = message => ({ }, }); -export const createBranchChangedCommitError = message => ({ +export const createBranchChangedCommitError = (message) => ({ title: __('Branch changed'), messageHTML: `${escape(message)}<br/><br/>${__('Would you like to create a new branch?')}`, primaryAction: { @@ -34,19 +34,19 @@ export const createBranchChangedCommitError = message => ({ }, }); -export const branchAlreadyExistsCommitError = message => ({ +export const branchAlreadyExistsCommitError = (message) => ({ title: __('Branch already exists'), messageHTML: `${escape(message)}<br/><br/>${__( 'Would you like to try auto-generating a branch name?', )}`, primaryAction: { text: __('Create new branch'), - callback: store => + callback: (store) => store.dispatch('commit/addSuffixToBranchName').then(() => createNewBranchAndCommit(store)), }, }); -export const parseCommitError = e => { +export const parseCommitError = (e) => { const { message } = e?.response?.data || {}; if (!message) { diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js index 789e09fa8f2..3fdf012bbb2 100644 --- a/app/assets/javascripts/ide/lib/files.js +++ b/app/assets/javascripts/ide/lib/files.js @@ -1,6 +1,6 @@ import { decorateData, sortTree } from '../stores/utils'; -export const splitParent = path => { +export const splitParent = (path) => { const idx = path.lastIndexOf('/'); return { @@ -11,8 +11,20 @@ export const splitParent = path => { /** * Create file objects from a list of file paths. + * + * @param {Array} options.data Array of blob paths to parse and create a file tree from. + * @param {Boolean} options.tempFile Web IDE flag for whether this is a "new" file or not. + * @param {String} options.content Content to initialize the new blob with. + * @param {String} options.rawPath Raw path used for the new blob. + * @param {Object} options.blobData Extra values to initialize each blob with. */ -export const decorateFiles = ({ data, tempFile = false, content = '', rawPath = '' }) => { +export const decorateFiles = ({ + data, + tempFile = false, + content = '', + rawPath = '', + blobData = {}, +}) => { const treeList = []; const entries = {}; @@ -20,7 +32,7 @@ export const decorateFiles = ({ data, tempFile = false, content = '', rawPath = let file; let parentPath; - const insertParent = path => { + const insertParent = (path) => { if (!path) { return null; } else if (entries[path]) { @@ -55,7 +67,7 @@ export const decorateFiles = ({ data, tempFile = false, content = '', rawPath = return tree; }; - data.forEach(path => { + data.forEach((path) => { const { parent, name } = splitParent(path); const fileFolder = parent && insertParent(parent); @@ -73,6 +85,7 @@ export const decorateFiles = ({ data, tempFile = false, content = '', rawPath = content, rawPath, parentPath, + ...blobData, }); Object.assign(entries, { diff --git a/app/assets/javascripts/ide/lib/languages/hcl.js b/app/assets/javascripts/ide/lib/languages/hcl.js index 4539719b1f2..bbb2ca66f33 100644 --- a/app/assets/javascripts/ide/lib/languages/hcl.js +++ b/app/assets/javascripts/ide/lib/languages/hcl.js @@ -11,7 +11,11 @@ const conf = { lineComment: '//', blockComment: ['/*', '*/'], }, - brackets: [['{', '}'], ['[', ']'], ['(', ')']], + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], autoClosingPairs: [ { open: '{', close: '}' }, { open: '[', close: ']' }, @@ -140,7 +144,7 @@ const language = { ], heredocBody: [ [ - /^([\w\-]+)$/, + /([\w\-]+)$/, { cases: { '$1==$S2': [ @@ -161,7 +165,11 @@ const language = { [/\/\/.*$/, 'comment'], [/#.*$/, 'comment'], ], - comment: [[/[^\/*]+/, 'comment'], [/\*\//, 'comment', '@pop'], [/[\/*]/, 'comment']], + comment: [ + [/[^\/*]+/, 'comment'], + [/\*\//, 'comment', '@pop'], + [/[\/*]/, 'comment'], + ], string: [ [/\$\{/, { token: 'delimiter', next: '@stringExpression' }], [/[^\\"\$]+/, 'string'], diff --git a/app/assets/javascripts/ide/lib/languages/vue.js b/app/assets/javascripts/ide/lib/languages/vue.js index b9ff5c5d776..f2f81307981 100644 --- a/app/assets/javascripts/ide/lib/languages/vue.js +++ b/app/assets/javascripts/ide/lib/languages/vue.js @@ -37,7 +37,13 @@ const conf = { blockComment: ['{{!--', '--}}'], }, - brackets: [['<!--', '-->'], ['<', '>'], ['{{', '}}'], ['{', '}'], ['(', ')']], + brackets: [ + ['<!--', '-->'], + ['<', '>'], + ['{{', '}}'], + ['{', '}'], + ['(', ')'], + ], autoClosingPairs: [ { open: '{', close: '}' }, diff --git a/app/assets/javascripts/ide/lib/mirror.js b/app/assets/javascripts/ide/lib/mirror.js index a516c28ad7a..6f9cfec9465 100644 --- a/app/assets/javascripts/ide/lib/mirror.js +++ b/app/assets/javascripts/ide/lib/mirror.js @@ -12,23 +12,23 @@ export const MSG_CONNECTION_ERROR = __('Could not connect to Web IDE file mirror const noop = () => {}; export const SERVICE_DELAY = 8000; -const cancellableWait = time => { +const cancellableWait = (time) => { let timeoutId = 0; const cancel = () => clearTimeout(timeoutId); - const promise = new Promise(resolve => { + const promise = new Promise((resolve) => { timeoutId = setTimeout(resolve, time); }); return [promise, cancel]; }; -const isErrorResponse = error => error && error.code !== 0; +const isErrorResponse = (error) => error && error.code !== 0; -const isErrorPayload = payload => payload && payload.status_code !== 200; +const isErrorPayload = (payload) => payload && payload.status_code !== 200; -const getErrorFromResponse = data => { +const getErrorFromResponse = (data) => { if (isErrorResponse(data.error)) { return { message: data.error.Message }; } else if (isErrorPayload(data.payload)) { @@ -38,9 +38,9 @@ const getErrorFromResponse = data => { return null; }; -const getFullPath = path => mergeUrlParams({ service: SERVICE_NAME }, getWebSocketUrl(path)); +const getFullPath = (path) => mergeUrlParams({ service: SERVICE_NAME }, getWebSocketUrl(path)); -const createWebSocket = fullPath => +const createWebSocket = (fullPath) => new Promise((resolve, reject) => { const socket = new WebSocket(fullPath, [PROTOCOL]); const resetCallbacks = () => { @@ -59,7 +59,7 @@ const createWebSocket = fullPath => }; }); -export const canConnect = ({ services = [] }) => services.some(name => name === SERVICE_NAME); +export const canConnect = ({ services = [] }) => services.some((name) => name === SERVICE_NAME); export const createMirror = () => { let socket = null; @@ -71,23 +71,23 @@ export const createMirror = () => { cancelHandler = noop; }; - const onCancelConnect = fn => { + const onCancelConnect = (fn) => { cancelHandler = fn; }; - const receiveMessage = ev => { + const receiveMessage = (ev) => { const handle = nextMessageHandler; nextMessageHandler = noop; handle(JSON.parse(ev.data)); }; - const onNextMessage = fn => { + const onNextMessage = (fn) => { nextMessageHandler = fn; }; const waitForNextMessage = () => new Promise((resolve, reject) => { - onNextMessage(data => { + onNextMessage((data) => { const err = getErrorFromResponse(data); if (err) { @@ -133,7 +133,7 @@ export const createMirror = () => { return wait .then(() => createWebSocket(fullPath)) - .then(newSocket => { + .then((newSocket) => { socket = newSocket; socket.onmessage = receiveMessage; }); diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index 70a6a6b423d..2264d63c737 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -4,9 +4,9 @@ import Api from '~/api'; import getUserPermissions from '../queries/getUserPermissions.query.graphql'; import { query } from './gql'; -const fetchApiProjectData = projectPath => Api.project(projectPath).then(({ data }) => data); +const fetchApiProjectData = (projectPath) => Api.project(projectPath).then(({ data }) => data); -const fetchGqlProjectData = projectPath => +const fetchGqlProjectData = (projectPath) => query({ query: getUserPermissions, variables: { projectPath }, @@ -27,9 +27,12 @@ export default { return Promise.resolve(file.raw); } + const options = file.binary ? { responseType: 'arraybuffer' } : {}; + return axios .get(file.rawPath, { - transformResponse: [f => f], + transformResponse: [(f) => f], + ...options, }) .then(({ data }) => data); }, @@ -51,7 +54,7 @@ export default { escapeFileUrl(filePath), ), { - transformResponse: [f => f], + transformResponse: [(f) => f], }, ) .then(({ data }) => data); diff --git a/app/assets/javascripts/ide/services/terminals.js b/app/assets/javascripts/ide/services/terminals.js index 17b4329037d..ea54733baa4 100644 --- a/app/assets/javascripts/ide/services/terminals.js +++ b/app/assets/javascripts/ide/services/terminals.js @@ -1,6 +1,6 @@ import axios from '~/lib/utils/axios_utils'; -export const baseUrl = projectPath => `/${projectPath}/ide_terminals`; +export const baseUrl = (projectPath) => `/${projectPath}/ide_terminals`; export const checkConfig = (projectPath, branch) => axios.post(`${baseUrl(projectPath)}/check_config`, { diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 710256b6377..d62dfc35d15 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -20,7 +20,7 @@ export const redirectToUrl = (self, url) => visitUrl(url); export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data); export const discardAllChanges = ({ state, commit, dispatch }) => { - state.changedFiles.forEach(file => dispatch('restoreOriginalFile', file.path)); + state.changedFiles.forEach((file) => dispatch('restoreOriginalFile', file.path)); commit(types.REMOVE_ALL_CHANGES_FILES); }; @@ -31,7 +31,7 @@ export const setResizingStatus = ({ commit }, resizing) => { export const createTempEntry = ( { state, commit, dispatch, getters }, - { name, type, content = '', rawPath = '', openFile = true, makeFileActive = true }, + { name, type, content = '', rawPath = '', openFile = true, makeFileActive = true, mimeType = '' }, ) => { const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name; @@ -56,6 +56,9 @@ export const createTempEntry = ( tempFile: true, content, rawPath, + blobData: { + mimeType, + }, }); const { file, parentPath } = data; @@ -103,7 +106,7 @@ export const stageAllChanges = ({ state, commit, dispatch, getters }) => { commit(types.SET_LAST_COMMIT_MSG, ''); - state.changedFiles.forEach(file => + state.changedFiles.forEach((file) => commit(types.STAGE_CHANGE, { path: file.path, diffInfo: getters.getDiffInfo(file.path) }), ); @@ -120,7 +123,7 @@ export const stageAllChanges = ({ state, commit, dispatch, getters }) => { export const unstageAllChanges = ({ state, commit, dispatch, getters }) => { const openFile = state.openFiles[0]; - state.stagedFiles.forEach(file => + state.stagedFiles.forEach((file) => commit(types.UNSTAGE_CHANGE, { path: file.path, diffInfo: getters.getDiffInfo(file.path) }), ); @@ -191,7 +194,7 @@ export const deleteEntry = ({ commit, dispatch, state }, path) => { if (entry.opened) dispatch('closeFile', entry); if (isTree) { - entry.tree.forEach(f => dispatch('deleteEntry', f.path)); + entry.tree.forEach((f) => dispatch('deleteEntry', f.path)); } commit(types.DELETE_ENTRY, path); @@ -218,7 +221,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name, commit(types.RENAME_ENTRY, { path, name, parentPath }); if (entry.type === 'tree') { - state.entries[newPath].tree.forEach(f => { + state.entries[newPath].tree.forEach((f) => { dispatch('renameEntry', { path: f.path, name: f.name, @@ -277,7 +280,7 @@ export const getBranchData = ({ commit, state }, { projectId, branchId, force = commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id }); resolve(data); }) - .catch(e => { + .catch((e) => { if (e.response.status === 404) { reject(e); } else { diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 8b43c7238fd..42668dec63a 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -10,22 +10,15 @@ import eventHub from '../../eventhub'; import service from '../../services'; import * as types from '../mutation_types'; import { setPageTitleForFile } from '../utils'; -import { viewerTypes, stageKeys } from '../../constants'; +import { viewerTypes, stageKeys, commitActionTypes } from '../../constants'; export const closeFile = ({ commit, state, dispatch, getters }, file) => { const { path } = file; - const indexOfClosedFile = state.openFiles.findIndex(f => f.key === file.key); + const indexOfClosedFile = state.openFiles.findIndex((f) => f.key === file.key); const fileWasActive = file.active; - if (file.pending) { - commit(types.REMOVE_PENDING_TAB, file); - } else { - commit(types.TOGGLE_FILE_OPEN, path); - commit(types.SET_FILE_ACTIVE, { path, active: false }); - } - - if (state.openFiles.length > 0 && fileWasActive) { - const nextIndexToOpen = indexOfClosedFile === 0 ? 0 : indexOfClosedFile - 1; + if (state.openFiles.length > 1 && fileWasActive) { + const nextIndexToOpen = indexOfClosedFile === 0 ? 1 : indexOfClosedFile - 1; const nextFileToOpen = state.openFiles[nextIndexToOpen]; if (nextFileToOpen.pending) { @@ -35,14 +28,22 @@ export const closeFile = ({ commit, state, dispatch, getters }, file) => { keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged', }); } else { + dispatch('setFileActive', nextFileToOpen.path); dispatch('router/push', getters.getUrlForPath(nextFileToOpen.path), { root: true }); } - } else if (!state.openFiles.length) { + } else if (state.openFiles.length === 1) { dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, { root: true, }); } + if (file.pending) { + commit(types.REMOVE_PENDING_TAB, file); + } else { + commit(types.TOGGLE_FILE_OPEN, path); + commit(types.SET_FILE_ACTIVE, { path, active: false }); + } + eventHub.$emit(`editor.update.model.dispose.${file.key}`); }; @@ -108,7 +109,7 @@ export const getFileData = ( .catch(() => { dispatch('setErrorMessage', { text: __('An error occurred while loading the file.'), - action: payload => + action: (payload) => dispatch('getFileData', payload).then(() => dispatch('setErrorMessage', null)), actionText: __('Please try again'), actionPayload: { path, makeFileActive }, @@ -125,13 +126,13 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => { export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) => { const file = state.entries[path]; - const stagedFile = state.stagedFiles.find(f => f.path === path); + const stagedFile = state.stagedFiles.find((f) => f.path === path); const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path); commit(types.TOGGLE_LOADING, { entry: file, forceValue: true }); return service .getRawFileData(fileDeletedAndReadded ? stagedFile : file) - .then(raw => { + .then((raw) => { if (!(file.tempFile && !file.prevPath && !fileDeletedAndReadded)) commit(types.SET_FILE_RAW_DATA, { file, raw, fileDeletedAndReadded }); @@ -139,7 +140,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) = const baseSha = (getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || ''; - return service.getBaseRawFileData(file, state.currentProjectId, baseSha).then(baseRaw => { + return service.getBaseRawFileData(file, state.currentProjectId, baseSha).then((baseRaw) => { commit(types.SET_FILE_BASE_RAW_DATA, { file, baseRaw, @@ -149,10 +150,10 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) = } return raw; }) - .catch(e => { + .catch((e) => { dispatch('setErrorMessage', { text: __('An error occurred while loading the file content.'), - action: payload => + action: (payload) => dispatch('getRawFileData', payload).then(() => dispatch('setErrorMessage', null)), actionText: __('Please try again'), actionPayload: { path }, @@ -164,7 +165,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) = }); }; -export const changeFileContent = ({ commit, state, getters }, { path, content }) => { +export const changeFileContent = ({ commit, dispatch, state, getters }, { path, content }) => { const file = state.entries[path]; // It's possible for monaco to hit a race condition where it tries to update renamed files. @@ -178,13 +179,15 @@ export const changeFileContent = ({ commit, state, getters }, { path, content }) content, }); - const indexOfChangedFile = state.changedFiles.findIndex(f => f.path === path); + const indexOfChangedFile = state.changedFiles.findIndex((f) => f.path === path); if (file.changed && indexOfChangedFile === -1) { commit(types.STAGE_CHANGE, { path, diffInfo: getters.getDiffInfo(path) }); } else if (!file.changed && !file.tempFile && indexOfChangedFile !== -1) { commit(types.REMOVE_FILE_FROM_CHANGED, path); } + + dispatch('triggerFilesChange', { type: commitActionTypes.update, path }); }; export const restoreOriginalFile = ({ dispatch, state, commit }, path) => { @@ -225,7 +228,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) = .then(() => { dispatch('router/push', getters.getUrlForPath(file.path), { root: true }); }) - .catch(e => { + .catch((e) => { throw e; }); } @@ -275,7 +278,7 @@ export const unstageChange = ({ commit, dispatch, getters }, path) => { export const openPendingTab = ({ commit, dispatch, getters, state }, { file, keyPrefix }) => { if (getters.activeFile && getters.activeFile.key === `${keyPrefix}-${file.key}`) return false; - state.openFiles.forEach(f => eventHub.$emit(`editor.update.model.dispose.${f.key}`)); + state.openFiles.forEach((f) => eventHub.$emit(`editor.update.model.dispose.${f.key}`)); commit(types.ADD_PENDING_TAB, { file, keyPrefix }); diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index 547665b49c6..8215cba7ccf 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -33,7 +33,7 @@ export const getMergeRequestsForBranch = ( commit(types.SET_CURRENT_MERGE_REQUEST, `${currentMR.iid}`); } }) - .catch(e => { + .catch((e) => { flash( __(`Error fetching merge requests for ${branchId}`), 'alert', @@ -66,7 +66,7 @@ export const getMergeRequestData = ( .catch(() => { dispatch('setErrorMessage', { text: __('An error occurred while loading the merge request.'), - action: payload => + action: (payload) => dispatch('getMergeRequestData', payload).then(() => dispatch('setErrorMessage', null), ), @@ -99,7 +99,7 @@ export const getMergeRequestChanges = ( .catch(() => { dispatch('setErrorMessage', { text: __('An error occurred while loading the merge request changes.'), - action: payload => + action: (payload) => dispatch('getMergeRequestChanges', payload).then(() => dispatch('setErrorMessage', null), ), @@ -121,8 +121,8 @@ export const getMergeRequestVersions = ( if (!state.projects[projectId].mergeRequests[mergeRequestId].versions.length || force) { service .getProjectMergeRequestVersions(targetProjectId || projectId, mergeRequestId) - .then(res => res.data) - .then(data => { + .then((res) => res.data) + .then((data) => { commit(types.SET_MERGE_REQUEST_VERSIONS, { projectPath: projectId, mergeRequestId, @@ -133,7 +133,7 @@ export const getMergeRequestVersions = ( .catch(() => { dispatch('setErrorMessage', { text: __('An error occurred while loading the merge request version data.'), - action: payload => + action: (payload) => dispatch('getMergeRequestVersions', payload).then(() => dispatch('setErrorMessage', null), ), @@ -156,7 +156,7 @@ export const openMergeRequest = ( targetProjectId, mergeRequestId, }) - .then(mr => { + .then((mr) => { dispatch('setCurrentBranchId', mr.source_branch); return dispatch('getBranchData', { @@ -186,7 +186,7 @@ export const openMergeRequest = ( mergeRequestId, }), ) - .then(mrChanges => { + .then((mrChanges) => { if (mrChanges.changes.length) { dispatch('updateActivityBarView', leftSidebarViews.review.name); } @@ -210,7 +210,7 @@ export const openMergeRequest = ( } }); }) - .catch(e => { + .catch((e) => { flash(__('Error while loading the merge request. Please try again.')); throw e; }); diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index 51e9bf6a84c..27f6848f1d6 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -11,8 +11,8 @@ export const getProjectData = ({ commit, state }, { namespace, projectId, force commit(types.TOGGLE_LOADING, { entry: state }); service .getProjectData(namespace, projectId) - .then(res => res.data) - .then(data => { + .then((res) => res.data) + .then((data) => { commit(types.TOGGLE_LOADING, { entry: state }); commit(types.SET_PROJECT, { projectPath: `${namespace}/${projectId}`, project: data }); commit(types.SET_CURRENT_PROJECT, `${namespace}/${projectId}`); @@ -44,8 +44,9 @@ export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {}) commit: data.commit, }); }) - .catch(() => { + .catch((e) => { flash(__('Error loading last commit.'), 'alert', document, null, false, true); + throw e; }); export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch) => @@ -61,7 +62,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch) .catch(() => { dispatch('setErrorMessage', { text: __('An error occurred creating the new branch.'), - action: payload => dispatch('createNewBranchFromDefault', payload), + action: (payload) => dispatch('createNewBranchFromDefault', payload), actionText: __('Please try again'), actionPayload: branch, }); @@ -76,7 +77,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { }, false, ), - action: payload => dispatch('createNewBranchFromDefault', payload), + action: (payload) => dispatch('createNewBranchFromDefault', payload), actionText: __('Create branch'), actionPayload: branchId, }); @@ -102,7 +103,7 @@ export const loadFile = ({ dispatch, state }, { basePath }) => { if (basePath) { const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath; const treeEntryKey = Object.keys(state.entries).find( - key => key === path && !state.entries[key].pending, + (key) => key === path && !state.entries[key].pending, ); const treeEntry = state.entries[treeEntryKey]; @@ -144,7 +145,7 @@ export const loadBranch = ({ dispatch, getters, state }, { projectId, branchId } ref: branch.commit.id, }); }) - .catch(err => { + .catch((err) => { dispatch('showBranchNotFoundError', branchId); throw err; }); diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index 23a5e26bc1c..150dfcb2726 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -87,10 +87,10 @@ export const getFiles = ({ state, commit, dispatch }, payload = {}) => { resolve(); }) - .catch(e => { + .catch((e) => { dispatch('setErrorMessage', { text: __('An error occurred while loading all the files.'), - action: actionPayload => + action: (actionPayload) => dispatch('getFiles', actionPayload).then(() => dispatch('setErrorMessage', null)), actionText: __('Please try again'), actionPayload: { projectId, branchId }, diff --git a/app/assets/javascripts/ide/stores/extend.js b/app/assets/javascripts/ide/stores/extend.js index 1c1636cf6ca..b2777ec89ff 100644 --- a/app/assets/javascripts/ide/stores/extend.js +++ b/app/assets/javascripts/ide/stores/extend.js @@ -8,7 +8,7 @@ const plugins = () => [ export default (store, el) => { // plugins is actually an array of plugin factories, so we have to create first then call - plugins().forEach(plugin => plugin(el)(store)); + plugins().forEach((plugin) => plugin(el)(store)); return store; }; diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index 500ce9f32d5..59e8d37a92a 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -9,19 +9,19 @@ import { import { addNumericSuffix } from '~/ide/utils'; import Api from '~/api'; -export const activeFile = state => state.openFiles.find(file => file.active) || null; +export const activeFile = (state) => state.openFiles.find((file) => file.active) || null; -export const addedFiles = state => state.changedFiles.filter(f => f.tempFile); +export const addedFiles = (state) => state.changedFiles.filter((f) => f.tempFile); -export const modifiedFiles = state => state.changedFiles.filter(f => !f.tempFile); +export const modifiedFiles = (state) => state.changedFiles.filter((f) => !f.tempFile); -export const projectsWithTrees = state => - Object.keys(state.projects).map(projectId => { +export const projectsWithTrees = (state) => + Object.keys(state.projects).map((projectId) => { const project = state.projects[projectId]; return { ...project, - branches: Object.keys(project.branches).map(branchId => { + branches: Object.keys(project.branches).map((branchId) => { const branch = project.branches[branchId]; return { @@ -32,7 +32,7 @@ export const projectsWithTrees = state => }; }); -export const currentMergeRequest = state => { +export const currentMergeRequest = (state) => { if ( state.projects[state.currentProjectId] && state.projects[state.currentProjectId].mergeRequests @@ -42,19 +42,19 @@ export const currentMergeRequest = state => { return null; }; -export const findProject = state => projectId => state.projects[projectId]; +export const findProject = (state) => (projectId) => state.projects[projectId]; export const currentProject = (state, getters) => getters.findProject(state.currentProjectId); -export const emptyRepo = state => +export const emptyRepo = (state) => state.projects[state.currentProjectId] && state.projects[state.currentProjectId].empty_repo; -export const currentTree = state => +export const currentTree = (state) => state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; -export const hasMergeRequest = state => Boolean(state.currentMergeRequestId); +export const hasMergeRequest = (state) => Boolean(state.currentMergeRequestId); -export const allBlobs = state => +export const allBlobs = (state) => Object.keys(state.entries) .reduce((acc, key) => { const entry = state.entries[key]; @@ -67,35 +67,35 @@ export const allBlobs = state => }, []) .sort((a, b) => b.lastOpenedAt - a.lastOpenedAt); -export const getChangedFile = state => path => state.changedFiles.find(f => f.path === path); -export const getStagedFile = state => path => state.stagedFiles.find(f => f.path === path); -export const getOpenFile = state => path => state.openFiles.find(f => f.path === path); +export const getChangedFile = (state) => (path) => state.changedFiles.find((f) => f.path === path); +export const getStagedFile = (state) => (path) => state.stagedFiles.find((f) => f.path === path); +export const getOpenFile = (state) => (path) => state.openFiles.find((f) => f.path === path); -export const lastOpenedFile = state => +export const lastOpenedFile = (state) => [...state.changedFiles, ...state.stagedFiles].sort((a, b) => b.lastOpenedAt - a.lastOpenedAt)[0]; -export const isEditModeActive = state => state.currentActivityView === leftSidebarViews.edit.name; -export const isCommitModeActive = state => +export const isEditModeActive = (state) => state.currentActivityView === leftSidebarViews.edit.name; +export const isCommitModeActive = (state) => state.currentActivityView === leftSidebarViews.commit.name; -export const isReviewModeActive = state => +export const isReviewModeActive = (state) => state.currentActivityView === leftSidebarViews.review.name; -export const someUncommittedChanges = state => +export const someUncommittedChanges = (state) => Boolean(state.changedFiles.length || state.stagedFiles.length); -export const getChangesInFolder = state => path => { - const changedFilesCount = state.changedFiles.filter(f => filePathMatches(f.path, path)).length; +export const getChangesInFolder = (state) => (path) => { + const changedFilesCount = state.changedFiles.filter((f) => filePathMatches(f.path, path)).length; const stagedFilesCount = state.stagedFiles.filter( - f => filePathMatches(f.path, path) && !getChangedFile(state)(f.path), + (f) => filePathMatches(f.path, path) && !getChangedFile(state)(f.path), ).length; return changedFilesCount + stagedFilesCount; }; -export const getUnstagedFilesCountForPath = state => path => +export const getUnstagedFilesCountForPath = (state) => (path) => getChangesCountForFiles(state.changedFiles, path); -export const getStagedFilesCountForPath = state => path => +export const getStagedFilesCountForPath = (state) => (path) => getChangesCountForFiles(state.stagedFiles, path); export const lastCommit = (state, getters) => { @@ -115,7 +115,7 @@ export const currentBranch = (state, getters) => export const branchName = (_state, getters) => getters.currentBranch && getters.currentBranch.name; -export const packageJson = state => state.entries[packageJsonPath]; +export const packageJson = (state) => state.entries[packageJsonPath]; export const isOnDefaultBranch = (_state, getters) => getters.currentProject && getters.currentProject.default_branch === getters.branchName; @@ -124,14 +124,14 @@ export const canPushToBranch = (_state, getters) => { return Boolean(getters.currentBranch ? getters.currentBranch.can_push : getters.canPushCode); }; -export const isFileDeletedAndReadded = (state, getters) => path => { +export const isFileDeletedAndReadded = (state, getters) => (path) => { const stagedFile = getters.getStagedFile(path); const file = state.entries[path]; return Boolean(stagedFile && stagedFile.deleted && file.tempFile); }; // checks if any diff exists in the staged or unstaged changes for this path -export const getDiffInfo = (state, getters) => path => { +export const getDiffInfo = (state, getters) => (path) => { const stagedFile = getters.getStagedFile(path); const file = state.entries[path]; const renamed = file.prevPath ? file.path !== file.prevPath : false; @@ -149,7 +149,7 @@ export const getDiffInfo = (state, getters) => path => { }; }; -export const findProjectPermissions = (state, getters) => projectId => +export const findProjectPermissions = (state, getters) => (projectId) => getters.findProject(projectId)?.userPermissions || {}; export const canReadMergeRequests = (state, getters) => @@ -161,10 +161,10 @@ export const canCreateMergeRequests = (state, getters) => export const canPushCode = (state, getters) => Boolean(getters.findProjectPermissions(state.currentProjectId)[PERMISSION_PUSH_CODE]); -export const entryExists = state => path => +export const entryExists = (state) => (path) => Boolean(state.entries[path] && !state.entries[path].deleted); -export const getAvailableFileName = (state, getters) => path => { +export const getAvailableFileName = (state, getters) => (path) => { let newPath = path; while (getters.entryExists(newPath)) { @@ -174,10 +174,10 @@ export const getAvailableFileName = (state, getters) => path => { return newPath; }; -export const getUrlForPath = state => path => +export const getUrlForPath = (state) => (path) => `/project/${state.currentProjectId}/tree/${state.currentBranchId}/-/${path}/`; -export const getJsonSchemaForPath = (state, getters) => path => { +export const getJsonSchemaForPath = (state, getters) => (path) => { const [namespace, ...project] = state.currentProjectId.split('/'); return { uri: diff --git a/app/assets/javascripts/ide/stores/modules/branches/actions.js b/app/assets/javascripts/ide/stores/modules/branches/actions.js index c46289f77e2..74a4cd9848b 100644 --- a/app/assets/javascripts/ide/stores/modules/branches/actions.js +++ b/app/assets/javascripts/ide/stores/modules/branches/actions.js @@ -8,7 +8,7 @@ export const receiveBranchesError = ({ commit, dispatch }, { search }) => { 'setErrorMessage', { text: __('Error loading branches.'), - action: payload => + action: (payload) => dispatch('fetchBranches', payload).then(() => dispatch('setErrorMessage', null, { root: true }), ), diff --git a/app/assets/javascripts/ide/stores/modules/branches/mutations.js b/app/assets/javascripts/ide/stores/modules/branches/mutations.js index 0a455f4500f..3883e1cc905 100644 --- a/app/assets/javascripts/ide/stores/modules/branches/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/branches/mutations.js @@ -9,7 +9,7 @@ export default { }, [types.RECEIVE_BRANCHES_SUCCESS](state, data) { state.isLoading = false; - state.branches = data.map(branch => ({ + state.branches = data.map((branch) => ({ name: branch.name, committedDate: branch.commit.committed_date, })); diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index e0d2028d2e1..29b9a8a9521 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -78,8 +78,8 @@ export const updateFilesAfterCommit = ({ commit, dispatch, rootState, rootGetter { root: true }, ); - rootState.stagedFiles.forEach(file => { - const changedFile = rootState.changedFiles.find(f => f.path === file.path); + rootState.stagedFiles.forEach((file) => { + const changedFile = rootState.changedFiles.find((f) => f.path === file.path); commit( rootTypes.UPDATE_FILE_AFTER_COMMIT, @@ -133,7 +133,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo return service.commit(rootState.currentProjectId, payload); }) - .catch(e => { + .catch((e) => { commit(types.UPDATE_LOADING, false); commit(types.SET_ERROR, parseCommitError(e)); @@ -193,37 +193,36 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo }, { root: true }, ) - .then(changeViewer => { + .then((changeViewer) => { if (changeViewer) { dispatch('updateViewer', 'diff', { root: true }); } }) - .catch(e => { + .catch((e) => { throw e; }); } else { dispatch('updateActivityBarView', leftSidebarViews.edit.name, { root: true }); dispatch('updateViewer', 'editor', { root: true }); - - if (rootGetters.activeFile) { - dispatch( - 'router/push', - `/project/${rootState.currentProjectId}/blob/${branchName}/-/${rootGetters.activeFile.path}`, - { root: true }, - ); - } } }) .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)) - .then(() => - dispatch( + .then(() => { + if (newBranch) { + const path = rootGetters.activeFile ? rootGetters.activeFile.path : ''; + + return dispatch( + 'router/push', + `/project/${rootState.currentProjectId}/blob/${branchName}/-/${path}`, + { root: true }, + ); + } + + return dispatch( 'refreshLastCommitData', - { - projectId: rootState.currentProjectId, - branchId: rootState.currentBranchId, - }, + { projectId: rootState.currentProjectId, branchId: branchName }, { root: true }, - ), - ); + ); + }); }); }; diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js index 416ca88d6c9..2301cf23f9f 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/getters.js +++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js @@ -11,7 +11,7 @@ const createTranslatedTextForFiles = (files, text) => { }); }; -export const discardDraftButtonDisabled = state => +export const discardDraftButtonDisabled = (state) => state.commitMessage === '' || state.submitCommitLoading; // Note: If changing the structure of the placeholder branch name, please also @@ -37,18 +37,18 @@ export const preBuiltCommitMessage = (state, _, rootState) => { if (state.commitMessage) return state.commitMessage; const files = rootState.stagedFiles.length ? rootState.stagedFiles : rootState.changedFiles; - const modifiedFiles = files.filter(f => !f.deleted); - const deletedFiles = files.filter(f => f.deleted); + const modifiedFiles = files.filter((f) => !f.deleted); + const deletedFiles = files.filter((f) => f.deleted); return [ createTranslatedTextForFiles(modifiedFiles, __('Update')), createTranslatedTextForFiles(deletedFiles, __('Deleted')), ] - .filter(t => t) + .filter((t) => t) .join('\n'); }; -export const isCreatingNewBranch = state => state.commitAction === consts.COMMIT_TO_NEW_BRANCH; +export const isCreatingNewBranch = (state) => state.commitAction === consts.COMMIT_TO_NEW_BRANCH; export const shouldHideNewMrOption = (_state, getters, _rootState, rootGetters) => !getters.isCreatingNewBranch && diff --git a/app/assets/javascripts/ide/stores/modules/editor/setup.js b/app/assets/javascripts/ide/stores/modules/editor/setup.js index c5a613c6baa..9f3163aa6f5 100644 --- a/app/assets/javascripts/ide/stores/modules/editor/setup.js +++ b/app/assets/javascripts/ide/stores/modules/editor/setup.js @@ -1,18 +1,23 @@ import eventHub from '~/ide/eventhub'; import { commitActionTypes } from '~/ide/constants'; -const removeUnusedFileEditors = store => { +const removeUnusedFileEditors = (store) => { Object.keys(store.state.editor.fileEditors) - .filter(path => !store.state.entries[path]) - .forEach(path => store.dispatch('editor/removeFileEditor', path)); + .filter((path) => !store.state.entries[path]) + .forEach((path) => store.dispatch('editor/removeFileEditor', path)); }; -export const setupFileEditorsSync = store => { +export const setupFileEditorsSync = (store) => { eventHub.$on('ide.files.change', ({ type, ...payload } = {}) => { + // Do nothing on file update because the file tree itself hasn't changed. + if (type === commitActionTypes.update) { + return; + } + if (type === commitActionTypes.move) { store.dispatch('editor/renameFileEditor', payload); } else { - // The files have changed, but the specific change is not known. + // The file tree has changed, but the specific change is not known. removeUnusedFileEditors(store); } }); diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js index 6b2c929cd44..6800f824da0 100644 --- a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js +++ b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js @@ -68,7 +68,7 @@ export const receiveTemplateError = ({ dispatch }, template) => { 'setErrorMessage', { text: __('Error loading template.'), - action: payload => + action: (payload) => dispatch('fetchTemplateTypes', payload).then(() => dispatch('setErrorMessage', null, { root: true }), ), diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/getters.js b/app/assets/javascripts/ide/stores/modules/file_templates/getters.js index 4a407aea557..0613fe9b12b 100644 --- a/app/assets/javascripts/ide/stores/modules/file_templates/getters.js +++ b/app/assets/javascripts/ide/stores/modules/file_templates/getters.js @@ -24,6 +24,6 @@ export const templateTypes = () => [ }, ]; -export const showFileTemplatesBar = (_, getters, rootState) => name => - getters.templateTypes.find(t => t.name === name) && +export const showFileTemplatesBar = (_, getters, rootState) => (name) => + getters.templateTypes.find((t) => t.name === name) && rootState.currentActivityView === leftSidebarViews.edit.name; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js index 6a1a0de033e..299f7a883d2 100644 --- a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js @@ -9,7 +9,7 @@ export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search } 'setErrorMessage', { text: __('Error loading merge requests.'), - action: payload => + action: (payload) => dispatch('fetchMergeRequests', payload).then(() => dispatch('setErrorMessage', null, { root: true }), ), diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js index 7576b2477d1..eae64ad80c3 100644 --- a/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js @@ -9,7 +9,7 @@ export default { }, [types.RECEIVE_MERGE_REQUESTS_SUCCESS](state, data) { state.isLoading = false; - state.mergeRequests = data.map(mergeRequest => ({ + state.mergeRequests = data.map((mergeRequest) => ({ id: mergeRequest.id, iid: mergeRequest.iid, title: mergeRequest.title, diff --git a/app/assets/javascripts/ide/stores/modules/pane/getters.js b/app/assets/javascripts/ide/stores/modules/pane/getters.js index ce597329df1..66d23c8ebdc 100644 --- a/app/assets/javascripts/ide/stores/modules/pane/getters.js +++ b/app/assets/javascripts/ide/stores/modules/pane/getters.js @@ -1,2 +1,2 @@ -export const isAliveView = state => view => +export const isAliveView = (state) => (view) => state.keepAliveViews[view] || (state.isOpen && state.currentView === view); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js index 99bd08ee876..2c2034d76d0 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -47,7 +47,7 @@ export const receiveLatestPipelineSuccess = ({ rootGetters, commit }, { pipeline if (pipelines && pipelines.length) { const lastCommitHash = rootGetters.lastCommit && rootGetters.lastCommit.id; - lastCommitPipeline = pipelines.find(pipeline => pipeline.commit.id === lastCommitHash); + lastCommitPipeline = pipelines.find((pipeline) => pipeline.commit.id === lastCommitHash); } commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, lastCommitPipeline); @@ -63,7 +63,7 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => { method: 'lastCommitPipelines', data: { getters: rootGetters }, successCallback: ({ data }) => dispatch('receiveLatestPipelineSuccess', data), - errorCallback: err => dispatch('receiveLatestPipelineError', err), + errorCallback: (err) => dispatch('receiveLatestPipelineError', err), }); if (!Visibility.hidden()) { @@ -85,7 +85,7 @@ export const receiveJobsError = ({ commit, dispatch }, stage) => { 'setErrorMessage', { text: __('An error occurred while loading the pipelines jobs.'), - action: payload => + action: (payload) => dispatch('fetchJobs', payload).then(() => dispatch('setErrorMessage', null, { root: true }), ), diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js index eb3cc027494..051159a0fd5 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js @@ -1,22 +1,23 @@ import { states } from './constants'; -export const hasLatestPipeline = state => !state.isLoadingPipeline && Boolean(state.latestPipeline); +export const hasLatestPipeline = (state) => + !state.isLoadingPipeline && Boolean(state.latestPipeline); -export const pipelineFailed = state => +export const pipelineFailed = (state) => state.latestPipeline && state.latestPipeline.details.status.text === states.failed; -export const failedStages = state => +export const failedStages = (state) => state.stages - .filter(stage => stage.status.text.toLowerCase() === states.failed) - .map(stage => ({ + .filter((stage) => stage.status.text.toLowerCase() === states.failed) + .map((stage) => ({ ...stage, - jobs: stage.jobs.filter(job => job.status.text.toLowerCase() === states.failed), + jobs: stage.jobs.filter((job) => job.status.text.toLowerCase() === states.failed), })); -export const failedJobsCount = state => +export const failedJobsCount = (state) => state.stages.reduce( - (acc, stage) => acc + stage.jobs.filter(j => j.status.text === states.failed).length, + (acc, stage) => acc + stage.jobs.filter((j) => j.status.text === states.failed).length, 0, ); -export const jobsCount = state => state.stages.reduce((acc, stage) => acc + stage.jobs.length, 0); +export const jobsCount = (state) => state.stages.reduce((acc, stage) => acc + stage.jobs.length, 0); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js index 3a3cb4a7cb2..09006df7e94 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js @@ -23,7 +23,7 @@ export default { yamlError: pipeline.yaml_errors, }; state.stages = pipeline.details.stages.map((stage, i) => { - const foundStage = state.stages.find(s => s.id === i); + const foundStage = state.stages.find((s) => s.id === i); return { id: i, dropdownPath: stage.dropdown_path, @@ -39,26 +39,26 @@ export default { } }, [types.REQUEST_JOBS](state, id) { - state.stages = state.stages.map(stage => ({ + state.stages = state.stages.map((stage) => ({ ...stage, isLoading: stage.id === id ? true : stage.isLoading, })); }, [types.RECEIVE_JOBS_ERROR](state, id) { - state.stages = state.stages.map(stage => ({ + state.stages = state.stages.map((stage) => ({ ...stage, isLoading: stage.id === id ? false : stage.isLoading, })); }, [types.RECEIVE_JOBS_SUCCESS](state, { id, data }) { - state.stages = state.stages.map(stage => ({ + state.stages = state.stages.map((stage) => ({ ...stage, isLoading: stage.id === id ? false : stage.isLoading, jobs: stage.id === id ? data.latest_statuses.map(normalizeJob) : stage.jobs, })); }, [types.TOGGLE_STAGE_COLLAPSE](state, id) { - state.stages = state.stages.map(stage => ({ + state.stages = state.stages.map((stage) => ({ ...stage, isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed, })); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/utils.js b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js index 95716e0a0c6..ded00196ab7 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/utils.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js @@ -1,4 +1,4 @@ -export const normalizeJob = job => ({ +export const normalizeJob = (job) => ({ id: job.id, name: job.name, status: job.status, diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/checks.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/checks.js index 43b6650b241..b2c1ddd877c 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/actions/checks.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/checks.js @@ -36,7 +36,7 @@ export const fetchConfigCheck = ({ dispatch, rootState, rootGetters }) => { .then(() => { dispatch('receiveConfigCheckSuccess'); }) - .catch(e => { + .catch((e) => { dispatch('receiveConfigCheckError', e); }); }; @@ -92,7 +92,7 @@ export const fetchRunnersCheck = ({ dispatch, rootGetters }, options = {}) => { .then(({ data }) => { dispatch('receiveRunnersCheckSuccess', data); }) - .catch(e => { + .catch((e) => { dispatch('receiveRunnersCheckError', e); }); }; diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js index f20f7fc9cd6..aa460859b4c 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js @@ -45,7 +45,7 @@ export const startSession = ({ state, dispatch, rootGetters, rootState }) => { .then(({ data }) => { dispatch('receiveStartSessionSuccess', data); }) - .catch(error => { + .catch((error) => { dispatch('receiveStartSessionError', error); }); }; @@ -73,7 +73,7 @@ export const stopSession = ({ state, dispatch }) => { .then(() => { dispatch('receiveStopSessionSuccess'); }) - .catch(err => { + .catch((err) => { dispatch('receiveStopSessionError', err); }); }; @@ -103,7 +103,7 @@ export const restartSession = ({ state, dispatch, rootState }) => { .then(({ data }) => { dispatch('receiveStartSessionSuccess', data); }) - .catch(error => { + .catch((error) => { const responseStatus = error.response && error.response.status; // We may have removed the build, in this case we'll just create a new session if ( diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js index d715d555aa9..3ab1817e662 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js @@ -58,7 +58,7 @@ export const fetchSessionStatus = ({ dispatch, state }) => { .then(({ data }) => { dispatch('receiveSessionStatusSuccess', data); }) - .catch(error => { + .catch((error) => { dispatch('receiveSessionStatusError', error); }); }; diff --git a/app/assets/javascripts/ide/stores/modules/terminal/getters.js b/app/assets/javascripts/ide/stores/modules/terminal/getters.js index b29d391845d..fb9a1a2fa39 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/getters.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/getters.js @@ -1,11 +1,11 @@ -export const allCheck = state => { +export const allCheck = (state) => { const checks = Object.values(state.checks); - if (checks.some(check => check.isLoading)) { + if (checks.some((check) => check.isLoading)) { return { isLoading: true }; } - const invalidCheck = checks.find(check => !check.isValid); + const invalidCheck = checks.find((check) => !check.isValid); const isValid = !invalidCheck; const message = !invalidCheck ? '' : invalidCheck.message; diff --git a/app/assets/javascripts/ide/stores/modules/terminal/messages.js b/app/assets/javascripts/ide/stores/modules/terminal/messages.js index bf35ce0f0bc..967ba80cd2c 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/messages.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/messages.js @@ -46,7 +46,7 @@ export const configCheckError = (status, helpUrl) => { return UNEXPECTED_ERROR_CONFIG; }; -export const runnersCheckEmpty = helpUrl => +export const runnersCheckEmpty = (helpUrl) => sprintf( EMPTY_RUNNERS, { diff --git a/app/assets/javascripts/ide/stores/modules/terminal/utils.js b/app/assets/javascripts/ide/stores/modules/terminal/utils.js index c30136b5277..1f4bca9f50a 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/utils.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/utils.js @@ -1,5 +1,5 @@ import { STARTING, PENDING, RUNNING } from './constants'; -export const isStartingStatus = status => status === STARTING || status === PENDING; -export const isRunningStatus = status => status === RUNNING; -export const isEndingStatus = status => !isStartingStatus(status) && !isRunningStatus(status); +export const isStartingStatus = (status) => status === STARTING || status === PENDING; +export const isRunningStatus = (status) => status === RUNNING; +export const isEndingStatus = (status) => !isStartingStatus(status) && !isRunningStatus(status); diff --git a/app/assets/javascripts/ide/stores/modules/terminal_sync/actions.js b/app/assets/javascripts/ide/stores/modules/terminal_sync/actions.js index 2fee6b4e974..006800f58c2 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal_sync/actions.js +++ b/app/assets/javascripts/ide/stores/modules/terminal_sync/actions.js @@ -9,7 +9,7 @@ export const upload = ({ rootState, commit }) => { .then(() => { commit(types.SET_SUCCESS); }) - .catch(err => { + .catch((err) => { commit(types.SET_ERROR, err); }); }; @@ -34,7 +34,7 @@ export const start = ({ rootState, commit }) => { .then(() => { commit(types.SET_SUCCESS); }) - .catch(err => { + .catch((err) => { commit(types.SET_ERROR, err); throw err; }); diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 460d3ced381..6ed6798a5b6 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -61,7 +61,7 @@ export default { }); } else { const tree = entry.tree.filter( - f => foundEntry.tree.find(e => e.path === f.path) === undefined, + (f) => foundEntry.tree.find((e) => e.path === f.path) === undefined, ); Object.assign(foundEntry, { tree: sortTree(foundEntry.tree.concat(tree)), @@ -72,7 +72,7 @@ export default { }, []); const currentTree = state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; - const foundEntry = currentTree.tree.find(e => e.path === data.treeList[0].path); + const foundEntry = currentTree.tree.find((e) => e.path === data.treeList[0].path); if (!foundEntry) { Object.assign(currentTree, { @@ -125,7 +125,7 @@ export default { }); }, [types.UPDATE_FILE_AFTER_COMMIT](state, { file, lastCommit }) { - const changedFile = state.changedFiles.find(f => f.path === file.path); + const changedFile = state.changedFiles.find((f) => f.path === file.path); const { prevPath } = file; Object.assign(state.entries[file.path], { @@ -172,7 +172,7 @@ export default { entry.deleted = true; if (parent) { - parent.tree = parent.tree.filter(f => f.path !== entry.path); + parent.tree = parent.tree.filter((f) => f.path !== entry.path); } if (entry.type === 'blob') { @@ -181,8 +181,8 @@ export default { // changed and staged. Otherwise, we'd need to somehow evaluate the difference between // changed and HEAD. // https://gitlab.com/gitlab-org/create-stage/-/issues/12669 - state.changedFiles = state.changedFiles.filter(f => f.path !== path); - state.stagedFiles = state.stagedFiles.filter(f => f.path !== path); + state.changedFiles = state.changedFiles.filter((f) => f.path !== path); + state.stagedFiles = state.stagedFiles.filter((f) => f.path !== path); } else { state.changedFiles = state.changedFiles.concat(entry); } diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js index 61a55d45128..4446971d5d6 100644 --- a/app/assets/javascripts/ide/stores/mutations/file.js +++ b/app/assets/javascripts/ide/stores/mutations/file.js @@ -12,7 +12,7 @@ export default { if (active && !state.entries[path].pending) { Object.assign(state, { - openFiles: state.openFiles.map(f => + openFiles: state.openFiles.map((f) => Object.assign(f, { active: f.pending ? false : f.active }), ), }); @@ -28,21 +28,21 @@ export default { if (entry.opened) { Object.assign(state, { - openFiles: state.openFiles.filter(f => f.path !== path).concat(state.entries[path]), + openFiles: state.openFiles.filter((f) => f.path !== path).concat(state.entries[path]), }); } else { Object.assign(state, { - openFiles: state.openFiles.filter(f => f.key !== entry.key), + openFiles: state.openFiles.filter((f) => f.key !== entry.key), }); } }, [types.SET_FILE_DATA](state, { data, file }) { const stateEntry = state.entries[file.path]; - const stagedFile = state.stagedFiles.find(f => f.path === file.path); - const openFile = state.openFiles.find(f => f.path === file.path); - const changedFile = state.changedFiles.find(f => f.path === file.path); + const stagedFile = state.stagedFiles.find((f) => f.path === file.path); + const openFile = state.openFiles.find((f) => f.path === file.path); + const changedFile = state.changedFiles.find((f) => f.path === file.path); - [stateEntry, stagedFile, openFile, changedFile].forEach(f => { + [stateEntry, stagedFile, openFile, changedFile].forEach((f) => { if (f) { Object.assign( f, @@ -57,10 +57,10 @@ export default { }, [types.SET_FILE_RAW_DATA](state, { file, raw, fileDeletedAndReadded = false }) { const openPendingFile = state.openFiles.find( - f => + (f) => f.path === file.path && f.pending && !(f.tempFile && !f.prevPath && !fileDeletedAndReadded), ); - const stagedFile = state.stagedFiles.find(f => f.path === file.path); + const stagedFile = state.stagedFiles.find((f) => f.path === file.path); if (file.tempFile && file.content === '' && !fileDeletedAndReadded) { Object.assign(state.entries[file.path], { content: raw }); @@ -86,7 +86,7 @@ export default { }); }, [types.UPDATE_FILE_CONTENT](state, { path, content }) { - const stagedFile = state.stagedFiles.find(f => f.path === path); + const stagedFile = state.stagedFiles.find((f) => f.path === path); const rawContent = stagedFile ? stagedFile.content : state.entries[path].raw; const changed = content !== rawContent; @@ -112,7 +112,7 @@ export default { }); }, [types.DISCARD_FILE_CHANGES](state, path) { - const stagedFile = state.stagedFiles.find(f => f.path === path); + const stagedFile = state.stagedFiles.find((f) => f.path === path); const entry = state.entries[path]; const { deleted } = entry; @@ -137,14 +137,14 @@ export default { }, [types.REMOVE_FILE_FROM_CHANGED](state, path) { Object.assign(state, { - changedFiles: state.changedFiles.filter(f => f.path !== path), + changedFiles: state.changedFiles.filter((f) => f.path !== path), }); }, [types.STAGE_CHANGE](state, { path, diffInfo }) { - const stagedFile = state.stagedFiles.find(f => f.path === path); + const stagedFile = state.stagedFiles.find((f) => f.path === path); Object.assign(state, { - changedFiles: state.changedFiles.filter(f => f.path !== path), + changedFiles: state.changedFiles.filter((f) => f.path !== path), entries: Object.assign(state.entries, { [path]: Object.assign(state.entries[path], { staged: diffInfo.exists, @@ -162,12 +162,12 @@ export default { } if (!diffInfo.exists) { - state.stagedFiles = state.stagedFiles.filter(f => f.path !== path); + state.stagedFiles = state.stagedFiles.filter((f) => f.path !== path); } }, [types.UNSTAGE_CHANGE](state, { path, diffInfo }) { - const changedFile = state.changedFiles.find(f => f.path === path); - const stagedFile = state.stagedFiles.find(f => f.path === path); + const changedFile = state.changedFiles.find((f) => f.path === path); + const stagedFile = state.stagedFiles.find((f) => f.path === path); if (!changedFile && stagedFile) { Object.assign(state.entries[path], { @@ -182,11 +182,11 @@ export default { } if (!diffInfo.exists) { - state.changedFiles = state.changedFiles.filter(f => f.path !== path); + state.changedFiles = state.changedFiles.filter((f) => f.path !== path); } Object.assign(state, { - stagedFiles: state.stagedFiles.filter(f => f.path !== path), + stagedFiles: state.stagedFiles.filter((f) => f.path !== path), entries: Object.assign(state.entries, { [path]: Object.assign(state.entries[path], { staged: false, @@ -206,7 +206,7 @@ export default { state.entries[file.path].opened = false; state.entries[file.path].active = false; state.entries[file.path].lastOpenedAt = new Date().getTime(); - state.openFiles.forEach(f => + state.openFiles.forEach((f) => Object.assign(f, { opened: false, active: false, @@ -224,13 +224,13 @@ export default { }, [types.REMOVE_PENDING_TAB](state, file) { Object.assign(state, { - openFiles: state.openFiles.filter(f => f.key !== file.key), + openFiles: state.openFiles.filter((f) => f.key !== file.key), }); }, [types.REMOVE_FILE_FROM_STAGED_AND_CHANGED](state, file) { Object.assign(state, { - changedFiles: state.changedFiles.filter(f => f.key !== file.key), - stagedFiles: state.stagedFiles.filter(f => f.key !== file.key), + changedFiles: state.changedFiles.filter((f) => f.key !== file.key), + stagedFiles: state.stagedFiles.filter((f) => f.key !== file.key), }); Object.assign(state.entries[file.path], { diff --git a/app/assets/javascripts/ide/stores/mutations/tree.js b/app/assets/javascripts/ide/stores/mutations/tree.js index cce43a99bd9..c38002bd4e0 100644 --- a/app/assets/javascripts/ide/stores/mutations/tree.js +++ b/app/assets/javascripts/ide/stores/mutations/tree.js @@ -45,7 +45,7 @@ export default { ? state.entries[entry.parentPath] : state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; - if (!parent.tree.find(f => f.path === path)) { + if (!parent.tree.find((f) => f.path === path)) { parent.tree = sortTree(parent.tree.concat(entry)); } }, diff --git a/app/assets/javascripts/ide/stores/plugins/terminal.js b/app/assets/javascripts/ide/stores/plugins/terminal.js index 66539c7bd4f..94139d5bdf0 100644 --- a/app/assets/javascripts/ide/stores/plugins/terminal.js +++ b/app/assets/javascripts/ide/stores/plugins/terminal.js @@ -11,7 +11,7 @@ function getPathsFromData(el) { } export default function createTerminalPlugin(el) { - return store => { + return (store) => { store.registerModule('terminal', terminalModule()); store.dispatch('terminal/setPaths', getPathsFromData(el)); diff --git a/app/assets/javascripts/ide/stores/plugins/terminal_sync.js b/app/assets/javascripts/ide/stores/plugins/terminal_sync.js index c60bba4293a..d925a5f7567 100644 --- a/app/assets/javascripts/ide/stores/plugins/terminal_sync.js +++ b/app/assets/javascripts/ide/stores/plugins/terminal_sync.js @@ -1,5 +1,6 @@ import { debounce } from 'lodash'; import eventHub from '~/ide/eventhub'; +import { commitActionTypes } from '~/ide/constants'; import terminalSyncModule from '../modules/terminal_sync'; import { isEndingStatus, isRunningStatus } from '../modules/terminal/utils'; @@ -12,23 +13,32 @@ const UPLOAD_DEBOUNCE = 200; * - Listens for file change event to control upload. */ export default function createMirrorPlugin() { - return store => { + return (store) => { store.registerModule('terminalSync', terminalSyncModule()); const upload = debounce(() => { store.dispatch(`terminalSync/upload`); }, UPLOAD_DEBOUNCE); + const onFilesChange = (payload) => { + // Do nothing on a file update since we only want to trigger manually on "save". + if (payload?.type === commitActionTypes.update) { + return; + } + + upload(); + }; + const stop = () => { store.dispatch(`terminalSync/stop`); - eventHub.$off('ide.files.change', upload); + eventHub.$off('ide.files.change', onFilesChange); }; const start = () => { store .dispatch(`terminalSync/start`) .then(() => { - eventHub.$on('ide.files.change', upload); + eventHub.$on('ide.files.change', onFilesChange); }) .catch(() => { // error is handled in store @@ -36,8 +46,8 @@ export default function createMirrorPlugin() { }; store.watch( - x => x.terminal && x.terminal.session && x.terminal.session.status, - val => { + (x) => x.terminal && x.terminal.session && x.terminal.session.status, + (val) => { if (isRunningStatus(val)) { start(); } else if (isEndingStatus(val)) { diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index 96f3caf1e98..04eacf271b8 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -31,9 +31,10 @@ export const dataStructure = () => ({ mrChange: null, deleted: false, prevPath: undefined, + mimeType: '', }); -export const decorateData = entity => { +export const decorateData = (entity) => { const { id, type, @@ -47,6 +48,7 @@ export const decorateData = entity => { rawPath = '', file_lock, parentPath = '', + mimeType = '', } = entity; return Object.assign(dataStructure(), { @@ -63,10 +65,11 @@ export const decorateData = entity => { rawPath, file_lock, parentPath, + mimeType, }); }; -export const setPageTitle = title => { +export const setPageTitle = (title) => { document.title = title; }; @@ -75,7 +78,7 @@ export const setPageTitleForFile = (state, file) => { setPageTitle(title); }; -export const commitActionForFile = file => { +export const commitActionForFile = (file) => { if (file.prevPath) { return commitActionTypes.move; } else if (file.deleted) { @@ -87,7 +90,7 @@ export const commitActionForFile = file => { return commitActionTypes.update; }; -export const getCommitFiles = stagedFiles => +export const getCommitFiles = (stagedFiles) => stagedFiles.reduce((acc, file) => { if (file.type === 'tree') return acc; @@ -106,7 +109,7 @@ export const createCommitPayload = ({ }) => ({ branch, commit_message: state.commitMessage || getters.preBuiltCommitMessage, - actions: getCommitFiles(rootState.stagedFiles).map(f => { + actions: getCommitFiles(rootState.stagedFiles).map((f) => { const isBlob = isBlobUrl(f.rawPath); const content = isBlob ? btoa(f.content) : f.content; @@ -136,9 +139,9 @@ const sortTreesByTypeAndName = (a, b) => { return 0; }; -export const sortTree = sortedTree => +export const sortTree = (sortedTree) => sortedTree - .map(entity => + .map((entity) => Object.assign(entity, { tree: entity.tree.length ? sortTree(entity.tree) : [], }), @@ -148,7 +151,7 @@ export const sortTree = sortedTree => export const filePathMatches = (filePath, path) => filePath.indexOf(`${path}/`) === 0; export const getChangesCountForFiles = (files, path) => - files.filter(f => filePathMatches(f.path, path)).length; + files.filter((f) => filePathMatches(f.path, path)).length; export const mergeTrees = (fromTree, toTree) => { if (!fromTree || !fromTree.length) { @@ -159,7 +162,7 @@ export const mergeTrees = (fromTree, toTree) => { if (!n) { return t; } - const existingTreeNode = t.find(el => el.path === n.path); + const existingTreeNode = t.find((el) => el.path === n.path); if (existingTreeNode && n.tree.length > 0) { existingTreeNode.opened = true; @@ -180,7 +183,7 @@ export const mergeTrees = (fromTree, toTree) => { export const swapInStateArray = (state, arr, key, entryPath) => Object.assign(state, { - [arr]: state[arr].map(f => (f.key === key ? state.entries[entryPath] : f)), + [arr]: state[arr].map((f) => (f.key === key ? state.entries[entryPath] : f)), }); export const getEntryOrRoot = (state, path) => @@ -213,12 +216,12 @@ export const removeFromParentTree = (state, oldKey, parentPath) => { }; export const updateFileCollections = (state, key, entryPath) => { - ['openFiles', 'changedFiles', 'stagedFiles'].forEach(fileCollection => { + ['openFiles', 'changedFiles', 'stagedFiles'].forEach((fileCollection) => { swapInStateArray(state, fileCollection, key, entryPath); }); }; -export const cleanTrailingSlash = path => path.replace(/\/$/, ''); +export const cleanTrailingSlash = (path) => path.replace(/\/$/, ''); export const pathsAreEqual = (a, b) => { const cleanA = a ? cleanTrailingSlash(a) : ''; @@ -251,12 +254,7 @@ export function extractMarkdownImagesFromEntries(mdFile, entries) { const imageContent = entries[imagePath]?.content || entries[imagePath]?.raw; if (!isAbsolute(path) && imageContent) { - const ext = path.includes('.') - ? path - .split('.') - .pop() - .trim() - : 'jpeg'; + const ext = path.includes('.') ? path.split('.').pop().trim() : 'jpeg'; const src = `data:image/${ext};base64,${imageContent}`; i += 1; const key = `{{${prefix}${i}}}`; diff --git a/app/assets/javascripts/ide/sync_router_and_store.js b/app/assets/javascripts/ide/sync_router_and_store.js index b33bcbb94ea..d73ac93dc1d 100644 --- a/app/assets/javascripts/ide/sync_router_and_store.js +++ b/app/assets/javascripts/ide/sync_router_and_store.js @@ -21,8 +21,8 @@ export const syncRouterAndStore = (router, store) => { // sync store to router disposables.push( store.watch( - state => state.router.fullPath, - fullPath => { + (state) => state.router.fullPath, + (fullPath) => { if (currentPath === fullPath) { return; } @@ -36,7 +36,7 @@ export const syncRouterAndStore = (router, store) => { // sync router to store disposables.push( - router.afterEach(to => { + router.afterEach((to) => { if (currentPath === to.fullPath) { return; } @@ -47,7 +47,7 @@ export const syncRouterAndStore = (router, store) => { ); const unsync = () => { - disposables.forEach(fn => fn()); + disposables.forEach((fn) => fn()); }; return unsync; diff --git a/app/assets/javascripts/ide/utils.js b/app/assets/javascripts/ide/utils.js index 43276f32322..8eb2d17b876 100644 --- a/app/assets/javascripts/ide/utils.js +++ b/app/assets/javascripts/ide/utils.js @@ -3,17 +3,17 @@ import { flatten, isString } from 'lodash'; import { SIDE_LEFT, SIDE_RIGHT } from './constants'; import { performanceMarkAndMeasure } from '~/performance/utils'; -const toLowerCase = x => x.toLowerCase(); +const toLowerCase = (x) => x.toLowerCase(); const monacoLanguages = languages.getLanguages(); const monacoExtensions = new Set( - flatten(monacoLanguages.map(lang => lang.extensions?.map(toLowerCase) || [])), + flatten(monacoLanguages.map((lang) => lang.extensions?.map(toLowerCase) || [])), ); const monacoMimetypes = new Set( - flatten(monacoLanguages.map(lang => lang.mimetypes?.map(toLowerCase) || [])), + flatten(monacoLanguages.map((lang) => lang.mimetypes?.map(toLowerCase) || [])), ); const monacoFilenames = new Set( - flatten(monacoLanguages.map(lang => lang.filenames?.map(toLowerCase) || [])), + flatten(monacoLanguages.map((lang) => lang.filenames?.map(toLowerCase) || [])), ); const KNOWN_TYPES = [ @@ -44,7 +44,7 @@ const KNOWN_TYPES = [ ]; export function isTextFile({ name, raw, content, mimeType = '' }) { - const knownType = KNOWN_TYPES.find(type => type.isMatch(mimeType, name)); + const knownType = KNOWN_TYPES.find((type) => type.isMatch(mimeType, name)); if (knownType) return knownType.isText; // does the string contain ascii characters only (ranges from space to tilde, tabs and new lines) @@ -56,20 +56,20 @@ export function isTextFile({ name, raw, content, mimeType = '' }) { return isString(fileContents) && (fileContents === '' || asciiRegex.test(fileContents)); } -export const createPathWithExt = p => { +export const createPathWithExt = (p) => { const ext = p.lastIndexOf('.') >= 0 ? p.substring(p.lastIndexOf('.') + 1) : ''; return `${p.substring(1, p.lastIndexOf('.') + 1 || p.length)}${ext || '.js'}`; }; -export const trimPathComponents = path => +export const trimPathComponents = (path) => path .split('/') - .map(s => s.trim()) + .map((s) => s.trim()) .join('/'); export function registerLanguages(def, ...defs) { - defs.forEach(lang => registerLanguages(lang)); + defs.forEach((lang) => registerLanguages(lang)); const languageId = def.id; @@ -80,7 +80,7 @@ export function registerLanguages(def, ...defs) { export function registerSchema(schema) { const defaults = [languages.json.jsonDefaults, languages.yaml.yamlDefaults]; - defaults.forEach(d => + defaults.forEach((d) => d.setDiagnosticsOptions({ validate: true, enableSchemaRequest: true, @@ -91,7 +91,7 @@ export function registerSchema(schema) { ); } -export const otherSide = side => (side === SIDE_RIGHT ? SIDE_LEFT : SIDE_RIGHT); +export const otherSide = (side) => (side === SIDE_RIGHT ? SIDE_LEFT : SIDE_RIGHT); export function trimTrailingWhitespace(content) { return content.replace(/[^\S\r\n]+$/gm, ''); @@ -125,9 +125,9 @@ export function getPathParent(path) { * @param {File} file */ export function readFileAsDataURL(file) { - return new Promise(resolve => { + return new Promise((resolve) => { const reader = new FileReader(); - reader.addEventListener('load', e => resolve(e.target.result), { once: true }); + reader.addEventListener('load', (e) => resolve(e.target.result), { once: true }); reader.readAsDataURL(file); }); } @@ -154,12 +154,7 @@ export function getFileEOL(content = '') { */ export function addNumericSuffix(filename, randomize = false) { return filename.replace(/([ _-]?)(\d*)(\..+?$|$)/, (_, before, number, after) => { - const n = randomize - ? Math.random() - .toString() - .substring(2, 7) - .slice(-5) - : Number(number) + 1; + const n = randomize ? Math.random().toString().substring(2, 7).slice(-5) : Number(number) + 1; return `${before || '-'}${n}${after}`; }); } |