diff options
Diffstat (limited to 'app/assets/javascripts/repo/components')
14 files changed, 497 insertions, 304 deletions
diff --git a/app/assets/javascripts/repo/components/new_branch_form.vue b/app/assets/javascripts/repo/components/new_branch_form.vue new file mode 100644 index 00000000000..eac43e692b0 --- /dev/null +++ b/app/assets/javascripts/repo/components/new_branch_form.vue @@ -0,0 +1,115 @@ +<script> + import flash, { hideFlash } from '../../flash'; + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; + import eventHub from '../event_hub'; + + export default { + components: { + loadingIcon, + }, + props: { + currentBranch: { + type: String, + required: true, + }, + }, + data() { + return { + branchName: '', + loading: false, + }; + }, + computed: { + btnDisabled() { + return this.loading || this.branchName === ''; + }, + }, + methods: { + toggleDropdown() { + this.$dropdown.dropdown('toggle'); + }, + submitNewBranch() { + // need to query as the element is appended outside of Vue + const flashEl = this.$refs.flashContainer.querySelector('.flash-alert'); + + this.loading = true; + + if (flashEl) { + hideFlash(flashEl, false); + } + + eventHub.$emit('createNewBranch', this.branchName); + }, + showErrorMessage(message) { + this.loading = false; + flash(message, 'alert', this.$el); + }, + createdNewBranch(newBranchName) { + this.loading = false; + this.branchName = ''; + + if (this.dropdownText) { + this.dropdownText.textContent = newBranchName; + } + }, + }, + created() { + // Dropdown is outside of Vue instance & is controlled by Bootstrap + this.$dropdown = $('.git-revision-dropdown'); + + // text element is outside Vue app + this.dropdownText = document.querySelector('.project-refs-form .dropdown-toggle-text'); + + eventHub.$on('createNewBranchSuccess', this.createdNewBranch); + eventHub.$on('createNewBranchError', this.showErrorMessage); + eventHub.$on('toggleNewBranchDropdown', this.toggleDropdown); + }, + destroyed() { + eventHub.$off('createNewBranchSuccess', this.createdNewBranch); + eventHub.$off('toggleNewBranchDropdown', this.toggleDropdown); + eventHub.$off('createNewBranchError', this.showErrorMessage); + }, + }; +</script> + +<template> + <div> + <div + class="flash-container" + ref="flashContainer" + > + </div> + <p> + Create from: + <code>{{ currentBranch }}</code> + </p> + <input + class="form-control js-new-branch-name" + type="text" + placeholder="Name new branch" + v-model="branchName" + @keyup.enter.stop.prevent="submitNewBranch" + /> + <div class="prepend-top-default clearfix"> + <button + type="button" + class="btn btn-primary pull-left" + :disabled="btnDisabled" + @click.stop.prevent="submitNewBranch" + > + <loading-icon + v-if="loading" + :inline="true" + /> + <span>Create</span> + </button> + <button + type="button" + class="btn btn-default pull-right" + @click.stop.prevent="toggleDropdown" + > + Cancel + </button> + </div> + </div> +</template> diff --git a/app/assets/javascripts/repo/components/repo.vue b/app/assets/javascripts/repo/components/repo.vue index cc60aa5939c..6310bdb3270 100644 --- a/app/assets/javascripts/repo/components/repo.vue +++ b/app/assets/javascripts/repo/components/repo.vue @@ -8,10 +8,14 @@ import RepoMixin from '../mixins/repo_mixin'; import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; import Store from '../stores/repo_store'; import Helper from '../helpers/repo_helper'; +import Service from '../services/repo_service'; import MonacoLoaderHelper from '../helpers/monaco_loader_helper'; +import eventHub from '../event_hub'; export default { - data: () => Store, + data() { + return Store; + }, mixins: [RepoMixin], components: { RepoSidebar, @@ -22,12 +26,19 @@ export default { PopupDialog, RepoPreview, }, - + created() { + eventHub.$on('createNewBranch', this.createNewBranch); + }, mounted() { Helper.getContent().catch(Helper.loadingError); }, - + destroyed() { + eventHub.$off('createNewBranch', this.createNewBranch); + }, methods: { + getCurrentLocation() { + return location.href; + }, toggleDialogOpen(toggle) { this.dialog.open = toggle; }, @@ -36,8 +47,25 @@ export default { this.toggleDialogOpen(false); this.dialog.status = status; }, - toggleBlobView: Store.toggleBlobView, + createNewBranch(branch) { + Service.createBranch({ + branch, + ref: Store.currentBranch, + }).then((res) => { + const newBranchName = res.data.name; + const newUrl = this.getCurrentLocation().replace(Store.currentBranch, newBranchName); + + Store.currentBranch = newBranchName; + + history.pushState({ key: Helper.key }, '', newUrl); + + eventHub.$emit('createNewBranchSuccess', newBranchName); + eventHub.$emit('toggleNewBranchDropdown'); + }).catch((err) => { + eventHub.$emit('createNewBranchError', err.response.data.message); + }); + }, }, }; </script> diff --git a/app/assets/javascripts/repo/components/repo_commit_section.vue b/app/assets/javascripts/repo/components/repo_commit_section.vue index 6d8cc964eb2..185cd90ac06 100644 --- a/app/assets/javascripts/repo/components/repo_commit_section.vue +++ b/app/assets/javascripts/repo/components/repo_commit_section.vue @@ -3,12 +3,20 @@ import Flash from '../../flash'; import Store from '../stores/repo_store'; import RepoMixin from '../mixins/repo_mixin'; import Service from '../services/repo_service'; +import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; +import { visitUrl } from '../../lib/utils/url_utility'; export default { - data: () => Store, - mixins: [RepoMixin], + data() { + return Store; + }, + + components: { + PopupDialog, + }, + computed: { showCommitable() { return this.isCommitable && this.changedFiles.length; @@ -28,7 +36,16 @@ export default { }, methods: { - makeCommit() { + commitToNewBranch(status) { + if (status) { + this.showNewBranchDialog = false; + this.tryCommit(null, true, true); + } else { + // reset the state + } + }, + + makeCommit(newBranch) { // see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions const commitMessage = this.commitMessage; const actions = this.changedFiles.map(f => ({ @@ -36,19 +53,63 @@ export default { file_path: f.path, content: f.newContent, })); + const branch = newBranch ? `${this.currentBranch}-${this.currentShortHash}` : this.currentBranch; const payload = { - branch: Store.currentBranch, + branch, commit_message: commitMessage, actions, }; - Store.submitCommitsLoading = true; + if (newBranch) { + payload.start_branch = this.currentBranch; + } + this.submitCommitsLoading = true; Service.commitFiles(payload) - .then(this.resetCommitState) - .catch(() => Flash('An error occurred while committing your changes')); + .then(() => { + this.resetCommitState(); + if (this.startNewMR) { + this.redirectToNewMr(branch); + } else { + this.redirectToBranch(branch); + } + }) + .catch(() => { + Flash('An error occurred while committing your changes'); + }); + }, + + tryCommit(e, skipBranchCheck = false, newBranch = false) { + if (skipBranchCheck) { + this.makeCommit(newBranch); + } else { + Store.setBranchHash() + .then(() => { + if (Store.branchChanged) { + Store.showNewBranchDialog = true; + return; + } + this.makeCommit(newBranch); + }) + .catch(() => { + Flash('An error occurred while committing your changes'); + }); + } + }, + + redirectToNewMr(branch) { + visitUrl(this.newMrTemplateUrl.replace('{{source_branch}}', branch)); + }, + + redirectToBranch(branch) { + visitUrl(this.customBranchURL.replace('{{branch}}', branch)); }, resetCommitState() { this.submitCommitsLoading = false; + this.openedFiles = this.openedFiles.map((file) => { + const f = file; + f.changed = false; + return f; + }); this.changedFiles = []; this.commitMessage = ''; this.editMode = false; @@ -62,9 +123,17 @@ export default { <div v-if="showCommitable" id="commit-area"> + <popup-dialog + v-if="showNewBranchDialog" + :primary-button-label="__('Create new branch')" + kind="primary" + :title="__('Branch has changed')" + :text="__('This branch has changed since you started editing. Would you like to create a new branch?')" + @submit="commitToNewBranch" + /> <form class="form-horizontal" - @submit.prevent="makeCommit"> + @submit.prevent="tryCommit"> <fieldset> <div class="form-group"> <label class="col-md-4 control-label staged-files"> @@ -117,7 +186,7 @@ export default { class="btn btn-success"> <i v-if="submitCommitsLoading" - class="fa fa-spinner fa-spin" + class="js-commit-loading-icon fa fa-spinner fa-spin" aria-hidden="true" aria-label="loading"> </i> @@ -126,6 +195,14 @@ export default { </span> </button> </div> + <div class="col-md-offset-4 col-md-6"> + <div class="checkbox"> + <label> + <input type="checkbox" v-model="startNewMR"> + <span>Start a <strong>new merge request</strong> with these changes</span> + </label> + </div> + </div> </fieldset> </form> </div> diff --git a/app/assets/javascripts/repo/components/repo_edit_button.vue b/app/assets/javascripts/repo/components/repo_edit_button.vue index 353142edeb7..e6e8b2e5205 100644 --- a/app/assets/javascripts/repo/components/repo_edit_button.vue +++ b/app/assets/javascripts/repo/components/repo_edit_button.vue @@ -3,7 +3,9 @@ import Store from '../stores/repo_store'; import RepoMixin from '../mixins/repo_mixin'; export default { - data: () => Store, + data() { + return Store; + }, mixins: [RepoMixin], computed: { buttonLabel() { diff --git a/app/assets/javascripts/repo/components/repo_editor.vue b/app/assets/javascripts/repo/components/repo_editor.vue index 02d9c775046..4639bee6d66 100644 --- a/app/assets/javascripts/repo/components/repo_editor.vue +++ b/app/assets/javascripts/repo/components/repo_editor.vue @@ -5,7 +5,9 @@ import Service from '../services/repo_service'; import Helper from '../helpers/repo_helper'; const RepoEditor = { - data: () => Store, + data() { + return Store; + }, destroyed() { if (Helper.monacoInstance) { @@ -22,7 +24,8 @@ const RepoEditor = { const monacoInstance = Helper.monaco.editor.create(this.$el, { model: null, readOnly: false, - contextmenu: false, + contextmenu: true, + scrollBeyondLastLine: false, }); Helper.monacoInstance = monacoInstance; @@ -92,7 +95,7 @@ const RepoEditor = { }, blobRaw() { - if (Helper.monacoInstance && !this.isTree) { + if (Helper.monacoInstance) { this.setupEditor(); } }, diff --git a/app/assets/javascripts/repo/components/repo_file.vue b/app/assets/javascripts/repo/components/repo_file.vue index 8b9cbd23456..8c86e87ed3a 100644 --- a/app/assets/javascripts/repo/components/repo_file.vue +++ b/app/assets/javascripts/repo/components/repo_file.vue @@ -1,107 +1,95 @@ <script> -import TimeAgoMixin from '../../vue_shared/mixins/timeago'; + import timeAgoMixin from '../../vue_shared/mixins/timeago'; + import eventHub from '../event_hub'; + import repoMixin from '../mixins/repo_mixin'; -const RepoFile = { - mixins: [TimeAgoMixin], - props: { - file: { - type: Object, - required: true, + export default { + mixins: [ + repoMixin, + timeAgoMixin, + ], + props: { + file: { + type: Object, + required: true, + }, }, - isMini: { - type: Boolean, - required: false, - default: false, + computed: { + fileIcon() { + const classObj = { + 'fa-spinner fa-spin': this.file.loading, + [this.file.icon]: !this.file.loading, + 'fa-folder-open': !this.file.loading && this.file.opened, + }; + return classObj; + }, + levelIndentation() { + return { + marginLeft: `${this.file.level * 16}px`, + }; + }, + shortId() { + return this.file.id.substr(0, 8); + }, }, - loading: { - type: Object, - required: false, - default() { return { tree: false }; }, + methods: { + linkClicked(file) { + eventHub.$emit('fileNameClicked', file); + }, }, - hasFiles: { - type: Boolean, - required: false, - default: false, - }, - activeFile: { - type: Object, - required: true, - }, - }, - - computed: { - canShowFile() { - return !this.loading.tree || this.hasFiles; - }, - - fileIcon() { - const classObj = { - 'fa-spinner fa-spin': this.file.loading, - [this.file.icon]: !this.file.loading, - }; - return classObj; - }, - - fileIndentation() { - return { - 'margin-left': `${this.file.level * 10}px`, - }; - }, - - activeFileClass() { - return { - active: this.activeFile.url === this.file.url, - }; - }, - }, - - methods: { - linkClicked(file) { - this.$emit('linkclicked', file); - }, - }, -}; - -export default RepoFile; + }; </script> <template> -<tr - v-if="canShowFile" - class="file" - :class="activeFileClass" - @click.prevent="linkClicked(file)"> - <td> - <i - class="fa fa-fw file-icon" - :class="fileIcon" - :style="fileIndentation" - aria-label="file icon"> - </i> - <a - :href="file.url" - class="repo-file-name" - :title="file.url"> - {{file.name}} - </a> - </td> + <tr + class="file" + @click.prevent="linkClicked(file)"> + <td> + <i + class="fa fa-fw file-icon" + :class="fileIcon" + :style="levelIndentation" + aria-hidden="true" + > + </i> + <a + :href="file.url" + class="repo-file-name" + > + {{ file.name }} + </a> + <template v-if="file.type === 'submodule' && file.id"> + @ + <span class="commit-sha"> + <a + @click.stop + :href="file.tree_url" + > + {{ shortId }} + </a> + </span> + </template> + </td> - <template v-if="!isMini"> - <td class="hidden-sm hidden-xs"> - <div class="commit-message"> - <a @click.stop :href="file.lastCommitUrl"> - {{file.lastCommitMessage}} + <template v-if="!isMini"> + <td class="hidden-sm hidden-xs"> + <a + @click.stop + :href="file.lastCommit.url" + class="commit-message" + > + {{ file.lastCommit.message }} </a> - </div> - </td> + </td> - <td class="hidden-xs text-right"> - <span - class="commit-update" - :title="tooltipTitle(file.lastCommitUpdate)"> - {{timeFormated(file.lastCommitUpdate)}} - </span> - </td> - </template> -</tr> + <td class="commit-update hidden-xs text-right"> + <span + v-if="file.lastCommit.updatedAt" + :title="tooltipTitle(file.lastCommit.updatedAt)" + > + {{ timeFormated(file.lastCommit.updatedAt) }} + </span> + </td> + </template> + </tr> </template> diff --git a/app/assets/javascripts/repo/components/repo_file_buttons.vue b/app/assets/javascripts/repo/components/repo_file_buttons.vue index e43ef366f47..03cd219e718 100644 --- a/app/assets/javascripts/repo/components/repo_file_buttons.vue +++ b/app/assets/javascripts/repo/components/repo_file_buttons.vue @@ -4,7 +4,9 @@ import Helper from '../helpers/repo_helper'; import RepoMixin from '../mixins/repo_mixin'; const RepoFileButtons = { - data: () => Store, + data() { + return Store; + }, mixins: [RepoMixin], diff --git a/app/assets/javascripts/repo/components/repo_file_options.vue b/app/assets/javascripts/repo/components/repo_file_options.vue deleted file mode 100644 index 6a15755f029..00000000000 --- a/app/assets/javascripts/repo/components/repo_file_options.vue +++ /dev/null @@ -1,25 +0,0 @@ -<script> -const RepoFileOptions = { - props: { - isMini: { - type: Boolean, - required: false, - default: false, - }, - projectName: { - type: String, - required: true, - }, - }, -}; - -export default RepoFileOptions; -</script> - -<template> - <tr v-if="isMini" class="repo-file-options"> - <td> - <span class="title">{{projectName}}</span> - </td> - </tr> -</template> diff --git a/app/assets/javascripts/repo/components/repo_loading_file.vue b/app/assets/javascripts/repo/components/repo_loading_file.vue index bc8c64c8362..832b45b2b29 100644 --- a/app/assets/javascripts/repo/components/repo_loading_file.vue +++ b/app/assets/javascripts/repo/components/repo_loading_file.vue @@ -1,43 +1,23 @@ <script> -const RepoLoadingFile = { - props: { - loading: { - type: Object, - required: false, - default: {}, - }, - hasFiles: { - type: Boolean, - required: false, - default: false, - }, - isMini: { - type: Boolean, - required: false, - default: false, - }, - }, - - computed: { - showGhostLines() { - return this.loading.tree && !this.hasFiles; - }, - }, + import repoMixin from '../mixins/repo_mixin'; - methods: { - lineOfCode(n) { - return `skeleton-line-${n}`; + export default { + mixins: [ + repoMixin, + ], + methods: { + lineOfCode(n) { + return `skeleton-line-${n}`; + }, }, - }, -}; - -export default RepoLoadingFile; + }; </script> <template> <tr - v-if="showGhostLines" - class="loading-file"> + class="loading-file" + aria-label="Loading files" + > <td> <div class="animation-container animation-container-small"> @@ -48,29 +28,28 @@ export default RepoLoadingFile; </div> </div> </td> - - <td - v-if="!isMini" - class="hidden-sm hidden-xs"> - <div class="animation-container"> - <div - v-for="n in 6" - :key="n" - :class="lineOfCode(n)"> + <template v-if="!isMini"> + <td + class="hidden-sm hidden-xs"> + <div class="animation-container"> + <div + v-for="n in 6" + :key="n" + :class="lineOfCode(n)"> + </div> </div> - </div> - </td> + </td> - <td - v-if="!isMini" - class="hidden-xs"> - <div class="animation-container animation-container-small"> - <div - v-for="n in 6" - :key="n" - :class="lineOfCode(n)"> + <td + class="hidden-xs"> + <div class="animation-container animation-container-small animation-container-right"> + <div + v-for="n in 6" + :key="n" + :class="lineOfCode(n)"> + </div> </div> - </div> - </td> + </td> + </template> </tr> </template> diff --git a/app/assets/javascripts/repo/components/repo_prev_directory.vue b/app/assets/javascripts/repo/components/repo_prev_directory.vue index bbdbdc61e38..c4bf6dcdec2 100644 --- a/app/assets/javascripts/repo/components/repo_prev_directory.vue +++ b/app/assets/javascripts/repo/components/repo_prev_directory.vue @@ -1,38 +1,38 @@ <script> -import RepoMixin from '../mixins/repo_mixin'; + import eventHub from '../event_hub'; + import repoMixin from '../mixins/repo_mixin'; -const RepoPreviousDirectory = { - props: { - prevUrl: { - type: String, - required: true, + export default { + mixins: [ + repoMixin, + ], + props: { + prevUrl: { + type: String, + required: true, + }, }, - }, - - mixins: [RepoMixin], - - computed: { - colSpanCondition() { - return this.isMini ? undefined : 3; + computed: { + colSpanCondition() { + return this.isMini ? undefined : 3; + }, }, - }, - - methods: { - linkClicked(file) { - this.$emit('linkclicked', file); + methods: { + linkClicked(file) { + eventHub.$emit('goToPreviousDirectoryClicked', file); + }, }, - }, -}; - -export default RepoPreviousDirectory; + }; </script> <template> -<tr class="prev-directory"> - <td - :colspan="colSpanCondition" - @click.prevent="linkClicked(prevUrl)"> - <a :href="prevUrl">..</a> - </td> -</tr> + <tr class="file prev-directory"> + <td + :colspan="colSpanCondition" + class="table-cell" + @click.prevent="linkClicked(prevUrl)" + > + <a :href="prevUrl">...</a> + </td> + </tr> </template> diff --git a/app/assets/javascripts/repo/components/repo_preview.vue b/app/assets/javascripts/repo/components/repo_preview.vue index a87bef6084a..b5be771d539 100644 --- a/app/assets/javascripts/repo/components/repo_preview.vue +++ b/app/assets/javascripts/repo/components/repo_preview.vue @@ -4,7 +4,9 @@ import Store from '../stores/repo_store'; export default { - data: () => Store, + data() { + return Store; + }, computed: { html() { return this.activeFile.html; diff --git a/app/assets/javascripts/repo/components/repo_sidebar.vue b/app/assets/javascripts/repo/components/repo_sidebar.vue index e0f3c33003a..09dc9ee25d7 100644 --- a/app/assets/javascripts/repo/components/repo_sidebar.vue +++ b/app/assets/javascripts/repo/components/repo_sidebar.vue @@ -1,9 +1,10 @@ <script> +import _ from 'underscore'; import Service from '../services/repo_service'; import Helper from '../helpers/repo_helper'; import Store from '../stores/repo_store'; +import eventHub from '../event_hub'; import RepoPreviousDirectory from './repo_prev_directory.vue'; -import RepoFileOptions from './repo_file_options.vue'; import RepoFile from './repo_file.vue'; import RepoLoadingFile from './repo_loading_file.vue'; import RepoMixin from '../mixins/repo_mixin'; @@ -11,21 +12,35 @@ import RepoMixin from '../mixins/repo_mixin'; export default { mixins: [RepoMixin], components: { - 'repo-file-options': RepoFileOptions, 'repo-previous-directory': RepoPreviousDirectory, 'repo-file': RepoFile, 'repo-loading-file': RepoLoadingFile, }, - created() { window.addEventListener('popstate', this.checkHistory); }, destroyed() { + eventHub.$off('fileNameClicked', this.fileClicked); + eventHub.$off('goToPreviousDirectoryClicked', this.goToPreviousDirectoryClicked); window.removeEventListener('popstate', this.checkHistory); }, + mounted() { + eventHub.$on('fileNameClicked', this.fileClicked); + eventHub.$on('goToPreviousDirectoryClicked', this.goToPreviousDirectoryClicked); + }, + data() { + return Store; + }, + computed: { + flattendFiles() { + const mapFiles = arr => (!arr.files.length ? [] : _.map(arr.files, a => [a, mapFiles(a)])); - data: () => Store, - + return _.chain(this.files) + .map(arr => [arr, mapFiles(arr)]) + .flatten() + .value(); + }, + }, methods: { checkHistory() { let selectedFile = this.files.find(file => location.pathname.indexOf(file.url) > -1); @@ -52,21 +67,25 @@ export default { }, fileClicked(clickedFile, lineNumber) { - let file = clickedFile; + const file = clickedFile; + if (file.loading) return; - file.loading = true; if (file.type === 'tree' && file.opened) { - file = Store.removeChildFilesOfTree(file); - file.loading = false; + Helper.setDirectoryToClosed(file); Store.setActiveLine(lineNumber); + } else if (file.type === 'submodule') { + file.loading = true; + + gl.utils.visitUrl(file.url); } else { const openFile = Helper.getFileFromPath(file.url); + if (openFile) { - file.loading = false; Store.setActiveFiles(openFile); Store.setActiveLine(lineNumber); } else { + file.loading = true; Service.url = file.url; Helper.getContent(file) .then(() => { @@ -81,7 +100,7 @@ export default { goToPreviousDirectoryClicked(prevURL) { Service.url = prevURL; - Helper.getContent(null) + Helper.getContent(null, true) .then(() => Helper.scrollTabsRight()) .catch(Helper.loadingError); }, @@ -92,38 +111,43 @@ export default { <template> <div id="sidebar" :class="{'sidebar-mini' : isMini}"> <table class="table"> - <thead v-if="!isMini"> + <thead> <tr> - <th class="name">Name</th> - <th class="hidden-sm hidden-xs last-commit">Last commit</th> - <th class="hidden-xs last-update text-right">Last update</th> + <th + v-if="isMini" + class="repo-file-options title" + > + <strong class="clgray"> + {{ projectName }} + </strong> + </th> + <template v-else> + <th class="name"> + Name + </th> + <th class="hidden-sm hidden-xs last-commit"> + Last commit + </th> + <th class="hidden-xs last-update text-right"> + Last update + </th> + </template> </tr> </thead> <tbody> - <repo-file-options - :is-mini="isMini" - :project-name="projectName" - /> <repo-previous-directory - v-if="isRoot" + v-if="!isRoot && !loading.tree" :prev-url="prevURL" - @linkclicked="goToPreviousDirectoryClicked(prevURL)"/> + /> <repo-loading-file + v-if="!flattendFiles.length && loading.tree" v-for="n in 5" :key="n" - :loading="loading" - :has-files="!!files.length" - :is-mini="isMini" /> <repo-file - v-for="file in files" + v-for="file in flattendFiles" :key="file.id" :file="file" - :is-mini="isMini" - @linkclicked="fileClicked(file)" - :is-tree="isTree" - :has-files="!!files.length" - :active-file="activeFile" /> </tbody> </table> diff --git a/app/assets/javascripts/repo/components/repo_tab.vue b/app/assets/javascripts/repo/components/repo_tab.vue index 0d0c34ec741..098715915b0 100644 --- a/app/assets/javascripts/repo/components/repo_tab.vue +++ b/app/assets/javascripts/repo/components/repo_tab.vue @@ -26,11 +26,13 @@ const RepoTab = { }, methods: { - tabClicked: Store.setActiveFiles, - + tabClicked(file) { + Store.setActiveFiles(file); + }, closeTab(file) { if (file.changed) return; - this.$emit('tabclosed', file); + + Store.removeFromOpenedFiles(file); }, }, }; @@ -39,25 +41,28 @@ export default RepoTab; </script> <template> -<li @click="tabClicked(tab)"> - <a - href="#0" - class="close" - @click.stop.prevent="closeTab(tab)" - :aria-label="closeLabel"> - <i - class="fa" - :class="changedClass" - aria-hidden="true"> - </i> - </a> + <li + :class="{ active : tab.active }" + @click="tabClicked(tab)" + > + <button + type="button" + class="close-btn" + @click.stop.prevent="closeTab(tab)" + :aria-label="closeLabel"> + <i + class="fa" + :class="changedClass" + aria-hidden="true"> + </i> + </button> - <a - href="#" - class="repo-tab" - :title="tab.url" - @click.prevent="tabClicked(tab)"> - {{tab.name}} - </a> -</li> + <a + href="#" + class="repo-tab" + :title="tab.url" + @click.prevent="tabClicked(tab)"> + {{tab.name}} + </a> + </li> </template> diff --git a/app/assets/javascripts/repo/components/repo_tabs.vue b/app/assets/javascripts/repo/components/repo_tabs.vue index 9c5bfc5d0cf..b57cd0960de 100644 --- a/app/assets/javascripts/repo/components/repo_tabs.vue +++ b/app/assets/javascripts/repo/components/repo_tabs.vue @@ -1,36 +1,29 @@ <script> -import Store from '../stores/repo_store'; -import RepoTab from './repo_tab.vue'; -import RepoMixin from '../mixins/repo_mixin'; + import Store from '../stores/repo_store'; + import RepoTab from './repo_tab.vue'; + import RepoMixin from '../mixins/repo_mixin'; -const RepoTabs = { - mixins: [RepoMixin], - - components: { - 'repo-tab': RepoTab, - }, - - data: () => Store, - - methods: { - tabClosed(file) { - Store.removeFromOpenedFiles(file); + export default { + mixins: [RepoMixin], + components: { + 'repo-tab': RepoTab, }, - }, -}; - -export default RepoTabs; + data() { + return Store; + }, + }; </script> <template> -<ul id="tabs"> - <repo-tab - v-for="tab in openedFiles" - :key="tab.id" - :tab="tab" - :class="{'active' : tab.active}" - @tabclosed="tabClosed" - /> - <li class="tabs-divider" /> -</ul> + <ul + id="tabs" + class="list-unstyled" + > + <repo-tab + v-for="tab in openedFiles" + :key="tab.id" + :tab="tab" + /> + <li class="tabs-divider" /> + </ul> </template> |