Commit e6d87021 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'bpj-repo-editor-fixes' into 'master'

Repo Editor Fixes

See merge request !13468
parents f82d8a22 85519977
...@@ -130,7 +130,7 @@ import Cookies from 'js-cookie'; ...@@ -130,7 +130,7 @@ import Cookies from 'js-cookie';
var action = $form.attr('action'); var action = $form.attr('action');
var divider = action.indexOf('?') === -1 ? '?' : '&'; var divider = action.indexOf('?') === -1 ? '?' : '&';
if (shouldVisit) { if (shouldVisit) {
gl.utils.visitUrl(action + '' + divider + '' + $form.serialize()); gl.utils.visitUrl(`${action}${divider}${$form.serialize()}`);
} }
} }
} }
......
...@@ -5,7 +5,7 @@ import RepoMixin from '../mixins/repo_mixin'; ...@@ -5,7 +5,7 @@ import RepoMixin from '../mixins/repo_mixin';
import Helper from '../helpers/repo_helper'; import Helper from '../helpers/repo_helper';
import Service from '../services/repo_service'; import Service from '../services/repo_service';
const RepoCommitSection = { export default {
data: () => Store, data: () => Store,
mixins: [RepoMixin], mixins: [RepoMixin],
...@@ -54,8 +54,6 @@ const RepoCommitSection = { ...@@ -54,8 +54,6 @@ const RepoCommitSection = {
}, },
}, },
}; };
export default RepoCommitSection;
</script> </script>
<template> <template>
......
...@@ -23,19 +23,21 @@ export default { ...@@ -23,19 +23,21 @@ export default {
this.editMode = !this.editMode; this.editMode = !this.editMode;
Store.toggleBlobView(); Store.toggleBlobView();
}, },
}, toggleProjectRefsForm() {
watch: {
editMode() {
if (this.editMode) { if (this.editMode) {
$('.project-refs-form').addClass('disabled'); $('.project-refs-form').addClass('disabled-content');
$('.js-tree-ref-target-holder').show(); $('.project-refs-target-form').show();
} else { } else {
$('.project-refs-form').removeClass('disabled'); $('.project-refs-form').removeClass('disabled-content');
$('.js-tree-ref-target-holder').hide(); $('.project-refs-target-form').hide();
} }
}, },
}, },
watch: {
editMode() {
this.toggleProjectRefsForm();
},
},
}; };
</script> </script>
......
...@@ -32,7 +32,6 @@ const RepoEditor = { ...@@ -32,7 +32,6 @@ const RepoEditor = {
const languages = this.monaco.languages.getLanguages(); const languages = this.monaco.languages.getLanguages();
const languageID = Helper.getLanguageIDForFile(this.activeFile, languages); const languageID = Helper.getLanguageIDForFile(this.activeFile, languages);
this.showHide();
const newModel = this.monaco.editor.createModel(this.blobRaw, languageID); const newModel = this.monaco.editor.createModel(this.blobRaw, languageID);
this.monacoInstance.setModel(newModel); this.monacoInstance.setModel(newModel);
...@@ -40,14 +39,6 @@ const RepoEditor = { ...@@ -40,14 +39,6 @@ const RepoEditor = {
}, },
methods: { methods: {
showHide() {
if (!this.openedFiles.length || (this.binary && !this.activeFile.raw)) {
this.$el.style.display = 'none';
} else {
this.$el.style.display = 'inline-block';
}
},
addMonacoEvents() { addMonacoEvents() {
this.monacoInstance.onMouseUp(this.onMonacoEditorMouseUp); this.monacoInstance.onMouseUp(this.onMonacoEditorMouseUp);
this.monacoInstance.onKeyUp(this.onMonacoEditorKeysPressed.bind(this)); this.monacoInstance.onKeyUp(this.onMonacoEditorKeysPressed.bind(this));
...@@ -73,11 +64,6 @@ const RepoEditor = { ...@@ -73,11 +64,6 @@ const RepoEditor = {
column: 1, column: 1,
}); });
}, },
activeFileLabel() {
this.showHide();
},
dialog: { dialog: {
handler(obj) { handler(obj) {
const newObj = obj; const newObj = obj;
...@@ -99,21 +85,7 @@ const RepoEditor = { ...@@ -99,21 +85,7 @@ const RepoEditor = {
deep: true, deep: true,
}, },
isTree() {
this.showHide();
},
openedFiles() {
this.showHide();
},
binary() {
this.showHide();
},
blobRaw() { blobRaw() {
this.showHide();
if (this.isTree) return; if (this.isTree) return;
this.monacoInstance.setModel(null); this.monacoInstance.setModel(null);
...@@ -125,11 +97,16 @@ const RepoEditor = { ...@@ -125,11 +97,16 @@ const RepoEditor = {
this.monacoInstance.setModel(newModel); this.monacoInstance.setModel(newModel);
}, },
}, },
computed: {
shouldHideEditor() {
return !this.openedFiles.length || (this.binary && !this.activeFile.raw);
},
},
}; };
export default RepoEditor; export default RepoEditor;
</script> </script>
<template> <template>
<div id="ide"></div> <div id="ide" v-if='!shouldHideEditor'></div>
</template> </template>
...@@ -8,7 +8,7 @@ import RepoFile from './repo_file.vue'; ...@@ -8,7 +8,7 @@ import RepoFile from './repo_file.vue';
import RepoLoadingFile from './repo_loading_file.vue'; import RepoLoadingFile from './repo_loading_file.vue';
import RepoMixin from '../mixins/repo_mixin'; import RepoMixin from '../mixins/repo_mixin';
const RepoSidebar = { export default {
mixins: [RepoMixin], mixins: [RepoMixin],
components: { components: {
'repo-file-options': RepoFileOptions, 'repo-file-options': RepoFileOptions,
...@@ -59,12 +59,10 @@ const RepoSidebar = { ...@@ -59,12 +59,10 @@ const RepoSidebar = {
}, },
}, },
}; };
export default RepoSidebar;
</script> </script>
<template> <template>
<div id="sidebar" :class="{'sidebar-mini' : isMini}" v-cloak> <div id="sidebar" :class="{'sidebar-mini' : isMini}">
<table class="table"> <table class="table">
<thead v-if="!isMini"> <thead v-if="!isMini">
<tr> <tr>
......
...@@ -28,9 +28,9 @@ const RepoTab = { ...@@ -28,9 +28,9 @@ const RepoTab = {
methods: { methods: {
tabClicked: Store.setActiveFiles, tabClicked: Store.setActiveFiles,
xClicked(file) { closeTab(file) {
if (file.changed) return; if (file.changed) return;
this.$emit('xclicked', file); this.$emit('tabclosed', file);
}, },
}, },
}; };
...@@ -43,7 +43,7 @@ export default RepoTab; ...@@ -43,7 +43,7 @@ export default RepoTab;
<a <a
href="#0" href="#0"
class="close" class="close"
@click.prevent="xClicked(tab)" @click.prevent="closeTab(tab)"
:aria-label="closeLabel"> :aria-label="closeLabel">
<i <i
class="fa" class="fa"
......
...@@ -13,7 +13,7 @@ const RepoTabs = { ...@@ -13,7 +13,7 @@ const RepoTabs = {
data: () => Store, data: () => Store,
methods: { methods: {
xClicked(file) { tabClosed(file) {
Store.removeFromOpenedFiles(file); Store.removeFromOpenedFiles(file);
}, },
}, },
...@@ -23,10 +23,15 @@ export default RepoTabs; ...@@ -23,10 +23,15 @@ export default RepoTabs;
</script> </script>
<template> <template>
<ul <ul id="tabs"
v-if="isMini" v-if="isMini">
id="tabs"> <repo-tab
<repo-tab v-for="tab in openedFiles" :key="tab.id" :tab="tab" :class="{'active' : tab.active}" @xclicked="xClicked"/> v-for="tab in openedFiles"
:key="tab.id"
:tab="tab"
:class="{'active' : tab.active}"
@tabclosed="tabClosed"
/>
<li class="tabs-divider" /> <li class="tabs-divider" />
</ul> </ul>
</template> </template>
...@@ -62,7 +62,7 @@ const RepoHelper = { ...@@ -62,7 +62,7 @@ const RepoHelper = {
file.opened = true; file.opened = true;
file.icon = 'fa-folder-open'; file.icon = 'fa-folder-open';
RepoHelper.toURL(file.url, file.name); RepoHelper.updateHistoryEntry(file.url, file.name);
return file; return file;
}, },
...@@ -276,7 +276,7 @@ const RepoHelper = { ...@@ -276,7 +276,7 @@ const RepoHelper = {
RepoHelper.key = key; RepoHelper.key = key;
}, },
toURL(url, title) { updateHistoryEntry(url, title) {
const history = window.history; const history = window.history;
RepoHelper.key = RepoHelper.genKey(); RepoHelper.key = RepoHelper.genKey();
......
...@@ -43,6 +43,9 @@ function initRepo(el) { ...@@ -43,6 +43,9 @@ function initRepo(el) {
components: { components: {
repo: Repo, repo: Repo,
}, },
render(createElement) {
return createElement('repo');
},
}); });
} }
......
...@@ -15,10 +15,12 @@ const RepoService = { ...@@ -15,10 +15,12 @@ const RepoService = {
checkCurrentBranchIsCommitable() { checkCurrentBranchIsCommitable() {
const url = Store.service.refsUrl; const url = Store.service.refsUrl;
return axios.get(url, { params: { return axios.get(url, {
params: {
ref: Store.currentBranch, ref: Store.currentBranch,
search: Store.currentBranch, search: Store.currentBranch,
} }); },
});
}, },
getRaw(url) { getRaw(url) {
......
...@@ -90,7 +90,7 @@ const RepoStore = { ...@@ -90,7 +90,7 @@ const RepoStore = {
}).catch(Helper.loadingError); }).catch(Helper.loadingError);
} }
if (!file.loading) Helper.toURL(file.url, file.name); if (!file.loading) Helper.updateHistoryEntry(file.url, file.name);
RepoStore.binary = file.binary; RepoStore.binary = file.binary;
}, },
......
<script> <script>
const PopupDialog = { export default {
name: 'popup-dialog', name: 'popup-dialog',
props: { props: {
open: Boolean, open: {
title: String, type: Boolean,
body: String, required: true,
},
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
kind: { kind: {
type: String, type: String,
required: false,
default: 'primary', default: 'primary',
}, },
closeButtonLabel: { closeButtonLabel: {
type: String, type: String,
required: false,
default: 'Cancel', default: 'Cancel',
}, },
primaryButtonLabel: { primaryButtonLabel: {
type: String, type: String,
default: 'Save changes', required: true,
}, },
}, },
computed: { computed: {
typeOfClass() { btnKindClass() {
const className = `btn-${this.kind}`; return {
const returnObj = {}; [`btn-${this.kind}`]: true,
returnObj[className] = true; };
return returnObj;
}, },
}, },
...@@ -33,33 +43,46 @@ const PopupDialog = { ...@@ -33,33 +43,46 @@ const PopupDialog = {
close() { close() {
this.$emit('toggle', false); this.$emit('toggle', false);
}, },
emitSubmit(status) {
yesClick() { this.$emit('submit', status);
this.$emit('submit', true);
},
noClick() {
this.$emit('submit', false);
}, },
}, },
}; };
export default PopupDialog;
</script> </script>
<template> <template>
<div class="modal popup-dialog" tabindex="-1" v-show="open" role="dialog"> <div
class="modal popup-dialog"
v-if="open"
role="dialog"
tabindex="-1">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" @click="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button"
class="close"
@click="close"
aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">{{this.title}}</h4> <h4 class="modal-title">{{this.title}}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>{{this.body}}</p> <p>{{this.body}}</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" @click="noClick">{{closeButtonLabel}}</button> <button
<button type="button" class="btn" :class="typeOfClass" @click="yesClick">{{primaryButtonLabel}}</button> type="button"
class="btn btn-default"
@click="emitSubmit(false)">
{{closeButtonLabel}}
</button>
<button type="button"
class="btn"
:class="btnKindClass"
@click="emitSubmit(true)">
{{primaryButtonLabel}}
</button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -28,11 +28,6 @@ ...@@ -28,11 +28,6 @@
.project-refs-form, .project-refs-form,
.project-refs-target-form { .project-refs-target-form {
display: inline-block; display: inline-block;
&.disabled {
opacity: 0.5;
pointer-events: none;
}
} }
.fade-enter, .fade-enter,
...@@ -133,7 +128,6 @@ ...@@ -133,7 +128,6 @@
a { a {
@include str-truncated(100px); @include str-truncated(100px);
color: $black; color: $black;
display: inline-block;
width: 100px; width: 100px;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
...@@ -298,7 +292,7 @@ ...@@ -298,7 +292,7 @@
} }
.fa { .fa {
font-size: $code_font_size; font-size: 12px;
margin-right: 5px; margin-right: 5px;
} }
} }
......
#repo{ data: { url: content_url, project_name: project.name, refs_url: refs_project_path(project, format: :json), project_url: project_path(project), project_id: project.id, can_commit: (!!can_push_branch?(project, @ref)).to_s } } #repo{ data: { url: content_url, project_name: project.name, refs_url: refs_project_path(project, format: :json), project_url: project_path(project), project_id: project.id, can_commit: (!!can_push_branch?(project, @ref)).to_s } }
%repo
...@@ -19,11 +19,13 @@ describe('RepoEditButton', () => { ...@@ -19,11 +19,13 @@ describe('RepoEditButton', () => {
expect(vm.$el.textContent).toMatch('Edit'); expect(vm.$el.textContent).toMatch('Edit');
spyOn(vm, 'editClicked').and.callThrough(); spyOn(vm, 'editClicked').and.callThrough();
spyOn(vm, 'toggleProjectRefsForm');
vm.$el.click(); vm.$el.click();
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.editClicked).toHaveBeenCalled(); expect(vm.editClicked).toHaveBeenCalled();
expect(vm.toggleProjectRefsForm).toHaveBeenCalled();
expect(vm.$el.textContent).toMatch('Cancel edit'); expect(vm.$el.textContent).toMatch('Cancel edit');
done(); done();
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import repoEditor from '~/repo/components/repo_editor.vue'; import repoEditor from '~/repo/components/repo_editor.vue';
import RepoStore from '~/repo/stores/repo_store';
describe('RepoEditor', () => { describe('RepoEditor', () => {
function createComponent() { beforeEach(() => {
const RepoEditor = Vue.extend(repoEditor); const RepoEditor = Vue.extend(repoEditor);
return new RepoEditor().$mount(); this.vm = new RepoEditor().$mount();
} });
it('renders an ide container', () => { it('renders an ide container', (done) => {
const monacoInstance = jasmine.createSpyObj('monacoInstance', ['onMouseUp', 'onKeyUp', 'setModel', 'updateOptions']); this.vm.openedFiles = ['idiidid'];
const monaco = { this.vm.binary = false;
editor: jasmine.createSpyObj('editor', ['create']),
}; Vue.nextTick(() => {
RepoStore.monaco = monaco; expect(this.vm.shouldHideEditor).toBe(false);
expect(this.vm.$el.id).toEqual('ide');
expect(this.vm.$el.tagName).toBe('DIV');
done();
});
});
describe('when there are no open files', () => {
it('does not render the ide', (done) => {
this.vm.openedFiles = [];
monaco.editor.create.and.returnValue(monacoInstance); Vue.nextTick(() => {
spyOn(repoEditor.watch, 'blobRaw'); expect(this.vm.shouldHideEditor).toBe(true);
expect(this.vm.$el.tagName).not.toBeDefined();
done();
});
});
});
const vm = createComponent(); describe('when open file is binary and not raw', () => {
it('does not render the IDE', (done) => {
this.vm.binary = true;
this.vm.activeFile = {
raw: false,
};
expect(vm.$el.id).toEqual('ide'); Vue.nextTick(() => {
expect(this.vm.shouldHideEditor).toBe(true);
expect(this.vm.$el.tagName).not.toBeDefined();
done();
});
});
}); });
}); });
...@@ -23,6 +23,7 @@ describe('RepoFileButtons', () => { ...@@ -23,6 +23,7 @@ describe('RepoFileButtons', () => {
RepoStore.activeFile = activeFile; RepoStore.activeFile = activeFile;
RepoStore.activeFileLabel = activeFileLabel; RepoStore.activeFileLabel = activeFileLabel;
RepoStore.editMode = true; RepoStore.editMode = true;
RepoStore.binary = false;
const vm = createComponent(); const vm = createComponent();
const raw = vm.$el.querySelector('.raw'); const raw = vm.$el.querySelector('.raw');
......
...@@ -21,7 +21,7 @@ describe('RepoTab', () => { ...@@ -21,7 +21,7 @@ describe('RepoTab', () => {
const close = vm.$el.querySelector('.close'); const close = vm.$el.querySelector('.close');
const name = vm.$el.querySelector(`a[title="${tab.url}"]`); const name = vm.$el.querySelector(`a[title="${tab.url}"]`);
spyOn(vm, 'xClicked'); spyOn(vm, 'closeTab');
spyOn(vm, 'tabClicked'); spyOn(vm, 'tabClicked');
expect(close.querySelector('.fa-times')).toBeTruthy(); expect(close.querySelector('.fa-times')).toBeTruthy();
...@@ -30,7 +30,7 @@ describe('RepoTab', () => { ...@@ -30,7 +30,7 @@ describe('RepoTab', () => {
close.click(); close.click();
name.click(); name.click();
expect(vm.xClicked).toHaveBeenCalledWith(tab); expect(vm.closeTab).toHaveBeenCalledWith(tab);
expect(vm.tabClicked).toHaveBeenCalledWith(tab); expect(vm.tabClicked).toHaveBeenCalledWith(tab);
}); });
...@@ -48,22 +48,22 @@ describe('RepoTab', () => { ...@@ -48,22 +48,22 @@ describe('RepoTab', () => {
}); });
describe('methods', () => { describe('methods', () => {
describe('xClicked', () => { describe('closeTab', () => {
const vm = jasmine.createSpyObj('vm', ['$emit']); const vm = jasmine.createSpyObj('vm', ['$emit']);
it('returns undefined and does not $emit if file is changed', () => { it('returns undefined and does not $emit if file is changed', () => {
const file = { changed: true }; const file = { changed: true };
const returnVal = repoTab.methods.xClicked.call(vm, file); const returnVal = repoTab.methods.closeTab.call(vm, file);
expect(returnVal).toBeUndefined(); expect(returnVal).toBeUndefined();
expect(vm.$emit).not.toHaveBeenCalled(); expect(vm.$emit).not.toHaveBeenCalled();
}); });
it('$emits xclicked event with file obj', () => { it('$emits tabclosed event with file obj', () => {
const file = { changed: false }; const file = { changed: false };
repoTab.methods.xClicked.call(vm, file); repoTab.methods.closeTab.call(vm, file);
expect(vm.$emit).toHaveBeenCalledWith('xclicked', file); expect(vm.$emit).toHaveBeenCalledWith('tabclosed', file);
}); });
}); });
}); });
......
...@@ -38,13 +38,13 @@ describe('RepoTabs', () => { ...@@ -38,13 +38,13 @@ describe('RepoTabs', () => {
}); });
describe('methods', () => { describe('methods', () => {
describe('xClicked', () => { describe('tabClosed', () => {
it('calls removeFromOpenedFiles with file obj', () => { it('calls removeFromOpenedFiles with file obj', () => {
const file = {}; const file = {};
spyOn(RepoStore, 'removeFromOpenedFiles'); spyOn(RepoStore, 'removeFromOpenedFiles');
repoTabs.methods.xClicked(file); repoTabs.methods.tabClosed(file);
expect(RepoStore.removeFromOpenedFiles).toHaveBeenCalledWith(file); expect(RepoStore.removeFromOpenedFiles).toHaveBeenCalledWith(file);
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment