summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-03-12 17:08:05 +0000
committerFilipa Lacerda <filipa@gitlab.com>2018-03-12 17:08:05 +0000
commite84c943fa0609d05184cb95c845fa35cc1fcd432 (patch)
tree6055f6c588a10e77af257a02ac3c8cb2c979ef70
parentbd26e012fcd50d0ff5c1ad7febc9d6355e43a6fc (diff)
downloadgitlab-ce-44149-issue-comment-buttons.tar.gz
Fix loading icon being visible in the wrong button44149-issue-comment-buttons
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue13
-rw-r--r--app/assets/javascripts/notes/stores/actions.js15
-rw-r--r--app/assets/javascripts/notes/stores/getters.js1
-rw-r--r--app/assets/javascripts/notes/stores/index.js3
-rw-r--r--app/assets/javascripts/notes/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js4
-rw-r--r--changelogs/unreleased/44149-issue-comment-buttons.yml5
-rw-r--r--spec/javascripts/notes/components/comment_form_spec.js14
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js16
-rw-r--r--spec/javascripts/notes/stores/mutation_spec.js66
10 files changed, 132 insertions, 6 deletions
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 1785be01a0d..a649e180131 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -52,6 +52,7 @@
'getNoteableData',
'getNotesData',
'openState',
+ 'isToggleStateButtonLoading',
]),
noteableDisplayName() {
return this.noteableType.replace(/_/g, ' ');
@@ -143,6 +144,7 @@
'closeIssue',
'reopenIssue',
'toggleIssueLocalState',
+ 'toggleStateButtonLoading',
]),
setIsSubmitButtonDisabled(note, isSubmitting) {
if (!_.isEmpty(note) && !isSubmitting) {
@@ -170,13 +172,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 +201,7 @@
}
})
.catch(() => {
- this.isSubmitting = false;
+ this.enableButton();
this.discard(false);
const msg =
`Your comment could not be submitted!
@@ -220,6 +223,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 +236,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 +424,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"
/>
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 08ca01e542e..70fc368a471 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -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: {
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index e6180101c58..9ff5b0ec63f 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -9,6 +9,7 @@ export const getNotesDataByProp = state => prop => state.notesData[prop];
export const getNoteableData = state => state.noteableData;
export const getNoteableDataByProp = state => prop => state.noteableData[prop];
export const openState = state => state.noteableData.state;
+export const isToggleStateButtonLoading = state => state.isToggleStateButtonLoading;
export const getUserData = state => state.userData || {};
export const getUserDataByProp = state => prop => state.userData && state.userData[prop];
diff --git a/app/assets/javascripts/notes/stores/index.js b/app/assets/javascripts/notes/stores/index.js
index 488a9ca38d3..9ed19bf171e 100644
--- a/app/assets/javascripts/notes/stores/index.js
+++ b/app/assets/javascripts/notes/stores/index.js
@@ -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: {},
diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js
index da1b5a9e51a..b455e23ecde 100644
--- a/app/assets/javascripts/notes/stores/mutation_types.js
+++ b/app/assets/javascripts/notes/stores/mutation_types.js
@@ -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';
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index 963b40be3fd..f07afbe4303 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -197,4 +197,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 });
+ },
};
diff --git a/changelogs/unreleased/44149-issue-comment-buttons.yml b/changelogs/unreleased/44149-issue-comment-buttons.yml
new file mode 100644
index 00000000000..c874c0d3d66
--- /dev/null
+++ b/changelogs/unreleased/44149-issue-comment-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken loading state for close issue button
+merge_request:
+author:
+type: fixed
diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js
index 90016436cb7..224debbeff6 100644
--- a/spec/javascripts/notes/components/comment_form_spec.js
+++ b/spec/javascripts/notes/components/comment_form_spec.js
@@ -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', () => {
diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js
index ab80ed7bbfb..0f092810574 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -87,6 +87,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);
@@ -98,6 +99,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);
@@ -116,6 +118,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', {}, [
diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js
index e4baefc5bfc..2627f721d9d 100644
--- a/spec/javascripts/notes/stores/mutation_spec.js
+++ b/spec/javascripts/notes/stores/mutation_spec.js
@@ -217,4 +217,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);
+ });
+ });
});