diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-16 18:09:38 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-16 18:09:38 +0300 |
commit | 2d8454515e7b631a8f39a6415c86154d6c62841c (patch) | |
tree | d3d5fac01f23a735226cf20a4073e2cb611664d3 /app/assets/javascripts/incidents_settings | |
parent | 9d67bc14cb59a27c9877474e77d155173a1dedff (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/incidents_settings')
6 files changed, 284 insertions, 27 deletions
diff --git a/app/assets/javascripts/incidents_settings/components/alerts_form.vue b/app/assets/javascripts/incidents_settings/components/alerts_form.vue index 40eaef55c48..a394f404ee1 100644 --- a/app/assets/javascripts/incidents_settings/components/alerts_form.vue +++ b/app/assets/javascripts/incidents_settings/components/alerts_form.vue @@ -9,15 +9,11 @@ import { GlNewDropdown, GlNewDropdownItem, } from '@gitlab/ui'; -import axios from '~/lib/utils/axios_utils'; -import { refreshCurrentPage } from '~/lib/utils/url_utility'; -import createFlash from '~/flash'; import { I18N_ALERT_SETTINGS_FORM, NO_ISSUE_TEMPLATE_SELECTED, TAKING_INCIDENT_ACTION_DOCS_LINK, ISSUE_TEMPLATES_DOCS_LINK, - ERROR_MSG, } from '../constants'; export default { @@ -31,7 +27,7 @@ export default { GlNewDropdown, GlNewDropdownItem, }, - inject: ['alertSettings', 'operationsSettingsEndpoint'], + inject: ['service', 'alertSettings'], data() { return { templates: [NO_ISSUE_TEMPLATE_SELECTED, ...this.alertSettings.templates], @@ -65,23 +61,10 @@ export default { }, updateAlertsIntegrationSettings() { this.loading = true; - return axios - .patch(this.operationsSettingsEndpoint, { - project: { - incident_management_setting_attributes: this.formData, - }, - }) - .then(() => { - refreshCurrentPage(); - }) - .catch(({ response }) => { - const message = response?.data?.message || ''; - createFlash(`${ERROR_MSG} ${message}`, 'alert'); - }) - .finally(() => { - this.loading = false; - }); + this.service.updateSettings(this.formData).catch(() => { + this.loading = false; + }); }, }, }; diff --git a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue index 763568fd2c9..0623c275c5a 100644 --- a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue +++ b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue @@ -1,6 +1,8 @@ <script> import { GlButton, GlTabs, GlTab } from '@gitlab/ui'; import AlertsSettingsForm from './alerts_form.vue'; +import PagerDutySettingsForm from './pagerduty_form.vue'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { INTEGRATION_TABS_CONFIG, I18N_INTEGRATION_TABS } from '../constants'; export default { @@ -9,9 +11,19 @@ export default { GlTabs, GlTab, AlertsSettingsForm, + PagerDutySettingsForm, }, + mixins: [glFeatureFlagMixin()], tabs: INTEGRATION_TABS_CONFIG, i18n: I18N_INTEGRATION_TABS, + methods: { + isFeatureFlagEnabled(tab) { + if (tab.featureFlag) { + return this.glFeatures[tab.featureFlag]; + } + return true; + }, + }, }; </script> @@ -37,7 +49,7 @@ export default { <gl-tabs> <gl-tab v-for="(tab, index) in $options.tabs" - v-if="tab.active" + v-if="tab.active && isFeatureFlagEnabled(tab)" :key="`${tab.title}_${index}`" :title="tab.title" > diff --git a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue new file mode 100644 index 00000000000..027848db6e9 --- /dev/null +++ b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue @@ -0,0 +1,183 @@ +<script> +import { + GlAlert, + GlButton, + GlSprintf, + GlLink, + GlIcon, + GlFormGroup, + GlFormInputGroup, + GlToggle, + GlModal, + GlModalDirective, +} from '@gitlab/ui'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import { I18N_PAGERDUTY_SETTINGS_FORM, CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK } from '../constants'; +import { isEqual } from 'lodash'; + +export default { + components: { + GlAlert, + GlButton, + GlSprintf, + GlLink, + GlIcon, + GlFormGroup, + GlFormInputGroup, + GlToggle, + GlModal, + ClipboardButton, + }, + directives: { + 'gl-modal': GlModalDirective, + }, + inject: ['service', 'pagerDutySettings'], + data() { + return { + active: this.pagerDutySettings.active, + webhookUrl: this.pagerDutySettings.webhookUrl, + loading: false, + resettingWebhook: false, + webhookUpdateFailed: false, + showAlert: false, + }; + }, + i18n: I18N_PAGERDUTY_SETTINGS_FORM, + CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK, + computed: { + formData() { + return { + pagerduty_active: this.active, + }; + }, + isFormUpdated() { + return isEqual(this.pagerDutySettings, { + active: this.active, + webhookUrl: this.webhookUrl, + }); + }, + isSaveDisabled() { + return this.isFormUpdated || this.loading || this.resettingWebhook; + }, + webhookUpdateAlertMsg() { + return this.webhookUpdateFailed + ? this.$options.i18n.webhookUrl.updateErrMsg + : this.$options.i18n.webhookUrl.updateSuccessMsg; + }, + webhookUpdateAlertVariant() { + return this.webhookUpdateFailed ? 'danger' : 'success'; + }, + }, + methods: { + updatePagerDutyIntegrationSettings() { + this.loading = true; + + this.service.updateSettings(this.formData).catch(() => { + this.loading = false; + }); + }, + resetWebhookUrl() { + this.resettingWebhook = true; + + this.service + .resetWebhookUrl() + .then(({ data: { pagerduty_webhook_url: url } }) => { + this.webhookUrl = url; + this.showAlert = true; + this.webhookUpdateFailed = false; + }) + .catch(() => { + this.showAlert = true; + this.webhookUpdateFailed = true; + }) + .finally(() => { + this.resettingWebhook = false; + }); + }, + }, +}; +</script> + +<template> + <div> + <gl-alert + v-if="showAlert" + class="gl-mb-3" + :variant="webhookUpdateAlertVariant" + @dismiss="showAlert = false" + > + {{ webhookUpdateAlertMsg }} + </gl-alert> + + <p>{{ $options.i18n.introText }}</p> + <form ref="settingsForm" @submit.prevent="updatePagerDutyIntegrationSettings"> + <gl-form-group class="col-8 col-md-9 gl-p-0"> + <gl-toggle + id="active" + v-model="active" + :is-loading="loading" + :label="$options.i18n.activeToggle.label" + /> + </gl-form-group> + + <gl-form-group + class="col-8 col-md-9 gl-p-0" + :label="$options.i18n.webhookUrl.label" + label-for="url" + label-class="label-bold" + > + <gl-form-input-group id="url" data-testid="webhook-url" readonly :value="webhookUrl"> + <template #append> + <clipboard-button + :text="webhookUrl" + :title="$options.i18n.webhookUrl.copyToClipboard" + /> + </template> + </gl-form-input-group> + + <div class="gl-text-gray-400 gl-pt-2"> + <gl-sprintf :message="$options.i18n.webhookUrl.helpText"> + <template #docsLink> + <gl-link + :href="$options.CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK" + target="_blank" + class="gl-display-inline-flex" + > + <span>{{ $options.i18n.webhookUrl.helpDocsLink }}</span> + <gl-icon name="external-link" /> + </gl-link> + </template> + </gl-sprintf> + </div> + <gl-button + v-gl-modal.resetWebhookModal + class="gl-mt-3" + :disabled="loading" + :loading="resettingWebhook" + data-testid="webhook-reset-btn" + > + {{ $options.i18n.webhookUrl.resetWebhookUrl }} + </gl-button> + <gl-modal + modal-id="resetWebhookModal" + :title="$options.i18n.webhookUrl.resetWebhookUrl" + :ok-title="$options.i18n.webhookUrl.resetWebhookUrl" + ok-variant="danger" + @ok="resetWebhookUrl" + > + {{ $options.i18n.webhookUrl.restKeyInfo }} + </gl-modal> + </gl-form-group> + + <gl-button + ref="submitBtn" + :disabled="isSaveDisabled" + variant="success" + type="submit" + class="js-no-auto-disable" + > + {{ $options.i18n.saveBtnLabel }} + </gl-button> + </form> + </div> +</template> diff --git a/app/assets/javascripts/incidents_settings/constants.js b/app/assets/javascripts/incidents_settings/constants.js index bd6ee55ae42..b443c237f0f 100644 --- a/app/assets/javascripts/incidents_settings/constants.js +++ b/app/assets/javascripts/incidents_settings/constants.js @@ -1,5 +1,6 @@ import { __, s__ } from '~/locale'; +/* Integration tabs constants */ export const INTEGRATION_TABS_CONFIG = [ { title: s__('IncidentSettings|Alert integration'), @@ -8,8 +9,9 @@ export const INTEGRATION_TABS_CONFIG = [ }, { title: s__('IncidentSettings|PagerDuty integration'), - component: '', - active: false, + component: 'PagerDutySettingsForm', + active: true, + featureFlag: 'pagerdutyWebhook', }, { title: s__('IncidentSettings|Grafana integration'), @@ -21,12 +23,13 @@ export const INTEGRATION_TABS_CONFIG = [ export const I18N_INTEGRATION_TABS = { headerText: s__('IncidentSettings|Incidents'), expandBtnLabel: __('Expand'), - saveBtnLabel: __('Save changes'), subHeaderText: s__( 'IncidentSettings|Set up integrations with external tools to help better manage incidents.', ), }; +/* Alerts integration settings constants */ + export const I18N_ALERT_SETTINGS_FORM = { saveBtnLabel: __('Save changes'), introText: __('Action to take when receiving an alert. %{docsLink}'), @@ -48,4 +51,33 @@ export const TAKING_INCIDENT_ACTION_DOCS_LINK = export const ISSUE_TEMPLATES_DOCS_LINK = '/help/user/project/description_templates#creating-issue-templates'; +/* PagerDuty integration settings constants */ + +export const I18N_PAGERDUTY_SETTINGS_FORM = { + introText: s__( + 'PagerDutySettings|Setting up a webhook with PagerDuty will automatically create a GitLab issue for each PagerDuty incident.', + ), + activeToggle: { + label: s__('PagerDutySettings|Active'), + }, + webhookUrl: { + label: s__('PagerDutySettings|Webhook URL'), + helpText: s__( + 'PagerDutySettings|Create a GitLab issue for each PagerDuty incident by %{docsLink}', + ), + helpDocsLink: s__('PagerDutySettings|configuring a webhook in PagerDuty'), + resetWebhookUrl: s__('PagerDutySettings|Reset webhook URL'), + copyToClipboard: __('Copy'), + updateErrMsg: s__('PagerDutySettings|Failed to update Webhook URL'), + updateSuccessMsg: s__('PagerDutySettings|Webhook URL update was successful'), + restKeyInfo: s__( + "PagerDutySettings|Resetting the webhook URL for this project will require updating this integration's settings in PagerDuty.", + ), + }, + saveBtnLabel: __('Save changes'), +}; + +export const CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK = 'https://support.pagerduty.com/docs/webhooks'; + +/* common constants */ export const ERROR_MSG = __('There was an error saving your changes.'); diff --git a/app/assets/javascripts/incidents_settings/incidents_settings_service.js b/app/assets/javascripts/incidents_settings/incidents_settings_service.js new file mode 100644 index 00000000000..bd4f5bb8820 --- /dev/null +++ b/app/assets/javascripts/incidents_settings/incidents_settings_service.js @@ -0,0 +1,32 @@ +import axios from '~/lib/utils/axios_utils'; +import { refreshCurrentPage } from '~/lib/utils/url_utility'; +import createFlash from '~/flash'; +import { ERROR_MSG } from './constants'; + +export default class IncidentsSettingsService { + constructor(settingsEndpoint, webhookUpdateEndpoint) { + this.settingsEndpoint = settingsEndpoint; + this.webhookUpdateEndpoint = webhookUpdateEndpoint; + } + + updateSettings(data) { + return axios + .patch(this.settingsEndpoint, { + project: { + incident_management_setting_attributes: data, + }, + }) + .then(() => { + refreshCurrentPage(); + }) + .catch(({ response }) => { + const message = response?.data?.message || ''; + + createFlash(`${ERROR_MSG} ${message}`, 'alert'); + }); + } + + resetWebhookUrl() { + return axios.post(this.webhookUpdateEndpoint); + } +} diff --git a/app/assets/javascripts/incidents_settings/index.js b/app/assets/javascripts/incidents_settings/index.js index 25fed0d10de..80e7d07feca 100644 --- a/app/assets/javascripts/incidents_settings/index.js +++ b/app/assets/javascripts/incidents_settings/index.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import { parseBoolean } from '~/lib/utils/common_utils'; import SettingsTabs from './components/incidents_settings_tabs.vue'; +import IncidentsSettingsService from './incidents_settings_service'; export default () => { const el = document.querySelector('.js-incidents-settings'); @@ -10,19 +11,33 @@ export default () => { } const { - dataset: { operationsSettingsEndpoint, templates, createIssue, issueTemplateKey, sendEmail }, + dataset: { + operationsSettingsEndpoint, + templates, + createIssue, + issueTemplateKey, + sendEmail, + pagerdutyActive, + pagerdutyWebhookUrl, + pagerdutyResetKeyPath, + }, } = el; + const service = new IncidentsSettingsService(operationsSettingsEndpoint, pagerdutyResetKeyPath); return new Vue({ el, provide: { - operationsSettingsEndpoint, + service, alertSettings: { templates: JSON.parse(templates), createIssue: parseBoolean(createIssue), issueTemplateKey, sendEmail: parseBoolean(sendEmail), }, + pagerDutySettings: { + active: parseBoolean(pagerdutyActive), + webhookUrl: pagerdutyWebhookUrl, + }, }, render(createElement) { return createElement(SettingsTabs); |