diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 09:08:11 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 09:08:11 +0000 |
commit | 5064bf8c5647d4c4430cbb4d097cf1592416de29 (patch) | |
tree | d051bf2abe2cc7061b3a7facb6669a56ccb9cf54 /app/assets/javascripts | |
parent | 9c83aadd2604e7e6cb1f84683f951e6b12872618 (diff) | |
download | gitlab-ce-5064bf8c5647d4c4430cbb4d097cf1592416de29.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
13 files changed, 298 insertions, 31 deletions
diff --git a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue index 7f0c232eea8..7418ca9edfc 100644 --- a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue +++ b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue @@ -1,7 +1,6 @@ <script> import { GlPopover, GlSprintf, GlButton, GlIcon } from '@gitlab/ui'; -import Cookies from 'js-cookie'; -import { parseBoolean, scrollToElement } from '~/lib/utils/common_utils'; +import { parseBoolean, scrollToElement, setCookie, getCookie } from '~/lib/utils/common_utils'; import { s__ } from '~/locale'; import { glEmojiTag } from '~/emoji'; import Tracking from '~/tracking'; @@ -51,7 +50,7 @@ export default { }, data() { return { - popoverDismissed: parseBoolean(Cookies.get(this.dismissKey)), + popoverDismissed: parseBoolean(getCookie(`${this.trackLabel}_${this.dismissKey}`)), tracking: { label: this.trackLabel, property: this.humanAccess, @@ -68,17 +67,27 @@ export default { emoji() { return popoverStates[this.trackLabel].emoji || ''; }, + dismissCookieName() { + return `${this.trackLabel}_${this.dismissKey}`; + }, + commitCookieName() { + return `suggest_gitlab_ci_yml_commit_${this.dismissKey}`; + }, }, mounted() { - if (this.trackLabel === 'suggest_commit_first_project_gitlab_ci_yml' && !this.popoverDismissed) + if ( + this.trackLabel === 'suggest_commit_first_project_gitlab_ci_yml' && + !this.popoverDismissed + ) { scrollToElement(document.querySelector(this.target)); + } this.trackOnShow(); }, methods: { onDismiss() { this.popoverDismissed = true; - Cookies.set(this.dismissKey, this.popoverDismissed, { expires: 365 }); + setCookie(this.dismissCookieName, this.popoverDismissed); }, trackOnShow() { if (!this.popoverDismissed) this.track(); diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index f4ce98037c8..5a77896f5ef 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -5,6 +5,7 @@ import NewCommitForm from '../new_commit_form'; import EditBlob from './edit_blob'; import BlobFileDropzone from '../blob/blob_file_dropzone'; import initPopover from '~/blob/suggest_gitlab_ci_yml'; +import { setCookie } from '~/lib/utils/common_utils'; export default () => { const editBlobForm = $('.js-edit-blob-form'); @@ -60,6 +61,16 @@ export default () => { } if (suggestEl) { + const commitButton = document.querySelector('#commit-changes'); + initPopover(suggestEl); + + if (commitButton) { + const commitCookieName = `suggest_gitlab_ci_yml_commit_${suggestEl.dataset.dismissKey}`; + + commitButton.addEventListener('click', () => { + setCookie(commitCookieName, true); + }); + } } }; diff --git a/app/assets/javascripts/environments/components/delete_environment_modal.vue b/app/assets/javascripts/environments/components/delete_environment_modal.vue new file mode 100644 index 00000000000..f731dc49a5b --- /dev/null +++ b/app/assets/javascripts/environments/components/delete_environment_modal.vue @@ -0,0 +1,66 @@ +<script> +import { GlTooltipDirective } from '@gitlab/ui'; +import GlModal from '~/vue_shared/components/gl_modal.vue'; +import { s__, sprintf } from '~/locale'; +import eventHub from '../event_hub'; + +export default { + id: 'delete-environment-modal', + name: 'DeleteEnvironmentModal', + + components: { + GlModal, + }, + + directives: { + GlTooltip: GlTooltipDirective, + }, + + props: { + environment: { + type: Object, + required: true, + }, + }, + + computed: { + confirmDeleteMessage() { + return sprintf( + s__( + `Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?`, + ), + { + environmentName: this.environment.name, + }, + false, + ); + }, + }, + + methods: { + onSubmit() { + eventHub.$emit('deleteEnvironment', this.environment); + }, + }, +}; +</script> + +<template> + <gl-modal + :id="$options.id" + :footer-primary-button-text="s__('Environments|Delete environment')" + footer-primary-button-variant="danger" + @submit="onSubmit" + > + <template slot="header"> + <h4 class="modal-title d-flex mw-100"> + {{ __('Delete') }} + <span v-gl-tooltip :title="environment.name" class="text-truncate mx-1 flex-fill"> + {{ environment.name }}? + </span> + </h4> + </template> + + <p>{{ confirmDeleteMessage }}</p> + </gl-modal> +</template> diff --git a/app/assets/javascripts/environments/components/environment_delete.vue b/app/assets/javascripts/environments/components/environment_delete.vue new file mode 100644 index 00000000000..b53c5fa6583 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_delete.vue @@ -0,0 +1,70 @@ +<script> +/** + * Renders the delete button that allows deleting a stopped environment. + * Used in the environments table and the environment detail view. + */ + +import $ from 'jquery'; +import { GlTooltipDirective } from '@gitlab/ui'; +import Icon from '~/vue_shared/components/icon.vue'; +import { s__ } from '~/locale'; +import eventHub from '../event_hub'; +import LoadingButton from '../../vue_shared/components/loading_button.vue'; + +export default { + components: { + Icon, + LoadingButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + environment: { + type: Object, + required: true, + }, + }, + data() { + return { + isLoading: false, + }; + }, + computed: { + title() { + return s__('Environments|Delete environment'); + }, + }, + mounted() { + eventHub.$on('deleteEnvironment', this.onDeleteEnvironment); + }, + beforeDestroy() { + eventHub.$off('deleteEnvironment', this.onDeleteEnvironment); + }, + methods: { + onClick() { + $(this.$el).tooltip('dispose'); + eventHub.$emit('requestDeleteEnvironment', this.environment); + }, + onDeleteEnvironment(environment) { + if (this.environment.id === environment.id) { + this.isLoading = true; + } + }, + }, +}; +</script> +<template> + <loading-button + v-gl-tooltip + :loading="isLoading" + :title="title" + :aria-label="title" + container-class="btn btn-danger d-none d-sm-none d-md-block" + data-toggle="modal" + data-target="#delete-environment-modal" + @click="onClick" + > + <icon name="remove" /> + </loading-button> +</template> diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index dc489c804e9..ec5b1092c14 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -15,8 +15,9 @@ import ActionsComponent from './environment_actions.vue'; import ExternalUrlComponent from './environment_external_url.vue'; import MonitoringButtonComponent from './environment_monitoring.vue'; import PinComponent from './environment_pin.vue'; -import RollbackComponent from './environment_rollback.vue'; +import DeleteComponent from './environment_delete.vue'; import StopComponent from './environment_stop.vue'; +import RollbackComponent from './environment_rollback.vue'; import TerminalButtonComponent from './environment_terminal_button.vue'; /** @@ -33,6 +34,7 @@ export default { Icon, MonitoringButtonComponent, PinComponent, + DeleteComponent, RollbackComponent, StopComponent, TerminalButtonComponent, @@ -113,6 +115,15 @@ export default { }, /** + * Returns whether the environment can be deleted. + * + * @returns {Boolean} + */ + canDeleteEnvironment() { + return Boolean(this.model && this.model.can_delete && this.model.delete_path); + }, + + /** * Verifies if the `deployable` key is present in `last_deployment` key. * Used to verify whether we should or not render the rollback partial. * @@ -485,6 +496,7 @@ export default { this.externalURL || this.monitoringUrl || this.canStopEnvironment || + this.canDeleteEnvironment || this.canRetry ); }, @@ -680,6 +692,8 @@ export default { /> <stop-component v-if="canStopEnvironment" :environment="model" /> + + <delete-component v-if="canDeleteEnvironment" :environment="model" /> </div> </div> </div> diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index 07b8d20fde0..cc1d86d06ed 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -9,6 +9,7 @@ import environmentsMixin from '../mixins/environments_mixin'; import CIPaginationMixin from '~/vue_shared/mixins/ci_pagination_api_mixin'; import EnableReviewAppButton from './enable_review_app_button.vue'; import StopEnvironmentModal from './stop_environment_modal.vue'; +import DeleteEnvironmentModal from './delete_environment_modal.vue'; import ConfirmRollbackModal from './confirm_rollback_modal.vue'; export default { @@ -18,6 +19,7 @@ export default { EnableReviewAppButton, GlButton, StopEnvironmentModal, + DeleteEnvironmentModal, }, mixins: [CIPaginationMixin, environmentsMixin, envrionmentsAppMixin], @@ -95,6 +97,7 @@ export default { <template> <div> <stop-environment-modal :environment="environmentInStopModal" /> + <delete-environment-modal :environment="environmentInDeleteModal" /> <confirm-rollback-modal :environment="environmentInRollbackModal" /> <div class="top-area"> diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue index 3caf723442e..d3e8fb7ff08 100644 --- a/app/assets/javascripts/environments/components/stop_environment_modal.vue +++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue @@ -63,10 +63,9 @@ export default { <template slot="header"> <h4 class="modal-title d-flex mw-100"> Stopping - <span v-gl-tooltip :title="environment.name" class="text-truncate ml-1 mr-1 flex-fill">{{ - environment.name - }}</span> - ? + <span v-gl-tooltip :title="environment.name" class="text-truncate ml-1 mr-1 flex-fill"> + {{ environment.name }}? + </span> </h4> </template> diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue index d60c2efd618..30b02585692 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.vue +++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue @@ -3,10 +3,12 @@ import folderMixin from 'ee_else_ce/environments/mixins/environments_folder_view import environmentsMixin from '../mixins/environments_mixin'; import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; import StopEnvironmentModal from '../components/stop_environment_modal.vue'; +import DeleteEnvironmentModal from '../components/delete_environment_modal.vue'; export default { components: { StopEnvironmentModal, + DeleteEnvironmentModal, }, mixins: [environmentsMixin, CIPaginationMixin, folderMixin], @@ -39,6 +41,7 @@ export default { <template> <div :class="cssContainerClass"> <stop-environment-modal :environment="environmentInStopModal" /> + <delete-environment-modal :environment="environmentInDeleteModal" /> <h4 class="js-folder-name environments-folder-name"> {{ s__('Environments|Environments') }} / diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index 1c5884b541c..4fadecdd3e9 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -27,6 +27,10 @@ export default { data() { const store = new EnvironmentsStore(); + const isDetailView = document.body.contains( + document.getElementById('environments-detail-view'), + ); + return { store, state: store.state, @@ -36,7 +40,9 @@ export default { page: getParameterByName('page') || '1', requestData: {}, environmentInStopModal: {}, + environmentInDeleteModal: {}, environmentInRollbackModal: {}, + isDetailView, }; }, @@ -121,6 +127,10 @@ export default { this.environmentInStopModal = environment; }, + updateDeleteModal(environment) { + this.environmentInDeleteModal = environment; + }, + updateRollbackModal(environment) { this.environmentInRollbackModal = environment; }, @@ -133,6 +143,30 @@ export default { this.postAction({ endpoint, errorMessage }); }, + deleteEnvironment(environment) { + const endpoint = environment.delete_path; + const mountedToShow = environment.mounted_to_show; + const errorMessage = s__( + 'Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.', + ); + + this.service + .deleteAction(endpoint) + .then(() => { + if (!mountedToShow) { + // Reload as a first solution to bust the ETag cache + window.location.reload(); + return; + } + const url = window.location.href.split('/'); + url.pop(); + window.location.href = url.join('/'); + }) + .catch(() => { + Flash(errorMessage); + }); + }, + rollbackEnvironment(environment) { const { retryUrl, isLastDeployment } = environment; const errorMessage = isLastDeployment @@ -178,36 +212,42 @@ export default { this.service = new EnvironmentsService(this.endpoint); this.requestData = { page: this.page, scope: this.scope, nested: true }; - this.poll = new Poll({ - resource: this.service, - method: 'fetchEnvironments', - data: this.requestData, - successCallback: this.successCallback, - errorCallback: this.errorCallback, - notificationCallback: isMakingRequest => { - this.isMakingRequest = isMakingRequest; - }, - }); - - if (!Visibility.hidden()) { - this.isLoading = true; - this.poll.makeRequest(); - } else { - this.fetchEnvironments(); - } + if (!this.isDetailView) { + this.poll = new Poll({ + resource: this.service, + method: 'fetchEnvironments', + data: this.requestData, + successCallback: this.successCallback, + errorCallback: this.errorCallback, + notificationCallback: isMakingRequest => { + this.isMakingRequest = isMakingRequest; + }, + }); - Visibility.change(() => { if (!Visibility.hidden()) { - this.poll.restart(); + this.isLoading = true; + this.poll.makeRequest(); } else { - this.poll.stop(); + this.fetchEnvironments(); } - }); + + Visibility.change(() => { + if (!Visibility.hidden()) { + this.poll.restart(); + } else { + this.poll.stop(); + } + }); + } eventHub.$on('postAction', this.postAction); + eventHub.$on('requestStopEnvironment', this.updateStopModal); eventHub.$on('stopEnvironment', this.stopEnvironment); + eventHub.$on('requestDeleteEnvironment', this.updateDeleteModal); + eventHub.$on('deleteEnvironment', this.deleteEnvironment); + eventHub.$on('requestRollbackEnvironment', this.updateRollbackModal); eventHub.$on('rollbackEnvironment', this.rollbackEnvironment); @@ -216,9 +256,13 @@ export default { beforeDestroy() { eventHub.$off('postAction', this.postAction); + eventHub.$off('requestStopEnvironment', this.updateStopModal); eventHub.$off('stopEnvironment', this.stopEnvironment); + eventHub.$off('requestDeleteEnvironment', this.updateDeleteModal); + eventHub.$off('deleteEnvironment', this.deleteEnvironment); + eventHub.$off('requestRollbackEnvironment', this.updateRollbackModal); eventHub.$off('rollbackEnvironment', this.rollbackEnvironment); diff --git a/app/assets/javascripts/environments/mount_show.js b/app/assets/javascripts/environments/mount_show.js new file mode 100644 index 00000000000..1929ed080a1 --- /dev/null +++ b/app/assets/javascripts/environments/mount_show.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import DeleteEnvironmentModal from './components/delete_environment_modal.vue'; +import environmentsMixin from './mixins/environments_mixin'; + +export default () => { + const el = document.getElementById('delete-environment-modal'); + const container = document.getElementById('environments-detail-view'); + + return new Vue({ + el, + components: { + DeleteEnvironmentModal, + }, + mixins: [environmentsMixin], + data() { + const environment = JSON.parse(JSON.stringify(container.dataset)); + environment.delete_path = environment.deletePath; + environment.mounted_to_show = true; + + return { + environment, + }; + }, + render(createElement) { + return createElement('delete-environment-modal', { + props: { + environment: this.environment, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/environments/services/environments_service.js b/app/assets/javascripts/environments/services/environments_service.js index cb4ff6856db..122c8f84a2c 100644 --- a/app/assets/javascripts/environments/services/environments_service.js +++ b/app/assets/javascripts/environments/services/environments_service.js @@ -16,6 +16,11 @@ export default class EnvironmentsService { return axios.post(endpoint, {}); } + // eslint-disable-next-line class-methods-use-this + deleteAction(endpoint) { + return axios.delete(endpoint, {}); + } + getFolderContent(folderUrl) { return axios.get(`${folderUrl}.json?per_page=${this.folderResults}`); } diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index abecfba5718..9b0ee40a30a 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -9,6 +9,7 @@ import { getLocationHash } from './url_utility'; import { convertToCamelCase, convertToSnakeCase } from './text_utility'; import { isObject } from './type_utility'; import { isFunction } from 'lodash'; +import Cookies from 'js-cookie'; export const getPagePath = (index = 0) => { const page = $('body').attr('data-page') || ''; @@ -902,3 +903,10 @@ window.gl.utils = { spriteIcon, imagePath, }; + +// Methods to set and get Cookie +export const setCookie = (name, value) => Cookies.set(name, value, { expires: 365 }); + +export const getCookie = name => Cookies.get(name); + +export const removeCookie = name => Cookies.remove(name); diff --git a/app/assets/javascripts/pages/projects/environments/show/index.js b/app/assets/javascripts/pages/projects/environments/show/index.js new file mode 100644 index 00000000000..10e3e28f024 --- /dev/null +++ b/app/assets/javascripts/pages/projects/environments/show/index.js @@ -0,0 +1,3 @@ +import initShowEnvironment from '~/environments/mount_show'; + +document.addEventListener('DOMContentLoaded', () => initShowEnvironment()); |