diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
commit | 85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch) | |
tree | 9160f299afd8c80c038f08e1545be119f5e3f1e1 /app/assets/javascripts/ide | |
parent | 15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff) | |
download | gitlab-ce-85dc423f7090da0a52c73eb66faf22ddb20efff9.tar.gz |
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'app/assets/javascripts/ide')
75 files changed, 324 insertions, 320 deletions
diff --git a/app/assets/javascripts/ide/components/activity_bar.vue b/app/assets/javascripts/ide/components/activity_bar.vue index a65af55fcac..183816921c1 100644 --- a/app/assets/javascripts/ide/components/activity_bar.vue +++ b/app/assets/javascripts/ide/components/activity_bar.vue @@ -1,13 +1,13 @@ <script> import $ from 'jquery'; import { mapActions, mapState } from 'vuex'; -import Icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; import { leftSidebarViews } from '../constants'; export default { components: { - Icon, + GlIcon, }, directives: { tooltip, @@ -44,11 +44,12 @@ export default { :aria-label="s__('IDE|Edit')" data-container="body" data-placement="right" + data-qa-selector="edit_mode_tab" type="button" class="ide-sidebar-link js-ide-edit-mode" @click.prevent="changedActivityView($event, $options.leftSidebarViews.edit.name)" > - <icon name="code" /> + <gl-icon name="code" /> </button> </li> <li> @@ -65,7 +66,7 @@ export default { class="ide-sidebar-link js-ide-review-mode" @click.prevent="changedActivityView($event, $options.leftSidebarViews.review.name)" > - <icon name="file-modified" /> + <gl-icon name="file-modified" /> </button> </li> <li> @@ -78,11 +79,12 @@ export default { :aria-label="s__('IDE|Commit')" data-container="body" data-placement="right" + data-qa-selector="commit_mode_tab" type="button" - class="ide-sidebar-link js-ide-commit-mode qa-commit-mode-tab" + class="ide-sidebar-link js-ide-commit-mode" @click.prevent="changedActivityView($event, $options.leftSidebarViews.commit.name)" > - <icon name="commit" /> + <gl-icon name="commit" /> </button> </li> </ul> diff --git a/app/assets/javascripts/ide/components/branches/item.vue b/app/assets/javascripts/ide/components/branches/item.vue index 49744d573da..2fe435b92ab 100644 --- a/app/assets/javascripts/ide/components/branches/item.vue +++ b/app/assets/javascripts/ide/components/branches/item.vue @@ -1,11 +1,11 @@ <script> /* eslint-disable @gitlab/vue-require-i18n-strings */ -import Icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import Timeago from '~/vue_shared/components/time_ago_tooltip.vue'; export default { components: { - Icon, + GlIcon, Timeago, }, props: { @@ -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"> - <icon v-if="isActive" :size="18" name="mobile-issue-close" /> + <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" /> </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 dd2d726d525..c317fadb656 100644 --- a/app/assets/javascripts/ide/components/branches/search_list.vue +++ b/app/assets/javascripts/ide/components/branches/search_list.vue @@ -1,14 +1,13 @@ <script> import { mapActions, mapState } from 'vuex'; import { debounce } from 'lodash'; -import { GlLoadingIcon } from '@gitlab/ui'; -import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import Item from './item.vue'; export default { components: { Item, - Icon, + GlIcon, GlLoadingIcon, }, data() { @@ -67,7 +66,7 @@ export default { class="form-control dropdown-input-field" @input="searchBranches" /> - <icon :size="18" name="search" class="ml-3 input-icon" /> + <gl-icon :size="18" name="search" class="ml-3 input-icon" /> </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/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue index 407e4c57cd8..de4b0a34002 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { escape } from 'lodash'; import { mapState, mapGetters, createNamespacedHelpers } from 'vuex'; import { sprintf, s__ } from '~/locale'; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index 9342ab87c1a..73c56514fce 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -1,6 +1,6 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; -import { GlModal } from '@gitlab/ui'; +import { GlModal, GlSafeHtmlDirective } from '@gitlab/ui'; import { n__, __ } from '~/locale'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import CommitMessageField from './message_field.vue'; @@ -8,6 +8,7 @@ import Actions from './actions.vue'; import SuccessMessage from './success_message.vue'; import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; import consts from '../../stores/modules/commit/constants'; +import { createUnexpectedCommitError } from '../../lib/errors'; export default { components: { @@ -17,15 +18,20 @@ export default { SuccessMessage, GlModal, }, + directives: { + SafeHtml: GlSafeHtmlDirective, + }, data() { return { isCompact: true, componentHeight: null, + // Keep track of "lastCommitError" so we hold onto the value even when "commitError" is cleared. + lastCommitError: createUnexpectedCommitError(), }; }, computed: { ...mapState(['changedFiles', 'stagedFiles', 'currentActivityView', 'lastCommitMsg']), - ...mapState('commit', ['commitMessage', 'submitCommitLoading']), + ...mapState('commit', ['commitMessage', 'submitCommitLoading', 'commitError']), ...mapGetters(['someUncommittedChanges']), ...mapGetters('commit', ['discardDraftButtonDisabled', 'preBuiltCommitMessage']), overviewText() { @@ -38,11 +44,28 @@ export default { currentViewIsCommitView() { return this.currentActivityView === leftSidebarViews.commit.name; }, + commitErrorPrimaryAction() { + if (!this.lastCommitError?.canCreateBranch) { + return undefined; + } + + return { + text: __('Create new branch'), + }; + }, }, watch: { currentActivityView: 'handleCompactState', someUncommittedChanges: 'handleCompactState', lastCommitMsg: 'handleCompactState', + commitError(val) { + if (!val) { + return; + } + + this.lastCommitError = val; + this.$refs.commitErrorModal.show(); + }, }, methods: { ...mapActions(['updateActivityBarView']), @@ -53,9 +76,7 @@ export default { 'updateCommitAction', ]), commit() { - return this.commitChanges().catch(() => { - this.$refs.createBranchModal.show(); - }); + return this.commitChanges(); }, forceCreateNewBranch() { return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit()); @@ -164,17 +185,14 @@ export default { </button> </div> <gl-modal - ref="createBranchModal" - modal-id="ide-create-branch-modal" - :ok-title="__('Create new branch')" - :title="__('Branch has changed')" - ok-variant="success" + ref="commitErrorModal" + modal-id="ide-commit-error-modal" + :title="lastCommitError.title" + :action-primary="commitErrorPrimaryAction" + :action-cancel="{ text: __('Cancel') }" @ok="forceCreateNewBranch" > - {{ - __(`This branch has changed since you started editing. - Would you like to create a new branch?`) - }} + <div v-safe-html="lastCommitError.messageHTML"></div> </gl-modal> </form> </transition> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue index d1422a506e7..609ce287d3f 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue @@ -1,14 +1,13 @@ <script> import { mapActions } from 'vuex'; -import { GlModal } from '@gitlab/ui'; +import { GlModal, GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; -import Icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import ListItem from './list_item.vue'; export default { components: { - Icon, + GlIcon, ListItem, GlModal, }, @@ -74,7 +73,7 @@ export default { <div class="ide-commit-list-container"> <header class="multi-file-commit-panel-header d-flex mb-0"> <div class="d-flex align-items-center flex-fill"> - <icon v-once :name="iconName" :size="18" class="gl-mr-3" /> + <gl-icon v-once :name="iconName" :size="18" class="gl-mr-3" /> <strong> {{ titleText }} </strong> <div class="d-flex ml-auto"> <button @@ -93,7 +92,7 @@ export default { data-boundary="viewport" @click="openDiscardModal" > - <icon :size="16" name="remove-all" class="ml-auto mr-auto position-top-0" /> + <gl-icon :size="16" name="remove-all" class="ml-auto mr-auto position-top-0" /> </button> </div> </div> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue index 1b257ca11cc..4821b8389ff 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue @@ -1,11 +1,11 @@ <script> -import Icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; import { sprintf, n__, __ } from '~/locale'; export default { components: { - Icon, + GlIcon, }, directives: { tooltip, @@ -77,7 +77,7 @@ export default { data-placement="left" class="gl-mb-5" > - <icon v-once :name="iconName" :size="18" /> + <gl-icon v-once :name="iconName" :size="18" /> </div> <div v-tooltip @@ -86,7 +86,7 @@ export default { data-placement="left" class="gl-mb-3" > - <icon :name="additionIconName" :size="18" :class="addedFilesIconClass" /> + <gl-icon :name="additionIconName" :size="18" :class="addedFilesIconClass" /> </div> {{ addedFilesLength }} <div @@ -96,7 +96,7 @@ export default { data-placement="left" class="gl-mt-3 gl-mb-3" > - <icon :name="modifiedIconName" :size="18" :class="modifiedFilesClass" /> + <gl-icon :name="modifiedIconName" :size="18" :class="modifiedFilesClass" /> </div> {{ modifiedFilesLength }} </div> 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 c65169f5d31..a0d6cf3c42d 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue @@ -1,14 +1,14 @@ <script> import { mapActions } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import { viewerTypes } from '../../constants'; import getCommitIconMap from '../../commit_icon'; export default { components: { - Icon, + GlIcon, FileIcon, }, directives: { @@ -95,7 +95,7 @@ export default { </span> <div class="ml-auto d-flex align-items-center"> <div class="d-flex align-items-center ide-commit-list-changed-icon"> - <icon :name="iconName" :size="16" :class="iconClass" /> + <gl-icon :name="iconName" :size="16" :class="iconClass" /> </div> </div> </div> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue index b37c7280a30..2787b10a48b 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue @@ -1,6 +1,6 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __, sprintf } from '../../../locale'; -import Icon from '../../../vue_shared/components/icon.vue'; import popover from '../../../vue_shared/directives/popover'; import { MAX_TITLE_LENGTH, MAX_BODY_LENGTH } from '../../constants'; @@ -9,7 +9,7 @@ export default { popover, }, components: { - Icon, + GlIcon, }, props: { text: { @@ -84,7 +84,7 @@ export default { <li> {{ __('Commit Message') }} <span v-popover="$options.popoverOptions" class="form-text text-muted gl-ml-3"> - <icon name="question" /> + <gl-icon name="question" /> </span> </li> </ul> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue index 327b0b8172f..977efb0ca22 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { mapState } from 'vuex'; export default { diff --git a/app/assets/javascripts/ide/components/error_message.vue b/app/assets/javascripts/ide/components/error_message.vue index d36adbd798e..08635b43b91 100644 --- a/app/assets/javascripts/ide/components/error_message.vue +++ b/app/assets/javascripts/ide/components/error_message.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { mapActions } from 'vuex'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; diff --git a/app/assets/javascripts/ide/components/file_row_extra.vue b/app/assets/javascripts/ide/components/file_row_extra.vue index f7cf7a5b251..48ab58e1cb7 100644 --- a/app/assets/javascripts/ide/components/file_row_extra.vue +++ b/app/assets/javascripts/ide/components/file_row_extra.vue @@ -1,8 +1,8 @@ <script> import { mapGetters } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import { n__ } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; import NewDropdown from './new_dropdown/index.vue'; import MrFileIcon from './mr_file_icon.vue'; @@ -13,7 +13,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, NewDropdown, ChangedFileIcon, MrFileIcon, @@ -69,7 +69,7 @@ export default { <mr-file-icon v-if="file.mrChange" /> <span v-if="showTreeChangesCount" class="ide-tree-changes"> {{ changesCount }} - <icon + <gl-icon v-tooltip :title="folderChangesTooltip" :size="12" diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 55b3eaf9737..1b03d9eee8b 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -47,6 +47,7 @@ export default { 'emptyRepo', 'currentTree', 'editorTheme', + 'getUrlForPath', ]), themeName() { return window.gon?.user_color_scheme; @@ -71,7 +72,7 @@ export default { return returnValue; }, openFile(file) { - this.$router.push(`/project${file.url}`); + this.$router.push(this.getUrlForPath(file.path)); }, createNewFile() { this.$refs.newModal.open(modalTypes.blob); diff --git a/app/assets/javascripts/ide/components/ide_file_row.vue b/app/assets/javascripts/ide/components/ide_file_row.vue index b777d89f0bb..248677d6a99 100644 --- a/app/assets/javascripts/ide/components/ide_file_row.vue +++ b/app/assets/javascripts/ide/components/ide_file_row.vue @@ -3,6 +3,7 @@ * This component is an iterative step towards refactoring and simplifying `vue_shared/components/file_row.vue` * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720 */ +import { mapGetters } from 'vuex'; import FileRow from '~/vue_shared/components/file_row.vue'; import FileRowExtra from './file_row_extra.vue'; @@ -23,6 +24,9 @@ export default { dropdownOpen: false, }; }, + computed: { + ...mapGetters(['getUrlForPath']), + }, methods: { toggleDropdown(val) { this.dropdownOpen = val; @@ -32,7 +36,13 @@ export default { </script> <template> - <file-row :file="file" v-bind="$attrs" @mouseleave="toggleDropdown(false)" v-on="$listeners"> + <file-row + :file="file" + :file-url="getUrlForPath(file.path)" + v-bind="$attrs" + @mouseleave="toggleDropdown(false)" + v-on="$listeners" + > <file-row-extra :file="file" :dropdown-open="dropdownOpen" @toggle="toggleDropdown($event)" /> </file-row> </template> diff --git a/app/assets/javascripts/ide/components/ide_review.vue b/app/assets/javascripts/ide/components/ide_review.vue index 95348711e1d..e36d0a5a5b1 100644 --- a/app/assets/javascripts/ide/components/ide_review.vue +++ b/app/assets/javascripts/ide/components/ide_review.vue @@ -10,7 +10,7 @@ export default { EditorModeDropdown, }, computed: { - ...mapGetters(['currentMergeRequest', 'activeFile']), + ...mapGetters(['currentMergeRequest', 'activeFile', 'getUrlForPath']), ...mapState(['viewer', 'currentMergeRequestId']), showLatestChangesText() { return !this.currentMergeRequestId || this.viewer === viewerTypes.diff; @@ -24,7 +24,7 @@ export default { }, mounted() { if (this.activeFile && this.activeFile.pending && !this.activeFile.deleted) { - this.$router.push(`/project${this.activeFile.url}`, () => { + this.$router.push(this.getUrlForPath(this.activeFile.path), () => { this.updateViewer('editor'); }); } else if (this.activeFile && this.activeFile.deleted) { diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index 1eb89b41495..ed68ca5cae9 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -1,6 +1,6 @@ <script> import { mapState, mapGetters } from 'vuex'; -import { GlSkeletonLoading } from '@gitlab/ui'; +import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import IdeTree from './ide_tree.vue'; import ResizablePanel from './resizable_panel.vue'; import ActivityBar from './activity_bar.vue'; diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index ddc126c3d77..146e818d654 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -1,9 +1,9 @@ <script> /* eslint-disable @gitlab/vue-require-i18n-strings */ import { mapActions, mapState, mapGetters } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import IdeStatusList from './ide_status_list.vue'; import IdeStatusMr from './ide_status_mr.vue'; -import icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import timeAgoMixin from '~/vue_shared/mixins/timeago'; import CiIcon from '../../vue_shared/components/ci_icon.vue'; @@ -12,7 +12,7 @@ import { rightSidebarViews } from '../constants'; export default { components: { - icon, + GlIcon, userAvatarImage, CiIcon, IdeStatusList, @@ -97,12 +97,13 @@ export default { {{ latestPipeline.details.status.text }} for </span> - <icon name="commit" /> + <gl-icon name="commit" /> <a v-tooltip :title="lastCommit.message" :href="getCommitPath(lastCommit.short_id)" class="commit-sha" + data-qa-selector="commit_sha_content" >{{ lastCommit.short_id }}</a > by diff --git a/app/assets/javascripts/ide/components/ide_status_list.vue b/app/assets/javascripts/ide/components/ide_status_list.vue index 1354fdc3d98..caa122f6ed2 100644 --- a/app/assets/javascripts/ide/components/ide_status_list.vue +++ b/app/assets/javascripts/ide/components/ide_status_list.vue @@ -2,7 +2,7 @@ import { mapGetters } from 'vuex'; import { GlLink, GlTooltipDirective } from '@gitlab/ui'; import TerminalSyncStatusSafe from './terminal_sync/terminal_sync_status_safe.vue'; -import { getFileEOL } from '../utils'; +import { isTextFile, getFileEOL } from '~/ide/utils'; export default { components: { @@ -17,6 +17,9 @@ export default { activeFileEOL() { return getFileEOL(this.activeFile.content); }, + activeFileIsText() { + return isTextFile(this.activeFile); + }, }, }; </script> @@ -30,7 +33,7 @@ export default { </gl-link> </div> <div>{{ activeFileEOL }}</div> - <div v-if="!activeFile.binary">{{ activeFile.editorRow }}:{{ activeFile.editorColumn }}</div> + <div v-if="activeFileIsText">{{ activeFile.editorRow }}:{{ activeFile.editorColumn }}</div> <div>{{ activeFile.fileLanguage }}</div> </template> <terminal-sync-status-safe /> diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue index 647f4d4be85..747d5044790 100644 --- a/app/assets/javascripts/ide/components/ide_tree.vue +++ b/app/assets/javascripts/ide/components/ide_tree.vue @@ -15,13 +15,13 @@ export default { }, computed: { ...mapState(['currentBranchId']), - ...mapGetters(['currentProject', 'currentTree', 'activeFile']), + ...mapGetters(['currentProject', 'currentTree', 'activeFile', 'getUrlForPath']), }, mounted() { if (!this.activeFile) return; if (this.activeFile.pending && !this.activeFile.deleted) { - this.$router.push(`/project${this.activeFile.url}`, () => { + this.$router.push(this.getUrlForPath(this.activeFile.path), () => { this.updateViewer('editor'); }); } else if (this.activeFile.deleted) { diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue index 36e8951bea3..776d8459515 100644 --- a/app/assets/javascripts/ide/components/ide_tree_list.vue +++ b/app/assets/javascripts/ide/components/ide_tree_list.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import { GlSkeletonLoading } from '@gitlab/ui'; +import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import FileTree from '~/vue_shared/components/file_tree.vue'; import IdeFileRow from './ide_file_row.vue'; import NavDropdown from './nav_dropdown.vue'; diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue index 975d54c7a4e..11033a5cc88 100644 --- a/app/assets/javascripts/ide/components/jobs/detail.vue +++ b/app/assets/javascripts/ide/components/jobs/detail.vue @@ -1,9 +1,10 @@ <script> +/* eslint-disable vue/no-v-html */ import { mapActions, mapState } from 'vuex'; import { throttle } from 'lodash'; +import { GlIcon } from '@gitlab/ui'; import { __ } from '../../../locale'; import tooltip from '../../../vue_shared/directives/tooltip'; -import Icon from '../../../vue_shared/components/icon.vue'; import ScrollButton from './detail/scroll_button.vue'; import JobDescription from './detail/description.vue'; @@ -17,7 +18,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, ScrollButton, JobDescription, }, @@ -39,10 +40,10 @@ export default { }, }, mounted() { - this.getTrace(); + this.getLogs(); }, methods: { - ...mapActions('pipelines', ['fetchJobTrace', 'setDetailJob']), + ...mapActions('pipelines', ['fetchJobLogs', 'setDetailJob']), scrollDown() { if (this.$refs.buildTrace) { this.$refs.buildTrace.scrollTo(0, this.$refs.buildTrace.scrollHeight); @@ -65,8 +66,8 @@ export default { this.scrollPos = ''; } }), - getTrace() { - return this.fetchJobTrace().then(() => this.scrollDown()); + getLogs() { + return this.fetchJobLogs().then(() => this.scrollDown()); }, }, }; @@ -76,7 +77,7 @@ export default { <div class="ide-pipeline build-page d-flex flex-column flex-fill"> <header class="ide-job-header d-flex align-items-center"> <button class="btn btn-default btn-sm d-flex" @click="setDetailJob(null)"> - <icon name="chevron-left" /> {{ __('View jobs') }} + <gl-icon name="chevron-left" /> {{ __('View jobs') }} </button> </header> <div class="top-bar d-flex border-left-0 mr-3"> diff --git a/app/assets/javascripts/ide/components/jobs/detail/description.vue b/app/assets/javascripts/ide/components/jobs/detail/description.vue index f1ba102fffe..9eaeabad5ef 100644 --- a/app/assets/javascripts/ide/components/jobs/detail/description.vue +++ b/app/assets/javascripts/ide/components/jobs/detail/description.vue @@ -1,10 +1,10 @@ <script> -import Icon from '../../../../vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import CiIcon from '../../../../vue_shared/components/ci_icon.vue'; export default { components: { - Icon, + GlIcon, CiIcon, }, props: { @@ -26,8 +26,14 @@ export default { <ci-icon :status="job.status" :borderless="true" :size="24" class="d-flex" /> <span class="gl-ml-3"> {{ job.name }} - <a :href="job.path" target="_blank" class="ide-external-link position-relative"> - {{ jobId }} <icon :size="12" name="external-link" /> + <a + v-if="job.path" + :href="job.path" + target="_blank" + class="ide-external-link gl-relative" + data-testid="description-detail-link" + > + {{ jobId }} <gl-icon :size="12" name="external-link" /> </a> </span> </div> diff --git a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue index 5674d3ffa80..2c679a3edc7 100644 --- a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue +++ b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue @@ -1,6 +1,6 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __ } from '../../../../locale'; -import Icon from '../../../../vue_shared/components/icon.vue'; import tooltip from '../../../../vue_shared/directives/tooltip'; const directions = { @@ -13,7 +13,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, }, props: { direction: { @@ -58,7 +58,7 @@ export default { type="button" @click="clickedScroll" > - <icon :name="iconName" /> + <gl-icon :name="iconName" /> </button> </div> </template> diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue index 75441e8c1c8..0b643947139 100644 --- a/app/assets/javascripts/ide/components/jobs/stage.vue +++ b/app/assets/javascripts/ide/components/jobs/stage.vue @@ -1,7 +1,6 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import tooltip from '../../../vue_shared/directives/tooltip'; -import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; import Item from './item.vue'; @@ -10,7 +9,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, CiIcon, Item, GlLoadingIcon, @@ -78,7 +77,7 @@ export default { <div v-if="!stage.isLoading || stage.jobs.length" class="gl-mr-3 gl-ml-2"> <span class="badge badge-pill"> {{ jobsCount }} </span> </div> - <icon :name="collapseIcon" class="ide-stage-collapse-icon" /> + <gl-icon :name="collapseIcon" class="ide-stage-collapse-icon" /> </div> <div v-show="!stage.isCollapsed" ref="jobList" class="card-body p-0"> <gl-loading-icon v-if="showLoadingIcon" /> diff --git a/app/assets/javascripts/ide/components/merge_requests/item.vue b/app/assets/javascripts/ide/components/merge_requests/item.vue index 8b7b8d5a91c..7aa9a4f864a 100644 --- a/app/assets/javascripts/ide/components/merge_requests/item.vue +++ b/app/assets/javascripts/ide/components/merge_requests/item.vue @@ -1,9 +1,9 @@ <script> -import Icon from '../../../vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; export default { components: { - Icon, + GlIcon, }, props: { item: { @@ -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"> - <icon v-if="isActive" :size="18" name="mobile-issue-close" /> + <gl-icon v-if="isActive" :size="18" name="mobile-issue-close" /> </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 af45d88b84a..4b3c6e61e11 100644 --- a/app/assets/javascripts/ide/components/merge_requests/list.vue +++ b/app/assets/javascripts/ide/components/merge_requests/list.vue @@ -1,9 +1,8 @@ <script> import { mapActions, mapState } from 'vuex'; import { debounce } from 'lodash'; -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; -import Icon from '~/vue_shared/components/icon.vue'; import Item from './item.vue'; import TokenedInput from '../shared/tokened_input.vue'; @@ -16,7 +15,7 @@ export default { components: { TokenedInput, Item, - Icon, + GlIcon, GlLoadingIcon, }, data() { @@ -85,7 +84,7 @@ export default { @input="searchMergeRequests" @removeToken="setSearchType(null)" /> - <icon :size="18" name="search" class="ml-3 input-icon" /> + <gl-icon :size="18" name="search" class="ml-3 input-icon" /> </label> <div class="dropdown-content ide-merge-requests-dropdown-content d-flex"> <gl-loading-icon @@ -103,7 +102,7 @@ export default { @click.stop="setSearchType(searchType)" > <span class="d-flex gl-mr-3 ide-search-list-current-icon"> - <icon :size="18" name="search" /> + <gl-icon :size="18" name="search" /> </span> <span>{{ searchType.label }}</span> </button> diff --git a/app/assets/javascripts/ide/components/mr_file_icon.vue b/app/assets/javascripts/ide/components/mr_file_icon.vue index 4fab57b6f3e..c8629a869e0 100644 --- a/app/assets/javascripts/ide/components/mr_file_icon.vue +++ b/app/assets/javascripts/ide/components/mr_file_icon.vue @@ -1,10 +1,10 @@ <script> -import icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; export default { components: { - icon, + GlIcon, }, directives: { tooltip, @@ -13,7 +13,7 @@ export default { </script> <template> - <icon + <gl-icon v-tooltip :title="__('Part of merge request changes')" :size="12" diff --git a/app/assets/javascripts/ide/components/nav_dropdown_button.vue b/app/assets/javascripts/ide/components/nav_dropdown_button.vue index 8dc22620eca..116d3cec03e 100644 --- a/app/assets/javascripts/ide/components/nav_dropdown_button.vue +++ b/app/assets/javascripts/ide/components/nav_dropdown_button.vue @@ -1,13 +1,13 @@ <script> import { mapState } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; -import Icon from '~/vue_shared/components/icon.vue'; const EMPTY_LABEL = '-'; export default { components: { - Icon, + GlIcon, DropdownButton, }, props: { @@ -33,10 +33,10 @@ export default { <dropdown-button> <span class="row flex-nowrap"> <span class="col-auto flex-fill text-truncate"> - <icon :size="16" :aria-label="__('Current Branch')" name="branch" /> {{ branchLabel }} + <gl-icon :size="16" :aria-label="__('Current Branch')" name="branch" /> {{ branchLabel }} </span> <span v-if="showMergeRequests" class="col-5 pl-0 text-truncate"> - <icon :size="16" :aria-label="__('Merge Request')" name="merge-request" /> + <gl-icon :size="16" :aria-label="__('Merge Request')" name="merge-request" /> {{ mergeRequestLabel }} </span> </span> diff --git a/app/assets/javascripts/ide/components/new_dropdown/button.vue b/app/assets/javascripts/ide/components/new_dropdown/button.vue index 5bd6642930c..8ae8f97f237 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/button.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/button.vue @@ -1,5 +1,5 @@ <script> -import Icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; export default { @@ -7,7 +7,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, }, props: { label: { @@ -52,7 +52,7 @@ export default { class="btn-blank" @click.stop.prevent="clicked" > - <icon :name="icon" :class="iconClasses" /> + <gl-icon :name="icon" :class="iconClasses" /> <template v-if="showLabel"> {{ label }} </template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue index b656e35f150..692878de5e1 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/index.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue @@ -1,6 +1,6 @@ <script> import { mapActions } from 'vuex'; -import icon from '~/vue_shared/components/icon.vue'; +import { GlIcon } from '@gitlab/ui'; import upload from './upload.vue'; import ItemButton from './button.vue'; import { modalTypes } from '../../constants'; @@ -8,7 +8,7 @@ import NewModal from './modal.vue'; export default { components: { - icon, + GlIcon, upload, ItemButton, NewModal, @@ -67,7 +67,7 @@ export default { data-qa-selector="dropdown_button" @click.stop="openDropdown()" > - <icon name="ellipsis_v" /> <icon name="chevron-down" /> + <gl-icon name="ellipsis_v" /> <gl-icon name="chevron-down" /> </button> <ul ref="dropdownMenu" class="dropdown-menu dropdown-menu-right"> <template v-if="type === 'tree'"> diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index 44986c8c575..528475849de 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapState, mapGetters } from 'vuex'; -import { GlModal } from '@gitlab/ui'; +import { GlModal, GlButton } from '@gitlab/ui'; import { deprecatedCreateFlash as flash } from '~/flash'; import { __, sprintf, s__ } from '~/locale'; import { modalTypes } from '../../constants'; @@ -9,6 +9,7 @@ import { trimPathComponents, getPathParent } from '../../utils'; export default { components: { GlModal, + GlButton, }, data() { return { @@ -156,13 +157,14 @@ export default { /> <ul v-if="isCreatingNewFile" class="file-templates gl-mt-3 list-inline qa-template-list"> <li v-for="(template, index) in templateTypes" :key="index" class="list-inline-item"> - <button - type="button" - class="btn btn-missing p-1 pr-2 pl-2" + <gl-button + variant="dashed" + category="secondary" + class="p-1 pr-2 pl-2" @click="createFromTemplate(template)" > {{ template.name }} - </button> + </gl-button> </li> </ul> </div> diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue index b2141c13d9f..84ff05c9750 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue @@ -28,14 +28,13 @@ export default { const { name } = file; const encodedContent = target.result.split('base64,')[1]; const rawContent = encodedContent ? atob(encodedContent) : ''; - const isText = isTextFile(rawContent, file.type, name); + const isText = isTextFile({ content: rawContent, mimeType: file.type, name }); const emitCreateEvent = content => this.$emit('create', { name: `${this.path ? `${this.path}/` : ''}${name}`, type: 'blob', content, - binary: !isText, rawPath: !isText ? target.result : '', }); diff --git a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue index 4e8e1e3a470..f1b882d8f29 100644 --- a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue +++ b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue @@ -1,7 +1,6 @@ <script> import { mapActions, mapState } from 'vuex'; import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; import IdeSidebarNav from '../ide_sidebar_nav.vue'; export default { @@ -10,7 +9,6 @@ export default { tooltip, }, components: { - Icon, IdeSidebarNav, }, props: { diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue index 6038e92f254..91bd64a2c9c 100644 --- a/app/assets/javascripts/ide/components/pipelines/list.vue +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -1,9 +1,8 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import { escape } from 'lodash'; -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import { sprintf, __ } from '../../../locale'; -import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; import Tabs from '../../../vue_shared/components/tabs/tabs'; import Tab from '../../../vue_shared/components/tabs/tab.vue'; @@ -14,7 +13,7 @@ import IDEServices from '~/ide/services'; export default { components: { - Icon, + GlIcon, CiIcon, Tabs, Tab, @@ -22,6 +21,9 @@ export default { EmptyState, GlLoadingIcon, }, + directives: { + SafeHtml, + }, computed: { ...mapState(['pipelinesEmptyStateSvgPath', 'links']), ...mapGetters(['currentProject']), @@ -70,7 +72,7 @@ export default { target="_blank" class="ide-external-link position-relative" > - #{{ latestPipeline.id }} <icon :size="12" name="external-link" /> + #{{ latestPipeline.id }} <gl-icon :size="12" name="external-link" /> </a> </span> </header> @@ -84,7 +86,7 @@ export default { <div v-else-if="latestPipeline.yamlError" class="bs-callout bs-callout-danger"> <p class="gl-mb-0">{{ __('Found errors in your .gitlab-ci.yml:') }}</p> <p class="gl-mb-0 break-word">{{ latestPipeline.yamlError }}</p> - <p class="gl-mb-0" v-html="ciLintText"></p> + <p v-safe-html="ciLintText" class="gl-mb-0"></p> </div> <tabs v-else class="ide-pipeline-list"> <tab :active="!pipelineFailed"> diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index 0de9dfd8827..60710251fef 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -1,11 +1,10 @@ <script> import { listen } from 'codesandbox-api'; -import { GlLoadingIcon } from '@gitlab/ui'; -import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; export default { components: { - Icon, + GlIcon, GlLoadingIcon, }, props: { @@ -97,7 +96,7 @@ export default { class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent" @click="back" > - <icon :size="24" name="chevron-left" class="m-auto" /> + <gl-icon :size="24" name="chevron-left" class="m-auto" /> </button> <button :aria-label="s__('IDE|Back')" @@ -109,7 +108,7 @@ export default { class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent" @click="forward" > - <icon :size="24" name="chevron-right" class="m-auto" /> + <gl-icon :size="24" name="chevron-right" class="m-auto" /> </button> <button :aria-label="s__('IDE|Refresh preview')" @@ -117,7 +116,7 @@ export default { class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent" @click="refresh" > - <icon :size="18" name="retry" class="m-auto" /> + <gl-icon :size="18" name="retry" 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 d22d430cb4a..f342ce1739c 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -14,7 +14,7 @@ import Editor from '../lib/editor'; import FileTemplatesBar from './file_templates/bar.vue'; import { __ } from '~/locale'; import { extractMarkdownImagesFromEntries } from '../stores/utils'; -import { getPathParent, readFileAsDataURL } from '../utils'; +import { getPathParent, readFileAsDataURL, registerSchema, isTextFile } from '../utils'; import { getRulesWithTraversal } from '../lib/editorconfig/parser'; import mapRulesToMonaco from '../lib/editorconfig/rules_mapper'; @@ -48,6 +48,7 @@ export default { 'renderWhitespaceInCode', 'editorTheme', 'entries', + 'currentProjectId', ]), ...mapGetters([ 'currentMergeRequest', @@ -55,10 +56,11 @@ export default { 'isEditModeActive', 'isCommitModeActive', 'currentBranch', + 'getJsonSchemaForPath', ]), ...mapGetters('fileTemplates', ['showFileTemplatesBar']), shouldHideEditor() { - return this.file && this.file.binary; + return this.file && !isTextFile(this.file); }, showContentViewer() { return ( @@ -196,6 +198,8 @@ export default { this.editor.clearEditor(); + this.registerSchemaForFile(); + Promise.all([this.fetchFileData(), this.fetchEditorconfigRules()]) .then(() => { this.createEditorInstance(); @@ -329,6 +333,10 @@ export default { // do nothing if no image is found in the clipboard return Promise.resolve(); }, + registerSchemaForFile() { + const schema = this.getJsonSchemaForPath(this.file.path); + registerSchema(schema); + }, }, viewerTypes, FILE_VIEW_MODE_EDITOR, @@ -379,7 +387,7 @@ export default { :path="file.rawPath || file.path" :file-path="file.path" :file-size="file.size" - :project-path="file.projectId" + :project-path="currentProjectId" :commit-sha="currentBranchCommit" :type="fileType" /> @@ -390,7 +398,7 @@ export default { :new-sha="currentMergeRequest.sha" :old-path="file.mrChange.old_path" :old-sha="currentMergeRequest.baseCommitSha" - :project-path="file.projectId" + :project-path="currentProjectId" /> </div> </template> diff --git a/app/assets/javascripts/ide/components/repo_file_status_icon.vue b/app/assets/javascripts/ide/components/repo_file_status_icon.vue index 9773e835a5c..1402f7aaf39 100644 --- a/app/assets/javascripts/ide/components/repo_file_status_icon.vue +++ b/app/assets/javascripts/ide/components/repo_file_status_icon.vue @@ -1,12 +1,12 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; -import icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import '~/lib/utils/datetime_utility'; export default { components: { - icon, + GlIcon, }, directives: { tooltip, @@ -29,6 +29,6 @@ export default { <template> <span v-if="file.file_lock" v-tooltip :title="lockTooltip" data-container="body"> - <icon name="lock" class="file-status-icon" /> + <gl-icon name="lock" class="file-status-icon" /> </span> </template> diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue index 8370833233a..60a80a31a8b 100644 --- a/app/assets/javascripts/ide/components/repo_tab.vue +++ b/app/assets/javascripts/ide/components/repo_tab.vue @@ -1,9 +1,9 @@ <script> -import { mapActions } from 'vuex'; +import { mapActions, mapGetters } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import FileIcon from '~/vue_shared/components/file_icon.vue'; -import Icon from '~/vue_shared/components/icon.vue'; import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; import FileStatusIcon from './repo_file_status_icon.vue'; @@ -11,7 +11,7 @@ export default { components: { FileStatusIcon, FileIcon, - Icon, + GlIcon, ChangedFileIcon, }, props: { @@ -26,6 +26,7 @@ export default { }; }, computed: { + ...mapGetters(['getUrlForPath']), closeLabel() { if (this.fileHasChanged) { return sprintf(__(`%{tabname} changed`), { tabname: this.tab.name }); @@ -52,7 +53,7 @@ export default { if (tab.pending) { this.openPendingTab({ file: tab, keyPrefix: tab.staged ? 'staged' : 'unstaged' }); } else { - this.$router.push(`/project${tab.url}`); + this.$router.push(this.getUrlForPath(tab.path)); } }, mouseOverTab() { @@ -79,7 +80,7 @@ export default { @mouseover="mouseOverTab" @mouseout="mouseOutTab" > - <div :title="tab.url" class="multi-file-tab"> + <div :title="getUrlForPath(tab.path)" class="multi-file-tab"> <file-icon :file-name="tab.name" :size="16" /> {{ tab.name }} <file-status-icon :file="tab" /> @@ -91,7 +92,7 @@ export default { class="multi-file-tab-close" @click.stop.prevent="closeFile(tab)" > - <icon v-if="!showChangedIcon" :size="12" name="close" /> + <gl-icon v-if="!showChangedIcon" :size="12" name="close" /> <changed-file-icon v-else :file="tab" /> </button> </li> diff --git a/app/assets/javascripts/ide/components/repo_tabs.vue b/app/assets/javascripts/ide/components/repo_tabs.vue index 47c75be3f7c..c03694e3619 100644 --- a/app/assets/javascripts/ide/components/repo_tabs.vue +++ b/app/assets/javascripts/ide/components/repo_tabs.vue @@ -1,5 +1,5 @@ <script> -import { mapActions } from 'vuex'; +import { mapActions, mapGetters } from 'vuex'; import RepoTab from './repo_tab.vue'; export default { @@ -20,6 +20,9 @@ export default { required: true, }, }, + computed: { + ...mapGetters(['getUrlForPath']), + }, methods: { ...mapActions(['updateViewer', 'removePendingTab']), openFileViewer(viewer) { @@ -27,7 +30,7 @@ export default { if (this.activeFile.pending) { return this.removePendingTab(this.activeFile).then(() => { - this.$router.push(`/project${this.activeFile.url}`); + this.$router.push(this.getUrlForPath(this.activeFile.path)); }); } diff --git a/app/assets/javascripts/ide/components/shared/tokened_input.vue b/app/assets/javascripts/ide/components/shared/tokened_input.vue index de3e71dad92..e7a4c5487d1 100644 --- a/app/assets/javascripts/ide/components/shared/tokened_input.vue +++ b/app/assets/javascripts/ide/components/shared/tokened_input.vue @@ -1,10 +1,10 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; -import Icon from '~/vue_shared/components/icon.vue'; export default { components: { - Icon, + GlIcon, }, props: { placeholder: { @@ -81,7 +81,7 @@ export default { > <div class="value-container rounded"> <div class="value">{{ token.label }}</div> - <div class="remove-token inverted"><icon :size="10" name="close" /></div> + <div class="remove-token inverted"><gl-icon :size="10" name="close" /></div> </div> </button> </div> diff --git a/app/assets/javascripts/ide/components/terminal/empty_state.vue b/app/assets/javascripts/ide/components/terminal/empty_state.vue index 5dd12e62820..3668dd24e81 100644 --- a/app/assets/javascripts/ide/components/terminal/empty_state.vue +++ b/app/assets/javascripts/ide/components/terminal/empty_state.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { GlLoadingIcon } from '@gitlab/ui'; export default { diff --git a/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue b/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue index deb13b5615e..c3f722d6052 100644 --- a/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue +++ b/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue @@ -1,8 +1,7 @@ <script> import { throttle } from 'lodash'; -import { GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; +import { GlTooltipDirective, GlLoadingIcon, GlIcon } from '@gitlab/ui'; import { mapState } from 'vuex'; -import Icon from '~/vue_shared/components/icon.vue'; import { MSG_TERMINAL_SYNC_CONNECTING, MSG_TERMINAL_SYNC_UPLOADING, @@ -11,7 +10,7 @@ import { export default { components: { - Icon, + GlIcon, GlLoadingIcon, }, directives: { @@ -70,7 +69,7 @@ export default { <span>{{ __('Terminal') }}:</span> <span class="square s16 d-flex-center ml-1" :aria-label="status.text"> <gl-loading-icon v-if="isLoading" inline size="sm" class="d-flex-center" /> - <icon v-else-if="status.icon" :name="status.icon" :size="16" /> + <gl-icon v-else-if="status.icon" :name="status.icon" :size="16" /> </span> </div> </template> diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index 82cf8d7a10a..396aedbfa10 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -33,7 +33,6 @@ const EmptyRouterComponent = { }, }; -// eslint-disable-next-line import/prefer-default-export export const createRouter = store => { const router = new IdeRouter({ mode: 'history', diff --git a/app/assets/javascripts/ide/lib/diff/diff.js b/app/assets/javascripts/ide/lib/diff/diff.js index 3a456b7c4d6..62ec798b372 100644 --- a/app/assets/javascripts/ide/lib/diff/diff.js +++ b/app/assets/javascripts/ide/lib/diff/diff.js @@ -1,8 +1,6 @@ import { diffLines } from 'diff'; import { defaultDiffOptions } from '../editor_options'; -// See: https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/20 -// eslint-disable-next-line import/prefer-default-export export const computeDiff = (originalContent, newContent) => { // prevent EOL changes from highlighting the entire file const changes = diffLines( diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index f061fcb1259..2b12230c7cd 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -7,10 +7,9 @@ import ModelManager from './common/model_manager'; import { editorOptions, defaultEditorOptions, defaultDiffEditorOptions } from './editor_options'; import { themes } from './themes'; import languages from './languages'; -import schemas from './schemas'; import keymap from './keymap.json'; import { clearDomElement } from '~/editor/utils'; -import { registerLanguages, registerSchemas } from '../utils'; +import { registerLanguages } from '../utils'; function setupThemes() { themes.forEach(theme => { @@ -46,10 +45,6 @@ export default class Editor { setupThemes(); registerLanguages(...languages); - if (gon.features?.schemaLinting) { - registerSchemas(...schemas); - } - this.debouncedUpdate = debounce(() => { this.updateDimensions(); }, 200); diff --git a/app/assets/javascripts/ide/lib/editorconfig/parser.js b/app/assets/javascripts/ide/lib/editorconfig/parser.js index a30a8cb868d..1597e4a8bfa 100644 --- a/app/assets/javascripts/ide/lib/editorconfig/parser.js +++ b/app/assets/javascripts/ide/lib/editorconfig/parser.js @@ -42,7 +42,6 @@ function getRulesWithConfigs(filePath, configFiles = [], rules = {}) { return isRoot ? result : getRulesWithConfigs(filePath, nextConfigs, result); } -// eslint-disable-next-line import/prefer-default-export export function getRulesWithTraversal(filePath, getFileContent) { const editorconfigPaths = [ ...getPathParents(filePath).map(x => `${x}/.editorconfig`), diff --git a/app/assets/javascripts/ide/lib/errors.js b/app/assets/javascripts/ide/lib/errors.js new file mode 100644 index 00000000000..6ae18bc8180 --- /dev/null +++ b/app/assets/javascripts/ide/lib/errors.js @@ -0,0 +1,39 @@ +import { escape } from 'lodash'; +import { __ } from '~/locale'; + +const CODEOWNERS_REGEX = /Push.*protected branches.*CODEOWNERS/; +const BRANCH_CHANGED_REGEX = /changed.*since.*start.*edit/; + +export const createUnexpectedCommitError = () => ({ + title: __('Unexpected error'), + messageHTML: __('Could not commit. An unexpected error occurred.'), + canCreateBranch: false, +}); + +export const createCodeownersCommitError = message => ({ + title: __('CODEOWNERS rule violation'), + messageHTML: escape(message), + canCreateBranch: true, +}); + +export const createBranchChangedCommitError = message => ({ + title: __('Branch changed'), + messageHTML: `${escape(message)}<br/><br/>${__('Would you like to create a new branch?')}`, + canCreateBranch: true, +}); + +export const parseCommitError = e => { + const { message } = e?.response?.data || {}; + + if (!message) { + return createUnexpectedCommitError(); + } + + if (CODEOWNERS_REGEX.test(message)) { + return createCodeownersCommitError(message); + } else if (BRANCH_CHANGED_REGEX.test(message)) { + return createBranchChangedCommitError(message); + } + + return createUnexpectedCommitError(); +}; diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js index 6d85e225fd5..789e09fa8f2 100644 --- a/app/assets/javascripts/ide/lib/files.js +++ b/app/assets/javascripts/ide/lib/files.js @@ -1,4 +1,3 @@ -import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils'; import { decorateData, sortTree } from '../stores/utils'; export const splitParent = path => { @@ -13,15 +12,7 @@ export const splitParent = path => { /** * Create file objects from a list of file paths. */ -export const decorateFiles = ({ - data, - projectId, - branchId, - tempFile = false, - content = '', - binary = false, - rawPath = '', -}) => { +export const decorateFiles = ({ data, tempFile = false, content = '', rawPath = '' }) => { const treeList = []; const entries = {}; @@ -41,12 +32,9 @@ export const decorateFiles = ({ parentPath = parentFolder && parentFolder.path; const tree = decorateData({ - projectId, - branchId, id: path, name, path, - url: `/${projectId}/tree/${branchId}/-/${path}/`, type: 'tree', tempFile, changed: tempFile, @@ -73,21 +61,16 @@ export const decorateFiles = ({ const fileFolder = parent && insertParent(parent); if (name) { - const previewMode = viewerInformationForPath(name); parentPath = fileFolder && fileFolder.path; file = decorateData({ - projectId, - branchId, id: path, name, path, - url: `/${projectId}/blob/${branchId}/-/${path}`, type: 'blob', tempFile, changed: tempFile, content, - binary: (previewMode && previewMode.binary) || binary, rawPath, parentPath, }); diff --git a/app/assets/javascripts/ide/lib/schemas/index.js b/app/assets/javascripts/ide/lib/schemas/index.js deleted file mode 100644 index 38a2f81921b..00000000000 --- a/app/assets/javascripts/ide/lib/schemas/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import json from './json'; -import yaml from './yaml'; - -export default [json, yaml]; diff --git a/app/assets/javascripts/ide/lib/schemas/json/index.js b/app/assets/javascripts/ide/lib/schemas/json/index.js deleted file mode 100644 index 900d5442bec..00000000000 --- a/app/assets/javascripts/ide/lib/schemas/json/index.js +++ /dev/null @@ -1,8 +0,0 @@ -export default { - language: 'json', - options: { - validate: true, - enableSchemaRequest: true, - schemas: [], - }, -}; diff --git a/app/assets/javascripts/ide/lib/schemas/yaml/gitlab_ci.js b/app/assets/javascripts/ide/lib/schemas/yaml/gitlab_ci.js deleted file mode 100644 index af20744abb3..00000000000 --- a/app/assets/javascripts/ide/lib/schemas/yaml/gitlab_ci.js +++ /dev/null @@ -1,4 +0,0 @@ -export default { - uri: 'https://json.schemastore.org/gitlab-ci', - fileMatch: ['*.gitlab-ci.yml'], -}; diff --git a/app/assets/javascripts/ide/lib/schemas/yaml/index.js b/app/assets/javascripts/ide/lib/schemas/yaml/index.js deleted file mode 100644 index e3fc406df4b..00000000000 --- a/app/assets/javascripts/ide/lib/schemas/yaml/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import gitlabCi from './gitlab_ci'; - -export default { - language: 'yaml', - options: { - validate: true, - enableSchemaRequest: true, - hover: true, - completion: true, - schemas: [gitlabCi], - }, -}; diff --git a/app/assets/javascripts/ide/services/gql.js b/app/assets/javascripts/ide/services/gql.js index 211cc78bd99..89dda187360 100644 --- a/app/assets/javascripts/ide/services/gql.js +++ b/app/assets/javascripts/ide/services/gql.js @@ -17,5 +17,4 @@ const getClient = memoize(() => ), ); -// eslint-disable-next-line import/prefer-default-export export const query = (...args) => getClient().query(...args); diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index ae4a1ba3db5..70a6a6b423d 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -33,7 +33,7 @@ export default { }) .then(({ data }) => data); }, - getBaseRawFileData(file, sha) { + getBaseRawFileData(file, projectId, ref) { if (file.tempFile || file.baseRaw) return Promise.resolve(file.baseRaw); // if files are renamed, their base path has changed @@ -44,10 +44,10 @@ export default { .get( joinPaths( gon.relative_url_root || '/', - file.projectId, + projectId, '-', 'raw', - sha, + ref, escapeFileUrl(filePath), ), { diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index b083dc6325f..b8d59f8bd36 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -25,15 +25,7 @@ export const setResizingStatus = ({ commit }, resizing) => { export const createTempEntry = ( { state, commit, dispatch, getters }, - { - name, - type, - content = '', - binary = false, - rawPath = '', - openFile = true, - makeFileActive = true, - }, + { name, type, content = '', rawPath = '', openFile = true, makeFileActive = true }, ) => { const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name; @@ -54,21 +46,14 @@ export const createTempEntry = ( const data = decorateFiles({ data: [fullName], - projectId: state.currentProjectId, - branchId: state.currentBranchId, type, tempFile: true, content, - binary, rawPath, }); const { file, parentPath } = data; - commit(types.CREATE_TMP_ENTRY, { - data, - projectId: state.currentProjectId, - branchId: state.currentBranchId, - }); + commit(types.CREATE_TMP_ENTRY, { data }); if (type === 'blob') { if (openFile) commit(types.TOGGLE_FILE_OPEN, file.path); @@ -90,7 +75,6 @@ export const addTempImage = ({ dispatch, getters }, { name, rawPath = '' }) => name: getters.getAvailableFileName(name), type: 'blob', content: rawPath.split('base64,')[1], - binary: true, rawPath, openFile: false, makeFileActive: false, @@ -254,7 +238,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name, } if (newEntry.opened) { - dispatch('router/push', `/project${newEntry.url}`, { root: true }); + dispatch('router/push', getters.getUrlForPath(newEntry.path), { root: true }); } } diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index c0cb924e749..3515d1fc933 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -6,7 +6,7 @@ import * as types from '../mutation_types'; import { setPageTitleForFile } from '../utils'; import { viewerTypes, stageKeys } from '../../constants'; -export const closeFile = ({ commit, state, dispatch }, file) => { +export const closeFile = ({ commit, state, dispatch, getters }, file) => { const { path } = file; const indexOfClosedFile = state.openFiles.findIndex(f => f.key === file.key); const fileWasActive = file.active; @@ -29,10 +29,12 @@ export const closeFile = ({ commit, state, dispatch }, file) => { keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged', }); } else { - dispatch('router/push', `/project${nextFileToOpen.url}`, { root: true }); + dispatch('router/push', getters.getUrlForPath(nextFileToOpen.path), { root: true }); } } else if (!state.openFiles.length) { - dispatch('router/push', `/project/${file.projectId}/tree/${file.branchId}/`, { root: true }); + dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, { + root: true, + }); } eventHub.$emit(`editor.update.model.dispose.${file.key}`); @@ -121,7 +123,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) = const baseSha = (getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || ''; - return service.getBaseRawFileData(file, baseSha).then(baseRaw => { + return service.getBaseRawFileData(file, state.currentProjectId, baseSha).then(baseRaw => { commit(types.SET_FILE_BASE_RAW_DATA, { file, baseRaw, @@ -218,7 +220,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) = if (!isDestructiveDiscard && file.path === getters.activeFile?.path) { dispatch('updateDelayViewerUpdated', true) .then(() => { - dispatch('router/push', `/project${file.url}`, { root: true }); + dispatch('router/push', getters.getUrlForPath(file.path), { root: true }); }) .catch(e => { throw e; @@ -274,7 +276,7 @@ export const openPendingTab = ({ commit, dispatch, getters, state }, { file, key commit(types.ADD_PENDING_TAB, { file, keyPrefix }); - dispatch('router/push', `/project/${file.projectId}/tree/${state.currentBranchId}/`, { + dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, { root: true, }); diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index 1ca608f1287..3a7daf30cc4 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -61,11 +61,7 @@ export const getFiles = ({ state, commit, dispatch }, payload = {}) => service .getFiles(selectedProject.path_with_namespace, ref) .then(({ data }) => { - const { entries, treeList } = decorateFiles({ - data, - projectId, - branchId, - }); + const { entries, treeList } = decorateFiles({ data }); commit(types.SET_ENTRIES, entries); diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index 53734fa626b..b8304a9b68d 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -6,6 +6,7 @@ import { PERMISSION_CREATE_MR, PERMISSION_PUSH_CODE, } from '../constants'; +import Api from '~/api'; export const activeFile = state => state.openFiles.find(file => file.active) || null; @@ -174,3 +175,21 @@ export const getAvailableFileName = (state, getters) => path => { return newPath; }; + +export const getUrlForPath = state => path => + `/project/${state.currentProjectId}/tree/${state.currentBranchId}/-/${path}/`; + +export const getJsonSchemaForPath = (state, getters) => path => { + const [namespace, ...project] = state.currentProjectId.split('/'); + return { + uri: + // eslint-disable-next-line no-restricted-globals + location.origin + + Api.buildUrl(Api.projectFileSchemaPath) + .replace(':namespace_path', namespace) + .replace(':project_path', project.join('/')) + .replace(':ref', getters.currentBranch?.commit.id || state.currentBranchId) + .replace(':filename', path), + fileMatch: [`*${path}`], + }; +}; diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index 277e6923f17..90a6c644d17 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -1,6 +1,5 @@ import { sprintf, __ } from '~/locale'; import { deprecatedCreateFlash as flash } from '~/flash'; -import httpStatusCodes from '~/lib/utils/http_status'; import * as rootTypes from '../../mutation_types'; import { createCommitPayload, createNewMergeRequestUrl } from '../../utils'; import service from '../../../services'; @@ -8,6 +7,7 @@ import * as types from './mutation_types'; import consts from './constants'; import { leftSidebarViews } from '../../../constants'; import eventHub from '../../../eventhub'; +import { parseCommitError } from '../../../lib/errors'; export const updateCommitMessage = ({ commit }, message) => { commit(types.UPDATE_COMMIT_MESSAGE, message); @@ -113,6 +113,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ? Promise.resolve() : dispatch('stageAllChanges', null, { root: true }); + commit(types.CLEAR_ERROR); commit(types.UPDATE_LOADING, true); return stageFilesPromise @@ -128,6 +129,12 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo return service.commit(rootState.currentProjectId, payload); }) + .catch(e => { + commit(types.UPDATE_LOADING, false); + commit(types.SET_ERROR, parseCommitError(e)); + + throw e; + }) .then(({ data }) => { commit(types.UPDATE_LOADING, false); @@ -214,24 +221,5 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo { root: true }, ), ); - }) - .catch(err => { - commit(types.UPDATE_LOADING, false); - - // don't catch bad request errors, let the view handle them - if (err.response.status === httpStatusCodes.BAD_REQUEST) throw err; - - dispatch( - 'setErrorMessage', - { - text: __('An error occurred while committing your changes.'), - action: () => - dispatch('commitChanges').then(() => dispatch('setErrorMessage', null, { root: true })), - actionText: __('Please try again'), - }, - { root: true }, - ); - - window.dispatchEvent(new Event('resize')); }); }; diff --git a/app/assets/javascripts/ide/stores/modules/commit/mutation_types.js b/app/assets/javascripts/ide/stores/modules/commit/mutation_types.js index 7ad8f3570b7..47ec2ffbdde 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/mutation_types.js +++ b/app/assets/javascripts/ide/stores/modules/commit/mutation_types.js @@ -3,3 +3,6 @@ export const UPDATE_COMMIT_ACTION = 'UPDATE_COMMIT_ACTION'; export const UPDATE_NEW_BRANCH_NAME = 'UPDATE_NEW_BRANCH_NAME'; export const UPDATE_LOADING = 'UPDATE_LOADING'; export const TOGGLE_SHOULD_CREATE_MR = 'TOGGLE_SHOULD_CREATE_MR'; + +export const CLEAR_ERROR = 'CLEAR_ERROR'; +export const SET_ERROR = 'SET_ERROR'; diff --git a/app/assets/javascripts/ide/stores/modules/commit/mutations.js b/app/assets/javascripts/ide/stores/modules/commit/mutations.js index 73b618e250f..2cf6e8e6f36 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/commit/mutations.js @@ -24,4 +24,10 @@ export default { shouldCreateMR: shouldCreateMR === undefined ? !state.shouldCreateMR : shouldCreateMR, }); }, + [types.CLEAR_ERROR](state) { + state.commitError = null; + }, + [types.SET_ERROR](state, error) { + state.commitError = error; + }, }; diff --git a/app/assets/javascripts/ide/stores/modules/commit/state.js b/app/assets/javascripts/ide/stores/modules/commit/state.js index f49737485f2..de092a569ad 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/state.js +++ b/app/assets/javascripts/ide/stores/modules/commit/state.js @@ -4,4 +4,5 @@ export default () => ({ newBranchName: '', submitCommitLoading: false, shouldCreateMR: true, + commitError: null, }); diff --git a/app/assets/javascripts/ide/stores/modules/pane/getters.js b/app/assets/javascripts/ide/stores/modules/pane/getters.js index 7816172bb6f..ce597329df1 100644 --- a/app/assets/javascripts/ide/stores/modules/pane/getters.js +++ b/app/assets/javascripts/ide/stores/modules/pane/getters.js @@ -1,3 +1,2 @@ -// eslint-disable-next-line import/prefer-default-export 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 86b889546b0..99bd08ee876 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -118,31 +118,31 @@ export const setDetailJob = ({ commit, dispatch }, job) => { }); }; -export const requestJobTrace = ({ commit }) => commit(types.REQUEST_JOB_TRACE); -export const receiveJobTraceError = ({ commit, dispatch }) => { +export const requestJobLogs = ({ commit }) => commit(types.REQUEST_JOB_LOGS); +export const receiveJobLogsError = ({ commit, dispatch }) => { dispatch( 'setErrorMessage', { - text: __('An error occurred while fetching the job trace.'), + text: __('An error occurred while fetching the job logs.'), action: () => - dispatch('fetchJobTrace').then(() => dispatch('setErrorMessage', null, { root: true })), + dispatch('fetchJobLogs').then(() => dispatch('setErrorMessage', null, { root: true })), actionText: __('Please try again'), actionPayload: null, }, { root: true }, ); - commit(types.RECEIVE_JOB_TRACE_ERROR); + commit(types.RECEIVE_JOB_LOGS_ERROR); }; -export const receiveJobTraceSuccess = ({ commit }, data) => - commit(types.RECEIVE_JOB_TRACE_SUCCESS, data); +export const receiveJobLogsSuccess = ({ commit }, data) => + commit(types.RECEIVE_JOB_LOGS_SUCCESS, data); -export const fetchJobTrace = ({ dispatch, state }) => { - dispatch('requestJobTrace'); +export const fetchJobLogs = ({ dispatch, state }) => { + dispatch('requestJobLogs'); return axios .get(`${state.detailJob.path}/trace`, { params: { format: 'json' } }) - .then(({ data }) => dispatch('receiveJobTraceSuccess', data)) - .catch(() => dispatch('receiveJobTraceError')); + .then(({ data }) => dispatch('receiveJobLogsSuccess', data)) + .catch(() => dispatch('receiveJobLogsError')); }; export const resetLatestPipeline = ({ commit }) => { diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/constants.js b/app/assets/javascripts/ide/stores/modules/pipelines/constants.js index f5b96327e40..bb4145934ff 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/constants.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/constants.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/prefer-default-export export const states = { failed: 'failed', }; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js index f4c36b9d96f..fea3055e0fe 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js @@ -10,6 +10,6 @@ export const TOGGLE_STAGE_COLLAPSE = 'TOGGLE_STAGE_COLLAPSE'; export const SET_DETAIL_JOB = 'SET_DETAIL_JOB'; -export const REQUEST_JOB_TRACE = 'REQUEST_JOB_TRACE'; -export const RECEIVE_JOB_TRACE_ERROR = 'RECEIVE_JOB_TRACE_ERROR'; -export const RECEIVE_JOB_TRACE_SUCCESS = 'RECEIVE_JOB_TRACE_SUCCESS'; +export const REQUEST_JOB_LOGS = 'REQUEST_JOB_LOGS'; +export const RECEIVE_JOB_LOGS_ERROR = 'RECEIVE_JOB_LOGS_ERROR'; +export const RECEIVE_JOB_LOGS_SUCCESS = 'RECEIVE_JOB_LOGS_SUCCESS'; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js index eaaa82cb339..3a3cb4a7cb2 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js @@ -66,13 +66,13 @@ export default { [types.SET_DETAIL_JOB](state, job) { state.detailJob = { ...job }; }, - [types.REQUEST_JOB_TRACE](state) { + [types.REQUEST_JOB_LOGS](state) { state.detailJob.isLoading = true; }, - [types.RECEIVE_JOB_TRACE_ERROR](state) { + [types.RECEIVE_JOB_LOGS_ERROR](state) { state.detailJob.isLoading = false; }, - [types.RECEIVE_JOB_TRACE_SUCCESS](state, data) { + [types.RECEIVE_JOB_LOGS_SUCCESS](state, data) { state.detailJob.isLoading = false; state.detailJob.output = data.html; }, diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/utils.js b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js index a6caca2d2dc..95716e0a0c6 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/utils.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/prefer-default-export export const normalizeJob = job => ({ id: job.id, name: job.name, diff --git a/app/assets/javascripts/ide/stores/modules/router/actions.js b/app/assets/javascripts/ide/stores/modules/router/actions.js index 849067599f2..321ac57817f 100644 --- a/app/assets/javascripts/ide/stores/modules/router/actions.js +++ b/app/assets/javascripts/ide/stores/modules/router/actions.js @@ -1,6 +1,5 @@ import * as types from './mutation_types'; -// eslint-disable-next-line import/prefer-default-export export const push = ({ commit }, fullPath) => { commit(types.PUSH, fullPath); }; diff --git a/app/assets/javascripts/ide/stores/modules/router/mutation_types.js b/app/assets/javascripts/ide/stores/modules/router/mutation_types.js index ae99073cc4c..8f5f949bd5f 100644 --- a/app/assets/javascripts/ide/stores/modules/router/mutation_types.js +++ b/app/assets/javascripts/ide/stores/modules/router/mutation_types.js @@ -1,2 +1 @@ -// eslint-disable-next-line import/prefer-default-export export const PUSH = 'PUSH'; diff --git a/app/assets/javascripts/ide/stores/modules/terminal/getters.js b/app/assets/javascripts/ide/stores/modules/terminal/getters.js index ef98547ccc4..b29d391845d 100644 --- a/app/assets/javascripts/ide/stores/modules/terminal/getters.js +++ b/app/assets/javascripts/ide/stores/modules/terminal/getters.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/prefer-default-export export const allCheck = state => { const checks = Object.values(state.checks); diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index c64839e5019..460d3ced381 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -7,7 +7,6 @@ import treeMutations from './mutations/tree'; import branchMutations from './mutations/branch'; import { sortTree, - replaceFileUrl, swapInParentTreeWithSorting, updateFileCollections, removeFromParentTree, @@ -49,7 +48,7 @@ export default { entries, }); }, - [types.CREATE_TMP_ENTRY](state, { data, projectId, branchId }) { + [types.CREATE_TMP_ENTRY](state, { data }) { Object.keys(data.entries).reduce((acc, key) => { const entry = data.entries[key]; const foundEntry = state.entries[key]; @@ -72,13 +71,12 @@ export default { return acc.concat(key); }, []); - const foundEntry = state.trees[`${projectId}/${branchId}`].tree.find( - e => e.path === data.treeList[0].path, - ); + const currentTree = state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; + const foundEntry = currentTree.tree.find(e => e.path === data.treeList[0].path); if (!foundEntry) { - Object.assign(state.trees[`${projectId}/${branchId}`], { - tree: sortTree(state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList)), + Object.assign(currentTree, { + tree: sortTree(currentTree.tree.concat(data.treeList)), }); } }, @@ -139,7 +137,6 @@ export default { prevId: undefined, prevPath: undefined, prevName: undefined, - prevUrl: undefined, prevKey: undefined, prevParentPath: undefined, }); @@ -195,9 +192,6 @@ export default { const oldEntry = state.entries[path]; const newPath = parentPath ? `${parentPath}/${name}` : name; const isRevert = newPath === oldEntry.prevPath; - - const newUrl = replaceFileUrl(oldEntry.url, oldEntry.path, newPath); - const newKey = oldEntry.key.replace(new RegExp(oldEntry.path, 'g'), newPath); const baseProps = { @@ -205,7 +199,6 @@ export default { name, id: newPath, path: newPath, - url: newUrl, key: newKey, parentPath: parentPath || '', }; @@ -216,7 +209,6 @@ export default { prevId: undefined, prevPath: undefined, prevName: undefined, - prevUrl: undefined, prevKey: undefined, prevParentPath: undefined, } @@ -224,7 +216,6 @@ export default { prevId: oldEntry.prevId || oldEntry.id, prevPath: oldEntry.prevPath || oldEntry.path, prevName: oldEntry.prevName || oldEntry.name, - prevUrl: oldEntry.prevUrl || oldEntry.url, prevKey: oldEntry.prevKey || oldEntry.key, prevParentPath: oldEntry.prevParentPath || oldEntry.parentPath, }; diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index f074e6880d0..d9cdc7727ad 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -12,10 +12,7 @@ export const dataStructure = () => ({ // it can also contain a prefix `pending-` for files opened in review mode key: '', type: '', - projectId: '', - branchId: '', name: '', - url: '', path: '', tempFile: false, tree: [], @@ -26,7 +23,6 @@ export const dataStructure = () => ({ staged: false, lastCommitSha: '', rawPath: '', - binary: false, raw: '', content: '', editorRow: 1, @@ -44,10 +40,7 @@ export const dataStructure = () => ({ export const decorateData = entity => { const { id, - projectId, - branchId, type, - url, name, path, content = '', @@ -55,7 +48,6 @@ export const decorateData = entity => { active = false, opened = false, changed = false, - binary = false, rawPath = '', file_lock, parentPath = '', @@ -63,19 +55,15 @@ export const decorateData = entity => { return Object.assign(dataStructure(), { id, - projectId, - branchId, key: `${name}-${type}-${id}`, type, name, - url, path, tempFile, opened, active, changed, content, - binary, rawPath, file_lock, parentPath, @@ -189,11 +177,6 @@ export const mergeTrees = (fromTree, toTree) => { return toTree; }; -export const replaceFileUrl = (url, oldPath, newPath) => { - // Add `/-/` so that we don't accidentally replace project path - return url.replace(`/-/${oldPath}`, `/-/${newPath}`); -}; - export const swapInStateArray = (state, arr, key, entryPath) => Object.assign(state, { [arr]: state[arr].map(f => (f.key === key ? state.entries[entryPath] : f)), diff --git a/app/assets/javascripts/ide/sync_router_and_store.js b/app/assets/javascripts/ide/sync_router_and_store.js index 1782c32b3b2..b33bcbb94ea 100644 --- a/app/assets/javascripts/ide/sync_router_and_store.js +++ b/app/assets/javascripts/ide/sync_router_and_store.js @@ -1,4 +1,3 @@ -/* eslint-disable import/prefer-default-export */ /** * This method adds listeners to the given router and store and syncs their state with eachother * diff --git a/app/assets/javascripts/ide/utils.js b/app/assets/javascripts/ide/utils.js index 58a6712c232..cde53e1ef00 100644 --- a/app/assets/javascripts/ide/utils.js +++ b/app/assets/javascripts/ide/utils.js @@ -1,5 +1,5 @@ import { languages } from 'monaco-editor'; -import { flatten } from 'lodash'; +import { flatten, isString } from 'lodash'; import { SIDE_LEFT, SIDE_RIGHT } from './constants'; const toLowerCase = x => x.toLowerCase(); @@ -42,15 +42,16 @@ const KNOWN_TYPES = [ }, ]; -export function isTextFile(content, mimeType, fileName) { - const knownType = KNOWN_TYPES.find(type => type.isMatch(mimeType, fileName)); +export function isTextFile({ name, content, mimeType = '' }) { + 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) const asciiRegex = /^[ -~\t\n\r]+$/; + // for unknown types, determine the type by evaluating the file contents - return asciiRegex.test(content); + return isString(content) && (content === '' || asciiRegex.test(content)); } export const createPathWithExt = p => { @@ -75,17 +76,17 @@ export function registerLanguages(def, ...defs) { languages.setLanguageConfiguration(languageId, def.conf); } -export function registerSchemas({ language, options }, ...schemas) { - schemas.forEach(schema => registerSchemas(schema)); - - const defaults = { - json: languages.json.jsonDefaults, - yaml: languages.yaml.yamlDefaults, - }; - - if (defaults[language]) { - defaults[language].setDiagnosticsOptions(options); - } +export function registerSchema(schema) { + const defaults = [languages.json.jsonDefaults, languages.yaml.yamlDefaults]; + defaults.forEach(d => + d.setDiagnosticsOptions({ + validate: true, + enableSchemaRequest: true, + hover: true, + completion: true, + schemas: [schema], + }), + ); } export const otherSide = side => (side === SIDE_RIGHT ? SIDE_LEFT : SIDE_RIGHT); |