Commit 695caab0 authored by Jacob Schatz's avatar Jacob Schatz Committed by Jarka Kadlecova

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

Repo Editor Fixes

See merge request !13468
parent 7753a0e0
......@@ -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()}`);
}
}
}
......
......@@ -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],
......@@ -54,8 +54,6 @@ const RepoCommitSection = {
},
},
};
export default RepoCommitSection;
</script>
<template>
......
......@@ -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>
......
......@@ -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);
......@@ -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));
......@@ -73,11 +64,6 @@ const RepoEditor = {
column: 1,
});
},
activeFileLabel() {
this.showHide();
},
dialog: {
handler(obj) {
const newObj = obj;
......@@ -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);
......@@ -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>
......@@ -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,
......@@ -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>
......
......@@ -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);
},
},
};
......@@ -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"
......
......@@ -13,7 +13,7 @@ const RepoTabs = {
data: () => Store,
methods: {
xClicked(file) {
tabClosed(file) {
Store.removeFromOpenedFiles(file);
},
},
......@@ -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>
......@@ -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;
},
......@@ -276,7 +276,7 @@ const RepoHelper = {
RepoHelper.key = key;
},
toURL(url, title) {
updateHistoryEntry(url, title) {
const history = window.history;
RepoHelper.key = RepoHelper.genKey();
......
......@@ -43,6 +43,9 @@ function initRepo(el) {
components: {
repo: Repo,
},
render(createElement) {
return createElement('repo');
},
});
}
......
......@@ -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) {
......
......@@ -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;
},
......
<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,
};
},
},
......@@ -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>
......
......@@ -28,11 +28,6 @@
.project-refs-form,
.project-refs-target-form {
display: inline-block;
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
.fade-enter,
......@@ -133,7 +128,6 @@
a {
@include str-truncated(100px);
color: $black;
display: inline-block;
width: 100px;
text-align: center;
vertical-align: middle;
......@@ -298,7 +292,7 @@
}
.fa {
font-size: $code_font_size;
font-size: 12px;
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
......@@ -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();
});
......
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();
});
});
});
});
......@@ -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');
......
......@@ -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();
......@@ -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);
});
......@@ -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);
});
});
});
......
......@@ -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);
});
......
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