Commit 6639a3cd authored by Phil Hughes's avatar Phil Hughes

Merge branch '33533-related-issues-ux-improvements' into 'master'

Related Issues UX improvements - loading

See merge request !2246
parents 0b86b67a ad21d826
<script>
import GfmAutoComplete from '~/gfm_auto_complete';
import eventHub from '../event_hub';
import IssueToken from './issue_token.vue';
import issueToken from './issue_token.vue';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
export default {
name: 'AddIssuableForm',
......@@ -40,7 +41,8 @@ export default {
},
components: {
issueToken: IssueToken,
issueToken,
loadingIcon,
},
computed: {
......@@ -139,6 +141,11 @@ export default {
@click="onFormSubmit"
:disabled="isSubmitButtonDisabled">
{{ addButtonLabel }}
<loadingIcon
ref="loadingIcon"
v-if="isSubmitting"
:inline="true"
label="Submitting related issues" />
</button>
<button
type="button"
......
......@@ -70,6 +70,12 @@ export default {
hasRelatedIssues() {
return this.relatedIssues.length > 0;
},
shouldShowTokenBody() {
return this.hasRelatedIssues || this.isFetching;
},
hasBody() {
return this.isFormVisible || this.shouldShowTokenBody;
},
relatedIssueCount() {
return this.relatedIssues.length;
},
......@@ -92,46 +98,38 @@ export default {
class="panel-slim panel-default">
<div
class="panel-heading"
:class="{ 'panel-empty-heading': !this.hasRelatedIssues }">
<h3 class="panel-title related-issues-panel-title">
<div>
Related issues
<a
v-if="hasHelpPath"
:href="helpPath">
:class="{ 'panel-empty-heading': !this.hasBody }">
<h3 class="panel-title">
Related issues
<a
v-if="hasHelpPath"
:href="helpPath">
<i
class="related-issues-header-help-icon fa fa-question-circle"
aria-label="Read more about related issues">
</i>
</a>
<div class="js-related-issues-header-issue-count related-issues-header-issue-count issue-count-badge">
<span
class="issue-count-badge-count"
:class="{ 'has-btn': this.canAddRelatedIssues }">
{{ relatedIssueCount }}
</span>
<button
v-if="canAddRelatedIssues"
v-tooltip
ref="issueCountBadgeAddButton"
type="button"
class="js-issue-count-badge-add-button issue-count-badge-add-button btn btn-small btn-default"
title="Add an issue"
aria-label="Add an issue"
data-placement="top"
@click="toggleAddRelatedIssuesForm">
<i
class="related-issues-header-help-icon fa fa-question-circle"
aria-label="Read more about related issues">
class="fa fa-plus"
aria-hidden="true">
</i>
</a>
<div class="js-related-issues-header-issue-count related-issues-header-issue-count issue-count-badge">
<span
class="issue-count-badge-count"
:class="{ 'has-btn': this.canAddRelatedIssues }">
{{ relatedIssueCount }}
</span>
<button
v-if="canAddRelatedIssues"
v-tooltip
ref="issueCountBadgeAddButton"
type="button"
class="js-issue-count-badge-add-button issue-count-badge-add-button btn btn-small btn-default"
title="Add an issue"
aria-label="Add an issue"
data-placement="top"
@click="toggleAddRelatedIssuesForm">
<i
class="fa fa-plus"
aria-hidden="true">
</i>
</button>
</div>
</div>
<div>
<loadingIcon
ref="loadingIcon"
v-if="isFetching"
label="Fetching related issues" />
</button>
</div>
</h3>
</div>
......@@ -149,8 +147,17 @@ export default {
:auto-complete-sources="autoCompleteSources" />
</div>
<div
v-if="hasRelatedIssues"
class="related-issues-token-body panel-body">
class="related-issues-token-body panel-body"
:class="{
'collapsed': !shouldShowTokenBody
}">
<div
v-if="isFetching"
class="related-issues-loading-icon">
<loadingIcon
ref="loadingIcon"
label="Fetching related issues" />
</div>
<ul
class="related-issues-token-list">
<li
......
......@@ -12,9 +12,18 @@
required: false,
default: '1',
},
inline: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
rootElementType() {
return this.inline ? 'span' : 'div';
},
cssClass() {
return `fa-${this.size}x`;
},
......@@ -22,12 +31,14 @@
};
</script>
<template>
<div class="text-center">
<component
:is="this.rootElementType"
class="text-center">
<i
class="fa fa-spin fa-spinner"
:class="cssClass"
aria-hidden="true"
:aria-label="label">
</i>
</div>
</component>
</template>
......@@ -4,11 +4,6 @@ $token_spacing_bottom: 0.5em;
margin-top: 3 * $gl-vert-padding;
}
.related-issues-panel-title {
display: flex;
justify-content: space-between;
}
.related-issues-header-help-icon {
margin-left: 0.25em;
color: $gl-text-color-secondary;
......@@ -24,6 +19,22 @@ $token_spacing_bottom: 0.5em;
.related-issues-token-body {
padding-bottom: calc(#{$gl-padding} - #{$token_spacing_bottom});
transition-property: max-height, padding, opacity;
transition-duration: $general-hover-transition-duration;
transition-timing-function: $general-hover-transition-curve;
&.collapsed {
overflow: hidden;
max-height: 0;
padding-top: 0;
padding-bottom: 0;
opacity: 0;
}
}
.related-issues-loading-icon {
margin-bottom: $token_spacing_bottom;
line-height: 1.75;
}
.related-issues-token-list {
......
......@@ -72,6 +72,11 @@
.js-related-issues-root{ data: { endpoint: namespace_project_issue_links_path(@project.namespace, @project, @issue),
can_add_related_issues: "#{can?(current_user, :update_issue, @issue)}",
help_path: help_page_path('user/project/issues/related_issues') } }
.related-issues-block
.panel-slim.panel-default
.panel-heading.panel-empty-heading
%h3.panel-title
Related issues
#merge-requests{ data: { url: referenced_merge_requests_namespace_project_issue_url(@project.namespace, @project, @issue) } }
// This element is filled in using JavaScript.
......
......@@ -39,32 +39,72 @@ describe('AddIssuableForm', () => {
});
describe('with data', () => {
const inputValue = 'foo #123';
const addButtonLabel = 'Add issuable';
describe('without references', () => {
beforeEach(() => {
vm = new AddIssuableForm({
propsData: {
inputValue: '',
addButtonLabel: 'Submit',
pendingReferences: [],
},
}).$mount();
});
beforeEach(() => {
vm = new AddIssuableForm({
propsData: {
inputValue,
addButtonLabel,
pendingReferences: [
issuable1.reference,
issuable2.reference,
],
},
}).$mount();
it('should have disabled submit button', () => {
expect(vm.$refs.addButton.disabled).toBe(true);
expect(vm.$refs.loadingIcon).toBeUndefined();
});
});
it('should put button label in place', () => {
expect(vm.$refs.addButton.textContent.trim()).toEqual(addButtonLabel);
});
describe('with references', () => {
const inputValue = 'foo #123';
const addButtonLabel = 'Add issuable';
beforeEach(() => {
vm = new AddIssuableForm({
propsData: {
inputValue,
addButtonLabel,
pendingReferences: [
issuable1.reference,
issuable2.reference,
],
},
}).$mount();
});
it('should put input value in place', () => {
expect(vm.$refs.input.value).toEqual(inputValue);
it('should put button label in place', () => {
expect(vm.$refs.addButton.textContent.trim()).toEqual(addButtonLabel);
});
it('should put input value in place', () => {
expect(vm.$refs.input.value).toEqual(inputValue);
});
it('should render pending issuables items', () => {
expect(vm.$el.querySelectorAll('.js-add-issuable-form-token-list-item').length).toEqual(2);
});
});
it('should render pending issuables items', () => {
expect(vm.$el.querySelectorAll('.js-add-issuable-form-token-list-item').length).toEqual(2);
describe('when submitting', () => {
beforeEach(() => {
vm = new AddIssuableForm({
propsData: {
inputValue: '',
addButtonLabel: 'Submit',
pendingReferences: [
issuable1.reference,
issuable2.reference,
],
isSubmitting: true,
},
}).$mount();
});
it('should have disabled submit button with loading icon', () => {
expect(vm.$refs.addButton.disabled).toBe(true);
expect(vm.$refs.loadingIcon).toBeDefined();
});
});
});
......
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