Commit 64eabc43 authored by David O'Regan's avatar David O'Regan Committed by Phil Hughes

Remove http_integrations_list feature flag

Remove http_integrations_list flag
and remove old code tied to this
feature flag that is no longer used
parent 695735e3
...@@ -11,7 +11,6 @@ import { ...@@ -11,7 +11,6 @@ import {
GlSprintf, GlSprintf,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { import {
trackAlertIntegrationsViewsOptions, trackAlertIntegrationsViewsOptions,
...@@ -54,7 +53,6 @@ export default { ...@@ -54,7 +53,6 @@ export default {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
GlModal: GlModalDirective, GlModal: GlModalDirective,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
integrations: { integrations: {
type: Array, type: Array,
...@@ -170,7 +168,7 @@ export default { ...@@ -170,7 +168,7 @@ export default {
</template> </template>
<template #cell(actions)="{ item }"> <template #cell(actions)="{ item }">
<gl-button-group v-if="glFeatures.httpIntegrationsList" class="gl-ml-3"> <gl-button-group class="gl-ml-3">
<gl-button icon="pencil" @click="$emit('edit-integration', { id: item.id })" /> <gl-button icon="pencil" @click="$emit('edit-integration', { id: item.id })" />
<gl-button <gl-button
v-gl-modal.deleteIntegration v-gl-modal.deleteIntegration
......
<script>
import {
GlAlert,
GlButton,
GlForm,
GlFormGroup,
GlFormInput,
GlFormInputGroup,
GlFormTextarea,
GlLink,
GlModal,
GlModalDirective,
GlSprintf,
GlFormSelect,
} from '@gitlab/ui';
import { debounce } from 'lodash';
import { doesHashExistInUrl } from '~/lib/utils/url_utility';
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,
integrationTypes,
JSON_VALIDATE_DELAY,
targetPrometheusUrlPlaceholder,
targetOpsgenieUrlPlaceholder,
sectionHash,
} from '../constants';
import createFlash, { FLASH_TYPES } from '~/flash';
export default {
i18n,
csrf,
targetOpsgenieUrlPlaceholder,
targetPrometheusUrlPlaceholder,
components: {
GlAlert,
GlButton,
GlForm,
GlFormGroup,
GlFormInput,
GlFormInputGroup,
GlFormSelect,
GlFormTextarea,
GlLink,
GlModal,
GlSprintf,
ClipboardButton,
ToggleButton,
},
directives: {
'gl-modal': GlModalDirective,
},
inject: ['prometheus', 'generic', 'opsgenie'],
data() {
return {
loading: false,
selectedIntegration: integrationTypes[0].value,
options: integrationTypes,
active: false,
token: '',
targetUrl: '',
feedback: {
variant: 'danger',
feedbackMessage: '',
isFeedbackDismissed: false,
},
testAlert: {
json: null,
error: null,
},
canSaveForm: false,
serverError: null,
};
},
computed: {
sections() {
return [
{
text: this.$options.i18n.usageSection,
url: this.generic.alertsUsageUrl,
},
{
text: this.$options.i18n.setupSection,
url: this.generic.alertsSetupUrl,
},
];
},
isPrometheus() {
return this.selectedIntegration === 'PROMETHEUS';
},
isOpsgenie() {
return this.selectedIntegration === 'OPSGENIE';
},
selectedIntegrationType() {
switch (this.selectedIntegration) {
case 'HTTP': {
return {
url: this.generic.url,
token: this.generic.token,
active: this.generic.active,
resetKey: this.resetKey.bind(this),
};
}
case 'PROMETHEUS': {
return {
url: this.prometheus.url,
token: this.prometheus.token,
active: this.prometheus.active,
resetKey: this.resetKey.bind(this, 'PROMETHEUS'),
targetUrl: this.prometheus.prometheusApiUrl,
};
}
case 'OPSGENIE': {
return {
targetUrl: this.opsgenie.opsgenieMvcTargetUrl,
active: this.opsgenie.active,
};
}
default: {
return {};
}
}
},
showFeedbackMsg() {
return this.feedback.feedbackMessage && !this.isFeedbackDismissed;
},
showAlertSave() {
return (
this.feedback.feedbackMessage === this.$options.i18n.testAlertFailed &&
!this.isFeedbackDismissed
);
},
prometheusInfo() {
return this.isPrometheus ? this.$options.i18n.prometheusInfo : '';
},
jsonIsValid() {
return this.testAlert.error === null;
},
canTestAlert() {
return this.active && this.testAlert.json !== null;
},
canSaveConfig() {
return !this.loading && this.canSaveForm;
},
baseUrlPlaceholder() {
return this.isOpsgenie
? this.$options.targetOpsgenieUrlPlaceholder
: this.$options.targetPrometheusUrlPlaceholder;
},
},
watch: {
'testAlert.json': debounce(function debouncedJsonValidate() {
this.validateJson();
}, JSON_VALIDATE_DELAY),
targetUrl(oldVal, newVal) {
if (newVal && oldVal !== this.selectedIntegrationType.targetUrl) {
this.canSaveForm = true;
}
},
},
mounted() {
if (this.prometheus.active || this.generic.active || !this.opsgenie.opsgenieMvcIsAvailable) {
this.removeOpsGenieOption();
} else if (this.opsgenie.active) {
this.setOpsgenieAsDefault();
}
this.active = this.selectedIntegrationType.active;
this.token = this.selectedIntegrationType.token ?? '';
},
methods: {
createUserErrorMessage(errors = {}) {
const error = Object.entries(errors)?.[0];
if (error) {
const [field, [msg]] = error;
this.serverError = `${field} ${msg}`;
}
},
setOpsgenieAsDefault() {
this.options = this.options.map(el => {
if (el.value !== 'OPSGENIE') {
return { ...el, disabled: true };
}
return { ...el, disabled: false };
});
this.selectedIntegration = this.options.find(({ value }) => value === 'OPSGENIE').value;
if (this.targetUrl === null) {
this.targetUrl = this.selectedIntegrationType.targetUrl;
}
},
removeOpsGenieOption() {
this.options = this.options.map(el => {
if (el.value !== 'OPSGENIE') {
return { ...el, disabled: false };
}
return { ...el, disabled: true };
});
},
resetFormValues() {
this.testAlert.json = null;
this.targetUrl = this.selectedIntegrationType.targetUrl;
this.active = this.selectedIntegrationType.active;
},
dismissFeedback() {
this.serverError = null;
this.feedback = { ...this.feedback, feedbackMessage: null };
this.isFeedbackDismissed = false;
},
resetKey(key) {
const fn = key === 'PROMETHEUS' ? this.resetPrometheusKey() : this.resetGenericKey();
return fn
.then(({ data: { token } }) => {
this.token = token;
this.setFeedback({ feedbackMessage: this.$options.i18n.tokenRest, variant: 'success' });
})
.catch(() => {
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
});
},
resetGenericKey() {
this.dismissFeedback();
return service.updateGenericKey({
endpoint: this.generic.formPath,
params: { service: { token: '' } },
});
},
resetPrometheusKey() {
return service.updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath });
},
toggleService(value) {
this.canSaveForm = true;
this.active = value;
},
toggle(value) {
return this.isPrometheus ? this.togglePrometheusActive(value) : this.toggleActivated(value);
},
toggleActivated(value) {
this.loading = true;
const path = this.isOpsgenie ? this.opsgenie.formPath : this.generic.formPath;
return service
.updateGenericActive({
endpoint: path,
params: this.isOpsgenie
? { service: { opsgenie_mvc_target_url: this.targetUrl, opsgenie_mvc_enabled: value } }
: { service: { active: value } },
})
.then(() => this.notifySuccessAndReload())
.catch(({ response: { data: { errors } = {} } = {} }) => {
this.createUserErrorMessage(errors);
this.setFeedback({
feedbackMessage: this.$options.i18n.errorMsg,
variant: 'danger',
});
})
.finally(() => {
this.loading = false;
this.canSaveForm = false;
});
},
reload() {
if (!doesHashExistInUrl(sectionHash)) {
window.location.hash = sectionHash;
}
window.location.reload();
},
togglePrometheusActive(value) {
this.loading = true;
return service
.updatePrometheusActive({
endpoint: this.prometheus.prometheusFormPath,
params: {
token: this.$options.csrf.token,
config: value,
url: this.targetUrl,
redirect: window.location,
},
})
.then(() => this.notifySuccessAndReload())
.catch(({ response: { data: { errors } = {} } = {} }) => {
this.createUserErrorMessage(errors);
this.setFeedback({
feedbackMessage: this.$options.i18n.errorMsg,
variant: 'danger',
});
})
.finally(() => {
this.loading = false;
this.canSaveForm = false;
});
},
notifySuccessAndReload() {
createFlash({ message: this.$options.i18n.changesSaved, type: FLASH_TYPES.NOTICE });
setTimeout(() => this.reload(), 1000);
},
setFeedback({ feedbackMessage, variant }) {
this.feedback = { feedbackMessage, variant };
},
validateJson() {
this.testAlert.error = null;
try {
JSON.parse(this.testAlert.json);
} catch (e) {
this.testAlert.error = JSON.stringify(e.message);
}
},
validateTestAlert() {
this.loading = true;
this.dismissFeedback();
this.validateJson();
return service
.updateTestAlert({
endpoint: this.selectedIntegrationType.url,
data: this.testAlert.json,
token: this.selectedIntegrationType.token,
})
.then(() => {
this.setFeedback({
feedbackMessage: this.$options.i18n.testAlertSuccess,
variant: 'success',
});
})
.catch(() => {
this.setFeedback({
feedbackMessage: this.$options.i18n.testAlertFailed,
variant: 'danger',
});
})
.finally(() => {
this.loading = false;
});
},
onSubmit() {
this.dismissFeedback();
this.toggle(this.active);
},
onReset() {
this.testAlert.json = null;
this.dismissFeedback();
this.targetUrl = this.selectedIntegrationType.targetUrl;
if (this.canSaveForm) {
this.canSaveForm = false;
this.active = this.selectedIntegrationType.active;
}
},
},
};
</script>
<template>
<gl-form @submit.prevent="onSubmit" @reset.prevent="onReset">
<h5 class="gl-font-lg gl-my-5">{{ $options.i18n.integrationsLabel }}</h5>
<gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback">
{{ feedback.feedbackMessage }}
<br />
<i v-if="serverError">{{ __('Error message:') }} {{ serverError }}</i>
<gl-button
v-if="showAlertSave"
variant="danger"
category="primary"
class="gl-display-block gl-mt-3"
@click="toggle(active)"
>
{{ __('Save anyway') }}
</gl-button>
</gl-alert>
<div data-testid="alert-settings-description">
<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-group label-for="integration-type" :label="$options.i18n.integration">
<gl-form-select
id="integration-type"
v-model="selectedIntegration"
:options="options"
data-testid="alert-settings-select"
@change="resetFormValues"
/>
<span class="gl-text-gray-500">
<gl-sprintf :message="$options.i18n.integrationsInfo">
<template #link="{ content }">
<gl-link
class="gl-display-inline-block"
href="https://gitlab.com/groups/gitlab-org/-/epics/4390"
target="_blank"
>{{ content }}</gl-link
>
</template>
</gl-sprintf>
</span>
</gl-form-group>
<gl-form-group :label="$options.i18n.activeLabel" label-for="active">
<toggle-button
id="active"
:disabled-input="loading"
:is-loading="loading"
:value="active"
@change="toggleService"
/>
</gl-form-group>
<gl-form-group
v-if="isOpsgenie || isPrometheus"
:label="$options.i18n.apiBaseUrlLabel"
label-for="api-url"
>
<gl-form-input
id="api-url"
v-model="targetUrl"
type="url"
:placeholder="baseUrlPlaceholder"
:disabled="!active"
/>
<span class="gl-text-gray-500">
{{ $options.i18n.apiBaseUrlHelpText }}
</span>
</gl-form-group>
<template v-if="!isOpsgenie">
<gl-form-group :label="$options.i18n.urlLabel" label-for="url">
<gl-form-input-group id="url" readonly :value="selectedIntegrationType.url">
<template #append>
<clipboard-button
:text="selectedIntegrationType.url"
:title="$options.i18n.copyToClipboard"
class="gl-m-0!"
/>
</template>
</gl-form-input-group>
<span class="gl-text-gray-500">
{{ prometheusInfo }}
</span>
</gl-form-group>
<gl-form-group :label="$options.i18n.tokenLabel" label-for="authorization-key">
<gl-form-input-group id="authorization-key" class="gl-mb-2" readonly :value="token">
<template #append>
<clipboard-button
:text="token"
:title="$options.i18n.copyToClipboard"
class="gl-m-0!"
/>
</template>
</gl-form-input-group>
<gl-button v-gl-modal.tokenModal :disabled="!active" class="gl-mt-3">{{
$options.i18n.resetKey
}}</gl-button>
<gl-modal
modal-id="tokenModal"
:title="$options.i18n.resetKey"
:ok-title="$options.i18n.resetKey"
ok-variant="danger"
@ok="selectedIntegrationType.resetKey"
>
{{ $options.i18n.restKeyInfo }}
</gl-modal>
</gl-form-group>
<gl-form-group
:label="$options.i18n.alertJson"
label-for="alert-json"
:invalid-feedback="testAlert.error"
>
<gl-form-textarea
id="alert-json"
v-model.trim="testAlert.json"
:disabled="!active"
:state="jsonIsValid"
:placeholder="$options.i18n.alertJsonPlaceholder"
rows="6"
max-rows="10"
/>
</gl-form-group>
<gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
$options.i18n.testAlertInfo
}}</gl-button>
</template>
<div class="footer-block row-content-block gl-display-flex gl-justify-content-space-between">
<gl-button variant="success" category="primary" :disabled="!canSaveConfig" @click="onSubmit">
{{ __('Save changes') }}
</gl-button>
<gl-button category="primary" :disabled="!canSaveConfig" @click="onReset">
{{ __('Cancel') }}
</gl-button>
</div>
</gl-form>
</template>
<script> <script>
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui'; import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import createFlash, { FLASH_TYPES } from '~/flash'; import createFlash, { FLASH_TYPES } from '~/flash';
import getIntegrationsQuery from '../graphql/queries/get_integrations.query.graphql'; import getIntegrationsQuery from '../graphql/queries/get_integrations.query.graphql';
...@@ -15,7 +14,6 @@ import resetHttpTokenMutation from '../graphql/mutations/reset_http_token.mutati ...@@ -15,7 +14,6 @@ import resetHttpTokenMutation from '../graphql/mutations/reset_http_token.mutati
import resetPrometheusTokenMutation from '../graphql/mutations/reset_prometheus_token.mutation.graphql'; import resetPrometheusTokenMutation from '../graphql/mutations/reset_prometheus_token.mutation.graphql';
import updateCurrentIntergrationMutation from '../graphql/mutations/update_current_intergration.mutation.graphql'; import updateCurrentIntergrationMutation from '../graphql/mutations/update_current_intergration.mutation.graphql';
import IntegrationsList from './alerts_integrations_list.vue'; import IntegrationsList from './alerts_integrations_list.vue';
import SettingsFormOld from './alerts_settings_form_old.vue';
import SettingsFormNew from './alerts_settings_form_new.vue'; import SettingsFormNew from './alerts_settings_form_new.vue';
import { typeSet } from '../constants'; import { typeSet } from '../constants';
import { import {
...@@ -44,10 +42,8 @@ export default { ...@@ -44,10 +42,8 @@ export default {
GlLink, GlLink,
GlSprintf, GlSprintf,
IntegrationsList, IntegrationsList,
SettingsFormOld,
SettingsFormNew, SettingsFormNew,
}, },
mixins: [glFeatureFlagsMixin()],
inject: { inject: {
generic: { generic: {
default: {}, default: {},
...@@ -101,20 +97,6 @@ export default { ...@@ -101,20 +97,6 @@ export default {
loading() { loading() {
return this.$apollo.queries.integrations.loading; return this.$apollo.queries.integrations.loading;
}, },
integrationsOptionsOld() {
return [
{
name: s__('AlertSettings|HTTP endpoint'),
type: s__('AlertsIntegrations|HTTP endpoint'),
active: this.generic.active,
},
{
name: s__('AlertSettings|External Prometheus'),
type: s__('AlertsIntegrations|Prometheus'),
active: this.prometheus.active,
},
];
},
canAddIntegration() { canAddIntegration() {
return this.multiIntegrations || this.integrations?.list?.length < 2; return this.multiIntegrations || this.integrations?.list?.length < 2;
}, },
...@@ -310,13 +292,12 @@ export default { ...@@ -310,13 +292,12 @@ export default {
</gl-alert> </gl-alert>
<integrations-list <integrations-list
v-else v-else
:integrations="glFeatures.httpIntegrationsList ? integrations.list : integrationsOptionsOld" :integrations="integrations.list"
:loading="loading" :loading="loading"
@edit-integration="editIntegration" @edit-integration="editIntegration"
@delete-integration="deleteIntegration" @delete-integration="deleteIntegration"
/> />
<settings-form-new <settings-form-new
v-if="glFeatures.httpIntegrationsList"
:loading="isUpdating" :loading="isUpdating"
:can-add-integration="canAddIntegration" :can-add-integration="canAddIntegration"
:can-manage-opsgenie="canManageOpsgenie" :can-manage-opsgenie="canManageOpsgenie"
...@@ -326,6 +307,5 @@ export default { ...@@ -326,6 +307,5 @@ export default {
@clear-current-integration="clearCurrentIntegration" @clear-current-integration="clearCurrentIntegration"
@test-payload-failure="testPayloadFailure" @test-payload-failure="testPayloadFailure"
/> />
<settings-form-old v-else />
</div> </div>
</template> </template>
...@@ -2,30 +2,9 @@ ...@@ -2,30 +2,9 @@
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
export default { export default {
// TODO: All this code save updateTestAlert will be deleted as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/255501
updateGenericKey({ endpoint, params }) {
return axios.put(endpoint, params);
},
updatePrometheusKey({ endpoint }) {
return axios.post(endpoint);
},
updateGenericActive({ endpoint, params }) { updateGenericActive({ endpoint, params }) {
return axios.put(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',
},
});
},
updateTestAlert({ endpoint, data, token }) { updateTestAlert({ endpoint, data, token }) {
return axios.post(endpoint, data, { return axios.post(endpoint, data, {
headers: { headers: {
......
...@@ -7,7 +7,6 @@ module Projects ...@@ -7,7 +7,6 @@ module Projects
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token] before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
before_action do before_action do
push_frontend_feature_flag(:http_integrations_list, @project)
push_frontend_feature_flag(:multiple_http_integrations_custom_mapping, @project) push_frontend_feature_flag(:multiple_http_integrations_custom_mapping, @project)
end end
......
---
title: Remove http_integrations_list feature flag
merge_request: 48030
author:
type: changed
---
name: http_integrations_list
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45993
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255502
milestone: '13.6'
type: development
group: group::health
default_enabled: false
...@@ -2565,9 +2565,6 @@ msgstr "" ...@@ -2565,9 +2565,6 @@ msgstr ""
msgid "AlertSettings|HTTP Endpoint" msgid "AlertSettings|HTTP Endpoint"
msgstr "" msgstr ""
msgid "AlertSettings|HTTP endpoint"
msgstr ""
msgid "AlertSettings|If you edit the payload, the stored mapping will be reset, and you'll need to re-map the fields." msgid "AlertSettings|If you edit the payload, the stored mapping will be reset, and you'll need to re-map the fields."
msgstr "" msgstr ""
...@@ -2688,9 +2685,6 @@ msgstr "" ...@@ -2688,9 +2685,6 @@ msgstr ""
msgid "AlertsIntegrations|Current integrations" msgid "AlertsIntegrations|Current integrations"
msgstr "" msgstr ""
msgid "AlertsIntegrations|HTTP endpoint"
msgstr ""
msgid "AlertsIntegrations|Integration Name" msgid "AlertsIntegrations|Integration Name"
msgstr "" msgstr ""
...@@ -2700,9 +2694,6 @@ msgstr "" ...@@ -2700,9 +2694,6 @@ msgstr ""
msgid "AlertsIntegrations|No integrations have been added yet" msgid "AlertsIntegrations|No integrations have been added yet"
msgstr "" msgstr ""
msgid "AlertsIntegrations|Prometheus"
msgstr ""
msgid "AlertsIntegrations|The current integration could not be updated. Please try again." msgid "AlertsIntegrations|The current integration could not be updated. Please try again."
msgstr "" msgstr ""
...@@ -10824,9 +10815,6 @@ msgstr "" ...@@ -10824,9 +10815,6 @@ msgstr ""
msgid "Error loading viewer" msgid "Error loading viewer"
msgstr "" msgstr ""
msgid "Error message:"
msgstr ""
msgid "Error occurred when fetching sidebar data" msgid "Error occurred when fetching sidebar data"
msgstr "" msgstr ""
...@@ -23558,9 +23546,6 @@ msgstr "" ...@@ -23558,9 +23546,6 @@ msgstr ""
msgid "Save Push Rules" msgid "Save Push Rules"
msgstr "" msgstr ""
msgid "Save anyway"
msgstr ""
msgid "Save application" msgid "Save application"
msgstr "" msgstr ""
......
...@@ -17,7 +17,7 @@ RSpec.describe 'Alert integrations settings form', :js do ...@@ -17,7 +17,7 @@ RSpec.describe 'Alert integrations settings form', :js do
end end
describe 'when viewing alert integrations as a maintainer' do describe 'when viewing alert integrations as a maintainer' do
context 'with feature flag enabled' do context 'with the default page permissions' do
before do before do
visit project_settings_operations_path(project, anchor: 'js-alert-management-settings') visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
wait_for_requests wait_for_requests
...@@ -33,19 +33,6 @@ RSpec.describe 'Alert integrations settings form', :js do ...@@ -33,19 +33,6 @@ RSpec.describe 'Alert integrations settings form', :js do
expect(page).to have_content('1. Select integration type') expect(page).to have_content('1. Select integration type')
end end
end end
context 'with feature flag disabled' do
before do
stub_feature_flags(http_integrations_list: false)
visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
wait_for_requests
end
it 'shows the old alerts setting form' do
expect(page).to have_content('Webhook URL')
end
end
end end
describe 'when viewing alert integrations as a developer' do describe 'when viewing alert integrations as a developer' do
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AlertsSettingsFormOld with default values renders the initial template 1`] = `
"<gl-form-stub>
<h5 class=\\"gl-font-lg gl-my-5\\"></h5>
<!---->
<div data-testid=\\"alert-settings-description\\">
<p>
<gl-sprintf-stub message=\\"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.\\"></gl-sprintf-stub>
</p>
<p>
<gl-sprintf-stub message=\\"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.\\"></gl-sprintf-stub>
</p>
</div>
<gl-form-group-stub label-for=\\"integration-type\\" label=\\"Integration\\">
<gl-form-select-stub id=\\"integration-type\\" options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"HTTP\\"></gl-form-select-stub> <span class=\\"gl-text-gray-500\\"><gl-sprintf-stub message=\\"Learn more about our our upcoming %{linkStart}integrations%{linkEnd}\\"></gl-sprintf-stub></span>
</gl-form-group-stub>
<gl-form-group-stub label=\\"Active\\" label-for=\\"active\\">
<toggle-button-stub id=\\"active\\"></toggle-button-stub>
</gl-form-group-stub>
<!---->
<gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\">
<gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-500\\">
</span>
</gl-form-group-stub>
<gl-form-group-stub label-for=\\"authorization-key\\">
<gl-form-input-group-stub value=\\"\\" predefinedoptions=\\"[object Object]\\" id=\\"authorization-key\\" readonly=\\"\\" class=\\"gl-mb-2\\"></gl-form-input-group-stub>
<gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub>
<gl-modal-stub modalid=\\"tokenModal\\" titletag=\\"h4\\" modalclass=\\"\\" size=\\"md\\" title=\\"Reset key\\" ok-title=\\"Reset key\\" ok-variant=\\"danger\\">
Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.
</gl-modal-stub>
</gl-form-group-stub>
<gl-form-group-stub label=\\"Alert test payload\\" label-for=\\"alert-json\\">
<gl-form-textarea-stub noresize=\\"true\\" id=\\"alert-json\\" disabled=\\"true\\" state=\\"true\\" placeholder=\\"Enter test alert JSON....\\" rows=\\"6\\" max-rows=\\"10\\"></gl-form-textarea-stub>
</gl-form-group-stub>
<gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub>
<div class=\\"footer-block row-content-block gl-display-flex gl-justify-content-space-between\\">
<gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">
Save changes
</gl-button-stub>
<gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">
Cancel
</gl-button-stub>
</div>
</gl-form-stub>"
`;
...@@ -35,9 +35,6 @@ describe('AlertIntegrationsList', () => { ...@@ -35,9 +35,6 @@ describe('AlertIntegrationsList', () => {
integrations: mockIntegrations, integrations: mockIntegrations,
...props, ...props,
}, },
provide: {
glFeatures: { httpIntegrationsList: true },
},
stubs: { stubs: {
GlIcon: true, GlIcon: true,
GlButton: true, GlButton: true,
......
import { shallowMount } from '@vue/test-utils';
import { GlModal, GlAlert } from '@gitlab/ui';
import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form_old.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import { i18n } from '~/alerts_settings/constants';
import service from '~/alerts_settings/services';
import { defaultAlertSettingsConfig } from './util';
jest.mock('~/alerts_settings/services');
describe('AlertsSettingsFormOld', () => {
let wrapper;
const createComponent = ({ methods } = {}, data) => {
wrapper = shallowMount(AlertsSettingsForm, {
data() {
return { ...data };
},
provide: {
...defaultAlertSettingsConfig,
},
methods,
});
};
const findSelect = () => wrapper.find('[data-testid="alert-settings-select"]');
const findJsonInput = () => wrapper.find('#alert-json');
const findUrl = () => wrapper.find('#url');
const findAuthorizationKey = () => wrapper.find('#authorization-key');
const findApiUrl = () => wrapper.find('#api-url');
beforeEach(() => {
setFixtures(`
<div>
<span class="js-service-active-status fa fa-circle" data-value="true"></span>
<span class="js-service-active-status fa fa-power-off" data-value="false"></span>
</div>`);
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
describe('with default values', () => {
beforeEach(() => {
createComponent();
});
it('renders the initial template', () => {
expect(wrapper.html()).toMatchSnapshot();
});
});
describe('reset key', () => {
it('triggers resetKey method', () => {
const resetKey = jest.fn();
const methods = { resetKey };
createComponent({ methods });
wrapper.find(GlModal).vm.$emit('ok');
expect(resetKey).toHaveBeenCalled();
});
it('updates the authorization key on success', () => {
createComponent(
{},
{
token: 'newToken',
},
);
expect(findAuthorizationKey().attributes('value')).toBe('newToken');
});
it('shows a alert message on error', () => {
service.updateGenericKey.mockRejectedValueOnce({});
createComponent();
return wrapper.vm.resetKey().then(() => {
expect(wrapper.find(GlAlert).exists()).toBe(true);
});
});
});
describe('activate toggle', () => {
it('triggers toggleActivated method', () => {
const toggleService = jest.fn();
const methods = { toggleService };
createComponent({ methods });
wrapper.find(ToggleButton).vm.$emit('change', true);
expect(toggleService).toHaveBeenCalled();
});
describe('error is encountered', () => {
it('restores previous value', () => {
service.updateGenericKey.mockRejectedValueOnce({});
createComponent();
return wrapper.vm.resetKey().then(() => {
expect(wrapper.find(ToggleButton).props('value')).toBe(false);
});
});
});
});
describe('prometheus is active', () => {
beforeEach(() => {
createComponent(
{},
{
selectedIntegration: 'PROMETHEUS',
},
);
});
it('renders a valid "select"', () => {
expect(findSelect().exists()).toBe(true);
});
it('shows the API URL input', () => {
expect(findApiUrl().exists()).toBe(true);
});
it('shows the correct default API URL', () => {
expect(findUrl().attributes('value')).toBe(defaultAlertSettingsConfig.prometheus.url);
});
});
describe('Opsgenie is active', () => {
beforeEach(() => {
createComponent(
{},
{
selectedIntegration: 'OPSGENIE',
},
);
});
it('shows a input for the Opsgenie target URL', () => {
expect(findApiUrl().exists()).toBe(true);
});
});
describe('trigger test alert', () => {
beforeEach(() => {
createComponent({});
});
it('should enable the JSON input', () => {
expect(findJsonInput().exists()).toBe(true);
expect(findJsonInput().props('value')).toBe(null);
});
it('should validate JSON input', async () => {
createComponent(true, {
testAlertJson: '{ "value": "test" }',
});
findJsonInput().vm.$emit('change');
await wrapper.vm.$nextTick();
expect(findJsonInput().attributes('state')).toBe('true');
});
describe('alert service is toggled', () => {
describe('error handling', () => {
const toggleService = true;
it('should show generic error', async () => {
service.updateGenericActive.mockRejectedValueOnce({});
createComponent();
await wrapper.vm.toggleActivated(toggleService);
expect(wrapper.vm.active).toBe(false);
expect(wrapper.find(GlAlert).attributes('variant')).toBe('danger');
expect(wrapper.find(GlAlert).text()).toBe(i18n.errorMsg);
});
it('should show first field specific error when available', async () => {
const err1 = "can't be blank";
const err2 = 'is not a valid URL';
const key = 'api_url';
service.updateGenericActive.mockRejectedValueOnce({
response: { data: { errors: { [key]: [err1, err2] } } },
});
createComponent();
await wrapper.vm.toggleActivated(toggleService);
expect(wrapper.find(GlAlert).text()).toContain(i18n.errorMsg);
expect(wrapper.find(GlAlert).text()).toContain(`${key} ${err1}`);
});
});
});
});
});
...@@ -5,7 +5,6 @@ import waitForPromises from 'helpers/wait_for_promises'; ...@@ -5,7 +5,6 @@ import waitForPromises from 'helpers/wait_for_promises';
import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer'; import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue'; import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue';
import AlertsSettingsFormOld from '~/alerts_settings/components/alerts_settings_form_old.vue';
import AlertsSettingsFormNew from '~/alerts_settings/components/alerts_settings_form_new.vue'; import AlertsSettingsFormNew from '~/alerts_settings/components/alerts_settings_form_new.vue';
import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue'; import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue';
import getIntegrationsQuery from '~/alerts_settings/graphql/queries/get_integrations.query.graphql'; import getIntegrationsQuery from '~/alerts_settings/graphql/queries/get_integrations.query.graphql';
...@@ -75,7 +74,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -75,7 +74,6 @@ describe('AlertsSettingsWrapper', () => {
}, },
provide: { provide: {
...defaultAlertSettingsConfig, ...defaultAlertSettingsConfig,
glFeatures: { httpIntegrationsList: false },
...provide, ...provide,
}, },
mocks: { mocks: {
...@@ -110,7 +108,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -110,7 +108,6 @@ describe('AlertsSettingsWrapper', () => {
apolloProvider: fakeApollo, apolloProvider: fakeApollo,
provide: { provide: {
...defaultAlertSettingsConfig, ...defaultAlertSettingsConfig,
glFeatures: { httpIntegrationsList: true },
}, },
}); });
} }
...@@ -122,27 +119,16 @@ describe('AlertsSettingsWrapper', () => { ...@@ -122,27 +119,16 @@ describe('AlertsSettingsWrapper', () => {
} }
}); });
describe('with httpIntegrationsList feature flag disabled', () => { describe('rendered via default permissions', () => {
it('renders data driven alerts integrations list and old form by default', () => {
createComponent();
expect(wrapper.find(IntegrationsList).exists()).toBe(true);
expect(wrapper.find(AlertsSettingsFormOld).exists()).toBe(true);
expect(wrapper.find(AlertsSettingsFormNew).exists()).toBe(false);
});
});
describe('with httpIntegrationsList feature flag enabled', () => {
it('renders the GraphQL alerts integrations list and new form', () => { it('renders the GraphQL alerts integrations list and new form', () => {
createComponent({ provide: { glFeatures: { httpIntegrationsList: true } } }); createComponent();
expect(wrapper.find(IntegrationsList).exists()).toBe(true); expect(wrapper.find(IntegrationsList).exists()).toBe(true);
expect(wrapper.find(AlertsSettingsFormOld).exists()).toBe(false);
expect(wrapper.find(AlertsSettingsFormNew).exists()).toBe(true); expect(wrapper.find(AlertsSettingsFormNew).exists()).toBe(true);
}); });
it('uses a loading state inside the IntegrationsList table', () => { it('uses a loading state inside the IntegrationsList table', () => {
createComponent({ createComponent({
data: { integrations: {} }, data: { integrations: {} },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: true, loading: true,
}); });
expect(wrapper.find(IntegrationsList).exists()).toBe(true); expect(wrapper.find(IntegrationsList).exists()).toBe(true);
...@@ -152,7 +138,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -152,7 +138,6 @@ describe('AlertsSettingsWrapper', () => {
it('renders the IntegrationsList table using the API data', () => { it('renders the IntegrationsList table using the API data', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
expect(findLoader().exists()).toBe(false); expect(findLoader().exists()).toBe(false);
...@@ -162,7 +147,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -162,7 +147,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `createHttpIntegrationMutation`', () => { it('calls `$apollo.mutate` with `createHttpIntegrationMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -185,7 +169,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -185,7 +169,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `updateHttpIntegrationMutation`', () => { it('calls `$apollo.mutate` with `updateHttpIntegrationMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -206,7 +189,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -206,7 +189,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `resetHttpTokenMutation`', () => { it('calls `$apollo.mutate` with `resetHttpTokenMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -229,7 +211,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -229,7 +211,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `createPrometheusIntegrationMutation`', () => { it('calls `$apollo.mutate` with `createPrometheusIntegrationMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -252,7 +233,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -252,7 +233,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `updatePrometheusIntegrationMutation`', () => { it('calls `$apollo.mutate` with `updatePrometheusIntegrationMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -273,7 +253,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -273,7 +253,6 @@ describe('AlertsSettingsWrapper', () => {
it('calls `$apollo.mutate` with `resetPrometheusTokenMutation`', () => { it('calls `$apollo.mutate` with `resetPrometheusTokenMutation`', () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -296,7 +275,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -296,7 +275,6 @@ describe('AlertsSettingsWrapper', () => {
it('shows an error alert when integration creation fails ', async () => { it('shows an error alert when integration creation fails ', async () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -311,7 +289,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -311,7 +289,6 @@ describe('AlertsSettingsWrapper', () => {
it('shows an error alert when integration token reset fails ', async () => { it('shows an error alert when integration token reset fails ', async () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -326,7 +303,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -326,7 +303,6 @@ describe('AlertsSettingsWrapper', () => {
it('shows an error alert when integration update fails ', async () => { it('shows an error alert when integration update fails ', async () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -341,7 +317,6 @@ describe('AlertsSettingsWrapper', () => { ...@@ -341,7 +317,6 @@ describe('AlertsSettingsWrapper', () => {
it('shows an error alert when integration test payload fails ', async () => { it('shows an error alert when integration test payload fails ', async () => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
loading: false, loading: false,
}); });
...@@ -405,7 +380,7 @@ describe('AlertsSettingsWrapper', () => { ...@@ -405,7 +380,7 @@ describe('AlertsSettingsWrapper', () => {
it.each([true, false])('it shows/hides the alert when opsgenie is %s', active => { it.each([true, false])('it shows/hides the alert when opsgenie is %s', active => {
createComponent({ createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] }, data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true }, opsgenie: { active } }, provide: { opsgenie: { active } },
loading: false, loading: false,
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment