summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/repo/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/repo/components')
-rw-r--r--app/assets/javascripts/repo/components/new_branch_form.vue115
-rw-r--r--app/assets/javascripts/repo/components/repo.vue36
-rw-r--r--app/assets/javascripts/repo/components/repo_commit_section.vue95
-rw-r--r--app/assets/javascripts/repo/components/repo_edit_button.vue4
-rw-r--r--app/assets/javascripts/repo/components/repo_editor.vue9
-rw-r--r--app/assets/javascripts/repo/components/repo_file.vue178
-rw-r--r--app/assets/javascripts/repo/components/repo_file_buttons.vue4
-rw-r--r--app/assets/javascripts/repo/components/repo_file_options.vue25
-rw-r--r--app/assets/javascripts/repo/components/repo_loading_file.vue87
-rw-r--r--app/assets/javascripts/repo/components/repo_prev_directory.vue58
-rw-r--r--app/assets/javascripts/repo/components/repo_preview.vue4
-rw-r--r--app/assets/javascripts/repo/components/repo_sidebar.vue84
-rw-r--r--app/assets/javascripts/repo/components/repo_tab.vue51
-rw-r--r--app/assets/javascripts/repo/components/repo_tabs.vue51
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>