Add inline edit button to issue_show app
This commit is contained in:
parent
951dab3bf7
commit
baf07e914d
6 changed files with 119 additions and 17 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue