Commit 9d759e18 authored by Scott Stern's avatar Scott Stern Committed by Martin Wortschack

Added stateful Apply button to assignees

WIP

Add GlDropdownForm from gitlab ui

Add assignee dropdown multiselect wrapper

Add changelog for assignees multiselect wrapper

Replace component with gitlab ui comp

WIP

Change approach

Add specs

Add spec

Add changelog

remove unused files

Fix jest spec
parent a6b383f2
<script> <script>
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { n__ } from '~/locale'; import { n__, __ } from '~/locale';
export default { export default {
name: 'AssigneeTitle', name: 'AssigneeTitle',
...@@ -26,12 +26,19 @@ export default { ...@@ -26,12 +26,19 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
changing: {
type: Boolean,
required: true,
},
}, },
computed: { computed: {
assigneeTitle() { assigneeTitle() {
const assignees = this.numberOfAssignees; const assignees = this.numberOfAssignees;
return n__('Assignee', `%d Assignees`, assignees); return n__('Assignee', `%d Assignees`, assignees);
}, },
titleCopy() {
return this.changing ? __('Apply') : __('Edit');
},
}, },
}; };
</script> </script>
...@@ -43,11 +50,12 @@ export default { ...@@ -43,11 +50,12 @@ export default {
v-if="editable" v-if="editable"
class="js-sidebar-dropdown-toggle edit-link float-right" class="js-sidebar-dropdown-toggle edit-link float-right"
href="#" href="#"
data-test-id="edit-link"
data-track-event="click_edit_button" data-track-event="click_edit_button"
data-track-label="right_sidebar" data-track-label="right_sidebar"
data-track-property="assignee" data-track-property="assignee"
> >
{{ __('Edit') }} {{ titleCopy }}
</a> </a>
<a <a
v-if="showToggle" v-if="showToggle"
......
...@@ -89,6 +89,8 @@ export default { ...@@ -89,6 +89,8 @@ export default {
.saveAssignees(this.field) .saveAssignees(this.field)
.then(() => { .then(() => {
this.loading = false; this.loading = false;
this.store.resetChanging();
refreshUserMergeRequestCounts(); refreshUserMergeRequestCounts();
}) })
.catch(() => { .catch(() => {
...@@ -113,6 +115,7 @@ export default { ...@@ -113,6 +115,7 @@ export default {
:loading="loading || store.isFetching.assignees" :loading="loading || store.isFetching.assignees"
:editable="store.editable" :editable="store.editable"
:show-toggle="!signedIn" :show-toggle="!signedIn"
:changing="store.changing"
/> />
<assignees <assignees
v-if="!store.isFetching.assignees" v-if="!store.isFetching.assignees"
......
...@@ -33,6 +33,7 @@ export default class SidebarStore { ...@@ -33,6 +33,7 @@ export default class SidebarStore {
this.projectEmailsDisabled = false; this.projectEmailsDisabled = false;
this.subscribeDisabledDescription = ''; this.subscribeDisabledDescription = '';
this.subscribed = null; this.subscribed = null;
this.changing = false;
SidebarStore.singleton = this; SidebarStore.singleton = this;
} }
...@@ -51,6 +52,10 @@ export default class SidebarStore { ...@@ -51,6 +52,10 @@ export default class SidebarStore {
} }
} }
resetChanging() {
this.changing = false;
}
setTimeTrackingData(data) { setTimeTrackingData(data) {
this.timeEstimate = data.time_estimate; this.timeEstimate = data.time_estimate;
this.totalTimeSpent = data.total_time_spent; this.totalTimeSpent = data.total_time_spent;
...@@ -80,6 +85,7 @@ export default class SidebarStore { ...@@ -80,6 +85,7 @@ export default class SidebarStore {
addAssignee(assignee) { addAssignee(assignee) {
if (!this.findAssignee(assignee)) { if (!this.findAssignee(assignee)) {
this.changing = true;
this.assignees.push(assignee); this.assignees.push(assignee);
} }
} }
...@@ -100,6 +106,7 @@ export default class SidebarStore { ...@@ -100,6 +106,7 @@ export default class SidebarStore {
removeAssignee(assignee) { removeAssignee(assignee) {
if (assignee) { if (assignee) {
this.changing = true;
this.assignees = this.assignees.filter(({ id }) => id !== assignee.id); this.assignees = this.assignees.filter(({ id }) => id !== assignee.id);
} }
} }
...@@ -111,6 +118,7 @@ export default class SidebarStore { ...@@ -111,6 +118,7 @@ export default class SidebarStore {
} }
removeAllAssignees() { removeAllAssignees() {
this.changing = true;
this.assignees = []; this.assignees = [];
} }
......
---
title: Add apply button when user changes assignees
merge_request: 44812
author:
type: added
...@@ -140,6 +140,18 @@ RSpec.describe 'Issue Sidebar' do ...@@ -140,6 +140,18 @@ RSpec.describe 'Issue Sidebar' do
end end
end end
end end
it 'shows label text as "Apply" when assignees are changed' do
project.add_developer(user)
visit_issue(project, issue2)
find('.block.assignee .edit-link').click
wait_for_requests
click_on 'Unassigned'
expect(page).to have_link('Apply')
end
end end
context 'as a allowed user' do context 'as a allowed user' do
......
...@@ -11,6 +11,7 @@ describe('AssigneeTitle component', () => { ...@@ -11,6 +11,7 @@ describe('AssigneeTitle component', () => {
propsData: { propsData: {
numberOfAssignees: 0, numberOfAssignees: 0,
editable: false, editable: false,
changing: false,
...props, ...props,
}, },
}); });
...@@ -62,6 +63,22 @@ describe('AssigneeTitle component', () => { ...@@ -62,6 +63,22 @@ describe('AssigneeTitle component', () => {
}); });
}); });
describe('when changing is false', () => {
it('renders "Edit"', () => {
wrapper = createComponent({ editable: true });
expect(wrapper.find('[data-test-id="edit-link"]').text()).toEqual('Edit');
});
});
describe('when changing is true', () => {
it('renders "Edit"', () => {
wrapper = createComponent({ editable: true, changing: true });
expect(wrapper.find('[data-test-id="edit-link"]').text()).toEqual('Apply');
});
});
it('does not render spinner by default', () => { it('does not render spinner by default', () => {
wrapper = createComponent({ wrapper = createComponent({
numberOfAssignees: 0, numberOfAssignees: 0,
......
...@@ -20,6 +20,7 @@ describe('sidebar assignees', () => { ...@@ -20,6 +20,7 @@ describe('sidebar assignees', () => {
mediator, mediator,
field: '', field: '',
projectPath: 'projectPath', projectPath: 'projectPath',
changing: false,
...props, ...props,
}, },
provide: { provide: {
......
...@@ -57,16 +57,40 @@ describe('Sidebar store', () => { ...@@ -57,16 +57,40 @@ describe('Sidebar store', () => {
expect(testContext.store.isFetching.assignees).toBe(true); expect(testContext.store.isFetching.assignees).toBe(true);
}); });
it('adds a new assignee', () => { it('resets changing when resetChanging is called', () => {
testContext.store.addAssignee(ASSIGNEE); testContext.store.changing = true;
testContext.store.resetChanging();
expect(testContext.store.assignees.length).toEqual(1); expect(testContext.store.changing).toBe(false);
}); });
it('removes an assignee', () => { describe('when it adds a new assignee', () => {
testContext.store.removeAssignee(ASSIGNEE); beforeEach(() => {
testContext.store.addAssignee(ASSIGNEE);
});
expect(testContext.store.assignees.length).toEqual(0); it('adds a new assignee', () => {
expect(testContext.store.assignees).toHaveLength(1);
});
it('sets changing to true', () => {
expect(testContext.store.changing).toBe(true);
});
});
describe('when it removes an assignee', () => {
beforeEach(() => {
testContext.store.removeAssignee(ASSIGNEE);
});
it('removes an assignee', () => {
expect(testContext.store.assignees).toHaveLength(0);
});
it('sets changing to true', () => {
expect(testContext.store.changing).toBe(true);
});
}); });
it('finds an existent assignee', () => { it('finds an existent assignee', () => {
...@@ -86,6 +110,7 @@ describe('Sidebar store', () => { ...@@ -86,6 +110,7 @@ describe('Sidebar store', () => {
testContext.store.removeAllAssignees(); testContext.store.removeAllAssignees();
expect(testContext.store.assignees.length).toEqual(0); expect(testContext.store.assignees.length).toEqual(0);
expect(testContext.store.changing).toBe(true);
}); });
it('sets participants data', () => { it('sets participants data', () => {
......
...@@ -38,7 +38,7 @@ RSpec.shared_examples 'multiple assignees merge request' do |action, save_button ...@@ -38,7 +38,7 @@ RSpec.shared_examples 'multiple assignees merge request' do |action, save_button
page.within '.issuable-sidebar' do page.within '.issuable-sidebar' do
page.within '.assignee' do page.within '.assignee' do
# Closing dropdown to persist # Closing dropdown to persist
click_link 'Edit' click_link 'Apply'
expect(page).to have_content user2.name expect(page).to have_content user2.name
end end
......
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