summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/releases
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:40:28 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:40:28 +0000
commitb595cb0c1dec83de5bdee18284abe86614bed33b (patch)
tree8c3d4540f193c5ff98019352f554e921b3a41a72 /app/assets/javascripts/releases
parent2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff)
downloadgitlab-ce-b595cb0c1dec83de5bdee18284abe86614bed33b.tar.gz
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'app/assets/javascripts/releases')
-rw-r--r--app/assets/javascripts/releases/components/app_edit_new.vue44
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue18
-rw-r--r--app/assets/javascripts/releases/components/confirm_delete_modal.vue77
-rw-r--r--app/assets/javascripts/releases/components/release_block_footer.vue30
-rw-r--r--app/assets/javascripts/releases/components/tag_field.vue4
-rw-r--r--app/assets/javascripts/releases/components/tag_field_new.vue15
-rw-r--r--app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql2
-rw-r--r--app/assets/javascripts/releases/graphql/mutations/delete_release.mutation.graphql5
-rw-r--r--app/assets/javascripts/releases/mount_edit.js2
-rw-r--r--app/assets/javascripts/releases/mount_index.js2
-rw-r--r--app/assets/javascripts/releases/mount_new.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/actions.js45
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/getters.js16
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/mutation_types.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/mutations.js9
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/state.js9
-rw-r--r--app/assets/javascripts/releases/util.js8
17 files changed, 248 insertions, 42 deletions
diff --git a/app/assets/javascripts/releases/components/app_edit_new.vue b/app/assets/javascripts/releases/components/app_edit_new.vue
index 327da1fb2a1..022c3224bb4 100644
--- a/app/assets/javascripts/releases/components/app_edit_new.vue
+++ b/app/assets/javascripts/releases/components/app_edit_new.vue
@@ -1,5 +1,13 @@
<script>
-import { GlButton, GlFormCheckbox, GlFormInput, GlFormGroup, GlLink, GlSprintf } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDatepicker,
+ GlFormCheckbox,
+ GlFormInput,
+ GlFormGroup,
+ GlLink,
+ GlSprintf,
+} from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
import { isSameOriginUrl, getParameterByName } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -7,6 +15,7 @@ import MilestoneCombobox from '~/milestones/components/milestone_combobox.vue';
import { BACK_URL_PARAM } from '~/releases/constants';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import AssetLinksForm from './asset_links_form.vue';
+import ConfirmDeleteModal from './confirm_delete_modal.vue';
import TagField from './tag_field.vue';
export default {
@@ -16,8 +25,10 @@ export default {
GlFormInput,
GlFormGroup,
GlButton,
+ GlDatepicker,
GlLink,
GlSprintf,
+ ConfirmDeleteModal,
MarkdownField,
AssetLinksForm,
MilestoneCombobox,
@@ -25,12 +36,14 @@ export default {
},
computed: {
...mapState('editNew', [
+ 'isExistingRelease',
'isFetchingRelease',
'isUpdatingRelease',
'fetchError',
'markdownDocsPath',
'markdownPreviewPath',
'editReleaseDocsPath',
+ 'upcomingReleaseDocsPath',
'releasesPagePath',
'release',
'newMilestonePath',
@@ -40,7 +53,7 @@ export default {
'groupMilestonesAvailable',
'tagNotes',
]),
- ...mapGetters('editNew', ['isValid', 'isExistingRelease', 'formattedReleaseNotes']),
+ ...mapGetters('editNew', ['isValid', 'formattedReleaseNotes']),
showForm() {
return Boolean(!this.isFetchingRelease && !this.fetchError && this.release);
},
@@ -76,6 +89,14 @@ export default {
this.updateIncludeTagNotes(includeTagNotes);
},
},
+ releasedAt: {
+ get() {
+ return this.release.releasedAt;
+ },
+ set(date) {
+ this.updateReleasedAt(date);
+ },
+ },
cancelPath() {
const backUrl = getParameterByName(BACK_URL_PARAM);
@@ -114,10 +135,12 @@ export default {
...mapActions('editNew', [
'initializeRelease',
'saveRelease',
+ 'deleteRelease',
'updateReleaseTitle',
'updateReleaseNotes',
'updateReleaseMilestones',
'updateIncludeTagNotes',
+ 'updateReleasedAt',
]),
submitForm() {
if (!this.isFormSubmissionDisabled) {
@@ -166,6 +189,22 @@ export default {
/>
</div>
</gl-form-group>
+ <gl-form-group :label="__('Release date')" label-for="release-released-at">
+ <template #label-description>
+ <gl-sprintf
+ :message="
+ __(
+ 'The date when the release is ready. A release with a date in the future is labeled as an %{linkStart}Upcoming Release%{linkEnd}.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="upcomingReleaseDocsPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ <gl-datepicker id="release-released-at" v-model="releasedAt" :default-date="releasedAt" />
+ </gl-form-group>
<gl-form-group data-testid="release-notes">
<label for="release-notes">{{ __('Release notes') }}</label>
<div class="bordered-box pr-3 pl-3">
@@ -224,6 +263,7 @@ export default {
>
{{ saveButtonLabel }}
</gl-button>
+ <confirm-delete-modal v-if="isExistingRelease" @delete="deleteRelease" />
<gl-button :href="cancelPath" class="js-cancel-button">{{ __('Cancel') }}</gl-button>
</div>
</form>
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index a949a9d1318..d63a83d1a08 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -4,9 +4,9 @@ import createFlash from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { setUrlParams, getParameterByName } from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import { PAGE_SIZE, DEFAULT_SORT } from '~/releases/constants';
-import { convertAllReleasesGraphQLResponse } from '~/releases/util';
+import { convertAllReleasesGraphQLResponse, deleteReleaseSessionKey } from '~/releases/util';
import allReleasesQuery from '../graphql/queries/all_releases.query.graphql';
import ReleaseBlock from './release_block.vue';
import ReleaseSkeletonLoader from './release_skeleton_loader.vue';
@@ -172,6 +172,20 @@ export default {
return this.isFullRequestLoaded && !this.shouldRenderEmptyState;
},
},
+ mounted() {
+ const key = deleteReleaseSessionKey(this.projectPath);
+ const deletedRelease = window.sessionStorage.getItem(key);
+
+ if (deletedRelease) {
+ this.$toast.show(
+ sprintf(__('Release %{deletedRelease} has been successfully deleted.'), {
+ deletedRelease,
+ }),
+ );
+ }
+
+ window.sessionStorage.removeItem(key);
+ },
created() {
this.updateQueryParamsFromUrl();
diff --git a/app/assets/javascripts/releases/components/confirm_delete_modal.vue b/app/assets/javascripts/releases/components/confirm_delete_modal.vue
new file mode 100644
index 00000000000..aa948fbbaf6
--- /dev/null
+++ b/app/assets/javascripts/releases/components/confirm_delete_modal.vue
@@ -0,0 +1,77 @@
+<script>
+import { GlModal, GlSprintf, GlLink, GlButton } from '@gitlab/ui';
+import { mapState } from 'vuex';
+import { __, s__, sprintf } from '~/locale';
+
+export default {
+ components: {
+ GlModal,
+ GlSprintf,
+ GlLink,
+ GlButton,
+ },
+ data() {
+ return {
+ visible: false,
+ };
+ },
+ computed: {
+ ...mapState('editNew', ['release', 'deleteReleaseDocsPath']),
+ title() {
+ return sprintf(__('Delete release %{release}?'), { release: this.release.name });
+ },
+ },
+ modalOptions: {
+ modalId: 'confirm-delete-release',
+ static: true,
+ actionPrimary: {
+ attributes: { variant: 'danger' },
+ text: __('Delete release'),
+ },
+ actionSecondary: {
+ text: __('Cancel'),
+ attributes: { variant: 'default' },
+ },
+ },
+ i18n: {
+ buttonLabel: __('Delete'),
+ line1: s__(
+ 'DeleteRelease|You are about to delete release %{release} and its assets. The Git tag %{tag} will not be deleted.',
+ ),
+ line2: s__(
+ 'DeleteRelease|For more details, see %{docsPathStart}Deleting a release%{docsPathEnd}.',
+ ),
+ line3: s__('DeleteRelease|Are you sure you want to delete this release?'),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-button class="gl-mr-3" variant="danger" @click="visible = true">
+ {{ $options.i18n.buttonLabel }}
+ </gl-button>
+ <gl-modal
+ v-bind="$options.modalOptions"
+ v-model="visible"
+ :title="title"
+ @primary="$emit('delete')"
+ >
+ <p>
+ <gl-sprintf :message="$options.i18n.line1">
+ <template #release>{{ release.name }}</template>
+ <template #tag>
+ <gl-link :href="release.tagPath">{{ release.tagName }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p>
+ <gl-sprintf :message="$options.i18n.line2">
+ <template #docsPath="{ content }">
+ <gl-link :href="deleteReleaseDocsPath" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p>{{ $options.i18n.line3 }}</p>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/releases/components/release_block_footer.vue b/app/assets/javascripts/releases/components/release_block_footer.vue
index 91d6d0911a4..3881c83b5c2 100644
--- a/app/assets/javascripts/releases/components/release_block_footer.vue
+++ b/app/assets/javascripts/releases/components/release_block_footer.vue
@@ -42,9 +42,9 @@ export default {
default: null,
},
releasedAt: {
- type: String,
+ type: Date,
required: false,
- default: '',
+ default: null,
},
},
computed: {
@@ -66,8 +66,11 @@ export default {
</script>
<template>
<div>
- <div v-if="commit" class="float-left mr-3 d-flex align-items-center js-commit-info">
- <gl-icon ref="commitIcon" name="commit" class="mr-1" />
+ <div
+ v-if="commit"
+ class="gl-float-left gl-mr-5 gl-display-flex gl-align-items-center js-commit-info"
+ >
+ <gl-icon ref="commitIcon" name="commit" class="gl-mr-2" />
<div v-gl-tooltip.bottom :title="commit.title">
<gl-link v-if="commitPath" :href="commitPath">
{{ commit.shortId }}
@@ -76,8 +79,11 @@ export default {
</div>
</div>
- <div v-if="tagName" class="float-left mr-3 d-flex align-items-center js-tag-info">
- <gl-icon name="tag" class="mr-1" />
+ <div
+ v-if="tagName"
+ class="gl-float-left gl-mr-5 gl-display-flex gl-align-items-center js-tag-info"
+ >
+ <gl-icon name="tag" class="gl-mr-2" />
<div v-gl-tooltip.bottom :title="__('Tag')">
<gl-link v-if="tagPath" :href="tagPath">
{{ tagName }}
@@ -88,23 +94,23 @@ export default {
<div
v-if="releasedAt || author"
- class="float-left d-flex align-items-center js-author-date-info"
+ class="gl-float-left gl-display-flex gl-align-items-center js-author-date-info"
>
- <span class="text-secondary">{{ createdTime }}&nbsp;</span>
+ <span class="gl-text-secondary">{{ createdTime }}&nbsp;</span>
<template v-if="releasedAt">
<span
v-gl-tooltip.bottom
:title="tooltipTitle(releasedAt)"
- class="text-secondary flex-shrink-0"
+ class="gl-text-secondary gl-flex-shrink-0"
>
{{ releasedAtTimeAgo }}&nbsp;
</span>
</template>
- <div v-if="author" class="d-flex">
- <span class="text-secondary">{{ __('by') }}&nbsp;</span>
+ <div v-if="author" class="gl-display-flex">
+ <span class="gl-text-secondary">{{ __('by') }}&nbsp;</span>
<user-avatar-link
- class="gl-my-n1"
+ class="gl-my-n1 gl-display-flex"
:link-href="author.webUrl"
:img-src="author.avatarUrl"
:img-alt="userImageAltDescription"
diff --git a/app/assets/javascripts/releases/components/tag_field.vue b/app/assets/javascripts/releases/components/tag_field.vue
index f4c0fd5e9ce..b4fea9bee35 100644
--- a/app/assets/javascripts/releases/components/tag_field.vue
+++ b/app/assets/javascripts/releases/components/tag_field.vue
@@ -1,5 +1,5 @@
<script>
-import { mapGetters } from 'vuex';
+import { mapState } from 'vuex';
import TagFieldExisting from './tag_field_existing.vue';
import TagFieldNew from './tag_field_new.vue';
@@ -9,7 +9,7 @@ export default {
TagFieldNew,
},
computed: {
- ...mapGetters('editNew', ['isExistingRelease']),
+ ...mapState('editNew', ['isExistingRelease']),
},
};
</script>
diff --git a/app/assets/javascripts/releases/components/tag_field_new.vue b/app/assets/javascripts/releases/components/tag_field_new.vue
index d3b6d07590f..08b727dcca0 100644
--- a/app/assets/javascripts/releases/components/tag_field_new.vue
+++ b/app/assets/javascripts/releases/components/tag_field_new.vue
@@ -22,12 +22,10 @@ export default {
// the input field. This is used to avoid showing validation
// errors immediately when the page loads.
isInputDirty: false,
-
- showCreateFrom: true,
};
},
computed: {
- ...mapState('editNew', ['projectId', 'release', 'createFrom']),
+ ...mapState('editNew', ['projectId', 'release', 'createFrom', 'showCreateFrom']),
...mapGetters('editNew', ['validationErrors']),
tagName: {
get() {
@@ -40,7 +38,7 @@ export default {
// When this is called, the selection originated from the
// dropdown list of existing tag names, so we know the tag
// already exists and don't need to show the "create from" input
- this.showCreateFrom = false;
+ this.updateShowCreateFrom(false);
},
},
createFromModel: {
@@ -70,7 +68,12 @@ export default {
},
},
methods: {
- ...mapActions('editNew', ['updateReleaseTagName', 'updateCreateFrom', 'fetchTagNotes']),
+ ...mapActions('editNew', [
+ 'updateReleaseTagName',
+ 'updateCreateFrom',
+ 'fetchTagNotes',
+ 'updateShowCreateFrom',
+ ]),
markInputAsDirty() {
this.isInputDirty = true;
},
@@ -80,7 +83,7 @@ export default {
// This method is called when the user selects the "create tag"
// option, so the tag does not already exist. Because of this,
// we need to show the "create from" input.
- this.showCreateFrom = true;
+ this.updateShowCreateFrom(true);
},
shouldShowCreateTagOption(isLoading, matches, query) {
// Show the "create tag" option if:
diff --git a/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql b/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql
index 236d266a40a..3ad66afa259 100644
--- a/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql
+++ b/app/assets/javascripts/releases/graphql/fragments/release_for_editing.fragment.graphql
@@ -3,6 +3,8 @@ fragment ReleaseForEditing on Release {
name
tagName
description
+ releasedAt
+ tagPath
assets {
links {
nodes {
diff --git a/app/assets/javascripts/releases/graphql/mutations/delete_release.mutation.graphql b/app/assets/javascripts/releases/graphql/mutations/delete_release.mutation.graphql
new file mode 100644
index 00000000000..7a8bf9944a3
--- /dev/null
+++ b/app/assets/javascripts/releases/graphql/mutations/delete_release.mutation.graphql
@@ -0,0 +1,5 @@
+mutation deleteRelease($input: ReleaseDeleteInput!) {
+ releaseDelete(input: $input) {
+ errors
+ }
+}
diff --git a/app/assets/javascripts/releases/mount_edit.js b/app/assets/javascripts/releases/mount_edit.js
index fad0451ceef..c3130a0b778 100644
--- a/app/assets/javascripts/releases/mount_edit.js
+++ b/app/assets/javascripts/releases/mount_edit.js
@@ -11,7 +11,7 @@ export default () => {
const store = createStore({
modules: {
- editNew: createEditNewModule(el.dataset),
+ editNew: createEditNewModule({ ...el.dataset, isExistingRelease: true }),
},
});
diff --git a/app/assets/javascripts/releases/mount_index.js b/app/assets/javascripts/releases/mount_index.js
index afb8ab461cd..8e806f0e8d7 100644
--- a/app/assets/javascripts/releases/mount_index.js
+++ b/app/assets/javascripts/releases/mount_index.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import { GlToast } from '@gitlab/ui';
import createDefaultClient from '~/lib/graphql';
import ReleaseIndexApp from './components/app_index.vue';
@@ -7,6 +8,7 @@ export default () => {
const el = document.getElementById('js-releases-page');
Vue.use(VueApollo);
+ Vue.use(GlToast);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(
diff --git a/app/assets/javascripts/releases/mount_new.js b/app/assets/javascripts/releases/mount_new.js
index b358a27f06d..0a3f8b5e63b 100644
--- a/app/assets/javascripts/releases/mount_new.js
+++ b/app/assets/javascripts/releases/mount_new.js
@@ -11,7 +11,7 @@ export default () => {
const store = createStore({
modules: {
- editNew: createEditNewModule(el.dataset),
+ editNew: createEditNewModule({ ...el.dataset, isExistingRelease: false }),
},
});
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
index 08197377f61..a71a8125d65 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
@@ -3,16 +3,21 @@ import createFlash from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import createReleaseMutation from '~/releases/graphql/mutations/create_release.mutation.graphql';
+import deleteReleaseMutation from '~/releases/graphql/mutations/delete_release.mutation.graphql';
import createReleaseAssetLinkMutation from '~/releases/graphql/mutations/create_release_link.mutation.graphql';
import deleteReleaseAssetLinkMutation from '~/releases/graphql/mutations/delete_release_link.mutation.graphql';
import updateReleaseMutation from '~/releases/graphql/mutations/update_release.mutation.graphql';
import oneReleaseForEditingQuery from '~/releases/graphql/queries/one_release_for_editing.query.graphql';
-import { gqClient, convertOneReleaseGraphQLResponse } from '~/releases/util';
+import {
+ gqClient,
+ convertOneReleaseGraphQLResponse,
+ deleteReleaseSessionKey,
+} from '~/releases/util';
import * as types from './mutation_types';
-export const initializeRelease = ({ commit, dispatch, getters }) => {
- if (getters.isExistingRelease) {
+export const initializeRelease = ({ commit, dispatch, state }) => {
+ if (state.isExistingRelease) {
// When editing an existing release,
// fetch the release object from the API
return dispatch('fetchRelease');
@@ -53,6 +58,9 @@ export const updateReleaseTagName = ({ commit }, tagName) =>
export const updateCreateFrom = ({ commit }, createFrom) =>
commit(types.UPDATE_CREATE_FROM, createFrom);
+export const updateShowCreateFrom = ({ commit }, showCreateFrom) =>
+ commit(types.UPDATE_SHOW_CREATE_FROM, showCreateFrom);
+
export const updateReleaseTitle = ({ commit }, title) => commit(types.UPDATE_RELEASE_TITLE, title);
export const updateReleaseNotes = ({ commit }, notes) => commit(types.UPDATE_RELEASE_NOTES, notes);
@@ -88,10 +96,10 @@ export const receiveSaveReleaseSuccess = ({ commit }, urlToRedirectTo) => {
redirectTo(urlToRedirectTo);
};
-export const saveRelease = ({ commit, dispatch, getters }) => {
+export const saveRelease = ({ commit, dispatch, state }) => {
commit(types.REQUEST_SAVE_RELEASE);
- dispatch(getters.isExistingRelease ? 'updateRelease' : 'createRelease');
+ dispatch(state.isExistingRelease ? 'updateRelease' : 'createRelease');
};
/**
@@ -246,3 +254,30 @@ export const fetchTagNotes = ({ commit, state }, tagName) => {
export const updateIncludeTagNotes = ({ commit }, includeTagNotes) => {
commit(types.UPDATE_INCLUDE_TAG_NOTES, includeTagNotes);
};
+
+export const updateReleasedAt = ({ commit }, releasedAt) => {
+ commit(types.UPDATE_RELEASED_AT, releasedAt);
+};
+
+export const deleteRelease = ({ commit, getters, dispatch, state }) => {
+ commit(types.REQUEST_SAVE_RELEASE);
+ return gqClient
+ .mutate({
+ mutation: deleteReleaseMutation,
+ variables: getters.releaseDeleteMutationVariables,
+ })
+ .then((response) => checkForErrorsAsData(response, 'releaseDelete', ''))
+ .then(() => {
+ window.sessionStorage.setItem(
+ deleteReleaseSessionKey(state.projectPath),
+ state.originalRelease.name,
+ );
+ return dispatch('receiveSaveReleaseSuccess', state.releasesPagePath);
+ })
+ .catch((error) => {
+ commit(types.RECEIVE_SAVE_RELEASE_ERROR, error);
+ createFlash({
+ message: s__('Release|Something went wrong while deleting the release.'),
+ });
+ });
+};
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/getters.js b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
index 0ca5eb9931a..62d6bd42d51 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
@@ -4,14 +4,6 @@ import { hasContent } from '~/lib/utils/text_utility';
import { getDuplicateItemsFromArray } from '~/lib/utils/array_utility';
/**
- * @returns {Boolean} `true` if the app is editing an existing release.
- * `false` if the app is creating a new release.
- */
-export const isExistingRelease = (state) => {
- return Boolean(state.tagName);
-};
-
-/**
* @param {Object} link The link to test
* @returns {Boolean} `true` if the release link is empty, i.e. it has
* empty (or whitespace-only) values for both `url` and `name`.
@@ -138,6 +130,7 @@ export const releaseUpdateMutatationVariables = (state, getters) => {
projectPath: state.projectPath,
tagName: state.release.tagName,
name,
+ releasedAt: state.release.releasedAt,
description: state.includeTagNotes
? getters.formattedReleaseNotes
: state.release.description,
@@ -163,6 +156,13 @@ export const releaseCreateMutatationVariables = (state, getters) => {
};
};
+export const releaseDeleteMutationVariables = (state) => ({
+ input: {
+ projectPath: state.projectPath,
+ tagName: state.release.tagName,
+ },
+});
+
export const formattedReleaseNotes = ({ includeTagNotes, release: { description }, tagNotes }) =>
includeTagNotes && tagNotes
? `${description}\n\n### ${s__('Releases|Tag message')}\n\n${tagNotes}\n`
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/mutation_types.js b/app/assets/javascripts/releases/stores/modules/edit_new/mutation_types.js
index daa077309a1..0ef017f4eb4 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/mutation_types.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/mutation_types.js
@@ -6,6 +6,7 @@ export const RECEIVE_RELEASE_ERROR = 'RECEIVE_RELEASE_ERROR';
export const UPDATE_RELEASE_TAG_NAME = 'UPDATE_RELEASE_TAG_NAME';
export const UPDATE_CREATE_FROM = 'UPDATE_CREATE_FROM';
+export const UPDATE_SHOW_CREATE_FROM = 'UPDATE_SHOW_CREATE_FROM';
export const UPDATE_RELEASE_TITLE = 'UPDATE_RELEASE_TITLE';
export const UPDATE_RELEASE_NOTES = 'UPDATE_RELEASE_NOTES';
export const UPDATE_RELEASE_MILESTONES = 'UPDATE_RELEASE_MILESTONES';
@@ -26,3 +27,4 @@ export const RECEIVE_TAG_NOTES_SUCCESS = 'RECEIVE_TAG_NOTES_SUCCESS';
export const RECEIVE_TAG_NOTES_ERROR = 'RECEIVE_TAG_NOTES_ERROR';
export const UPDATE_INCLUDE_TAG_NOTES = 'UPDATE_INCLUDE_TAG_NOTES';
+export const UPDATE_RELEASED_AT = 'UPDATE_RELEASED_AT';
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/mutations.js b/app/assets/javascripts/releases/stores/modules/edit_new/mutations.js
index 6b22468bbfe..ea794f91f66 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/mutations.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/mutations.js
@@ -9,11 +9,12 @@ const findReleaseLink = (release, id) => {
export default {
[types.INITIALIZE_EMPTY_RELEASE](state) {
state.release = {
- tagName: null,
+ tagName: state.tagName,
name: '',
description: '',
milestones: [],
groupMilestones: [],
+ releasedAt: new Date(),
assets: {
links: [],
},
@@ -41,6 +42,9 @@ export default {
[types.UPDATE_CREATE_FROM](state, createFrom) {
state.createFrom = createFrom;
},
+ [types.UPDATE_SHOW_CREATE_FROM](state, showCreateFrom) {
+ state.showCreateFrom = showCreateFrom;
+ },
[types.UPDATE_RELEASE_TITLE](state, title) {
state.release.name = title;
},
@@ -113,4 +117,7 @@ export default {
[types.UPDATE_INCLUDE_TAG_NOTES](state, includeTagNotes) {
state.includeTagNotes = includeTagNotes;
},
+ [types.UPDATE_RELEASED_AT](state, releasedAt) {
+ state.release.releasedAt = releasedAt;
+ },
};
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/state.js b/app/assets/javascripts/releases/stores/modules/edit_new/state.js
index 33cb3ee06d0..cb447cf9aaf 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/state.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/state.js
@@ -1,4 +1,5 @@
export default ({
+ isExistingRelease,
projectId,
groupId,
groupMilestonesAvailable = false,
@@ -10,10 +11,13 @@ export default ({
newMilestonePath,
releasesPagePath,
editReleaseDocsPath,
+ upcomingReleaseDocsPath,
+ deleteReleaseDocsPath = '',
tagName = null,
defaultBranch = null,
}) => ({
+ isExistingRelease,
projectId,
groupId,
groupMilestonesAvailable: Boolean(groupMilestonesAvailable),
@@ -25,12 +29,15 @@ export default ({
newMilestonePath,
releasesPagePath,
editReleaseDocsPath,
+ upcomingReleaseDocsPath,
+ deleteReleaseDocsPath,
/**
* The name of the tag associated with the release, provided by the backend.
- * When creating a new release, this value is null.
+ * When creating a new release, this is the default from the URL
*/
tagName,
+ showCreateFrom: !tagName,
defaultBranch,
createFrom: defaultBranch,
diff --git a/app/assets/javascripts/releases/util.js b/app/assets/javascripts/releases/util.js
index 22d5fb4f620..f1f5f4bca4c 100644
--- a/app/assets/javascripts/releases/util.js
+++ b/app/assets/javascripts/releases/util.js
@@ -11,10 +11,13 @@ const convertScalarProperties = (graphQLRelease) =>
'tagPath',
'description',
'descriptionHtml',
- 'releasedAt',
'upcomingRelease',
]);
+const convertDateProperties = ({ releasedAt }) => ({
+ releasedAt: new Date(releasedAt),
+});
+
const convertAssets = (graphQLRelease) => {
let sources = [];
if (graphQLRelease.assets.sources?.nodes) {
@@ -88,6 +91,7 @@ const convertMilestones = (graphQLRelease) => ({
*/
export const convertGraphQLRelease = (graphQLRelease) => ({
...convertScalarProperties(graphQLRelease),
+ ...convertDateProperties(graphQLRelease),
...convertAssets(graphQLRelease),
...convertEvidences(graphQLRelease),
...convertLinks(graphQLRelease),
@@ -129,3 +133,5 @@ export const convertOneReleaseGraphQLResponse = (response) => {
return { data: release };
};
+
+export const deleteReleaseSessionKey = (projectPath) => `deleteRelease:${projectPath}`;