Skip to content
Snippets Groups Projects
Commit e6d87021 authored by Jacob Schatz's avatar Jacob Schatz
Browse files

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

Repo Editor Fixes

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