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:
commit
c3d3103840
|
@ -24,6 +24,11 @@ export default {
|
||||||
required: true,
|
required: true,
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
|
showInlineEditButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
issuableRef: {
|
issuableRef: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -222,20 +227,25 @@ export default {
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<title-component
|
<title-component
|
||||||
:issuable-ref="issuableRef"
|
:issuable-ref="issuableRef"
|
||||||
|
:can-update="canUpdate"
|
||||||
:title-html="state.titleHtml"
|
:title-html="state.titleHtml"
|
||||||
:title-text="state.titleText" />
|
:title-text="state.titleText"
|
||||||
|
:show-inline-edit-button="showInlineEditButton"
|
||||||
|
/>
|
||||||
<description-component
|
<description-component
|
||||||
v-if="state.descriptionHtml"
|
v-if="state.descriptionHtml"
|
||||||
:can-update="canUpdate"
|
:can-update="canUpdate"
|
||||||
:description-html="state.descriptionHtml"
|
:description-html="state.descriptionHtml"
|
||||||
:description-text="state.descriptionText"
|
:description-text="state.descriptionText"
|
||||||
:updated-at="state.updatedAt"
|
:updated-at="state.updatedAt"
|
||||||
:task-status="state.taskStatus" />
|
:task-status="state.taskStatus"
|
||||||
|
/>
|
||||||
<edited-component
|
<edited-component
|
||||||
v-if="hasUpdated"
|
v-if="hasUpdated"
|
||||||
:updated-at="state.updatedAt"
|
:updated-at="state.updatedAt"
|
||||||
:updated-by-name="state.updatedByName"
|
:updated-by-name="state.updatedByName"
|
||||||
:updated-by-path="state.updatedByPath" />
|
:updated-by-path="state.updatedByPath"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import animateMixin from '../mixins/animate';
|
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 {
|
export default {
|
||||||
mixins: [animateMixin],
|
mixins: [animateMixin],
|
||||||
|
@ -15,6 +18,11 @@
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
canUpdate: {
|
||||||
|
required: false,
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
titleHtml: {
|
titleHtml: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -23,6 +31,14 @@
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
showInlineEditButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
tooltip,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
titleHtml() {
|
titleHtml() {
|
||||||
|
@ -30,24 +46,46 @@
|
||||||
this.animateChange();
|
this.animateChange();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
pencilIcon() {
|
||||||
|
return spriteIcon('pencil', 'link-highlight');
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setPageTitle() {
|
setPageTitle() {
|
||||||
const currentPageTitleScope = this.titleEl.innerText.split('·');
|
const currentPageTitleScope = this.titleEl.innerText.split('·');
|
||||||
currentPageTitleScope[0] = `${this.titleText} (${this.issuableRef}) `;
|
currentPageTitleScope[0] = `${this.titleText} (${this.issuableRef}) `;
|
||||||
this.titleEl.textContent = currentPageTitleScope.join('·');
|
this.titleEl.textContent = currentPageTitleScope.join('·');
|
||||||
},
|
},
|
||||||
|
edit() {
|
||||||
|
eventHub.$emit('open.form');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h2
|
<div class="title-container">
|
||||||
class="title"
|
<h2
|
||||||
:class="{
|
class="title"
|
||||||
'issue-realtime-pre-pulse': preAnimation,
|
:class="{
|
||||||
'issue-realtime-trigger-pulse': pulseAnimation
|
'issue-realtime-pre-pulse': preAnimation,
|
||||||
}"
|
'issue-realtime-trigger-pulse': pulseAnimation
|
||||||
v-html="titleHtml"
|
}"
|
||||||
>
|
v-html="titleHtml"
|
||||||
</h2>
|
>
|
||||||
|
</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>
|
</template>
|
||||||
|
|
|
@ -72,12 +72,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-edit {
|
||||||
|
margin-left: auto;
|
||||||
|
// Set height to match title height
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
// Border around images in issue and MR descriptions.
|
// Border around images in issue and MR descriptions.
|
||||||
.description img:not(.emoji) {
|
.description img:not(.emoji) {
|
||||||
border: 1px solid $white-normal;
|
border: 1px solid $white-normal;
|
||||||
|
|
|
@ -531,14 +531,13 @@ ul.notes {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
min-width: 16px;
|
min-width: 16px;
|
||||||
color: $gray-darkest;
|
color: $gray-darkest;
|
||||||
|
fill: $gray-darkest;
|
||||||
|
|
||||||
.fa {
|
.fa {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
|
@ -566,6 +565,7 @@ ul.notes {
|
||||||
|
|
||||||
.link-highlight {
|
.link-highlight {
|
||||||
color: $gl-link-color;
|
color: $gl-link-color;
|
||||||
|
fill: $gl-link-color;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
fill: $gl-link-color;
|
fill: $gl-link-color;
|
||||||
|
|
|
@ -332,4 +332,15 @@ describe('Issuable output', () => {
|
||||||
.catch(done.fail);
|
.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 Vue from 'vue';
|
||||||
import Store from '~/issue_show/stores';
|
import Store from '~/issue_show/stores';
|
||||||
import titleComponent from '~/issue_show/components/title.vue';
|
import titleComponent from '~/issue_show/components/title.vue';
|
||||||
|
import eventHub from '~/issue_show/event_hub';
|
||||||
|
|
||||||
describe('Title component', () => {
|
describe('Title component', () => {
|
||||||
let vm;
|
let vm;
|
||||||
|
@ -25,7 +26,7 @@ describe('Title component', () => {
|
||||||
|
|
||||||
it('renders title HTML', () => {
|
it('renders title HTML', () => {
|
||||||
expect(
|
expect(
|
||||||
vm.$el.innerHTML.trim(),
|
vm.$el.querySelector('.title').innerHTML.trim(),
|
||||||
).toBe('Testing <img>');
|
).toBe('Testing <img>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,12 +48,12 @@ describe('Title component', () => {
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
expect(
|
expect(
|
||||||
vm.$el.classList.contains('issue-realtime-pre-pulse'),
|
vm.$el.querySelector('.title').classList.contains('issue-realtime-pre-pulse'),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(
|
expect(
|
||||||
vm.$el.classList.contains('issue-realtime-trigger-pulse'),
|
vm.$el.querySelector('.title').classList.contains('issue-realtime-trigger-pulse'),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
@ -72,4 +73,36 @@ describe('Title component', () => {
|
||||||
done();
|
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 New Issue