Merge branch '44149-issue-comment-buttons' into 'master'
Resolve "Wrong button has the loading state when submitting a comment in issues" Closes #44149 See merge request gitlab-org/gitlab-ce!17698
This commit is contained in:
commit
0e51c82b50
9 changed files with 134 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import _ from 'underscore';
|
||||
import Autosize from 'autosize';
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
@ -53,6 +53,9 @@
|
|||
'getNotesData',
|
||||
'openState',
|
||||
]),
|
||||
...mapState([
|
||||
'isToggleStateButtonLoading',
|
||||
]),
|
||||
noteableDisplayName() {
|
||||
return this.noteableType.replace(/_/g, ' ');
|
||||
},
|
||||
|
@ -143,6 +146,7 @@
|
|||
'closeIssue',
|
||||
'reopenIssue',
|
||||
'toggleIssueLocalState',
|
||||
'toggleStateButtonLoading',
|
||||
]),
|
||||
setIsSubmitButtonDisabled(note, isSubmitting) {
|
||||
if (!_.isEmpty(note) && !isSubmitting) {
|
||||
|
@ -170,13 +174,14 @@
|
|||
if (this.noteType === constants.DISCUSSION) {
|
||||
noteData.data.note.type = constants.DISCUSSION_NOTE;
|
||||
}
|
||||
|
||||
this.note = ''; // Empty textarea while being requested. Repopulate in catch
|
||||
this.resizeTextarea();
|
||||
this.stopPolling();
|
||||
|
||||
this.saveNote(noteData)
|
||||
.then((res) => {
|
||||
this.isSubmitting = false;
|
||||
this.enableButton();
|
||||
this.restartPolling();
|
||||
|
||||
if (res.errors) {
|
||||
|
@ -198,7 +203,7 @@
|
|||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.isSubmitting = false;
|
||||
this.enableButton();
|
||||
this.discard(false);
|
||||
const msg =
|
||||
`Your comment could not be submitted!
|
||||
|
@ -220,6 +225,7 @@ Please check your network connection and try again.`;
|
|||
.then(() => this.enableButton())
|
||||
.catch(() => {
|
||||
this.enableButton();
|
||||
this.toggleStateButtonLoading(false);
|
||||
Flash(
|
||||
sprintf(
|
||||
__('Something went wrong while closing the %{issuable}. Please try again later'),
|
||||
|
@ -232,6 +238,7 @@ Please check your network connection and try again.`;
|
|||
.then(() => this.enableButton())
|
||||
.catch(() => {
|
||||
this.enableButton();
|
||||
this.toggleStateButtonLoading(false);
|
||||
Flash(
|
||||
sprintf(
|
||||
__('Something went wrong while reopening the %{issuable}. Please try again later'),
|
||||
|
@ -419,13 +426,13 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
|
|||
|
||||
<loading-button
|
||||
v-if="canUpdateIssue"
|
||||
:loading="isSubmitting"
|
||||
:loading="isToggleStateButtonLoading"
|
||||
@click="handleSave(true)"
|
||||
:container-class="[
|
||||
actionButtonClassNames,
|
||||
'btn btn-comment btn-comment-and-close js-action-button'
|
||||
]"
|
||||
:disabled="isSubmitting"
|
||||
:disabled="isToggleStateButtonLoading || isSubmitting"
|
||||
:label="issueActionButtonTitle"
|
||||
/>
|
||||
|
||||
|
|
|
@ -71,21 +71,32 @@ export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion
|
|||
commit(mutationType, res);
|
||||
});
|
||||
|
||||
export const closeIssue = ({ commit, dispatch, state }) => service
|
||||
export const closeIssue = ({ commit, dispatch, state }) => {
|
||||
dispatch('toggleStateButtonLoading', true);
|
||||
return service
|
||||
.toggleIssueState(state.notesData.closePath)
|
||||
.then(res => res.json())
|
||||
.then((data) => {
|
||||
commit(types.CLOSE_ISSUE);
|
||||
dispatch('emitStateChangedEvent', data);
|
||||
dispatch('toggleStateButtonLoading', false);
|
||||
});
|
||||
};
|
||||
|
||||
export const reopenIssue = ({ commit, dispatch, state }) => service
|
||||
export const reopenIssue = ({ commit, dispatch, state }) => {
|
||||
dispatch('toggleStateButtonLoading', true);
|
||||
return service
|
||||
.toggleIssueState(state.notesData.reopenPath)
|
||||
.then(res => res.json())
|
||||
.then((data) => {
|
||||
commit(types.REOPEN_ISSUE);
|
||||
dispatch('emitStateChangedEvent', data);
|
||||
dispatch('toggleStateButtonLoading', false);
|
||||
});
|
||||
};
|
||||
|
||||
export const toggleStateButtonLoading = ({ commit }, value) =>
|
||||
commit(types.TOGGLE_STATE_BUTTON_LOADING, value);
|
||||
|
||||
export const emitStateChangedEvent = ({ commit, getters }, data) => {
|
||||
const event = new CustomEvent('issuable_vue_app:change', { detail: {
|
||||
|
|
|
@ -12,6 +12,9 @@ export default new Vuex.Store({
|
|||
targetNoteHash: null,
|
||||
lastFetchedAt: null,
|
||||
|
||||
// View layer
|
||||
isToggleStateButtonLoading: false,
|
||||
|
||||
// holds endpoints and permissions provided through haml
|
||||
notesData: {},
|
||||
userData: {},
|
||||
|
|
|
@ -17,3 +17,4 @@ export const UPDATE_DISCUSSION = 'UPDATE_DISCUSSION';
|
|||
// Issue
|
||||
export const CLOSE_ISSUE = 'CLOSE_ISSUE';
|
||||
export const REOPEN_ISSUE = 'REOPEN_ISSUE';
|
||||
export const TOGGLE_STATE_BUTTON_LOADING = 'TOGGLE_STATE_BUTTON_LOADING';
|
||||
|
|
|
@ -199,4 +199,8 @@ export default {
|
|||
[types.REOPEN_ISSUE](state) {
|
||||
Object.assign(state.noteableData, { state: constants.REOPENED });
|
||||
},
|
||||
|
||||
[types.TOGGLE_STATE_BUTTON_LOADING](state, value) {
|
||||
Object.assign(state, { isToggleStateButtonLoading: value });
|
||||
},
|
||||
};
|
||||
|
|
5
changelogs/unreleased/44149-issue-comment-buttons.yml
Normal file
5
changelogs/unreleased/44149-issue-comment-buttons.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix broken loading state for close issue button
|
||||
merge_request:
|
||||
author:
|
||||
type: fixed
|
|
@ -200,6 +200,20 @@ describe('issue_comment_form component', () => {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when clicking close/reopen button', () => {
|
||||
it('should disable button and show a loading spinner', (done) => {
|
||||
const toggleStateButton = vm.$el.querySelector('.js-action-button');
|
||||
|
||||
toggleStateButton.click();
|
||||
Vue.nextTick(() => {
|
||||
expect(toggleStateButton.disabled).toEqual(true);
|
||||
expect(toggleStateButton.querySelector('.js-loading-button-icon')).not.toBeNull();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('issue is confidential', () => {
|
||||
|
|
|
@ -88,6 +88,7 @@ describe('Actions Notes Store', () => {
|
|||
store.dispatch('closeIssue', { notesData: { closeIssuePath: '' } })
|
||||
.then(() => {
|
||||
expect(store.state.noteableData.state).toEqual('closed');
|
||||
expect(store.state.isToggleStateButtonLoading).toEqual(false);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
|
@ -99,6 +100,7 @@ describe('Actions Notes Store', () => {
|
|||
store.dispatch('reopenIssue', { notesData: { reopenIssuePath: '' } })
|
||||
.then(() => {
|
||||
expect(store.state.noteableData.state).toEqual('reopened');
|
||||
expect(store.state.isToggleStateButtonLoading).toEqual(false);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
|
@ -117,6 +119,20 @@ describe('Actions Notes Store', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('toggleStateButtonLoading', () => {
|
||||
it('should set loading as true', (done) => {
|
||||
testAction(actions.toggleStateButtonLoading, true, {}, [
|
||||
{ type: 'TOGGLE_STATE_BUTTON_LOADING', payload: true },
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should set loading as false', (done) => {
|
||||
testAction(actions.toggleStateButtonLoading, false, {}, [
|
||||
{ type: 'TOGGLE_STATE_BUTTON_LOADING', payload: false },
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggleIssueLocalState', () => {
|
||||
it('sets issue state as closed', (done) => {
|
||||
testAction(actions.toggleIssueLocalState, 'closed', {}, [
|
||||
|
|
|
@ -228,4 +228,70 @@ describe('Notes Store mutations', () => {
|
|||
expect(state.notes[0].notes[0].note).toEqual('Foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CLOSE_ISSUE', () => {
|
||||
it('should set issue as closed', () => {
|
||||
const state = {
|
||||
notes: [],
|
||||
targetNoteHash: null,
|
||||
lastFetchedAt: null,
|
||||
isToggleStateButtonLoading: false,
|
||||
notesData: {},
|
||||
userData: {},
|
||||
noteableData: {},
|
||||
};
|
||||
|
||||
mutations.CLOSE_ISSUE(state);
|
||||
expect(state.noteableData.state).toEqual('closed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('REOPEN_ISSUE', () => {
|
||||
it('should set issue as closed', () => {
|
||||
const state = {
|
||||
notes: [],
|
||||
targetNoteHash: null,
|
||||
lastFetchedAt: null,
|
||||
isToggleStateButtonLoading: false,
|
||||
notesData: {},
|
||||
userData: {},
|
||||
noteableData: {},
|
||||
};
|
||||
|
||||
mutations.REOPEN_ISSUE(state);
|
||||
expect(state.noteableData.state).toEqual('reopened');
|
||||
});
|
||||
});
|
||||
|
||||
describe('TOGGLE_STATE_BUTTON_LOADING', () => {
|
||||
it('should set isToggleStateButtonLoading as true', () => {
|
||||
const state = {
|
||||
notes: [],
|
||||
targetNoteHash: null,
|
||||
lastFetchedAt: null,
|
||||
isToggleStateButtonLoading: false,
|
||||
notesData: {},
|
||||
userData: {},
|
||||
noteableData: {},
|
||||
};
|
||||
|
||||
mutations.TOGGLE_STATE_BUTTON_LOADING(state, true);
|
||||
expect(state.isToggleStateButtonLoading).toEqual(true);
|
||||
});
|
||||
|
||||
it('should set isToggleStateButtonLoading as false', () => {
|
||||
const state = {
|
||||
notes: [],
|
||||
targetNoteHash: null,
|
||||
lastFetchedAt: null,
|
||||
isToggleStateButtonLoading: true,
|
||||
notesData: {},
|
||||
userData: {},
|
||||
noteableData: {},
|
||||
};
|
||||
|
||||
mutations.TOGGLE_STATE_BUTTON_LOADING(state, false);
|
||||
expect(state.isToggleStateButtonLoading).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue