diff options
Diffstat (limited to 'app/assets')
14 files changed, 591 insertions, 65 deletions
diff --git a/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue b/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue index 46fed973d6d..a2d94fb8083 100644 --- a/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue +++ b/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue @@ -123,9 +123,6 @@ export default { .then(() => { this.activated = value; this.loadingActivated = false; - if (value) { - window.location.reload(); - } }) .catch(() => { createFlash(__('Update failed. Please try again.')); diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue new file mode 100644 index 00000000000..7dde9edbd27 --- /dev/null +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue @@ -0,0 +1,343 @@ +<script> +import { + GlAlert, + GlButton, + GlForm, + GlFormGroup, + GlFormInput, + GlLink, + GlModal, + GlModalDirective, + GlSprintf, + GlFormSelect, +} from '@gitlab/ui'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import ToggleButton from '~/vue_shared/components/toggle_button.vue'; +import csrf from '~/lib/utils/csrf'; +import service from '../services'; +import { i18n, serviceOptions } from '../constants'; + +export default { + i18n, + csrf, + components: { + GlAlert, + GlButton, + GlForm, + GlFormGroup, + GlFormInput, + GlFormSelect, + GlLink, + GlModal, + GlSprintf, + ClipboardButton, + ToggleButton, + }, + directives: { + 'gl-modal': GlModalDirective, + }, + mixins: [glFeatureFlagsMixin()], + props: { + prometheus: { + type: Object, + required: true, + validator: ({ prometheusIsActivated }) => { + return prometheusIsActivated !== undefined; + }, + }, + generic: { + type: Object, + required: true, + validator: ({ formPath }) => { + return formPath !== undefined; + }, + }, + }, + data() { + return { + activated: { + generic: this.generic.initialActivated, + prometheus: this.prometheus.prometheusIsActivated, + }, + loading: false, + authorizationKey: { + generic: this.generic.initialAuthorizationKey, + prometheus: this.prometheus.prometheusAuthorizationKey, + }, + selectedEndpoint: null, + options: serviceOptions, + prometheusApiKey: this.prometheus.prometheusApiUrl, + feedback: { + variant: 'danger', + feedbackMessage: null, + isFeedbackDismissed: false, + }, + }; + }, + computed: { + sections() { + return [ + { + text: this.$options.i18n.usageSection, + url: this.generic.alertsUsageUrl, + }, + { + text: this.$options.i18n.setupSection, + url: this.generic.alertsSetupUrl, + }, + ]; + }, + isGeneric() { + return this.selectedEndpoint === 'generic'; + }, + selectedService() { + return this.isGeneric + ? { + url: this.generic.url, + authKey: this.authorizationKey.generic, + active: this.activated.generic, + resetKey: this.resetGenericKey.bind(this), + } + : { + authKey: this.authorizationKey.prometheus, + url: this.prometheus.prometheusUrl, + active: this.activated.prometheus, + resetKey: this.resetPrometheusKey.bind(this), + }; + }, + showFeedbackMsg() { + return this.feedback.feedbackMessage && !this.isFeedbackDismissed; + }, + prometheusInfo() { + return !this.isGeneric ? this.$options.i18n.prometheusInfo : ''; + }, + prometheusFeatureEnabled() { + return !this.isGeneric && this.glFeatures.alertIntegrationsDropdown; + }, + }, + created() { + if (this.glFeatures.alertIntegrationsDropdown) { + this.selectedEndpoint = this.prometheus.prometheusIsActivated + ? this.options[1].value + : this.options[0].value; + } else { + this.selectedEndpoint = this.options[0].value; + } + }, + methods: { + dismissFeedback() { + this.feedback = { ...this.feedback, feedbackMessage: null }; + this.isFeedbackDismissed = false; + }, + resetGenericKey() { + return service + .updateGenericKey({ endpoint: this.generic.formPath, params: { service: { token: '' } } }) + .then(({ data: { token } }) => { + this.authorizationKey.generic = token; + }) + .catch(() => { + this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); + }); + }, + resetPrometheusKey() { + return service + .updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath }) + .then(({ data: { token } }) => { + this.authorizationKey.prometheus = token; + }) + .catch(() => { + this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); + }); + }, + toggleActivated(value) { + return this.isGeneric + ? this.toggleGenericActivated(value) + : this.togglePrometheusActive(value); + }, + toggleGenericActivated(value) { + this.loading = true; + return service + .updateGenericActive({ + endpoint: this.generic.formPath, + params: { service: { active: value } }, + }) + .then(() => { + this.activated.generic = value; + + if (value) { + this.setFeedback({ + feedbackMessage: this.$options.i18n.endPointActivated, + variant: 'success', + }); + } + }) + .catch(() => {}) + .finally(() => { + this.loading = false; + }); + }, + togglePrometheusActive(value) { + this.loading = true; + return service + .updatePrometheusActive({ + endpoint: this.prometheus.prometheusFormPath, + params: { + token: this.$options.csrf.token, + config: value ? 1 : 0, + url: this.prometheusApiKey, + redirect: window.location, + }, + }) + .then(() => { + this.activated.prometheus = value; + if (value) { + this.setFeedback({ + feedbackMessage: this.$options.i18n.endPointActivated, + variant: 'success', + }); + } + }) + .catch(() => { + this.setFeedback({ + feedbackMessage: this.$options.i18n.errorApiUrlMsg, + variant: 'danger', + }); + }) + .finally(() => { + this.loading = false; + }); + }, + setFeedback({ feedbackMessage, variant }) { + this.feedback = { feedbackMessage, variant }; + }, + onSubmit(evt) { + // TODO: Add form submit as part of https://gitlab.com/gitlab-org/gitlab/-/issues/215356 + evt.preventDefault(); + }, + onReset(evt) { + // TODO: Add form reset as part of https://gitlab.com/gitlab-org/gitlab/-/issues/215356 + evt.preventDefault(); + }, + }, +}; +</script> + +<template> + <div> + <gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback"> + {{ feedback.feedbackMessage }} + </gl-alert> + <div data-testid="alert-settings-description" class="gl-mt-5"> + <p v-for="section in sections" :key="section.text"> + <gl-sprintf :message="section.text"> + <template #link="{ content }"> + <gl-link :href="section.url" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + </div> + <gl-form @submit="onSubmit" @reset="onReset"> + <gl-form-group + v-if="glFeatures.alertIntegrationsDropdown" + :label="$options.i18n.integrationsLabel" + label-for="integrations" + label-class="label-bold" + > + <gl-form-select + v-model="selectedEndpoint" + :options="options" + data-testid="alert-settings-select" + /> + <span class="gl-text-gray-400"> + <gl-sprintf :message="$options.i18n.integrationsInfo"> + <template #link="{ content }"> + <gl-link + class="gl-display-inline-block" + href="https://gitlab.com/groups/gitlab-org/-/epics/3362" + target="_blank" + >{{ content }}</gl-link + > + </template> + </gl-sprintf> + </span> + </gl-form-group> + <gl-form-group + :label="$options.i18n.activeLabel" + label-for="activated" + label-class="label-bold" + > + <toggle-button + id="activated" + :disabled-input="loading" + :is-loading="loading" + :value="selectedService.active" + @change="toggleActivated" + /> + </gl-form-group> + <gl-form-group + v-if="prometheusFeatureEnabled" + :label="$options.i18n.apiBaseUrlLabel" + label-for="api-url" + label-class="label-bold" + > + <gl-form-input + id="api-url" + v-model="prometheusApiKey" + type="url" + :value="prometheusApiKey" + :placeholder="$options.i18n.prometheusApiPlaceholder" + /> + <span class="gl-text-gray-400"> + {{ $options.i18n.apiBaseUrlHelpText }} + </span> + </gl-form-group> + <gl-form-group :label="$options.i18n.urlLabel" label-for="url" label-class="label-bold"> + <div class="input-group"> + <gl-form-input id="url" :readonly="true" :value="selectedService.url" /> + <span class="input-group-append"> + <clipboard-button :text="selectedService.url" :title="$options.i18n.copyToClipboard" /> + </span> + </div> + <span class="gl-text-gray-400"> + {{ prometheusInfo }} + </span> + </gl-form-group> + <gl-form-group + :label="$options.i18n.authKeyLabel" + label-for="authorization-key" + label-class="label-bold" + > + <div class="input-group"> + <gl-form-input id="authorization-key" :readonly="true" :value="selectedService.authKey" /> + <span class="input-group-append"> + <clipboard-button + :text="selectedService.authKey" + :title="$options.i18n.copyToClipboard" + /> + </span> + </div> + <gl-button v-gl-modal.authKeyModal class="gl-mt-3">{{ $options.i18n.resetKey }}</gl-button> + <gl-modal + modal-id="authKeyModal" + :title="$options.i18n.resetKey" + :ok-title="$options.i18n.resetKey" + ok-variant="danger" + @ok="selectedService.resetKey" + > + {{ $options.i18n.restKeyInfo }} + </gl-modal> + </gl-form-group> + <div + class="footer-block row-content-block gl-display-flex gl-justify-content-space-between d-none" + > + <gl-button type="submit" variant="success" category="primary"> + {{ __('Save and test changes') }} + </gl-button> + <gl-button type="reset" variant="default" category="primary"> + {{ __('Cancel') }} + </gl-button> + </div> + </gl-form> + </div> +</template> diff --git a/app/assets/javascripts/alerts_settings/constants.js b/app/assets/javascripts/alerts_settings/constants.js new file mode 100644 index 00000000000..15618978145 --- /dev/null +++ b/app/assets/javascripts/alerts_settings/constants.js @@ -0,0 +1,41 @@ +import { s__ } from '~/locale'; + +export const i18n = { + usageSection: s__( + 'AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.', + ), + setupSection: s__( + "AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.", + ), + errorMsg: s__( + 'AlertSettings|There was an error updating the the alert settings. Please refresh the page to try again.', + ), + errorKeyMsg: s__( + 'AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again.', + ), + errorApiUrlMsg: s__( + 'AlertSettings|There was an error while trying to enable the alert settings. Please ensure you are using a valid URL.', + ), + prometheusApiPlaceholder: s__('AlertSettings|http://prometheus.example.com/'), + restKeyInfo: s__( + 'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.', + ), + endPointActivated: s__('AlertSettings|Alerts endpoint successfully activated.'), + prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'), + integrationsInfo: s__( + 'AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}', + ), + resetKey: s__('AlertSettings|Reset key'), + copyToClipboard: s__('AlertSettings|Copy'), + integrationsLabel: s__('AlertSettings|Integrations'), + apiBaseUrlLabel: s__('AlertSettings|Prometheus API Base URL'), + authKeyLabel: s__('AlertSettings|Authorization key'), + urlLabel: s__('AlertSettings|Webhook URL'), + activeLabel: s__('AlertSettings|Active'), + apiBaseUrlHelpText: s__(' AlertSettings|URL cannot be blank and must start with http or https'), +}; + +export const serviceOptions = [ + { value: 'generic', text: s__('AlertSettings|Generic') }, + { value: 'prometheus', text: s__('AlertSettings|External Prometheus') }, +]; diff --git a/app/assets/javascripts/alerts_settings/index.js b/app/assets/javascripts/alerts_settings/index.js new file mode 100644 index 00000000000..e7a810742b9 --- /dev/null +++ b/app/assets/javascripts/alerts_settings/index.js @@ -0,0 +1,53 @@ +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import AlertSettingsForm from './components/alerts_settings_form.vue'; + +export default el => { + if (!el) { + return null; + } + + const { + prometheusActivated, + prometheusUrl, + prometheusAuthorizationKey, + prometheusFormPath, + prometheusResetKeyPath, + prometheusApiUrl, + activated: activatedStr, + alertsSetupUrl, + alertsUsageUrl, + formPath, + authorizationKey, + url, + } = el.dataset; + + const activated = parseBoolean(activatedStr); + const prometheusIsActivated = parseBoolean(prometheusActivated); + + return new Vue({ + el, + render(createElement) { + return createElement(AlertSettingsForm, { + props: { + prometheus: { + prometheusIsActivated, + prometheusUrl, + prometheusAuthorizationKey, + prometheusFormPath, + prometheusResetKeyPath, + prometheusApiUrl, + }, + generic: { + alertsSetupUrl, + alertsUsageUrl, + initialActivated: activated, + formPath, + initialAuthorizationKey: authorizationKey, + url, + }, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/alerts_settings/services/index.js b/app/assets/javascripts/alerts_settings/services/index.js new file mode 100644 index 00000000000..669c40bc86b --- /dev/null +++ b/app/assets/javascripts/alerts_settings/services/index.js @@ -0,0 +1,27 @@ +import axios from '~/lib/utils/axios_utils'; + +export default { + updateGenericKey({ endpoint, params }) { + return axios.put(endpoint, params); + }, + updatePrometheusKey({ endpoint }) { + return axios.post(endpoint); + }, + updateGenericActive({ endpoint, params }) { + return axios.put(endpoint, params); + }, + updatePrometheusActive({ endpoint, params: { token, config, url, redirect } }) { + const data = new FormData(); + data.set('_method', 'put'); + data.set('authenticity_token', token); + data.set('service[manual_configuration]', config); + data.set('service[api_url]', url); + data.set('redirect_to', redirect); + + return axios.post(endpoint, data, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }); + }, +}; diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue index 5040e9f7e18..10909230726 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue @@ -16,6 +16,7 @@ import { } from '@gitlab/ui'; import Cookies from 'js-cookie'; import { mapActions, mapState } from 'vuex'; +import { mapComputed } from '~/vuex_shared/bindings'; import { __ } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { @@ -30,6 +31,9 @@ import CiEnvironmentsDropdown from './ci_environments_dropdown.vue'; export default { modalId: ADD_CI_VARIABLE_MODAL_ID, + tokens: awsTokens, + tokenList: awsTokenList, + awsTipMessage: AWS_TIP_MESSAGE, components: { CiEnvironmentsDropdown, CiKeyField, @@ -48,9 +52,6 @@ export default { GlSprintf, }, mixins: [glFeatureFlagsMixin()], - tokens: awsTokens, - tokenList: awsTokenList, - awsTipMessage: AWS_TIP_MESSAGE, data() { return { isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true', @@ -74,22 +75,34 @@ export default { 'protectedEnvironmentVariablesLink', 'maskedEnvironmentVariablesLink', ]), + ...mapComputed( + [ + { key: 'key', updateFn: 'updateVariableKey' }, + { key: 'secret_value', updateFn: 'updateVariableValue' }, + { key: 'variable_type', updateFn: 'updateVariableType' }, + { key: 'environment_scope', updateFn: 'setEnvironmentScope' }, + { key: 'protected_variable', updateFn: 'updateVariableProtected' }, + { key: 'masked', updateFn: 'updateVariableMasked' }, + ], + false, + 'variable', + ), isTipVisible() { - return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variableData.key); + return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key); }, canSubmit() { return ( this.variableValidationState && - this.variableData.key !== '' && - this.variableData.secret_value !== '' + this.variable.key !== '' && + this.variable.secret_value !== '' ); }, canMask() { const regex = RegExp(this.maskableRegex); - return regex.test(this.variableData.secret_value); + return regex.test(this.variable.secret_value); }, displayMaskedError() { - return !this.canMask && this.variableData.masked; + return !this.canMask && this.variable.masked; }, maskedState() { if (this.displayMaskedError) { @@ -97,9 +110,6 @@ export default { } return true; }, - variableData() { - return this.variableBeingEdited || this.variable; - }, modalActionText() { return this.variableBeingEdited ? __('Update variable') : __('Add variable'); }, @@ -107,7 +117,7 @@ export default { return this.displayMaskedError ? __('This variable can not be masked.') : ''; }, tokenValidationFeedback() { - const tokenSpecificFeedback = this.$options.tokens?.[this.variableData.key]?.invalidMessage; + const tokenSpecificFeedback = this.$options.tokens?.[this.variable.key]?.invalidMessage; if (!this.tokenValidationState && tokenSpecificFeedback) { return tokenSpecificFeedback; } @@ -119,10 +129,10 @@ export default { return true; } - const validator = this.$options.tokens?.[this.variableData.key]?.validation; + const validator = this.$options.tokens?.[this.variable.key]?.validation; if (validator) { - return validator(this.variableData.secret_value); + return validator(this.variable.secret_value); } return true; @@ -131,14 +141,7 @@ export default { return `${this.tokenValidationFeedback} ${this.maskedFeedback}`; }, variableValidationState() { - if ( - this.variableData.secret_value === '' || - (this.tokenValidationState && this.maskedState) - ) { - return true; - } - - return false; + return this.variable.secret_value === '' || (this.tokenValidationState && this.maskedState); }, }, methods: { @@ -160,7 +163,7 @@ export default { this.isTipDismissed = true; }, deleteVarAndClose() { - this.deleteVariable(this.variableBeingEdited); + this.deleteVariable(); this.hideModal(); }, hideModal() { @@ -169,14 +172,14 @@ export default { resetModalHandler() { if (this.variableBeingEdited) { this.resetEditing(); - } else { - this.clearModal(); } + + this.clearModal(); this.resetSelectedEnvironment(); }, updateOrAddVariable() { if (this.variableBeingEdited) { - this.updateVariable(this.variableBeingEdited); + this.updateVariable(); } else { this.addVariable(); } @@ -204,14 +207,14 @@ export default { <form> <ci-key-field v-if="glFeatures.ciKeyAutocomplete" - v-model="variableData.key" + v-model="key" :token-list="$options.tokenList" /> <gl-form-group v-else :label="__('Key')" label-for="ci-variable-key"> <gl-form-input id="ci-variable-key" - v-model="variableData.key" + v-model="key" data-qa-selector="ci_variable_key_field" /> </gl-form-group> @@ -225,7 +228,7 @@ export default { <gl-form-textarea id="ci-variable-value" ref="valueField" - v-model="variableData.secret_value" + v-model="secret_value" :state="variableValidationState" rows="3" max-rows="6" @@ -241,11 +244,7 @@ export default { class="w-50 append-right-15" :class="{ 'w-100': isGroup }" > - <gl-form-select - id="ci-variable-type" - v-model="variableData.variable_type" - :options="typeOptions" - /> + <gl-form-select id="ci-variable-type" v-model="variable_type" :options="typeOptions" /> </gl-form-group> <gl-form-group @@ -256,7 +255,7 @@ export default { > <ci-environments-dropdown class="w-100" - :value="variableData.environment_scope" + :value="environment_scope" @selectEnvironment="setEnvironmentScope" @createClicked="addWildCardScope" /> @@ -264,7 +263,7 @@ export default { </div> <gl-form-group :label="__('Flags')" label-for="ci-variable-flags"> - <gl-form-checkbox v-model="variableData.protected" class="mb-0"> + <gl-form-checkbox v-model="protected_variable" class="mb-0"> {{ __('Protect variable') }} <gl-link target="_blank" :href="protectedEnvironmentVariablesLink"> <gl-icon name="question" :size="12" /> @@ -276,7 +275,7 @@ export default { <gl-form-checkbox ref="masked-ci-variable" - v-model="variableData.masked" + v-model="masked" data-qa-selector="ci_variable_masked_checkbox" > {{ __('Mask variable') }} diff --git a/app/assets/javascripts/ci_variable_list/store/actions.js b/app/assets/javascripts/ci_variable_list/store/actions.js index d9129c919f8..60c7a480769 100644 --- a/app/assets/javascripts/ci_variable_list/store/actions.js +++ b/app/assets/javascripts/ci_variable_list/store/actions.js @@ -65,10 +65,10 @@ export const receiveUpdateVariableError = ({ commit }, error) => { commit(types.RECEIVE_UPDATE_VARIABLE_ERROR, error); }; -export const updateVariable = ({ state, dispatch }, variable) => { +export const updateVariable = ({ state, dispatch }) => { dispatch('requestUpdateVariable'); - const updatedVariable = prepareDataForApi(variable); + const updatedVariable = prepareDataForApi(state.variable); updatedVariable.secrect_value = updateVariable.value; return axios @@ -121,13 +121,13 @@ export const receiveDeleteVariableError = ({ commit }, error) => { commit(types.RECEIVE_DELETE_VARIABLE_ERROR, error); }; -export const deleteVariable = ({ dispatch, state }, variable) => { +export const deleteVariable = ({ dispatch, state }) => { dispatch('requestDeleteVariable'); const destroy = true; return axios - .patch(state.endpoint, { variables_attributes: [prepareDataForApi(variable, destroy)] }) + .patch(state.endpoint, { variables_attributes: [prepareDataForApi(state.variable, destroy)] }) .then(() => { dispatch('receiveDeleteVariableSuccess'); dispatch('fetchVariables'); @@ -176,3 +176,23 @@ export const resetSelectedEnvironment = ({ commit }) => { export const setSelectedEnvironment = ({ commit }, environment) => { commit(types.SET_SELECTED_ENVIRONMENT, environment); }; + +export const updateVariableKey = ({ commit }, { key }) => { + commit(types.UPDATE_VARIABLE_KEY, key); +}; + +export const updateVariableValue = ({ commit }, { secret_value }) => { + commit(types.UPDATE_VARIABLE_VALUE, secret_value); +}; + +export const updateVariableType = ({ commit }, { variable_type }) => { + commit(types.UPDATE_VARIABLE_TYPE, variable_type); +}; + +export const updateVariableProtected = ({ commit }, { protected_variable }) => { + commit(types.UPDATE_VARIABLE_PROTECTED, protected_variable); +}; + +export const updateVariableMasked = ({ commit }, { masked }) => { + commit(types.UPDATE_VARIABLE_MASKED, masked); +}; diff --git a/app/assets/javascripts/ci_variable_list/store/mutation_types.js b/app/assets/javascripts/ci_variable_list/store/mutation_types.js index ccf8fbd3cb5..5db8f610192 100644 --- a/app/assets/javascripts/ci_variable_list/store/mutation_types.js +++ b/app/assets/javascripts/ci_variable_list/store/mutation_types.js @@ -25,3 +25,9 @@ export const SET_ENVIRONMENT_SCOPE = 'SET_ENVIRONMENT_SCOPE'; export const ADD_WILD_CARD_SCOPE = 'ADD_WILD_CARD_SCOPE'; export const RESET_SELECTED_ENVIRONMENT = 'RESET_SELECTED_ENVIRONMENT'; export const SET_SELECTED_ENVIRONMENT = 'SET_SELECTED_ENVIRONMENT'; + +export const UPDATE_VARIABLE_KEY = 'UPDATE_VARIABLE_KEY'; +export const UPDATE_VARIABLE_VALUE = 'UPDATE_VARIABLE_VALUE'; +export const UPDATE_VARIABLE_TYPE = 'UPDATE_VARIABLE_TYPE'; +export const UPDATE_VARIABLE_PROTECTED = 'UPDATE_VARIABLE_PROTECTED'; +export const UPDATE_VARIABLE_MASKED = 'UPDATE_VARIABLE_MASKED'; diff --git a/app/assets/javascripts/ci_variable_list/store/mutations.js b/app/assets/javascripts/ci_variable_list/store/mutations.js index 7d9cd0dd727..8903b742537 100644 --- a/app/assets/javascripts/ci_variable_list/store/mutations.js +++ b/app/assets/javascripts/ci_variable_list/store/mutations.js @@ -65,7 +65,8 @@ export default { }, [types.VARIABLE_BEING_EDITED](state, variable) { - state.variableBeingEdited = variable; + state.variableBeingEdited = true; + state.variable = variable; }, [types.CLEAR_MODAL](state) { @@ -80,16 +81,12 @@ export default { }, [types.RESET_EDITING](state) { - state.variableBeingEdited = null; + state.variableBeingEdited = false; state.showInputValue = false; }, [types.SET_ENVIRONMENT_SCOPE](state, environment) { - if (state.variableBeingEdited) { - state.variableBeingEdited.environment_scope = environment; - } else { - state.variable.environment_scope = environment; - } + state.variable.environment_scope = environment; }, [types.ADD_WILD_CARD_SCOPE](state, environment) { @@ -108,4 +105,24 @@ export default { [types.SET_VARIABLE_PROTECTED](state) { state.variable.protected = true; }, + + [types.UPDATE_VARIABLE_KEY](state, key) { + state.variable.key = key; + }, + + [types.UPDATE_VARIABLE_VALUE](state, value) { + state.variable.secret_value = value; + }, + + [types.UPDATE_VARIABLE_TYPE](state, type) { + state.variable.variable_type = type; + }, + + [types.UPDATE_VARIABLE_PROTECTED](state, bool) { + state.variable.protected_variable = bool; + }, + + [types.UPDATE_VARIABLE_MASKED](state, bool) { + state.variable.masked = bool; + }, }; diff --git a/app/assets/javascripts/ci_variable_list/store/state.js b/app/assets/javascripts/ci_variable_list/store/state.js index 2fffd115589..96b27792664 100644 --- a/app/assets/javascripts/ci_variable_list/store/state.js +++ b/app/assets/javascripts/ci_variable_list/store/state.js @@ -12,7 +12,7 @@ export default () => ({ variable_type: displayText.variableText, key: '', secret_value: '', - protected: false, + protected_variable: false, masked: false, environment_scope: displayText.allEnvironmentsText, }, @@ -21,6 +21,6 @@ export default () => ({ error: null, environments: [], typeOptions: [displayText.variableText, displayText.fileText], - variableBeingEdited: null, + variableBeingEdited: false, selectedEnvironment: '', }); diff --git a/app/assets/javascripts/ci_variable_list/store/utils.js b/app/assets/javascripts/ci_variable_list/store/utils.js index 3cd8c85024b..f04530359e7 100644 --- a/app/assets/javascripts/ci_variable_list/store/utils.js +++ b/app/assets/javascripts/ci_variable_list/store/utils.js @@ -18,6 +18,7 @@ export const prepareDataForDisplay = variables => { if (variableCopy.environment_scope === types.allEnvironmentsType) { variableCopy.environment_scope = displayText.allEnvironmentsText; } + variableCopy.protected_variable = variableCopy.protected; variablesToDisplay.push(variableCopy); }); return variablesToDisplay; @@ -25,7 +26,8 @@ export const prepareDataForDisplay = variables => { export const prepareDataForApi = (variable, destroy = false) => { const variableCopy = cloneDeep(variable); - variableCopy.protected = variableCopy.protected.toString(); + variableCopy.protected = variableCopy.protected_variable.toString(); + delete variableCopy.protected_variable; variableCopy.masked = variableCopy.masked.toString(); variableCopy.variable_type = variableTypeHandler(variableCopy.variable_type); if (variableCopy.environment_scope === displayText.allEnvironmentsText) { diff --git a/app/assets/javascripts/pages/projects/settings/operations/show/index.js b/app/assets/javascripts/pages/projects/settings/operations/show/index.js index d71ec58c3c0..00c6fe9838e 100644 --- a/app/assets/javascripts/pages/projects/settings/operations/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/operations/show/index.js @@ -1,5 +1,5 @@ import mountErrorTrackingForm from '~/error_tracking_settings'; -import initAlertsSettings from '~/alerts_service_settings'; +import mountAlertsSettings from '~/alerts_settings'; import mountOperationSettings from '~/operation_settings'; import mountGrafanaIntegration from '~/grafana_integration'; import initSettingsPanels from '~/settings_panels'; @@ -11,5 +11,5 @@ document.addEventListener('DOMContentLoaded', () => { if (!IS_EE) { initSettingsPanels(); } - initAlertsSettings(document.querySelector('.js-alerts-service-settings')); + mountAlertsSettings(document.querySelector('.js-alerts-settings')); }); diff --git a/app/assets/javascripts/prometheus_alerts/components/reset_key.vue b/app/assets/javascripts/prometheus_alerts/components/reset_key.vue index 15b6a29e5cf..941a05583ad 100644 --- a/app/assets/javascripts/prometheus_alerts/components/reset_key.vue +++ b/app/assets/javascripts/prometheus_alerts/components/reset_key.vue @@ -41,6 +41,11 @@ export default { type: String, required: true, }, + disabled: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -88,7 +93,11 @@ export default { <div class="input-group"> <gl-form-input id="notify-url" :readonly="true" :value="notifyUrl" /> <span class="input-group-append"> - <clipboard-button :text="notifyUrl" :title="$options.copyToClipboard" /> + <clipboard-button + :text="notifyUrl" + :title="$options.copyToClipboard" + :disabled="disabled" + /> </span> </div> </gl-form-group> @@ -100,7 +109,11 @@ export default { <div class="input-group"> <gl-form-input id="authorization-key" :readonly="true" :value="authorizationKey" /> <span class="input-group-append"> - <clipboard-button :text="authorizationKey" :title="$options.copyToClipboard" /> + <clipboard-button + :text="authorizationKey" + :title="$options.copyToClipboard" + :disabled="disabled" + /> </span> </div> </gl-form-group> @@ -118,13 +131,20 @@ export default { ) }} </gl-modal> - <gl-deprecated-button v-gl-modal.authKeyModal class="js-reset-auth-key">{{ - __('Reset key') - }}</gl-deprecated-button> + <gl-deprecated-button + v-gl-modal.authKeyModal + class="js-reset-auth-key" + :disabled="disabled" + >{{ __('Reset key') }}</gl-deprecated-button + > </template> - <gl-deprecated-button v-else class="js-reset-auth-key" @click="resetKey">{{ - __('Generate key') - }}</gl-deprecated-button> + <gl-deprecated-button + v-else + :disabled="disabled" + class="js-reset-auth-key" + @click="resetKey" + >{{ __('Generate key') }}</gl-deprecated-button + > </div> </div> </template> diff --git a/app/assets/javascripts/prometheus_alerts/index.js b/app/assets/javascripts/prometheus_alerts/index.js index a42f19e5245..7efe6ed186b 100644 --- a/app/assets/javascripts/prometheus_alerts/index.js +++ b/app/assets/javascripts/prometheus_alerts/index.js @@ -8,7 +8,7 @@ export default () => { return; } - const { authorizationKey, changeKeyUrl, notifyUrl, learnMoreUrl } = el.dataset; + const { authorizationKey, changeKeyUrl, notifyUrl, learnMoreUrl, disabled } = el.dataset; // eslint-disable-next-line no-new new Vue({ @@ -20,6 +20,7 @@ export default () => { changeKeyUrl, notifyUrl, learnMoreUrl, + disabled, }, }); }, |