debian-mirror-gitlab/app/assets/javascripts/notes/stores/actions.js

434 lines
13 KiB
JavaScript
Raw Normal View History

2019-02-15 15:39:39 +05:30
import Vue from 'vue';
2018-05-09 12:01:36 +05:30
import $ from 'jquery';
2018-11-08 19:23:39 +05:30
import axios from '~/lib/utils/axios_utils';
2018-03-17 18:26:18 +05:30
import Visibility from 'visibilityjs';
2019-02-15 15:39:39 +05:30
import TaskList from '../../task_list';
2018-03-17 18:26:18 +05:30
import Flash from '../../flash';
import Poll from '../../lib/utils/poll';
import * as types from './mutation_types';
import * as utils from './utils';
import * as constants from '../constants';
import service from '../services/notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
2019-02-15 15:39:39 +05:30
import { isInViewport, scrollToElement, isInMRPage } from '../../lib/utils/common_utils';
2018-12-05 23:21:45 +05:30
import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
2018-12-13 13:39:08 +05:30
import { __ } from '~/locale';
2018-03-17 18:26:18 +05:30
let eTagPoll;
2019-02-15 15:39:39 +05:30
export const expandDiscussion = ({ commit, dispatch }, data) => {
if (data.discussionId) {
dispatch('diffs/renderFileForDiscussionId', data.discussionId, { root: true });
}
commit(types.EXPAND_DISCUSSION, data);
};
2018-11-08 19:23:39 +05:30
export const collapseDiscussion = ({ commit }, data) => commit(types.COLLAPSE_DISCUSSION, data);
export const setNotesData = ({ commit }, data) => commit(types.SET_NOTES_DATA, data);
export const setNoteableData = ({ commit }, data) => commit(types.SET_NOTEABLE_DATA, data);
export const setUserData = ({ commit }, data) => commit(types.SET_USER_DATA, data);
export const setLastFetchedAt = ({ commit }, data) => commit(types.SET_LAST_FETCHED_AT, data);
export const setInitialNotes = ({ commit }, discussions) =>
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
export const setTargetNoteHash = ({ commit }, data) => commit(types.SET_TARGET_NOTE_HASH, data);
export const setNotesFetchedState = ({ commit }, state) =>
commit(types.SET_NOTES_FETCHED_STATE, state);
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
2019-02-15 15:39:39 +05:30
export const fetchDiscussions = ({ commit, dispatch }, { path, filter }) =>
2018-05-09 12:01:36 +05:30
service
2018-12-13 13:39:08 +05:30
.fetchDiscussions(path, filter)
2018-05-09 12:01:36 +05:30
.then(res => res.json())
2018-11-08 19:23:39 +05:30
.then(discussions => {
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
2019-02-15 15:39:39 +05:30
dispatch('updateResolvableDiscussonsCounts');
2018-11-08 19:23:39 +05:30
});
2018-12-05 23:21:45 +05:30
export const updateDiscussion = ({ commit, state }, discussion) => {
commit(types.UPDATE_DISCUSSION, discussion);
return utils.findNoteObjectById(state.discussions, discussion.id);
};
2018-03-17 18:26:18 +05:30
2019-02-15 15:39:39 +05:30
export const deleteNote = ({ commit, dispatch, state }, note) =>
2018-05-09 12:01:36 +05:30
service.deleteNote(note.path).then(() => {
2019-02-15 15:39:39 +05:30
const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
2018-03-17 18:26:18 +05:30
commit(types.DELETE_NOTE, note);
2018-12-05 23:21:45 +05:30
dispatch('updateMergeRequestWidget');
2019-02-15 15:39:39 +05:30
dispatch('updateResolvableDiscussonsCounts');
if (isInMRPage()) {
dispatch('diffs/removeDiscussionsFromDiff', discussion);
}
2018-03-17 18:26:18 +05:30
});
2019-02-15 15:39:39 +05:30
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
2018-05-09 12:01:36 +05:30
service
.updateNote(endpoint, note)
.then(res => res.json())
.then(res => {
commit(types.UPDATE_NOTE, res);
2019-02-15 15:39:39 +05:30
dispatch('startTaskList');
2018-05-09 12:01:36 +05:30
});
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
export const replyToDiscussion = ({ commit }, { endpoint, data }) =>
service
.replyToDiscussion(endpoint, data)
.then(res => res.json())
.then(res => {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, res);
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
return res;
});
2018-03-17 18:26:18 +05:30
2018-12-05 23:21:45 +05:30
export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
2018-05-09 12:01:36 +05:30
service
.createNewNote(endpoint, data)
.then(res => res.json())
.then(res => {
if (!res.errors) {
commit(types.ADD_NEW_NOTE, res);
2018-12-05 23:21:45 +05:30
dispatch('updateMergeRequestWidget');
2019-02-15 15:39:39 +05:30
dispatch('startTaskList');
dispatch('updateResolvableDiscussonsCounts');
2018-05-09 12:01:36 +05:30
}
return res;
});
2018-03-17 18:26:18 +05:30
2018-11-08 19:23:39 +05:30
export const removePlaceholderNotes = ({ commit }) => commit(types.REMOVE_PLACEHOLDER_NOTES);
2018-03-17 18:26:18 +05:30
2018-12-05 23:21:45 +05:30
export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) =>
2018-05-09 12:01:36 +05:30
service
.toggleResolveNote(endpoint, isResolved)
.then(res => res.json())
.then(res => {
2018-11-08 19:23:39 +05:30
const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
2018-03-27 19:54:05 +05:30
2018-05-09 12:01:36 +05:30
commit(mutationType, res);
2018-12-05 23:21:45 +05:30
2019-02-15 15:39:39 +05:30
dispatch('updateResolvableDiscussonsCounts');
2018-12-05 23:21:45 +05:30
dispatch('updateMergeRequestWidget');
2018-05-09 12:01:36 +05:30
});
2018-03-27 19:54:05 +05:30
export const closeIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
return service
2018-05-09 12:01:36 +05:30
.toggleIssueState(state.notesData.closePath)
.then(res => res.json())
.then(data => {
commit(types.CLOSE_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
2018-03-27 19:54:05 +05:30
};
export const reopenIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
return service
2018-05-09 12:01:36 +05:30
.toggleIssueState(state.notesData.reopenPath)
.then(res => res.json())
.then(data => {
commit(types.REOPEN_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
2018-03-27 19:54:05 +05:30
};
export const toggleStateButtonLoading = ({ commit }, value) =>
commit(types.TOGGLE_STATE_BUTTON_LOADING, value);
2018-11-08 19:23:39 +05:30
export const emitStateChangedEvent = ({ getters }, data) => {
2018-05-09 12:01:36 +05:30
const event = new CustomEvent('issuable_vue_app:change', {
detail: {
data,
isClosed: getters.openState === constants.CLOSED,
},
});
2018-03-27 19:54:05 +05:30
document.dispatchEvent(event);
};
export const toggleIssueLocalState = ({ commit }, newState) => {
if (newState === constants.CLOSED) {
commit(types.CLOSE_ISSUE);
} else if (newState === constants.REOPENED) {
commit(types.REOPEN_ISSUE);
}
};
2018-03-17 18:26:18 +05:30
export const saveNote = ({ commit, dispatch }, noteData) => {
2018-11-08 19:23:39 +05:30
// For MR discussuions we need to post as `note[note]` and issue we use `note.note`.
2018-12-05 23:21:45 +05:30
// For batch comments, we use draft_note
const note = noteData.data.draft_note || noteData.data['note[note]'] || noteData.data.note.note;
2018-03-17 18:26:18 +05:30
let placeholderText = note;
const hasQuickActions = utils.hasQuickActions(placeholderText);
const replyId = noteData.data.in_reply_to_discussion_id;
2018-12-05 23:21:45 +05:30
let methodToDispatch;
const postData = Object.assign({}, noteData);
if (postData.isDraft === true) {
methodToDispatch = replyId
? 'batchComments/addDraftToDiscussion'
: 'batchComments/createNewDraft';
if (!postData.draft_note && noteData.note) {
postData.draft_note = postData.note;
delete postData.note;
}
} else {
methodToDispatch = replyId ? 'replyToDiscussion' : 'createNewNote';
}
2018-03-17 18:26:18 +05:30
$('.notes-form .flash-container').hide(); // hide previous flash notification
2018-11-20 20:47:30 +05:30
commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders
2018-03-17 18:26:18 +05:30
2018-11-20 20:47:30 +05:30
if (replyId) {
if (hasQuickActions) {
placeholderText = utils.stripQuickActions(placeholderText);
}
2018-03-17 18:26:18 +05:30
2018-11-20 20:47:30 +05:30
if (placeholderText.length) {
commit(types.SHOW_PLACEHOLDER_NOTE, {
noteBody: placeholderText,
replyId,
});
}
2018-03-17 18:26:18 +05:30
2018-11-20 20:47:30 +05:30
if (hasQuickActions) {
commit(types.SHOW_PLACEHOLDER_NOTE, {
isSystemNote: true,
noteBody: utils.getQuickActionText(note),
replyId,
});
}
2018-03-17 18:26:18 +05:30
}
2018-12-05 23:21:45 +05:30
return dispatch(methodToDispatch, postData, { root: true }).then(res => {
2018-05-09 12:01:36 +05:30
const { errors } = res;
const commandsChanges = res.commands_changes;
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
if (hasQuickActions && errors && Object.keys(errors).length) {
eTagPoll.makeRequest();
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
$('.js-gfm-input').trigger('clear-commands-cache.atwho');
Flash('Commands applied', 'notice', noteData.flashContainer);
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
if (commandsChanges) {
if (commandsChanges.emoji_award) {
const votesBlock = $('.js-awards-block').eq(0);
loadAwardsHandler()
.then(awardsHandler => {
2018-11-08 19:23:39 +05:30
awardsHandler.addAwardToEmojiBar(votesBlock, commandsChanges.emoji_award);
2018-05-09 12:01:36 +05:30
awardsHandler.scrollToAwards();
})
.catch(() => {
Flash(
'Something went wrong while adding your award. Please try again.',
'alert',
noteData.flashContainer,
);
});
2018-03-17 18:26:18 +05:30
}
2018-11-08 19:23:39 +05:30
if (commandsChanges.spend_time != null || commandsChanges.time_estimate != null) {
2018-05-09 12:01:36 +05:30
sidebarTimeTrackingEventHub.$emit('timeTrackingUpdated', res);
2018-03-17 18:26:18 +05:30
}
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
if (errors && errors.commands_only) {
Flash(errors.commands_only, 'notice', noteData.flashContainer);
}
2018-11-20 20:47:30 +05:30
if (replyId) {
commit(types.REMOVE_PLACEHOLDER_NOTES);
}
2018-05-09 12:01:36 +05:30
return res;
});
2018-03-17 18:26:18 +05:30
};
2018-11-08 19:23:39 +05:30
const pollSuccessCallBack = (resp, commit, state, getters, dispatch) => {
2018-03-17 18:26:18 +05:30
if (resp.notes && resp.notes.length) {
const { notesById } = getters;
2018-05-09 12:01:36 +05:30
resp.notes.forEach(note => {
2018-03-17 18:26:18 +05:30
if (notesById[note.id]) {
commit(types.UPDATE_NOTE, note);
2018-11-08 19:23:39 +05:30
} else if (note.type === constants.DISCUSSION_NOTE || note.type === constants.DIFF_NOTE) {
const discussion = utils.findNoteObjectById(state.discussions, note.discussion_id);
2018-03-17 18:26:18 +05:30
if (discussion) {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, note);
2018-11-08 19:23:39 +05:30
} else if (note.type === constants.DIFF_NOTE) {
2018-12-13 13:39:08 +05:30
dispatch('fetchDiscussions', { path: state.notesData.discussionsPath });
2018-03-17 18:26:18 +05:30
} else {
commit(types.ADD_NEW_NOTE, note);
}
} else {
commit(types.ADD_NEW_NOTE, note);
}
});
2019-02-15 15:39:39 +05:30
dispatch('startTaskList');
2018-03-17 18:26:18 +05:30
}
2018-03-27 19:54:05 +05:30
commit(types.SET_LAST_FETCHED_AT, resp.last_fetched_at);
2018-03-17 18:26:18 +05:30
return resp;
};
2018-11-08 19:23:39 +05:30
export const poll = ({ commit, state, getters, dispatch }) => {
2018-03-17 18:26:18 +05:30
eTagPoll = new Poll({
resource: service,
method: 'poll',
2018-03-27 19:54:05 +05:30
data: state,
2018-05-09 12:01:36 +05:30
successCallback: resp =>
2018-11-08 19:23:39 +05:30
resp.json().then(data => pollSuccessCallBack(data, commit, state, getters, dispatch)),
errorCallback: () => Flash('Something went wrong while fetching latest comments.'),
2018-03-17 18:26:18 +05:30
});
if (!Visibility.hidden()) {
eTagPoll.makeRequest();
} else {
2018-03-27 19:54:05 +05:30
service.poll(state);
2018-03-17 18:26:18 +05:30
}
Visibility.change(() => {
if (!Visibility.hidden()) {
eTagPoll.restart();
} else {
eTagPoll.stop();
}
});
};
export const stopPolling = () => {
eTagPoll.stop();
};
export const restartPolling = () => {
eTagPoll.restart();
};
export const fetchData = ({ commit, state, getters }) => {
2018-05-09 12:01:36 +05:30
const requestData = {
endpoint: state.notesData.notesPath,
lastFetchedAt: state.lastFetchedAt,
};
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
service
.poll(requestData)
2018-03-17 18:26:18 +05:30
.then(resp => resp.json)
.then(data => pollSuccessCallBack(data, commit, state, getters))
.catch(() => Flash('Something went wrong while fetching latest comments.'));
};
2018-11-08 19:23:39 +05:30
export const toggleAward = ({ commit, getters }, { awardName, noteId }) => {
2018-03-17 18:26:18 +05:30
commit(types.TOGGLE_AWARD, { awardName, note: getters.notesById[noteId] });
};
2018-11-08 19:23:39 +05:30
export const toggleAwardRequest = ({ dispatch }, data) => {
2018-03-17 18:26:18 +05:30
const { endpoint, awardName } = data;
return service
.toggleAward(endpoint, { name: awardName })
.then(res => res.json())
.then(() => {
dispatch('toggleAward', data);
});
};
export const scrollToNoteIfNeeded = (context, el) => {
if (!isInViewport(el[0])) {
scrollToElement(el);
}
};
2018-10-15 14:42:47 +05:30
2018-11-08 19:23:39 +05:30
export const fetchDiscussionDiffLines = ({ commit }, discussion) =>
2019-02-15 15:39:39 +05:30
axios.get(discussion.truncated_diff_lines_path).then(({ data }) => {
2018-11-08 19:23:39 +05:30
commit(types.SET_DISCUSSION_DIFF_LINES, {
discussionId: discussion.id,
diffLines: data.truncated_diff_lines,
});
});
2018-12-05 23:21:45 +05:30
export const updateMergeRequestWidget = () => {
mrWidgetEventHub.$emit('mr.discussion.updated');
};
2018-12-13 13:39:08 +05:30
export const setLoadingState = ({ commit }, data) => {
commit(types.SET_NOTES_LOADING_STATE, data);
};
export const filterDiscussion = ({ dispatch }, { path, filter }) => {
dispatch('setLoadingState', true);
dispatch('fetchDiscussions', { path, filter })
.then(() => {
dispatch('setLoadingState', false);
dispatch('setNotesFetchedState', true);
})
.catch(() => {
dispatch('setLoadingState', false);
dispatch('setNotesFetchedState', true);
Flash(__('Something went wrong while fetching comments. Please try again.'));
});
};
export const setCommentsDisabled = ({ commit }, data) => {
commit(types.DISABLE_COMMENTS, data);
};
2019-02-15 15:39:39 +05:30
export const startTaskList = ({ dispatch }) =>
Vue.nextTick(
() =>
new TaskList({
dataType: 'note',
fieldName: 'note',
selector: '.notes .is-editable',
onSuccess: () => dispatch('startTaskList'),
}),
);
export const updateResolvableDiscussonsCounts = ({ commit }) =>
commit(types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS);
export const submitSuggestion = (
{ commit },
{ discussionId, noteId, suggestionId, flashContainer, callback },
) => {
service
.applySuggestion(suggestionId)
.then(() => {
commit(types.APPLY_SUGGESTION, { discussionId, noteId, suggestionId });
callback();
})
.catch(err => {
const defaultMessage = __(
'Something went wrong while applying the suggestion. Please try again.',
);
const flashMessage = err.response.data ? `${err.response.data.message}.` : defaultMessage;
Flash(__(flashMessage), 'alert', flashContainer);
callback();
});
};
2019-03-02 22:35:43 +05:30
export const convertToDiscussion = ({ commit }, noteId) =>
commit(types.CONVERT_TO_DISCUSSION, noteId);
2018-10-15 14:42:47 +05:30
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};