Commit c269a1b4 authored by Bryce Johnson's avatar Bryce Johnson Committed by Eric Eastwood

Repo Editor Fixes

Conflicts:
	app/assets/javascripts/repo/components/repo_edit_button.vue
	app/assets/javascripts/repo/components/repo_editor.vue
	app/assets/javascripts/repo/components/repo_tab.vue
	app/assets/javascripts/repo/components/repo_tabs.vue
	app/assets/javascripts/repo/helpers/repo_helper.js
	app/assets/javascripts/repo/services/repo_service.js
	app/assets/javascripts/vue_shared/components/popup_dialog.vue
	app/assets/stylesheets/pages/repo.scss
	app/views/shared/repo/_repo.html.haml
	spec/javascripts/repo/components/repo_edit_button_spec.js
parent f034190e
......@@ -142,7 +142,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()}`);
}
}
}
......
......@@ -4,7 +4,7 @@ import Store from '../stores/repo_store';
import RepoMixin from '../mixins/repo_mixin';
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>
......
......@@ -26,12 +26,15 @@ export default {
this.editMode = !this.editMode;
Store.toggleBlobView();
},
toggleProjectRefsForm() {
$('.project-refs-form').toggleClass('disabled', this.editMode);
$('.js-tree-ref-target-holder').toggle(this.editMode);
},
},
watch: {
editMode() {
$('.project-refs-form').toggleClass('disabled', this.editMode);
$('.js-tree-ref-target-holder').toggle(this.editMode);
this.toggleProjectRefsForm();
},
},
};
......
......@@ -74,10 +74,6 @@ const RepoEditor = {
},
watch: {
activeFileLabel() {
this.showHide();
},
dialog: {
handler(obj) {
const newObj = obj;
......@@ -100,29 +96,22 @@ const RepoEditor = {
deep: true,
},
isTree() {
this.showHide();
},
openedFiles() {
this.showHide();
},
binary() {
this.showHide();
},
blobRaw() {
if (Helper.monacoInstance && !this.isTree) {
this.setupEditor();
}
},
},
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,8 +59,6 @@ const RepoSidebar = {
},
},
};
export default RepoSidebar;
</script>
<template>
......
......@@ -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.stop.prevent="xClicked(tab)"
@click.stop.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,9 +23,14 @@ export default RepoTabs;
</script>
<template>
<ul
id="tabs">
<repo-tab v-for="tab in openedFiles" :key="tab.id" :tab="tab" :class="{'active' : tab.active}" @xclicked="xClicked"/>
<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>
</template>
......@@ -64,7 +64,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;
},
......@@ -247,7 +247,7 @@ const RepoHelper = {
return RepoHelper.Time.now().toFixed(3);
},
toURL(url, title) {
updateHistoryEntry(url, title) {
const history = window.history;
RepoHelper.key = RepoHelper.genKey();
......
......@@ -45,6 +45,9 @@ function initRepo(el) {
components: {
repo: Repo,
},
render(createElement) {
return createElement('repo');
},
});
}
......
......@@ -84,7 +84,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: {
title: String,
body: String,
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,
};
},
},
......@@ -32,33 +39,48 @@ 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-dialog" role="document">
<div
class="modal popup-dialog"
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,
......@@ -134,7 +129,6 @@
a {
@include str-truncated(100px);
color: $black;
display: inline-block;
width: 100px;
text-align: center;
vertical-align: middle;
......
#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, on_top_of_branch: (!!on_top_of_branch?(project, @ref)).to_s } }
%repo
#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,
on_top_of_branch: (!!on_top_of_branch?(project, @ref)).to_s } }
......@@ -21,11 +21,13 @@ describe('RepoEditButton', () => {
expect(vm.$el.textContent).toMatch('Edit');
spyOn(vm, 'editCancelClicked').and.callThrough();
spyOn(vm, 'toggleProjectRefsForm');
vm.$el.click();
Vue.nextTick(() => {
expect(vm.editCancelClicked).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);
});
});
});
......
......@@ -30,13 +30,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