Commit a0f7ee43 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'issue-edit-inline-title-field' into 'issue-edit-inline'

Issue inline edit title field

See merge request !11331
parents 47881254 64e159ad
......@@ -7,7 +7,7 @@ import Service from '../services/index';
import Store from '../stores';
import titleComponent from './title.vue';
import descriptionComponent from './description.vue';
import editActions from './edit_actions.vue';
import formComponent from './form.vue';
export default {
props: {
......@@ -41,10 +41,6 @@ export default {
required: false,
default: '',
},
showForm: {
type: Boolean,
required: true,
},
},
data() {
const store = new Store({
......@@ -56,17 +52,31 @@ export default {
return {
store,
state: store.state,
formState: store.formState,
showForm: false,
};
},
computed: {
formState() {
return this.store.formState;
},
},
components: {
descriptionComponent,
titleComponent,
editActions,
formComponent,
},
methods: {
openForm() {
this.showForm = true;
this.store.formState = {
title: this.state.titleText,
};
},
closeForm() {
this.showForm = false;
},
updateIssuable() {
this.service.updateIssuable(this.formState)
this.service.updateIssuable(this.store.formState)
.then(() => {
eventHub.$emit('close.form');
})
......@@ -117,29 +127,36 @@ export default {
eventHub.$on('delete.issuable', this.deleteIssuable);
eventHub.$on('update.issuable', this.updateIssuable);
eventHub.$on('close.form', this.closeForm);
eventHub.$on('open.form', this.openForm);
},
beforeDestroy() {
eventHub.$off('delete.issuable', this.deleteIssuable);
eventHub.$off('update.issuable', this.updateIssuable);
eventHub.$off('close.form', this.closeForm);
eventHub.$off('open.form', this.openForm);
},
};
</script>
<template>
<div>
<title-component
:issuable-ref="issuableRef"
:title-html="state.titleHtml"
:title-text="state.titleText" />
<description-component
v-if="state.descriptionHtml"
:can-update="canUpdate"
:description-html="state.descriptionHtml"
:description-text="state.descriptionText"
:updated-at="state.updatedAt"
:task-status="state.taskStatus" />
<edit-actions
<form-component
v-if="canUpdate && showForm"
:form-state="formState"
:can-destroy="canDestroy" />
<div v-else>
<title-component
:issuable-ref="issuableRef"
:title-html="state.titleHtml"
:title-text="state.titleText" />
<description-component
v-if="state.descriptionHtml"
:can-update="canUpdate"
:description-html="state.descriptionHtml"
:description-text="state.descriptionText"
:updated-at="state.updatedAt"
:task-status="state.taskStatus" />
</div>
</div>
</template>
<script>
export default {
props: {
formState: {
type: Object,
required: true,
},
},
};
</script>
<template>
<fieldset>
<label
class="sr-only"
for="issue-title">
Title
</label>
<input
id="issue-title"
class="form-control"
type="text"
placeholder="Issue title"
aria-label="Issue title"
v-model="formState.title" />
</fieldset>
</template>
<script>
import titleField from './fields/title.vue';
import editActions from './edit_actions.vue';
export default {
props: {
canDestroy: {
type: Boolean,
required: true,
},
formState: {
type: Object,
required: true,
},
},
components: {
titleField,
editActions,
},
};
</script>
<template>
<form>
<title-field
:form-state="formState" />
<edit-actions
:can-destroy="canDestroy" />
</form>
</template>
......@@ -35,25 +35,8 @@ document.addEventListener('DOMContentLoaded', () => {
initialTitle: issuableTitleElement.innerHTML,
initialDescriptionHtml: issuableDescriptionElement ? issuableDescriptionElement.innerHTML : '',
initialDescriptionText: issuableDescriptionTextarea ? issuableDescriptionTextarea.textContent : '',
showForm: false,
};
},
methods: {
openForm() {
this.showForm = true;
},
closeForm() {
this.showForm = false;
},
},
created() {
eventHub.$on('open.form', this.openForm);
eventHub.$on('close.form', this.closeForm);
},
beforeDestroy() {
eventHub.$off('open.form', this.openForm);
eventHub.$off('close.form', this.closeForm);
},
render(createElement) {
return createElement('issuable-app', {
props: {
......@@ -64,7 +47,6 @@ document.addEventListener('DOMContentLoaded', () => {
initialTitle: this.initialTitle,
initialDescriptionHtml: this.initialDescriptionHtml,
initialDescriptionText: this.initialDescriptionText,
showForm: this.showForm,
},
});
},
......
......@@ -12,7 +12,9 @@ export default class Store {
taskStatus: '',
updatedAt: '',
};
this.formState = {};
this.formState = {
title: '',
};
}
updateState(data) {
......
......@@ -75,6 +75,18 @@ describe('Issuable output', () => {
});
});
it('changes element for `form` when open', (done) => {
vm.showForm = true;
Vue.nextTick(() => {
expect(
vm.$el.tagName,
).toBe('FORM');
done();
});
});
it('does not show actions if permissions are incorrect', (done) => {
vm.showForm = true;
vm.canUpdate = false;
......
import Vue from 'vue';
import Store from '~/issue_show/stores';
import titleField from '~/issue_show/components/fields/title.vue';
describe('Title field component', () => {
let vm;
let store;
beforeEach(() => {
const Component = Vue.extend(titleField);
store = new Store({
titleHtml: '',
descriptionHtml: '',
issuableRef: '',
});
store.formState.title = 'test';
vm = new Component({
propsData: {
formState: store.formState,
},
}).$mount();
});
it('renders form control with formState title', () => {
expect(
vm.$el.querySelector('.form-control').value,
).toBe('test');
});
});
import Vue from 'vue';
import Store from '~/issue_show/stores';
import titleComponent from '~/issue_show/components/title.vue';
describe('Title component', () => {
......@@ -6,18 +7,25 @@ describe('Title component', () => {
beforeEach(() => {
const Component = Vue.extend(titleComponent);
const store = new Store({
titleHtml: '',
descriptionHtml: '',
issuableRef: '',
});
vm = new Component({
propsData: {
issuableRef: '#1',
titleHtml: 'Testing <img />',
titleText: 'Testing',
showForm: false,
formState: store.formState,
},
}).$mount();
});
it('renders title HTML', () => {
expect(
vm.$el.innerHTML.trim(),
vm.$el.querySelector('h2').innerHTML.trim(),
).toBe('Testing <img>');
});
......@@ -39,12 +47,12 @@ describe('Title component', () => {
Vue.nextTick(() => {
expect(
vm.$el.classList.contains('issue-realtime-pre-pulse'),
vm.$el.querySelector('h2').classList.contains('issue-realtime-pre-pulse'),
).toBeTruthy();
setTimeout(() => {
expect(
vm.$el.classList.contains('issue-realtime-trigger-pulse'),
vm.$el.querySelector('h2').classList.contains('issue-realtime-trigger-pulse'),
).toBeTruthy();
done();
......
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