diff options
Diffstat (limited to 'app/assets/javascripts/ide/components')
15 files changed, 132 insertions, 91 deletions
diff --git a/app/assets/javascripts/ide/components/branches/item.vue b/app/assets/javascripts/ide/components/branches/item.vue index 2fe435b92ab..35e2f99cb6a 100644 --- a/app/assets/javascripts/ide/components/branches/item.vue +++ b/app/assets/javascripts/ide/components/branches/item.vue @@ -34,7 +34,7 @@ export default { <template> <a :href="branchHref" class="btn-link d-flex align-items-center"> <span class="d-flex gl-mr-3 ide-search-list-current-icon"> - <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" /> + <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" use-deprecated-sizes /> </span> <span> <strong> {{ item.name }} </strong> diff --git a/app/assets/javascripts/ide/components/branches/search_list.vue b/app/assets/javascripts/ide/components/branches/search_list.vue index 1ae7cf9339d..5e93b7c1bbb 100644 --- a/app/assets/javascripts/ide/components/branches/search_list.vue +++ b/app/assets/javascripts/ide/components/branches/search_list.vue @@ -57,7 +57,10 @@ export default { <template> <div> - <label class="dropdown-input pt-3 pb-3 mb-0 border-bottom block position-relative" @click.stop> + <label + class="dropdown-input gl-pt-3 gl-pb-5 gl-mb-0 gl-border-b-1 gl-border-b-solid gl-display-block" + @click.stop + > <input ref="searchInput" v-model="search" @@ -66,7 +69,7 @@ export default { class="form-control dropdown-input-field" @input="searchBranches" /> - <gl-icon :size="18" name="search" class="ml-3 input-icon" /> + <gl-icon :size="18" name="search" class="ml-3 input-icon" use-deprecated-sizes /> </label> <div class="dropdown-content ide-merge-requests-dropdown-content d-flex"> <gl-loading-icon diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index cdb3eaff207..2897f4cbf77 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -1,17 +1,13 @@ <script> import { GlModal, GlSafeHtmlDirective, GlButton, GlTooltipDirective } from '@gitlab/ui'; import { mapState, mapActions, mapGetters } from 'vuex'; -import { n__, s__ } from '~/locale'; +import { n__ } from '~/locale'; import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; import { createUnexpectedCommitError } from '../../lib/errors'; import Actions from './actions.vue'; import CommitMessageField from './message_field.vue'; import SuccessMessage from './success_message.vue'; -const MSG_CANNOT_PUSH_CODE = s__( - 'WebIDE|You need permission to edit files directly in this project.', -); - export default { components: { Actions, @@ -35,14 +31,14 @@ export default { computed: { ...mapState(['changedFiles', 'stagedFiles', 'currentActivityView', 'lastCommitMsg']), ...mapState('commit', ['commitMessage', 'submitCommitLoading', 'commitError']), - ...mapGetters(['someUncommittedChanges', 'canPushCode']), + ...mapGetters(['someUncommittedChanges', 'canPushCodeStatus']), ...mapGetters('commit', ['discardDraftButtonDisabled', 'preBuiltCommitMessage']), commitButtonDisabled() { - return !this.canPushCode || !this.someUncommittedChanges; + return !this.canPushCodeStatus.isAllowed || !this.someUncommittedChanges; }, commitButtonTooltip() { - if (!this.canPushCode) { - return MSG_CANNOT_PUSH_CODE; + if (!this.canPushCodeStatus.isAllowed) { + return this.canPushCodeStatus.messageShort; } return ''; @@ -86,7 +82,7 @@ export default { commit() { // Even though the submit button will be disabled, we need to disable the submission // since hitting enter on the branch name text input also submits the form. - if (!this.canPushCode) { + if (!this.canPushCodeStatus.isAllowed) { return false; } @@ -130,8 +126,6 @@ export default { this.componentHeight = null; }, }, - // Expose for tests - MSG_CANNOT_PUSH_CODE, }; </script> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue b/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue index 121dae4b87e..43bf2e1a90c 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue @@ -41,7 +41,6 @@ export default { :disabled="shouldDisableNewMrOption" :checked="shouldCreateMR" type="checkbox" - data-qa-selector="start_new_mr_checkbox" @change="toggleShouldCreateMR" /> <span class="gl-ml-3 ide-option-label"> diff --git a/app/assets/javascripts/ide/components/file_templates/bar.vue b/app/assets/javascripts/ide/components/file_templates/bar.vue index bd4c4f18141..0803925104d 100644 --- a/app/assets/javascripts/ide/components/file_templates/bar.vue +++ b/app/assets/javascripts/ide/components/file_templates/bar.vue @@ -49,7 +49,9 @@ export default { </script> <template> - <div class="d-flex align-items-center ide-file-templates qa-file-templates-bar"> + <div + class="d-flex align-items-center ide-file-templates qa-file-templates-bar gl-relative gl-z-index-1" + > <strong class="gl-mr-3"> {{ __('File templates') }} </strong> <dropdown :data="templateTypes" diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 2816f89d60d..ff2644704d9 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -1,7 +1,7 @@ <script> import { GlAlert, GlButton, GlLoadingIcon } from '@gitlab/ui'; import { mapActions, mapGetters, mapState } from 'vuex'; -import { __, s__ } from '~/locale'; +import { __ } from '~/locale'; import { WEBIDE_MARK_APP_START, WEBIDE_MARK_FILE_FINISH, @@ -25,10 +25,6 @@ eventHub.$on(WEBIDE_MEASURE_FILE_AFTER_INTERACTION, () => ), ); -const MSG_CANNOT_PUSH_CODE = s__( - 'WebIDE|You need permission to edit files directly in this project. Fork this project to make your changes and submit a merge request.', -); - export default { components: { IdeSidebar, @@ -63,7 +59,7 @@ export default { 'loading', ]), ...mapGetters([ - 'canPushCode', + 'canPushCodeStatus', 'activeFile', 'someUncommittedChanges', 'isCommitModeActive', @@ -116,7 +112,6 @@ export default { this.loadDeferred = true; }, }, - MSG_CANNOT_PUSH_CODE, }; </script> @@ -125,8 +120,8 @@ export default { class="ide position-relative d-flex flex-column align-items-stretch" :class="{ [`theme-${themeName}`]: themeName }" > - <gl-alert v-if="!canPushCode" :dismissible="false">{{ - $options.MSG_CANNOT_PUSH_CODE + <gl-alert v-if="!canPushCodeStatus.isAllowed" :dismissible="false">{{ + canPushCodeStatus.message }}</gl-alert> <error-message v-if="errorMessage" :message="errorMessage" /> <div class="ide-view flex-grow d-flex"> diff --git a/app/assets/javascripts/ide/components/merge_requests/item.vue b/app/assets/javascripts/ide/components/merge_requests/item.vue index 7aa9a4f864a..639937481f3 100644 --- a/app/assets/javascripts/ide/components/merge_requests/item.vue +++ b/app/assets/javascripts/ide/components/merge_requests/item.vue @@ -41,7 +41,7 @@ export default { <template> <a :href="mergeRequestHref" class="btn-link d-flex align-items-center"> <span class="d-flex gl-mr-3 ide-search-list-current-icon"> - <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" /> + <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" use-deprecated-sizes /> </span> <span> <strong> {{ item.title }} </strong> diff --git a/app/assets/javascripts/ide/components/merge_requests/list.vue b/app/assets/javascripts/ide/components/merge_requests/list.vue index 680e8841a1f..f7cfe80df5c 100644 --- a/app/assets/javascripts/ide/components/merge_requests/list.vue +++ b/app/assets/javascripts/ide/components/merge_requests/list.vue @@ -75,7 +75,10 @@ export default { <template> <div> - <label class="dropdown-input pt-3 pb-3 mb-0 border-bottom block" @click.stop> + <label + class="dropdown-input gl-pt-3 gl-pb-5 gl-mb-0 gl-border-b-1 gl-border-b-solid gl-display-block" + @click.stop + > <tokened-input v-model="search" :tokens="searchTokens" @@ -84,7 +87,7 @@ export default { @input="searchMergeRequests" @removeToken="setSearchType(null)" /> - <gl-icon :size="18" name="search" class="ml-3 input-icon" /> + <gl-icon :size="18" name="search" class="ml-3 input-icon" use-deprecated-sizes /> </label> <div class="dropdown-content ide-merge-requests-dropdown-content d-flex"> <gl-loading-icon @@ -102,7 +105,7 @@ export default { @click.stop="setSearchType(searchType)" > <span class="d-flex gl-mr-3 ide-search-list-current-icon"> - <gl-icon :size="18" name="search" /> + <gl-icon :size="18" name="search" use-deprecated-sizes /> </span> <span>{{ searchType.label }}</span> </button> diff --git a/app/assets/javascripts/ide/components/nav_form.vue b/app/assets/javascripts/ide/components/nav_form.vue index 62bb4841760..98f0504298b 100644 --- a/app/assets/javascripts/ide/components/nav_form.vue +++ b/app/assets/javascripts/ide/components/nav_form.vue @@ -1,13 +1,12 @@ <script> -import Tab from '~/vue_shared/components/tabs/tab.vue'; -import Tabs from '~/vue_shared/components/tabs/tabs'; +import { GlTab, GlTabs } from '@gitlab/ui'; import BranchesSearchList from './branches/search_list.vue'; import MergeRequestSearchList from './merge_requests/list.vue'; export default { components: { - Tabs, - Tab, + GlTab, + GlTabs, BranchesSearchList, MergeRequestSearchList, }, @@ -23,20 +22,14 @@ export default { <template> <div class="ide-nav-form p-0"> - <tabs v-if="showMergeRequests" stop-propagation> - <tab active> - <template #title> - {{ __('Branches') }} - </template> + <gl-tabs v-if="showMergeRequests"> + <gl-tab :title="__('Branches')"> <branches-search-list /> - </tab> - <tab> - <template #title> - {{ __('Merge Requests') }} - </template> + </gl-tab> + <gl-tab :title="__('Merge Requests')"> <merge-request-search-list /> - </tab> - </tabs> + </gl-tab> + </gl-tabs> <branches-search-list v-else /> </div> </template> diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue index 2526db0cd7b..907ac496982 100644 --- a/app/assets/javascripts/ide/components/pipelines/list.vue +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -32,7 +32,7 @@ export default { SafeHtml, }, computed: { - ...mapState(['pipelinesEmptyStateSvgPath', 'links']), + ...mapState(['pipelinesEmptyStateSvgPath']), ...mapGetters(['currentProject']), ...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']), ...mapState('pipelines', [ @@ -85,7 +85,6 @@ export default { </header> <empty-state v-if="!latestPipeline" - :help-page-path="links.ciHelpPagePath" :empty-state-svg-path="pipelinesEmptyStateSvgPath" :can-set-ci="true" class="mb-auto mt-auto" diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index 0c6cb041095..4d35e946d89 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -117,7 +117,7 @@ export default { class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent" @click="refresh" > - <gl-icon :size="18" name="retry" class="m-auto" /> + <gl-icon :size="18" name="retry" use-deprecated-sizes class="m-auto" /> </button> <div class="position-relative w-100 gl-ml-2"> <input diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 690060f5cb0..b57dcd4276c 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -1,6 +1,15 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; +import { + EDITOR_TYPE_DIFF, + EDITOR_CODE_INSTANCE_FN, + EDITOR_DIFF_INSTANCE_FN, +} from '~/editor/constants'; +import EditorLite from '~/editor/editor_lite'; +import { EditorWebIdeExtension } from '~/editor/extensions/editor_lite_webide_ext'; import { deprecatedCreateFlash as flash } from '~/flash'; +import ModelManager from '~/ide/lib/common/model_manager'; +import { defaultDiffEditorOptions, defaultEditorOptions } from '~/ide/lib/editor_options'; import { __ } from '~/locale'; import { WEBIDE_MARK_FILE_CLICKED, @@ -20,7 +29,6 @@ import { FILE_VIEW_MODE_PREVIEW, } from '../constants'; import eventHub from '../eventhub'; -import Editor from '../lib/editor'; import { getRulesWithTraversal } from '../lib/editorconfig/parser'; import mapRulesToMonaco from '../lib/editorconfig/rules_mapper'; import { getFileEditorOrDefault } from '../stores/modules/editor/utils'; @@ -46,6 +54,9 @@ export default { content: '', images: {}, rules: {}, + globalEditor: null, + modelManager: new ModelManager(), + isEditorLoading: true, }; }, computed: { @@ -132,6 +143,7 @@ export default { // Compare key to allow for files opened in review mode to be cached differently if (oldVal.key !== this.file.key) { + this.isEditorLoading = true; this.initEditor(); if (this.currentActivityView !== leftSidebarViews.edit.name) { @@ -149,6 +161,7 @@ export default { } }, viewer() { + this.isEditorLoading = false; if (!this.file.pending) { this.createEditorInstance(); } @@ -181,11 +194,11 @@ export default { }, }, beforeDestroy() { - this.editor.dispose(); + this.globalEditor.dispose(); }, mounted() { - if (!this.editor) { - this.editor = Editor.create(this.$store, this.editorOptions); + if (!this.globalEditor) { + this.globalEditor = new EditorLite(); } this.initEditor(); @@ -211,8 +224,6 @@ export default { return; } - this.editor.clearEditor(); - this.registerSchemaForFile(); Promise.all([this.fetchFileData(), this.fetchEditorconfigRules()]) @@ -251,20 +262,45 @@ export default { return; } - this.editor.dispose(); + const isDiff = this.viewer !== viewerTypes.edit; + const shouldDisposeEditor = isDiff !== (this.editor?.getEditorType() === EDITOR_TYPE_DIFF); - this.$nextTick(() => { - if (this.viewer === viewerTypes.edit) { - this.editor.createInstance(this.$refs.editor); - } else { - this.editor.createDiffInstance(this.$refs.editor); + if (this.editor && !shouldDisposeEditor) { + this.setupEditor(); + } else { + if (this.editor && shouldDisposeEditor) { + this.editor.dispose(); } + const instanceOptions = isDiff ? defaultDiffEditorOptions : defaultEditorOptions; + const method = isDiff ? EDITOR_DIFF_INSTANCE_FN : EDITOR_CODE_INSTANCE_FN; - this.setupEditor(); - }); + this.editor = this.globalEditor[method]({ + el: this.$refs.editor, + blobPath: this.file.path, + blobGlobalId: this.file.key, + blobContent: this.content || this.file.content, + ...instanceOptions, + ...this.editorOptions, + }); + + this.editor.use( + new EditorWebIdeExtension({ + instance: this.editor, + modelManager: this.modelManager, + store: this.$store, + file: this.file, + options: this.editorOptions, + }), + ); + + this.$nextTick(() => { + this.setupEditor(); + }); + } }, + setupEditor() { - if (!this.file || !this.editor.instance || this.file.loading) return; + if (!this.file || !this.editor || this.file.loading) return; const head = this.getStagedFile(this.file.path); @@ -279,6 +315,8 @@ export default { this.editor.attachModel(this.model); } + this.isEditorLoading = false; + this.model.updateOptions(this.rules); this.model.onChange((model) => { @@ -298,7 +336,7 @@ export default { }); }); - this.editor.setPosition({ + this.editor.setPos({ lineNumber: this.fileEditor.editorRow, column: this.fileEditor.editorColumn, }); @@ -308,6 +346,10 @@ export default { fileLanguage: this.model.language, }); + this.$nextTick(() => { + this.editor.updateDimensions(); + }); + this.$emit('editorSetup'); if (performance.getEntriesByName(WEBIDE_MARK_FILE_CLICKED).length) { eventHub.$emit(WEBIDE_MEASURE_FILE_AFTER_INTERACTION); @@ -344,7 +386,7 @@ export default { }); }, onPaste(event) { - const editor = this.editor.instance; + const { editor } = this; const reImage = /^image\/(png|jpg|jpeg|gif)$/; const file = event.clipboardData.files[0]; @@ -395,6 +437,7 @@ export default { <a href="javascript:void(0);" role="button" + data-testid="edit-tab" @click.prevent="updateEditor({ viewMode: $options.FILE_VIEW_MODE_EDITOR })" > {{ __('Edit') }} @@ -404,6 +447,7 @@ export default { <a href="javascript:void(0);" role="button" + data-testid="preview-tab" @click.prevent="updateEditor({ viewMode: $options.FILE_VIEW_MODE_PREVIEW })" >{{ previewMode.previewTitle }}</a > @@ -414,6 +458,7 @@ export default { <div v-show="showEditor" ref="editor" + :key="`content-editor`" :class="{ 'is-readonly': isCommitModeActive, 'is-deleted': file.deleted, @@ -421,6 +466,8 @@ export default { }" class="multi-file-editor-holder" data-qa-selector="editor_container" + data-testid="editor-container" + :data-editor-loading="isEditorLoading" @focusout="triggerFilesChange" ></div> <content-viewer diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue index d28751c9571..64ec2cc67c7 100644 --- a/app/assets/javascripts/ide/components/repo_tab.vue +++ b/app/assets/javascripts/ide/components/repo_tab.vue @@ -1,5 +1,5 @@ <script> -import { GlIcon } from '@gitlab/ui'; +import { GlIcon, GlTab } from '@gitlab/ui'; import { mapActions, mapGetters } from 'vuex'; import { __, sprintf } from '~/locale'; @@ -13,6 +13,7 @@ export default { FileIcon, GlIcon, ChangedFileIcon, + GlTab, }, props: { tab: { @@ -71,29 +72,30 @@ export default { </script> <template> - <li - :class="{ - active: tab.active, - disabled: tab.pending, - }" + <gl-tab + :active="tab.active" + :disabled="tab.pending" + :title="tab.name" @click="clickFile(tab)" @mouseover="mouseOverTab" @mouseout="mouseOutTab" > - <div :title="getUrlForPath(tab.path)" class="multi-file-tab"> - <file-icon :file-name="tab.name" :size="16" /> - {{ tab.name }} - <file-status-icon :file="tab" /> - </div> - <button - :aria-label="closeLabel" - :disabled="tab.pending" - type="button" - class="multi-file-tab-close" - @click.stop.prevent="closeFile(tab)" - > - <gl-icon v-if="!showChangedIcon" :size="12" name="close" /> - <changed-file-icon v-else :file="tab" /> - </button> - </li> + <template #title> + <div :title="getUrlForPath(tab.path)" class="multi-file-tab"> + <file-icon :file-name="tab.name" :size="16" /> + {{ tab.name }} + <file-status-icon :file="tab" /> + </div> + <button + :aria-label="closeLabel" + :disabled="tab.pending" + type="button" + class="multi-file-tab-close" + @click.stop.prevent="closeFile(tab)" + > + <gl-icon v-if="!showChangedIcon" :size="12" name="close" /> + <changed-file-icon v-else :file="tab" /> + </button> + </template> + </gl-tab> </template> diff --git a/app/assets/javascripts/ide/components/repo_tabs.vue b/app/assets/javascripts/ide/components/repo_tabs.vue index c03694e3619..932040c7fa5 100644 --- a/app/assets/javascripts/ide/components/repo_tabs.vue +++ b/app/assets/javascripts/ide/components/repo_tabs.vue @@ -1,10 +1,12 @@ <script> +import { GlTabs } from '@gitlab/ui'; import { mapActions, mapGetters } from 'vuex'; import RepoTab from './repo_tab.vue'; export default { components: { RepoTab, + GlTabs, }, props: { activeFile: { @@ -42,8 +44,8 @@ export default { <template> <div class="multi-file-tabs"> - <ul ref="tabsScroller" class="list-unstyled gl-mb-0"> + <gl-tabs> <repo-tab v-for="tab in files" :key="tab.key" :tab="tab" /> - </ul> + </gl-tabs> </div> </template> diff --git a/app/assets/javascripts/ide/components/shared/tokened_input.vue b/app/assets/javascripts/ide/components/shared/tokened_input.vue index e7a4c5487d1..ed0dab47947 100644 --- a/app/assets/javascripts/ide/components/shared/tokened_input.vue +++ b/app/assets/javascripts/ide/components/shared/tokened_input.vue @@ -81,7 +81,9 @@ export default { > <div class="value-container rounded"> <div class="value">{{ token.label }}</div> - <div class="remove-token inverted"><gl-icon :size="10" name="close" /></div> + <div class="remove-token inverted"> + <gl-icon :size="10" name="close" use-deprecated-sizes /> + </div> </div> </button> </div> |