2021-01-29 00:20:46 +05:30
|
|
|
<script>
|
|
|
|
import {
|
|
|
|
GlButton,
|
|
|
|
GlForm,
|
|
|
|
GlFormGroup,
|
|
|
|
GlFormSelect,
|
|
|
|
GlFormInput,
|
|
|
|
GlFormInputGroup,
|
|
|
|
GlFormTextarea,
|
|
|
|
GlModal,
|
|
|
|
GlModalDirective,
|
|
|
|
GlToggle,
|
2021-04-17 20:07:23 +05:30
|
|
|
GlTabs,
|
|
|
|
GlTab,
|
2021-01-29 00:20:46 +05:30
|
|
|
} from '@gitlab/ui';
|
2021-04-17 20:07:23 +05:30
|
|
|
import * as Sentry from '@sentry/browser';
|
2021-04-29 21:17:54 +05:30
|
|
|
import { isEqual, isEmpty, omit } from 'lodash';
|
2021-01-29 00:20:46 +05:30
|
|
|
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
2021-12-11 22:18:48 +05:30
|
|
|
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
|
2021-01-29 00:20:46 +05:30
|
|
|
import {
|
2021-03-08 18:12:59 +05:30
|
|
|
integrationTypes,
|
2021-04-17 20:07:23 +05:30
|
|
|
integrationSteps,
|
|
|
|
createStepNumbers,
|
|
|
|
editStepNumbers,
|
2021-01-29 00:20:46 +05:30
|
|
|
JSON_VALIDATE_DELAY,
|
|
|
|
targetPrometheusUrlPlaceholder,
|
|
|
|
typeSet,
|
2021-04-17 20:07:23 +05:30
|
|
|
i18n,
|
2021-04-29 21:17:54 +05:30
|
|
|
tabIndices,
|
|
|
|
testAlertModalId,
|
2021-01-29 00:20:46 +05:30
|
|
|
} from '../constants';
|
2021-03-11 19:13:27 +05:30
|
|
|
import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql';
|
2021-04-17 20:07:23 +05:30
|
|
|
import parseSamplePayloadQuery from '../graphql/queries/parse_sample_payload.query.graphql';
|
2021-03-11 19:13:27 +05:30
|
|
|
import MappingBuilder from './alert_mapping_builder.vue';
|
|
|
|
import AlertSettingsFormHelpBlock from './alert_settings_form_help_block.vue';
|
2021-02-22 17:27:13 +05:30
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
export default {
|
|
|
|
placeholders: {
|
|
|
|
prometheus: targetPrometheusUrlPlaceholder,
|
|
|
|
},
|
|
|
|
JSON_VALIDATE_DELAY,
|
|
|
|
typeSet,
|
2021-04-17 20:07:23 +05:30
|
|
|
integrationSteps,
|
2021-02-22 17:27:13 +05:30
|
|
|
i18n,
|
2021-04-29 21:17:54 +05:30
|
|
|
primaryProps: { text: i18n.integrationFormSteps.testPayload.savedAndTest },
|
|
|
|
secondaryProps: { text: i18n.integrationFormSteps.testPayload.proceedWithoutSave },
|
|
|
|
cancelProps: { text: i18n.integrationFormSteps.testPayload.cancel },
|
|
|
|
testAlertModalId,
|
2021-01-29 00:20:46 +05:30
|
|
|
components: {
|
|
|
|
ClipboardButton,
|
|
|
|
GlButton,
|
|
|
|
GlForm,
|
|
|
|
GlFormGroup,
|
|
|
|
GlFormInput,
|
|
|
|
GlFormInputGroup,
|
|
|
|
GlFormTextarea,
|
|
|
|
GlFormSelect,
|
|
|
|
GlModal,
|
|
|
|
GlToggle,
|
2021-04-17 20:07:23 +05:30
|
|
|
GlTabs,
|
|
|
|
GlTab,
|
2021-01-29 00:20:46 +05:30
|
|
|
AlertSettingsFormHelpBlock,
|
|
|
|
MappingBuilder,
|
|
|
|
},
|
|
|
|
directives: {
|
|
|
|
GlModal: GlModalDirective,
|
|
|
|
},
|
|
|
|
inject: {
|
2021-04-29 21:17:54 +05:30
|
|
|
alertsUsageUrl: {
|
|
|
|
default: '#',
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-03-11 19:13:27 +05:30
|
|
|
multiIntegrations: {
|
|
|
|
default: false,
|
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
projectPath: {
|
|
|
|
default: '',
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
props: {
|
|
|
|
loading: {
|
|
|
|
type: Boolean,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
canAddIntegration: {
|
|
|
|
type: Boolean,
|
|
|
|
required: true,
|
|
|
|
},
|
2021-03-11 19:13:27 +05:30
|
|
|
alertFields: {
|
|
|
|
type: Array,
|
|
|
|
required: false,
|
|
|
|
default: null,
|
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
tabIndex: {
|
|
|
|
type: Number,
|
|
|
|
required: false,
|
|
|
|
default: tabIndices.configureDetails,
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
apollo: {
|
|
|
|
currentIntegration: {
|
|
|
|
query: getCurrentIntegrationQuery,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2021-04-17 20:07:23 +05:30
|
|
|
integrationTypesOptions: Object.values(integrationTypes),
|
|
|
|
samplePayload: {
|
2021-01-29 00:20:46 +05:30
|
|
|
json: null,
|
|
|
|
error: null,
|
2021-04-29 21:17:54 +05:30
|
|
|
loading: false,
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
testPayload: {
|
|
|
|
json: null,
|
|
|
|
error: null,
|
|
|
|
},
|
|
|
|
resetPayloadAndMappingConfirmed: false,
|
2021-03-11 19:13:27 +05:30
|
|
|
mapping: [],
|
2021-04-29 21:17:54 +05:30
|
|
|
integrationForm: {
|
|
|
|
active: false,
|
|
|
|
type: integrationTypes.none.value,
|
|
|
|
name: '',
|
|
|
|
token: '',
|
|
|
|
url: '',
|
|
|
|
apiUrl: '',
|
|
|
|
},
|
|
|
|
activeTabIndex: this.tabIndex,
|
2021-01-29 00:20:46 +05:30
|
|
|
currentIntegration: null,
|
2021-04-17 20:07:23 +05:30
|
|
|
parsedPayload: [],
|
2021-04-29 21:17:54 +05:30
|
|
|
validationState: {
|
|
|
|
name: true,
|
|
|
|
apiUrl: true,
|
|
|
|
},
|
2021-12-11 22:18:48 +05:30
|
|
|
pricingLink: `${PROMO_URL}/pricing`,
|
2021-01-29 00:20:46 +05:30
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
isPrometheus() {
|
2021-04-29 21:17:54 +05:30
|
|
|
return this.integrationForm.type === typeSet.prometheus;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
isHttp() {
|
2021-04-29 21:17:54 +05:30
|
|
|
return this.integrationForm.type === typeSet.http;
|
|
|
|
},
|
|
|
|
isNone() {
|
|
|
|
return !this.isHttp && !this.isPrometheus;
|
2021-04-17 20:07:23 +05:30
|
|
|
},
|
|
|
|
isCreating() {
|
|
|
|
return !this.currentIntegration;
|
|
|
|
},
|
|
|
|
isSampePayloadValid() {
|
|
|
|
return this.samplePayload.error === null;
|
|
|
|
},
|
|
|
|
isTestPayloadValid() {
|
|
|
|
return this.testPayload.error === null;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
testAlertPayload() {
|
|
|
|
return {
|
2021-04-17 20:07:23 +05:30
|
|
|
data: this.testPayload.json,
|
2021-01-29 00:20:46 +05:30
|
|
|
endpoint: this.integrationForm.url,
|
|
|
|
token: this.integrationForm.token,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
showMappingBuilder() {
|
2021-04-17 20:07:23 +05:30
|
|
|
return this.multiIntegrations && this.isHttp && this.alertFields?.length;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
hasSamplePayload() {
|
2021-04-17 20:07:23 +05:30
|
|
|
return this.isValidNonEmptyJSON(this.currentIntegration?.payloadExample);
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
canEditPayload() {
|
2021-04-17 20:07:23 +05:30
|
|
|
return this.hasSamplePayload && !this.resetPayloadAndMappingConfirmed;
|
|
|
|
},
|
|
|
|
canParseSamplePayload() {
|
2021-04-29 21:17:54 +05:30
|
|
|
return this.isSampePayloadValid && this.samplePayload.json;
|
2021-02-22 17:27:13 +05:30
|
|
|
},
|
|
|
|
isSelectDisabled() {
|
|
|
|
return this.currentIntegration !== null || !this.canAddIntegration;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
viewCredentialsHelpMsg() {
|
|
|
|
return this.isPrometheus
|
|
|
|
? i18n.integrationFormSteps.setupCredentials.prometheusHelp
|
|
|
|
: i18n.integrationFormSteps.setupCredentials.help;
|
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
isFormValid() {
|
|
|
|
return (
|
|
|
|
Object.values(this.validationState).every(Boolean) &&
|
|
|
|
!this.isNone &&
|
|
|
|
this.isSampePayloadValid
|
|
|
|
);
|
|
|
|
},
|
|
|
|
isFormDirty() {
|
|
|
|
const { type, active, name, apiUrl, payloadAlertFields = [], payloadAttributeMappings = [] } =
|
|
|
|
this.currentIntegration || {};
|
|
|
|
const {
|
|
|
|
name: formName,
|
|
|
|
apiUrl: formApiUrl,
|
|
|
|
active: formActive,
|
|
|
|
type: formType,
|
|
|
|
} = this.integrationForm;
|
|
|
|
|
|
|
|
const isDirty =
|
|
|
|
type !== formType ||
|
|
|
|
active !== formActive ||
|
|
|
|
name !== formName ||
|
|
|
|
apiUrl !== formApiUrl ||
|
|
|
|
!isEqual(this.parsedPayload, payloadAlertFields) ||
|
|
|
|
!isEqual(this.mapping, this.getCleanMapping(payloadAttributeMappings));
|
|
|
|
|
|
|
|
return isDirty;
|
|
|
|
},
|
|
|
|
canSubmitForm() {
|
|
|
|
return this.isFormValid && this.isFormDirty;
|
|
|
|
},
|
|
|
|
dataForSave() {
|
|
|
|
const { name, apiUrl, active } = this.integrationForm;
|
|
|
|
const customMappingVariables = {
|
|
|
|
payloadAttributeMappings: this.mapping,
|
|
|
|
payloadExample: this.samplePayload.json || '{}',
|
|
|
|
};
|
|
|
|
|
|
|
|
const variables = this.isHttp
|
|
|
|
? { name, active, ...customMappingVariables }
|
|
|
|
: { apiUrl, active };
|
|
|
|
|
|
|
|
return { type: this.integrationForm.type, variables };
|
|
|
|
},
|
|
|
|
testAlertModal() {
|
|
|
|
return this.isFormDirty ? testAlertModalId : null;
|
|
|
|
},
|
|
|
|
prometheusUrlInvalidFeedback() {
|
|
|
|
const { blankUrlError, invalidUrlError } = i18n.integrationFormSteps.prometheusFormUrl;
|
|
|
|
return this.integrationForm.apiUrl?.length ? invalidUrlError : blankUrlError;
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
watch: {
|
2021-04-29 21:17:54 +05:30
|
|
|
tabIndex(val) {
|
|
|
|
this.activeTabIndex = val;
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
currentIntegration(val) {
|
|
|
|
if (val === null) {
|
2021-04-17 20:07:23 +05:30
|
|
|
this.reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
this.resetPayloadAndMapping();
|
|
|
|
const {
|
|
|
|
name,
|
|
|
|
type,
|
|
|
|
active,
|
|
|
|
url,
|
|
|
|
apiUrl,
|
|
|
|
token,
|
|
|
|
payloadExample,
|
|
|
|
payloadAlertFields,
|
|
|
|
payloadAttributeMappings,
|
|
|
|
} = val;
|
|
|
|
this.integrationForm = { type, name, active, url, apiUrl, token };
|
|
|
|
|
|
|
|
if (this.showMappingBuilder) {
|
|
|
|
this.resetPayloadAndMappingConfirmed = false;
|
2021-04-17 20:07:23 +05:30
|
|
|
this.parsedPayload = payloadAlertFields;
|
2021-04-29 21:17:54 +05:30
|
|
|
this.samplePayload.json = this.getPrettifiedPayload(payloadExample);
|
|
|
|
this.updateMapping(this.getCleanMapping(payloadAttributeMappings));
|
2021-01-29 00:20:46 +05:30
|
|
|
}
|
2021-04-17 20:07:23 +05:30
|
|
|
this.$el.scrollIntoView({ block: 'center' });
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
2021-04-29 21:17:54 +05:30
|
|
|
getCleanMapping(mapping) {
|
|
|
|
return mapping.map((mappingItem) => omit(mappingItem, '__typename'));
|
|
|
|
},
|
|
|
|
validateName() {
|
|
|
|
this.validationState.name = Boolean(this.integrationForm.name?.length);
|
|
|
|
},
|
|
|
|
validateApiUrl() {
|
|
|
|
try {
|
|
|
|
const parsedUrl = new URL(this.integrationForm.apiUrl);
|
|
|
|
this.validationState.apiUrl = ['http:', 'https:'].includes(parsedUrl.protocol);
|
|
|
|
} catch (e) {
|
|
|
|
this.validationState.apiUrl = false;
|
|
|
|
}
|
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
isValidNonEmptyJSON(JSONString) {
|
|
|
|
if (JSONString) {
|
|
|
|
let parsed;
|
|
|
|
try {
|
|
|
|
parsed = JSON.parse(JSONString);
|
|
|
|
} catch (error) {
|
|
|
|
Sentry.captureException(error);
|
|
|
|
}
|
|
|
|
if (parsed) return !isEmpty(parsed);
|
2021-01-29 00:20:46 +05:30
|
|
|
}
|
2021-04-17 20:07:23 +05:30
|
|
|
return false;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
getPrettifiedPayload(payload) {
|
|
|
|
return this.isValidNonEmptyJSON(payload)
|
|
|
|
? JSON.stringify(JSON.parse(payload), null, '\t')
|
|
|
|
: null;
|
|
|
|
},
|
|
|
|
triggerValidation() {
|
|
|
|
if (this.isHttp) {
|
|
|
|
this.validationState.apiUrl = true;
|
|
|
|
this.validateName();
|
|
|
|
if (!this.validationState.name) {
|
|
|
|
this.$refs.integrationName.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
|
|
}
|
|
|
|
} else if (this.isPrometheus) {
|
|
|
|
this.validationState.name = true;
|
|
|
|
this.validateApiUrl();
|
|
|
|
}
|
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
sendTestAlert() {
|
|
|
|
this.$emit('test-alert-payload', this.testAlertPayload);
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
saveAndSendTestAlert() {
|
|
|
|
this.$emit('save-and-test-alert-payload', this.dataForSave, this.testAlertPayload);
|
|
|
|
},
|
|
|
|
submit(testAfterSubmit = false) {
|
|
|
|
this.triggerValidation();
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
if (!this.isFormValid) {
|
|
|
|
return;
|
2021-01-29 00:20:46 +05:30
|
|
|
}
|
2021-04-29 21:17:54 +05:30
|
|
|
const event = this.currentIntegration ? 'update-integration' : 'create-new-integration';
|
|
|
|
this.$emit(event, this.dataForSave, testAfterSubmit);
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
reset() {
|
2021-04-17 20:07:23 +05:30
|
|
|
this.resetFormValues();
|
|
|
|
this.resetPayloadAndMapping();
|
|
|
|
this.$emit('clear-current-integration', { type: this.currentIntegration?.type });
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
resetFormValues() {
|
2021-04-29 21:17:54 +05:30
|
|
|
this.integrationForm.type = integrationTypes.none.value;
|
2021-01-29 00:20:46 +05:30
|
|
|
this.integrationForm.name = '';
|
2021-04-29 21:17:54 +05:30
|
|
|
this.integrationForm.active = false;
|
2021-01-29 00:20:46 +05:30
|
|
|
this.integrationForm.apiUrl = '';
|
2021-04-17 20:07:23 +05:30
|
|
|
this.samplePayload = {
|
2021-01-29 00:20:46 +05:30
|
|
|
json: null,
|
|
|
|
error: null,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
resetAuthKey() {
|
|
|
|
if (!this.currentIntegration) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$emit('reset-token', {
|
2021-04-29 21:17:54 +05:30
|
|
|
type: this.integrationForm.type,
|
2021-01-29 00:20:46 +05:30
|
|
|
variables: { id: this.currentIntegration.id },
|
|
|
|
});
|
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
validateJson(isSamplePayload = true) {
|
|
|
|
const payload = isSamplePayload ? this.samplePayload : this.testPayload;
|
|
|
|
|
|
|
|
payload.error = null;
|
|
|
|
if (payload.json === '') {
|
2021-01-29 00:20:46 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2021-04-17 20:07:23 +05:30
|
|
|
JSON.parse(payload.json);
|
2021-01-29 00:20:46 +05:30
|
|
|
} catch (e) {
|
2021-04-17 20:07:23 +05:30
|
|
|
payload.error = JSON.stringify(e.message);
|
2021-01-29 00:20:46 +05:30
|
|
|
}
|
|
|
|
},
|
2021-04-29 21:17:54 +05:30
|
|
|
parseSamplePayload() {
|
|
|
|
this.samplePayload.loading = true;
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
return this.$apollo
|
|
|
|
.query({
|
|
|
|
query: parseSamplePayloadQuery,
|
|
|
|
variables: { projectPath: this.projectPath, payload: this.samplePayload.json },
|
|
|
|
})
|
|
|
|
.then(
|
|
|
|
({
|
|
|
|
data: {
|
|
|
|
project: { alertManagementPayloadFields },
|
|
|
|
},
|
|
|
|
}) => {
|
|
|
|
this.parsedPayload = alertManagementPayloadFields;
|
|
|
|
this.resetPayloadAndMappingConfirmed = false;
|
|
|
|
|
|
|
|
this.$toast.show(
|
2021-04-29 21:17:54 +05:30
|
|
|
this.$options.i18n.integrationFormSteps.mapFields.payloadParsedSucessMsg,
|
2021-04-17 20:07:23 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.catch(({ message }) => {
|
|
|
|
this.samplePayload.error = message;
|
2021-01-29 00:20:46 +05:30
|
|
|
})
|
|
|
|
.finally(() => {
|
2021-04-29 21:17:54 +05:30
|
|
|
this.samplePayload.loading = false;
|
2021-01-29 00:20:46 +05:30
|
|
|
});
|
|
|
|
},
|
2021-03-11 19:13:27 +05:30
|
|
|
updateMapping(mapping) {
|
|
|
|
this.mapping = mapping;
|
|
|
|
},
|
2021-04-17 20:07:23 +05:30
|
|
|
resetPayloadAndMapping() {
|
|
|
|
this.resetPayloadAndMappingConfirmed = true;
|
|
|
|
this.parsedPayload = [];
|
|
|
|
this.updateMapping([]);
|
|
|
|
},
|
|
|
|
getLabelWithStepNumber(step, label) {
|
|
|
|
let stepNumber = editStepNumbers[step];
|
|
|
|
|
|
|
|
if (this.isCreating) {
|
|
|
|
stepNumber = createStepNumbers[step];
|
|
|
|
}
|
|
|
|
|
|
|
|
return stepNumber ? `${stepNumber}.${label}` : label;
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<gl-form class="gl-mt-6" @submit.prevent="submit" @reset.prevent="reset">
|
2021-04-17 20:07:23 +05:30
|
|
|
<gl-tabs v-model="activeTabIndex">
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-tab :title="$options.i18n.integrationTabs.configureDetails" class="gl-mt-3">
|
2021-01-29 00:20:46 +05:30
|
|
|
<gl-form-group
|
2021-04-17 20:07:23 +05:30
|
|
|
v-if="isCreating"
|
|
|
|
id="integration-type"
|
|
|
|
:label="
|
|
|
|
getLabelWithStepNumber(
|
|
|
|
$options.integrationSteps.selectType,
|
|
|
|
$options.i18n.integrationFormSteps.selectType.label,
|
|
|
|
)
|
|
|
|
"
|
|
|
|
label-for="integration-type"
|
2021-01-29 00:20:46 +05:30
|
|
|
>
|
2021-04-17 20:07:23 +05:30
|
|
|
<gl-form-select
|
2021-04-29 21:17:54 +05:30
|
|
|
v-model="integrationForm.type"
|
2021-04-17 20:07:23 +05:30
|
|
|
:disabled="isSelectDisabled"
|
|
|
|
class="gl-max-w-full"
|
|
|
|
:options="integrationTypesOptions"
|
2021-01-29 00:20:46 +05:30
|
|
|
/>
|
2021-04-17 20:07:23 +05:30
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
<alert-settings-form-help-block
|
2021-04-17 20:07:23 +05:30
|
|
|
v-if="!canAddIntegration"
|
|
|
|
disabled="true"
|
|
|
|
class="gl-display-inline-block gl-my-4"
|
|
|
|
:message="$options.i18n.integrationFormSteps.selectType.enterprise"
|
2021-12-11 22:18:48 +05:30
|
|
|
:link="pricingLink"
|
2021-04-17 20:07:23 +05:30
|
|
|
data-testid="multi-integrations-not-supported"
|
2021-01-29 00:20:46 +05:30
|
|
|
/>
|
2021-04-17 20:07:23 +05:30
|
|
|
</gl-form-group>
|
|
|
|
<div class="gl-mt-3">
|
|
|
|
<gl-form-group
|
|
|
|
v-if="isHttp"
|
|
|
|
:label="
|
|
|
|
getLabelWithStepNumber(
|
|
|
|
$options.integrationSteps.nameIntegration,
|
|
|
|
$options.i18n.integrationFormSteps.nameIntegration.label,
|
|
|
|
)
|
|
|
|
"
|
|
|
|
label-for="name-integration"
|
2021-04-29 21:17:54 +05:30
|
|
|
:invalid-feedback="$options.i18n.integrationFormSteps.nameIntegration.error"
|
|
|
|
:state="validationState.name"
|
2021-04-17 20:07:23 +05:30
|
|
|
>
|
|
|
|
<gl-form-input
|
2021-04-29 21:17:54 +05:30
|
|
|
id="name-integration"
|
|
|
|
ref="integrationName"
|
2021-04-17 20:07:23 +05:30
|
|
|
v-model="integrationForm.name"
|
|
|
|
type="text"
|
|
|
|
:placeholder="$options.i18n.integrationFormSteps.nameIntegration.placeholder"
|
2021-04-29 21:17:54 +05:30
|
|
|
@input="validateName"
|
2021-04-17 20:07:23 +05:30
|
|
|
/>
|
|
|
|
</gl-form-group>
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-form-group
|
|
|
|
v-if="!isNone"
|
|
|
|
:label="
|
|
|
|
getLabelWithStepNumber(
|
|
|
|
isHttp
|
|
|
|
? $options.integrationSteps.enableHttpIntegration
|
|
|
|
: $options.integrationSteps.enablePrometheusIntegration,
|
|
|
|
$options.i18n.integrationFormSteps.enableIntegration.label,
|
|
|
|
)
|
|
|
|
"
|
|
|
|
>
|
|
|
|
<span>{{ $options.i18n.integrationFormSteps.enableIntegration.help }}</span>
|
|
|
|
|
|
|
|
<gl-toggle
|
|
|
|
id="enable-integration"
|
|
|
|
v-model="integrationForm.active"
|
|
|
|
:is-loading="loading"
|
|
|
|
:label="$options.i18n.integrationFormSteps.nameIntegration.activeToggle"
|
|
|
|
class="gl-mt-4 gl-font-weight-normal"
|
|
|
|
/>
|
|
|
|
</gl-form-group>
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-form-group
|
|
|
|
v-if="isPrometheus"
|
|
|
|
class="gl-my-4"
|
|
|
|
:label="$options.i18n.integrationFormSteps.prometheusFormUrl.label"
|
|
|
|
label-for="api-url"
|
|
|
|
:invalid-feedback="prometheusUrlInvalidFeedback"
|
|
|
|
:state="validationState.apiUrl"
|
|
|
|
>
|
2021-01-29 00:20:46 +05:30
|
|
|
<gl-form-input
|
2021-04-29 21:17:54 +05:30
|
|
|
id="api-url"
|
2021-01-29 00:20:46 +05:30
|
|
|
v-model="integrationForm.apiUrl"
|
|
|
|
type="text"
|
|
|
|
:placeholder="$options.placeholders.prometheus"
|
2021-04-29 21:17:54 +05:30
|
|
|
@input="validateApiUrl"
|
2021-01-29 00:20:46 +05:30
|
|
|
/>
|
|
|
|
<span class="gl-text-gray-400">
|
|
|
|
{{ $options.i18n.integrationFormSteps.prometheusFormUrl.help }}
|
|
|
|
</span>
|
2021-04-29 21:17:54 +05:30
|
|
|
</gl-form-group>
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
<template v-if="showMappingBuilder">
|
|
|
|
<gl-form-group
|
|
|
|
data-testid="sample-payload-section"
|
|
|
|
:label="
|
|
|
|
getLabelWithStepNumber(
|
2021-04-29 21:17:54 +05:30
|
|
|
$options.integrationSteps.customizeMapping,
|
|
|
|
$options.i18n.integrationFormSteps.mapFields.label,
|
2021-04-17 20:07:23 +05:30
|
|
|
)
|
|
|
|
"
|
|
|
|
label-for="sample-payload"
|
|
|
|
class="gl-mb-0!"
|
|
|
|
:invalid-feedback="samplePayload.error"
|
|
|
|
>
|
2021-04-29 21:17:54 +05:30
|
|
|
<span>{{ $options.i18n.integrationFormSteps.mapFields.help }}</span>
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
<gl-form-textarea
|
|
|
|
id="sample-payload"
|
2021-04-29 21:17:54 +05:30
|
|
|
v-model="samplePayload.json"
|
|
|
|
:disabled="canEditPayload"
|
2021-04-17 20:07:23 +05:30
|
|
|
:state="isSampePayloadValid"
|
2021-04-29 21:17:54 +05:30
|
|
|
:placeholder="$options.i18n.integrationFormSteps.mapFields.placeholder"
|
2021-04-17 20:07:23 +05:30
|
|
|
class="gl-my-3"
|
|
|
|
:debounce="$options.JSON_VALIDATE_DELAY"
|
|
|
|
rows="6"
|
|
|
|
max-rows="10"
|
|
|
|
@input="validateJson"
|
|
|
|
/>
|
|
|
|
</gl-form-group>
|
|
|
|
|
|
|
|
<gl-button
|
|
|
|
v-if="canEditPayload"
|
|
|
|
v-gl-modal.resetPayloadModal
|
|
|
|
data-testid="payload-action-btn"
|
2021-04-29 21:17:54 +05:30
|
|
|
:disabled="!integrationForm.active"
|
2021-04-17 20:07:23 +05:30
|
|
|
class="gl-mt-3"
|
|
|
|
>
|
2021-04-29 21:17:54 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.mapFields.editPayload }}
|
2021-04-17 20:07:23 +05:30
|
|
|
</gl-button>
|
|
|
|
|
|
|
|
<gl-button
|
|
|
|
v-else
|
|
|
|
data-testid="payload-action-btn"
|
|
|
|
:class="{ 'gl-mt-3': samplePayload.error }"
|
2021-04-29 21:17:54 +05:30
|
|
|
:disabled="!canParseSamplePayload"
|
|
|
|
:loading="samplePayload.loading"
|
|
|
|
@click="parseSamplePayload"
|
2021-04-17 20:07:23 +05:30
|
|
|
>
|
2021-04-29 21:17:54 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.mapFields.parsePayload }}
|
2021-04-17 20:07:23 +05:30
|
|
|
</gl-button>
|
|
|
|
<gl-modal
|
|
|
|
modal-id="resetPayloadModal"
|
2021-04-29 21:17:54 +05:30
|
|
|
:title="$options.i18n.integrationFormSteps.mapFields.resetHeader"
|
|
|
|
:ok-title="$options.i18n.integrationFormSteps.mapFields.resetOk"
|
2021-04-17 20:07:23 +05:30
|
|
|
ok-variant="danger"
|
2021-04-29 21:17:54 +05:30
|
|
|
@ok="resetPayloadAndMappingConfirmed = true"
|
2021-04-17 20:07:23 +05:30
|
|
|
>
|
2021-04-29 21:17:54 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.mapFields.resetBody }}
|
2021-04-17 20:07:23 +05:30
|
|
|
</gl-modal>
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<div class="gl-mt-5">
|
|
|
|
<span>{{ $options.i18n.integrationFormSteps.mapFields.mapIntro }}</span>
|
2021-04-17 20:07:23 +05:30
|
|
|
<mapping-builder
|
|
|
|
:parsed-payload="parsedPayload"
|
|
|
|
:saved-mapping="mapping"
|
|
|
|
:alert-fields="alertFields"
|
|
|
|
@onMappingUpdate="updateMapping"
|
|
|
|
/>
|
2021-04-29 21:17:54 +05:30
|
|
|
</div>
|
2021-04-17 20:07:23 +05:30
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
<div class="gl-display-flex gl-justify-content-start gl-py-3">
|
|
|
|
<gl-button
|
2021-04-29 21:17:54 +05:30
|
|
|
:disabled="!canSubmitForm"
|
2021-04-17 20:07:23 +05:30
|
|
|
variant="confirm"
|
|
|
|
class="js-no-auto-disable"
|
|
|
|
data-testid="integration-form-submit"
|
2021-04-29 21:17:54 +05:30
|
|
|
@click="submit(false)"
|
2021-04-17 20:07:23 +05:30
|
|
|
>
|
|
|
|
{{ $options.i18n.saveIntegration }}
|
|
|
|
</gl-button>
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-button
|
|
|
|
:disabled="!canSubmitForm"
|
|
|
|
variant="confirm"
|
|
|
|
category="secondary"
|
|
|
|
class="gl-ml-3 js-no-auto-disable"
|
|
|
|
data-testid="integration-form-test-and-submit"
|
|
|
|
@click="submit(true)"
|
|
|
|
>
|
|
|
|
{{ $options.i18n.saveAndTestIntegration }}
|
|
|
|
</gl-button>
|
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">{{
|
|
|
|
$options.i18n.cancelAndClose
|
|
|
|
}}</gl-button>
|
|
|
|
</div>
|
|
|
|
</gl-tab>
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-tab
|
|
|
|
:title="$options.i18n.integrationTabs.viewCredentials"
|
|
|
|
:disabled="isCreating"
|
|
|
|
class="gl-mt-3"
|
|
|
|
>
|
2021-04-17 20:07:23 +05:30
|
|
|
<alert-settings-form-help-block
|
|
|
|
:message="viewCredentialsHelpMsg"
|
|
|
|
link="https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<gl-form-group id="integration-webhook">
|
2021-01-29 00:20:46 +05:30
|
|
|
<div class="gl-my-4">
|
|
|
|
<span class="gl-font-weight-bold">
|
2021-04-17 20:07:23 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.setupCredentials.webhookUrl }}
|
2021-01-29 00:20:46 +05:30
|
|
|
</span>
|
|
|
|
|
|
|
|
<gl-form-input-group id="url" readonly :value="integrationForm.url">
|
|
|
|
<template #append>
|
|
|
|
<clipboard-button
|
|
|
|
:text="integrationForm.url || ''"
|
2021-04-17 20:07:23 +05:30
|
|
|
:title="$options.i18n.copy"
|
2021-01-29 00:20:46 +05:30
|
|
|
class="gl-m-0!"
|
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
</gl-form-input-group>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="gl-my-4">
|
|
|
|
<span class="gl-font-weight-bold">
|
2021-04-17 20:07:23 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.setupCredentials.authorizationKey }}
|
2021-01-29 00:20:46 +05:30
|
|
|
</span>
|
|
|
|
|
|
|
|
<gl-form-input-group
|
|
|
|
id="authorization-key"
|
|
|
|
class="gl-mb-3"
|
|
|
|
readonly
|
|
|
|
:value="integrationForm.token"
|
|
|
|
>
|
|
|
|
<template #append>
|
|
|
|
<clipboard-button
|
|
|
|
:text="integrationForm.token || ''"
|
2021-04-17 20:07:23 +05:30
|
|
|
:title="$options.i18n.copy"
|
2021-01-29 00:20:46 +05:30
|
|
|
class="gl-m-0!"
|
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
</gl-form-input-group>
|
|
|
|
</div>
|
|
|
|
</gl-form-group>
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<div class="gl-display-flex gl-justify-content-start gl-py-3">
|
|
|
|
<gl-button v-gl-modal.authKeyModal variant="danger">
|
|
|
|
{{ $options.i18n.integrationFormSteps.setupCredentials.reset }}
|
|
|
|
</gl-button>
|
2021-04-17 20:07:23 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">
|
|
|
|
{{ $options.i18n.cancelAndClose }}
|
|
|
|
</gl-button>
|
|
|
|
</div>
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
<gl-modal
|
|
|
|
modal-id="authKeyModal"
|
|
|
|
:title="$options.i18n.integrationFormSteps.setupCredentials.reset"
|
|
|
|
:ok-title="$options.i18n.integrationFormSteps.setupCredentials.reset"
|
|
|
|
ok-variant="danger"
|
|
|
|
@ok="resetAuthKey"
|
2021-01-29 00:20:46 +05:30
|
|
|
>
|
2021-04-17 20:07:23 +05:30
|
|
|
{{ $options.i18n.integrationFormSteps.restKeyInfo.label }}
|
|
|
|
</gl-modal>
|
|
|
|
</gl-tab>
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-tab
|
|
|
|
:title="$options.i18n.integrationTabs.sendTestAlert"
|
|
|
|
:disabled="isCreating"
|
|
|
|
class="gl-mt-3"
|
|
|
|
>
|
2021-04-17 20:07:23 +05:30
|
|
|
<gl-form-group id="test-integration" :invalid-feedback="testPayload.error">
|
2021-01-29 00:20:46 +05:30
|
|
|
<alert-settings-form-help-block
|
2021-04-29 21:17:54 +05:30
|
|
|
:message="$options.i18n.integrationFormSteps.testPayload.help"
|
|
|
|
:link="alertsUsageUrl"
|
2021-01-29 00:20:46 +05:30
|
|
|
/>
|
|
|
|
|
|
|
|
<gl-form-textarea
|
|
|
|
id="test-payload"
|
2021-04-29 21:17:54 +05:30
|
|
|
v-model="testPayload.json"
|
2021-04-17 20:07:23 +05:30
|
|
|
:state="isTestPayloadValid"
|
2021-04-29 21:17:54 +05:30
|
|
|
:placeholder="$options.i18n.integrationFormSteps.testPayload.placeholder"
|
2021-01-29 00:20:46 +05:30
|
|
|
class="gl-my-3"
|
|
|
|
:debounce="$options.JSON_VALIDATE_DELAY"
|
|
|
|
rows="6"
|
|
|
|
max-rows="10"
|
2021-04-17 20:07:23 +05:30
|
|
|
@input="validateJson(false)"
|
2021-01-29 00:20:46 +05:30
|
|
|
/>
|
|
|
|
</gl-form-group>
|
2021-04-29 21:17:54 +05:30
|
|
|
<div class="gl-display-flex gl-justify-content-start gl-py-3">
|
|
|
|
<gl-button
|
|
|
|
v-gl-modal="testAlertModal"
|
|
|
|
:disabled="!isTestPayloadValid"
|
|
|
|
:loading="loading"
|
|
|
|
data-testid="send-test-alert"
|
|
|
|
variant="confirm"
|
|
|
|
class="js-no-auto-disable"
|
|
|
|
@click="isFormDirty ? null : sendTestAlert()"
|
|
|
|
>
|
|
|
|
{{ $options.i18n.send }}
|
|
|
|
</gl-button>
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">
|
|
|
|
{{ $options.i18n.cancelAndClose }}
|
|
|
|
</gl-button>
|
|
|
|
</div>
|
2021-04-17 20:07:23 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
<gl-modal
|
|
|
|
:modal-id="$options.testAlertModalId"
|
|
|
|
:title="$options.i18n.integrationFormSteps.testPayload.modalTitle"
|
|
|
|
:action-primary="$options.primaryProps"
|
|
|
|
:action-secondary="$options.secondaryProps"
|
|
|
|
:action-cancel="$options.cancelProps"
|
|
|
|
@primary="saveAndSendTestAlert"
|
|
|
|
@secondary="sendTestAlert"
|
|
|
|
>
|
|
|
|
{{ $options.i18n.integrationFormSteps.testPayload.modalBody }}
|
|
|
|
</gl-modal>
|
2021-04-17 20:07:23 +05:30
|
|
|
</gl-tab>
|
|
|
|
</gl-tabs>
|
2021-01-29 00:20:46 +05:30
|
|
|
</gl-form>
|
|
|
|
</template>
|