diff options
author | Clement Ho <clemmakesapps@gmail.com> | 2017-10-17 17:04:33 +0000 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-10-17 17:04:33 +0000 |
commit | baf07e914d744f9c6b4daa6f84b96d506f1ffe46 (patch) | |
tree | 9b5bed2891e89762dfdb55ba46ea63216a846486 | |
parent | 951dab3bf793ff00e785815c308a8379e9d58a60 (diff) | |
download | gitlab-ce-baf07e914d744f9c6b4daa6f84b96d506f1ffe46.tar.gz |
Add inline edit button to issue_show app
-rw-r--r-- | app/assets/javascripts/issue_show/components/app.vue | 16 | ||||
-rw-r--r-- | app/assets/javascripts/issue_show/components/title.vue | 56 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/issuable.scss | 10 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/notes.scss | 4 | ||||
-rw-r--r-- | spec/javascripts/issue_show/components/app_spec.js | 11 | ||||
-rw-r--r-- | spec/javascripts/issue_show/components/title_spec.js | 39 |
6 files changed, 119 insertions, 17 deletions
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index eecb56cb185..d1aa83ea57f 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -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> diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue index a9dabd4cff1..00002709ac6 100644 --- a/app/assets/javascripts/issue_show/components/title.vue +++ b/app/assets/javascripts/issue_show/components/title.vue @@ -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> diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index c93c4e93af5..48532503263 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -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; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 96b7db3b85d..ebad429c2ba 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -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; diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 583a3a74d77..2ea290108a4 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -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(); + }); + }); }); diff --git a/spec/javascripts/issue_show/components/title_spec.js b/spec/javascripts/issue_show/components/title_spec.js index a2d90a9b9f5..c1edc785d0f 100644 --- a/spec/javascripts/issue_show/components/title_spec.js +++ b/spec/javascripts/issue_show/components/title_spec.js @@ -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'); + }); + }); + }); }); |