Merge branch 'add-inline-edit-button' into 'master'

Add inline edit button to issue_show app

See merge request gitlab-org/gitlab-ce!14875
This commit is contained in:
Filipa Lacerda 2017-10-17 17:04:33 +00:00
commit c3d3103840
6 changed files with 119 additions and 17 deletions

View file

@ -24,6 +24,11 @@ export default {
required: true,
type: Boolean,
},
showInlineEditButton: {
type: Boolean,
required: false,
default: false,
},
issuableRef: {
type: String,
required: true,
@ -222,20 +227,25 @@ export default {
<div v-else>
<title-component
:issuable-ref="issuableRef"
:can-update="canUpdate"
:title-html="state.titleHtml"
:title-text="state.titleText" />
:title-text="state.titleText"
:show-inline-edit-button="showInlineEditButton"
/>
<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" />
:task-status="state.taskStatus"
/>
<edited-component
v-if="hasUpdated"
:updated-at="state.updatedAt"
:updated-by-name="state.updatedByName"
:updated-by-path="state.updatedByPath" />
:updated-by-path="state.updatedByPath"
/>
</div>
</div>
</template>

View file

@ -1,5 +1,8 @@
<script>
import animateMixin from '../mixins/animate';
import eventHub from '../event_hub';
import tooltip from '../../vue_shared/directives/tooltip';
import { spriteIcon } from '../../lib/utils/common_utils';
export default {
mixins: [animateMixin],
@ -15,6 +18,11 @@
type: String,
required: true,
},
canUpdate: {
required: false,
type: Boolean,
default: false,
},
titleHtml: {
type: String,
required: true,
@ -23,6 +31,14 @@
type: String,
required: true,
},
showInlineEditButton: {
type: Boolean,
required: false,
default: false,
},
},
directives: {
tooltip,
},
watch: {
titleHtml() {
@ -30,24 +46,46 @@
this.animateChange();
},
},
computed: {
pencilIcon() {
return spriteIcon('pencil', 'link-highlight');
},
},
methods: {
setPageTitle() {
const currentPageTitleScope = this.titleEl.innerText.split('·');
currentPageTitleScope[0] = `${this.titleText} (${this.issuableRef}) `;
this.titleEl.textContent = currentPageTitleScope.join('·');
},
edit() {
eventHub.$emit('open.form');
},
},
};
</script>
<template>
<h2
class="title"
:class="{
'issue-realtime-pre-pulse': preAnimation,
'issue-realtime-trigger-pulse': pulseAnimation
}"
v-html="titleHtml"
>
</h2>
<div class="title-container">
<h2
class="title"
:class="{
'issue-realtime-pre-pulse': preAnimation,
'issue-realtime-trigger-pulse': pulseAnimation
}"
v-html="titleHtml"
>
</h2>
<button
v-tooltip
v-if="showInlineEditButton && canUpdate"
type="button"
class="btn-blank btn-edit note-action-button"
v-html="pencilIcon"
title="Edit title and description"
data-placement="bottom"
data-container="body"
@click="edit"
>
</button>
</div>
</template>

View file

@ -72,12 +72,22 @@
}
}
.title-container {
display: flex;
}
.title {
padding: 0;
margin-bottom: 16px;
border-bottom: none;
}
.btn-edit {
margin-left: auto;
// Set height to match title height
height: 2em;
}
// Border around images in issue and MR descriptions.
.description img:not(.emoji) {
border: 1px solid $white-normal;

View file

@ -531,14 +531,13 @@ ul.notes {
padding: 0;
min-width: 16px;
color: $gray-darkest;
fill: $gray-darkest;
.fa {
position: relative;
font-size: 16px;
}
svg {
height: 16px;
width: 16px;
@ -566,6 +565,7 @@ ul.notes {
.link-highlight {
color: $gl-link-color;
fill: $gl-link-color;
svg {
fill: $gl-link-color;

View file

@ -332,4 +332,15 @@ describe('Issuable output', () => {
.catch(done.fail);
});
});
describe('show inline edit button', () => {
it('should not render by default', () => {
expect(vm.$el.querySelector('.title-container .note-action-button')).toBeDefined();
});
it('should render if showInlineEditButton', () => {
vm.showInlineEditButton = true;
expect(vm.$el.querySelector('.title-container .note-action-button')).toBeDefined();
});
});
});

View file

@ -1,6 +1,7 @@
import Vue from 'vue';
import Store from '~/issue_show/stores';
import titleComponent from '~/issue_show/components/title.vue';
import eventHub from '~/issue_show/event_hub';
describe('Title component', () => {
let vm;
@ -25,7 +26,7 @@ describe('Title component', () => {
it('renders title HTML', () => {
expect(
vm.$el.innerHTML.trim(),
vm.$el.querySelector('.title').innerHTML.trim(),
).toBe('Testing <img>');
});
@ -47,12 +48,12 @@ describe('Title component', () => {
Vue.nextTick(() => {
expect(
vm.$el.classList.contains('issue-realtime-pre-pulse'),
vm.$el.querySelector('.title').classList.contains('issue-realtime-pre-pulse'),
).toBeTruthy();
setTimeout(() => {
expect(
vm.$el.classList.contains('issue-realtime-trigger-pulse'),
vm.$el.querySelector('.title').classList.contains('issue-realtime-trigger-pulse'),
).toBeTruthy();
done();
@ -72,4 +73,36 @@ describe('Title component', () => {
done();
});
});
describe('inline edit button', () => {
beforeEach(() => {
spyOn(eventHub, '$emit');
});
it('should not show by default', () => {
expect(vm.$el.querySelector('.note-action-button')).toBeNull();
});
it('should not show if canUpdate is false', () => {
vm.showInlineEditButton = true;
vm.canUpdate = false;
expect(vm.$el.querySelector('.note-action-button')).toBeNull();
});
it('should show if showInlineEditButton and canUpdate', () => {
vm.showInlineEditButton = true;
vm.canUpdate = true;
expect(vm.$el.querySelector('.note-action-button')).toBeDefined();
});
it('should trigger open.form event when clicked', () => {
vm.showInlineEditButton = true;
vm.canUpdate = true;
Vue.nextTick(() => {
vm.$el.querySelector('.note-action-button').click();
expect(eventHub.$emit).toHaveBeenCalledWith('open.form');
});
});
});
});