diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-14 21:07:45 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-14 21:07:45 +0000 |
commit | 0b12a5312c9701fbfed25fbb334d47900ced736b (patch) | |
tree | a29a27e297134f573fd8e5c298d241f3156c207a /app/assets/javascripts/self_monitor | |
parent | 92f95ccac81911d1fcc32e999a7f1ce04624a56c (diff) | |
download | gitlab-ce-0b12a5312c9701fbfed25fbb334d47900ced736b.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/self_monitor')
7 files changed, 373 insertions, 0 deletions
diff --git a/app/assets/javascripts/self_monitor/components/self_monitor_form.vue b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue new file mode 100644 index 00000000000..2f364eae67f --- /dev/null +++ b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue @@ -0,0 +1,160 @@ +<script> +import Vue from 'vue'; +import { GlFormGroup, GlButton, GlModal, GlToast, GlToggle } from '@gitlab/ui'; +import { mapState, mapActions } from 'vuex'; +import { __, s__, sprintf } from '~/locale'; +import { visitUrl, getBaseURL } from '~/lib/utils/url_utility'; + +Vue.use(GlToast); + +export default { + components: { + GlFormGroup, + GlButton, + GlModal, + GlToggle, + }, + formLabels: { + createProject: __('Create Project'), + }, + data() { + return { + modalId: 'delete-self-monitor-modal', + }; + }, + computed: { + ...mapState('selfMonitoring', [ + 'projectEnabled', + 'projectCreated', + 'showAlert', + 'projectPath', + 'loading', + 'alertContent', + ]), + selfMonitorEnabled: { + get() { + return this.projectEnabled; + }, + set(projectEnabled) { + this.setSelfMonitor(projectEnabled); + }, + }, + selfMonitorProjectFullUrl() { + return `${getBaseURL()}/${this.projectPath}`; + }, + selfMonitoringFormText() { + if (this.projectCreated) { + return sprintf( + s__( + 'SelfMonitoring|Enabling this feature creates a %{projectLinkStart}project%{projectLinkEnd} that can be used to monitor the health of your instance.', + ), + { + projectLinkStart: `<a href="${this.selfMonitorProjectFullUrl}">`, + projectLinkEnd: '</a>', + }, + false, + ); + } + + return s__( + 'SelfMonitoring|Enabling this feature creates a project that can be used to monitor the health of your instance.', + ); + }, + }, + watch: { + selfMonitorEnabled() { + this.saveChangesSelfMonitorProject(); + }, + showAlert() { + let toastOptions = { + onComplete: () => { + this.resetAlert(); + }, + }; + + if (this.showAlert) { + if (this.alertContent.actionName && this.alertContent.actionName.length > 0) { + toastOptions = { + ...toastOptions, + action: { + text: this.alertContent.actionText, + onClick: (_, toastObject) => { + this[this.alertContent.actionName](); + toastObject.goAway(0); + }, + }, + }; + } + this.$toast.show(this.alertContent.message, toastOptions); + } + }, + }, + methods: { + ...mapActions('selfMonitoring', [ + 'setSelfMonitor', + 'createProject', + 'deleteProject', + 'resetAlert', + ]), + hideSelfMonitorModal() { + this.$root.$emit('bv::hide::modal', this.modalId); + this.setSelfMonitor(true); + }, + showSelfMonitorModal() { + this.$root.$emit('bv::show::modal', this.modalId); + }, + saveChangesSelfMonitorProject() { + if (this.projectCreated && !this.projectEnabled) { + this.showSelfMonitorModal(); + } else { + this.createProject(); + } + }, + viewSelfMonitorProject() { + visitUrl(this.selfMonitorProjectFullUrl); + }, + }, +}; +</script> +<template> + <section class="settings no-animate js-self-monitoring-settings"> + <div class="settings-header"> + <h4 class="js-section-header"> + {{ s__('SelfMonitoring|Self monitoring') }} + </h4> + <gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button> + <p class="js-section-sub-header"> + {{ s__('SelfMonitoring|Enable or disable instance self monitoring') }} + </p> + </div> + <div class="settings-content"> + <form name="self-monitoring-form"> + <p v-html="selfMonitoringFormText"></p> + <gl-form-group :label="$options.formLabels.createProject" label-for="self-monitor-toggle"> + <gl-toggle + v-model="selfMonitorEnabled" + :is-loading="loading" + name="self-monitor-toggle" + /> + </gl-form-group> + </form> + </div> + <gl-modal + :title="s__('SelfMonitoring|Disable self monitoring?')" + :modal-id="modalId" + :ok-title="__('Delete project')" + :cancel-title="__('Cancel')" + ok-variant="danger" + @ok="deleteProject" + @cancel="hideSelfMonitorModal" + > + <div> + {{ + s__( + 'SelfMonitoring|Disabling this feature will delete the self monitoring project. Are you sure you want to delete the project?', + ) + }} + </div> + </gl-modal> + </section> +</template> diff --git a/app/assets/javascripts/self_monitor/index.js b/app/assets/javascripts/self_monitor/index.js new file mode 100644 index 00000000000..42c94e11989 --- /dev/null +++ b/app/assets/javascripts/self_monitor/index.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; +import store from './store'; +import SelfMonitorForm from './components/self_monitor_form.vue'; + +export default () => { + const el = document.querySelector('.js-self-monitoring-settings'); + let selfMonitorProjectCreated; + + if (el) { + selfMonitorProjectCreated = el.dataset.selfMonitoringProjectExists; + // eslint-disable-next-line no-new + new Vue({ + el, + store: store({ + projectEnabled: selfMonitorProjectCreated, + ...el.dataset, + }), + render(createElement) { + return createElement(SelfMonitorForm); + }, + }); + } +}; diff --git a/app/assets/javascripts/self_monitor/store/actions.js b/app/assets/javascripts/self_monitor/store/actions.js new file mode 100644 index 00000000000..f8430a9b136 --- /dev/null +++ b/app/assets/javascripts/self_monitor/store/actions.js @@ -0,0 +1,126 @@ +import { __, s__ } from '~/locale'; +import axios from '~/lib/utils/axios_utils'; +import statusCodes from '~/lib/utils/http_status'; +import { backOff } from '~/lib/utils/common_utils'; +import * as types from './mutation_types'; + +const TWO_MINUTES = 120000; + +function backOffRequest(makeRequestCallback) { + return backOff((next, stop) => { + makeRequestCallback() + .then(resp => { + if (resp.status === statusCodes.ACCEPTED) { + next(); + } else { + stop(resp); + } + }) + .catch(stop); + }, TWO_MINUTES); +} + +export const setSelfMonitor = ({ commit }, enabled) => commit(types.SET_ENABLED, enabled); + +export const createProject = ({ dispatch }) => dispatch('requestCreateProject'); + +export const resetAlert = ({ commit }) => commit(types.SET_SHOW_ALERT, false); + +export const requestCreateProject = ({ dispatch, state, commit }) => { + commit(types.SET_LOADING, true); + axios + .post(state.createProjectEndpoint) + .then(resp => { + if (resp.status === statusCodes.ACCEPTED) { + dispatch('requestCreateProjectStatus', resp.data.job_id); + } + }) + .catch(error => { + dispatch('requestCreateProjectError', error); + }); +}; + +export const requestCreateProjectStatus = ({ dispatch, state }, jobId) => { + backOffRequest(() => axios.get(state.createProjectStatusEndpoint, { params: { job_id: jobId } })) + .then(resp => { + if (resp.status === statusCodes.OK) { + dispatch('requestCreateProjectSuccess', resp.data); + } + }) + .catch(error => { + dispatch('requestCreateProjectError', error); + }); +}; + +export const requestCreateProjectSuccess = ({ commit }, selfMonitorData) => { + commit(types.SET_LOADING, false); + commit(types.SET_PROJECT_URL, selfMonitorData.project_full_path); + commit(types.SET_ALERT_CONTENT, { + message: s__('SelfMonitoring|Self monitoring project has been successfully created.'), + actionText: __('View project'), + actionName: 'viewSelfMonitorProject', + }); + commit(types.SET_SHOW_ALERT, true); + commit(types.SET_PROJECT_CREATED, true); +}; + +export const requestCreateProjectError = ({ commit }, error) => { + const { response } = error; + const message = response.data && response.data.message ? response.data.message : ''; + + commit(types.SET_ALERT_CONTENT, { + message: `${__('There was an error saving your changes.')} ${message}`, + }); + commit(types.SET_SHOW_ALERT, true); + commit(types.SET_LOADING, false); +}; + +export const deleteProject = ({ dispatch }) => dispatch('requestDeleteProject'); + +export const requestDeleteProject = ({ dispatch, state, commit }) => { + commit(types.SET_LOADING, true); + axios + .delete(state.deleteProjectEndpoint) + .then(resp => { + if (resp.status === statusCodes.ACCEPTED) { + dispatch('requestDeleteProjectStatus', resp.data.job_id); + } + }) + .catch(error => { + dispatch('requestDeleteProjectError', error); + }); +}; + +export const requestDeleteProjectStatus = ({ dispatch, state }, jobId) => { + backOffRequest(() => axios.get(state.deleteProjectStatusEndpoint, { params: { job_id: jobId } })) + .then(resp => { + if (resp.status === statusCodes.OK) { + dispatch('requestDeleteProjectSuccess', resp.data); + } + }) + .catch(error => { + dispatch('requestDeleteProjectError', error); + }); +}; + +export const requestDeleteProjectSuccess = ({ commit }) => { + commit(types.SET_PROJECT_URL, ''); + commit(types.SET_PROJECT_CREATED, false); + commit(types.SET_ALERT_CONTENT, { + message: s__('SelfMonitoring|Self monitoring project has been successfully deleted.'), + actionText: __('Undo'), + actionName: 'createProject', + }); + commit(types.SET_SHOW_ALERT, true); + commit(types.SET_LOADING, false); +}; + +export const requestDeleteProjectError = ({ commit }, error) => { + const { response } = error; + const message = response.data && response.data.message ? response.data.message : ''; + + commit(types.SET_ALERT_CONTENT, { + message: `${__('There was an error saving your changes.')} ${message}`, + }); + commit(types.SET_LOADING, false); +}; diff --git a/app/assets/javascripts/self_monitor/store/index.js b/app/assets/javascripts/self_monitor/store/index.js new file mode 100644 index 00000000000..a222e9c87b8 --- /dev/null +++ b/app/assets/javascripts/self_monitor/store/index.js @@ -0,0 +1,21 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import createState from './state'; +import * as actions from './actions'; +import mutations from './mutations'; + +Vue.use(Vuex); + +export const createStore = initialState => + new Vuex.Store({ + modules: { + selfMonitoring: { + namespaced: true, + state: createState(initialState), + actions, + mutations, + }, + }, + }); + +export default createStore; diff --git a/app/assets/javascripts/self_monitor/store/mutation_types.js b/app/assets/javascripts/self_monitor/store/mutation_types.js new file mode 100644 index 00000000000..c5952b66144 --- /dev/null +++ b/app/assets/javascripts/self_monitor/store/mutation_types.js @@ -0,0 +1,6 @@ +export const SET_ENABLED = 'SET_ENABLED'; +export const SET_PROJECT_CREATED = 'SET_PROJECT_CREATED'; +export const SET_SHOW_ALERT = 'SET_SHOW_ALERT'; +export const SET_PROJECT_URL = 'SET_PROJECT_URL'; +export const SET_LOADING = 'SET_LOADING'; +export const SET_ALERT_CONTENT = 'SET_ALERT_CONTENT'; diff --git a/app/assets/javascripts/self_monitor/store/mutations.js b/app/assets/javascripts/self_monitor/store/mutations.js new file mode 100644 index 00000000000..7dca8bcdc4d --- /dev/null +++ b/app/assets/javascripts/self_monitor/store/mutations.js @@ -0,0 +1,22 @@ +import * as types from './mutation_types'; + +export default { + [types.SET_ENABLED](state, enabled) { + state.projectEnabled = enabled; + }, + [types.SET_PROJECT_CREATED](state, created) { + state.projectCreated = created; + }, + [types.SET_SHOW_ALERT](state, show) { + state.showAlert = show; + }, + [types.SET_PROJECT_URL](state, url) { + state.projectPath = url; + }, + [types.SET_LOADING](state, loading) { + state.loading = loading; + }, + [types.SET_ALERT_CONTENT](state, content) { + state.alertContent = content; + }, +}; diff --git a/app/assets/javascripts/self_monitor/store/state.js b/app/assets/javascripts/self_monitor/store/state.js new file mode 100644 index 00000000000..b8b4a4af614 --- /dev/null +++ b/app/assets/javascripts/self_monitor/store/state.js @@ -0,0 +1,15 @@ +import { parseBoolean } from '~/lib/utils/common_utils'; + +export default (initialState = {}) => ({ + projectEnabled: parseBoolean(initialState.projectEnabled) || false, + projectCreated: parseBoolean(initialState.selfMonitorProjectCreated) || false, + createProjectEndpoint: initialState.createSelfMonitoringProjectPath || '', + deleteProjectEndpoint: initialState.deleteSelfMonitoringProjectPath || '', + createProjectStatusEndpoint: initialState.statusCreateSelfMonitoringProjectPath || '', + deleteProjectStatusEndpoint: initialState.statusDeleteSelfMonitoringProjectPath || '', + selfMonitorProjectPath: initialState.selfMonitoringProjectFullPath || '', + showAlert: false, + projectPath: '', + loading: false, + alertContent: {}, +}); |