import * as types from './mutation_types'; import api from '~/api'; import createFlash from '~/flash'; import { s__ } from '~/locale'; import { redirectTo } from '~/lib/utils/url_utility'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; export const requestRelease = ({ commit }) => commit(types.REQUEST_RELEASE); export const receiveReleaseSuccess = ({ commit }, data) => commit(types.RECEIVE_RELEASE_SUCCESS, data); export const receiveReleaseError = ({ commit }, error) => { commit(types.RECEIVE_RELEASE_ERROR, error); createFlash(s__('Release|Something went wrong while getting the release details')); }; export const fetchRelease = ({ dispatch, state }) => { dispatch('requestRelease'); return api .release(state.projectId, state.tagName) .then(({ data }) => { const release = { ...data, milestones: data.milestones || [], }; dispatch('receiveReleaseSuccess', convertObjectPropsToCamelCase(release, { deep: true })); }) .catch(error => { dispatch('receiveReleaseError', error); }); }; export const updateReleaseTitle = ({ commit }, title) => commit(types.UPDATE_RELEASE_TITLE, title); export const updateReleaseNotes = ({ commit }, notes) => commit(types.UPDATE_RELEASE_NOTES, notes); export const updateReleaseMilestones = ({ commit }, milestones) => commit(types.UPDATE_RELEASE_MILESTONES, milestones); export const requestUpdateRelease = ({ commit }) => commit(types.REQUEST_UPDATE_RELEASE); export const receiveUpdateReleaseSuccess = ({ commit, state, rootState }) => { commit(types.RECEIVE_UPDATE_RELEASE_SUCCESS); redirectTo( rootState.featureFlags.releaseShowPage ? state.release._links.self : state.releasesPagePath, ); }; export const receiveUpdateReleaseError = ({ commit }, error) => { commit(types.RECEIVE_UPDATE_RELEASE_ERROR, error); createFlash(s__('Release|Something went wrong while saving the release details')); }; export const updateRelease = ({ dispatch, state, getters }) => { dispatch('requestUpdateRelease'); const { release } = state; const milestones = release.milestones ? release.milestones.map(milestone => milestone.title) : []; return ( api .updateRelease(state.projectId, state.tagName, { name: release.name, description: release.description, milestones, }) /** * Currently, we delete all existing links and then * recreate new ones on each edit. This is because the * REST API doesn't support bulk updating of Release links, * and updating individual links can lead to validation * race conditions (in particular, the "URLs must be unique") * constraint. * * This isn't ideal since this is no longer an atomic * operation - parts of it can fail while others succeed, * leaving the Release in an inconsistent state. * * This logic should be refactored to use GraphQL once * https://gitlab.com/gitlab-org/gitlab/-/issues/208702 * is closed. */ .then(() => { // Delete all links currently associated with this Release return Promise.all( getters.releaseLinksToDelete.map(l => api.deleteReleaseLink(state.projectId, release.tagName, l.id), ), ); }) .then(() => { // Create a new link for each link in the form return Promise.all( getters.releaseLinksToCreate.map(l => api.createReleaseLink(state.projectId, release.tagName, l), ), ); }) .then(() => dispatch('receiveUpdateReleaseSuccess')) .catch(error => { dispatch('receiveUpdateReleaseError', error); }) ); }; export const navigateToReleasesPage = ({ state }) => { redirectTo(state.releasesPagePath); }; export const addEmptyAssetLink = ({ commit }) => { commit(types.ADD_EMPTY_ASSET_LINK); }; export const updateAssetLinkUrl = ({ commit }, { linkIdToUpdate, newUrl }) => { commit(types.UPDATE_ASSET_LINK_URL, { linkIdToUpdate, newUrl }); }; export const updateAssetLinkName = ({ commit }, { linkIdToUpdate, newName }) => { commit(types.UPDATE_ASSET_LINK_NAME, { linkIdToUpdate, newName }); }; export const removeAssetLink = ({ commit }, linkIdToRemove) => { commit(types.REMOVE_ASSET_LINK, linkIdToRemove); };