diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-05 21:08:48 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-05 21:08:48 +0300 |
commit | 3e1c760141a27097d74d191a619fa6edecd86fe7 (patch) | |
tree | dc26e1842b355d2ebad6c8923077b0a016aa82c9 /app/assets/javascripts/alerts_settings | |
parent | 74dd67ddea70f70830f3fe1ca65b06b604ec229f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/alerts_settings')
10 files changed, 224 insertions, 56 deletions
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue index 1c22f035a15..5ecb2dd3e58 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue @@ -1,5 +1,12 @@ <script> -import { GlTable, GlIcon, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; +import { + GlButtonGroup, + GlButton, + GlIcon, + GlLoadingIcon, + GlTable, + GlTooltipDirective, +} from '@gitlab/ui'; import { s__, __ } from '~/locale'; import Tracking from '~/tracking'; import { trackAlertIntegrationsViewsOptions } from '../constants'; @@ -25,9 +32,11 @@ const bodyTrClass = export default { i18n, components: { - GlTable, + GlButtonGroup, + GlButton, GlIcon, GlLoadingIcon, + GlTable, }, directives: { GlTooltip: GlTooltipDirective, @@ -57,6 +66,10 @@ export default { key: 'type', label: __('Type'), }, + { + key: 'actions', + label: __('Actions'), + }, ], computed: { tbodyTrClass() { @@ -111,6 +124,13 @@ export default { </span> </template> + <template #cell(actions)="{ item }"> + <gl-button-group> + <gl-button icon="pencil" @click="$emit('edit-integration', { id: item.id })" /> + <gl-button icon="remove" @click="$emit('delete-integration', { id: item.id })" /> + </gl-button-group> + </template> + <template #table-busy> <gl-loading-icon size="lg" color="dark" class="mt-3" /> </template> diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue index 84ee2fb524d..c5322c9865e 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue @@ -21,12 +21,14 @@ import { JSON_VALIDATE_DELAY, targetPrometheusUrlPlaceholder, typeSet, + defaultFormState, } from '../constants'; export default { targetPrometheusUrlPlaceholder, JSON_VALIDATE_DELAY, typeSet, + defaultFormState, i18n: { integrationFormSteps: { step1: { @@ -62,6 +64,11 @@ export default { label: s__('AlertSettings|Prometheus API base URL'), help: s__('AlertSettings|URL cannot be blank and must start with http or https'), }, + restKeyInfo: { + label: s__( + 'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.', + ), + }, }, }, components: { @@ -95,23 +102,18 @@ export default { type: Boolean, required: true, }, + currentIntegration: { + type: Object, + required: false, + default: null, + }, }, data() { return { selectedIntegration: integrationTypesNew[0].value, + active: false, options: integrationTypesNew, formVisible: false, - integrationForm: { - name: '', - integrationTestPayload: { - json: null, - error: null, - }, - active: false, - authKey: '', - url: '', - apiUrl: '', - }, }; }, computed: { @@ -125,9 +127,29 @@ export default { case this.$options.typeSet.prometheus: return this.prometheus; default: - return {}; + return this.defaultFormState; } }, + integrationForm() { + return { + name: this.currentIntegration?.name || '', + integrationTestPayload: { + json: null, + error: null, + }, + active: this.currentIntegration?.active || false, + token: this.currentIntegration?.token || '', + url: this.currentIntegration?.url || '', + apiUrl: this.currentIntegration?.apiUrl || '', + }; + }, + }, + watch: { + currentIntegration(val) { + this.selectedIntegration = val.type; + this.active = val.active; + this.onIntegrationTypeSelect(); + }, }, methods: { onIntegrationTypeSelect() { @@ -142,18 +164,29 @@ export default { this.onSubmit(); }, onSubmit() { - const { name, apiUrl, active } = this.integrationForm; + const { name, apiUrl } = this.integrationForm; const variables = this.selectedIntegration === this.$options.typeSet.http - ? { name, active } - : { apiUrl, active }; - this.$emit('on-create-new-integration', { type: this.selectedIntegration, variables }); + ? { name, active: this.active } + : { apiUrl, active: this.active }; + const integrationPayload = { type: this.selectedIntegration, variables }; + + if (this.currentIntegration) { + return this.$emit('update-integration', integrationPayload); + } + + return this.$emit('create-new-integration', integrationPayload); }, onReset() { - // TODO: Reset form values + this.integrationForm = this.defaultFormState; + this.selectedIntegration = integrationTypesNew[0].value; + this.onIntegrationTypeSelect(); }, onResetAuthKey() { - // TODO: Handle reset auth key via GraphQL + this.$emit('reset-token', { + type: this.selectedIntegration, + variables: { id: this.currentIntegration.id }, + }); }, validateJson() { this.integrationForm.integrationTestPayload.error = null; @@ -214,7 +247,7 @@ export default { /> <gl-toggle - v-model="integrationForm.active" + v-model="active" :is-loading="loading" :label="__('Active')" class="gl-my-4 gl-font-weight-normal" @@ -242,13 +275,9 @@ export default { {{ s__('AlertSettings|Webhook URL') }} </span> - <gl-form-input-group id="url" readonly :value="selectedIntegrationType.url"> + <gl-form-input-group id="url" readonly :value="integrationForm.url"> <template #append> - <clipboard-button - :text="selectedIntegrationType.url || ''" - :title="__('Copy')" - class="gl-m-0!" - /> + <clipboard-button :text="integrationForm.url" :title="__('Copy')" class="gl-m-0!" /> </template> </gl-form-input-group> </div> @@ -262,14 +291,10 @@ export default { id="authorization-key" class="gl-mb-2" readonly - :value="selectedIntegrationType.authKey" + :value="integrationForm.token" > <template #append> - <clipboard-button - :text="selectedIntegrationType.authKey || ''" - :title="__('Copy')" - class="gl-m-0!" - /> + <clipboard-button :text="integrationForm.token" :title="__('Copy')" class="gl-m-0!" /> </template> </gl-form-input-group> @@ -281,9 +306,9 @@ export default { :title="$options.i18n.integrationFormSteps.step3.reset" :ok-title="$options.i18n.integrationFormSteps.step3.reset" ok-variant="danger" - @ok="() => {}" + @ok="onResetAuthKey" > - {{ $options.i18n.integrationFormSteps.step3.reset }} + {{ $options.i18n.integrationFormSteps.restKeyInfo.label }} </gl-modal> </div> </gl-form-group> diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_old.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_old.vue index 7d5ea9aa8c4..e4ba87c4e14 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_old.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_old.vue @@ -59,7 +59,7 @@ export default { selectedIntegration: integrationTypes[0].value, options: integrationTypes, active: false, - authKey: '', + token: '', targetUrl: '', feedback: { variant: 'danger', @@ -98,7 +98,7 @@ export default { case 'HTTP': { return { url: this.generic.url, - authKey: this.generic.authKey, + token: this.generic.token, active: this.generic.active, resetKey: this.resetKey.bind(this), }; @@ -106,7 +106,7 @@ export default { case 'PROMETHEUS': { return { url: this.prometheus.url, - authKey: this.prometheus.authKey, + token: this.prometheus.token, active: this.prometheus.active, resetKey: this.resetKey.bind(this, 'PROMETHEUS'), targetUrl: this.prometheus.prometheusApiUrl, @@ -167,7 +167,7 @@ export default { this.setOpsgenieAsDefault(); } this.active = this.selectedIntegrationType.active; - this.authKey = this.selectedIntegrationType.authKey ?? ''; + this.token = this.selectedIntegrationType.token ?? ''; }, methods: { createUserErrorMessage(errors = {}) { @@ -212,8 +212,8 @@ export default { return fn .then(({ data: { token } }) => { - this.authKey = token; - this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' }); + this.token = token; + this.setFeedback({ feedbackMessage: this.$options.i18n.tokenRest, variant: 'success' }); }) .catch(() => { this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); @@ -313,7 +313,7 @@ export default { .updateTestAlert({ endpoint: this.selectedIntegrationType.url, data: this.testAlert.json, - authKey: this.selectedIntegrationType.authKey, + token: this.selectedIntegrationType.token, }) .then(() => { this.setFeedback({ @@ -439,21 +439,21 @@ export default { {{ prometheusInfo }} </span> </gl-form-group> - <gl-form-group :label="$options.i18n.authKeyLabel" label-for="authorization-key"> - <gl-form-input-group id="authorization-key" class="gl-mb-2" readonly :value="authKey"> + <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="authKey" + :text="token" :title="$options.i18n.copyToClipboard" class="gl-m-0!" /> </template> </gl-form-input-group> - <gl-button v-gl-modal.authKeyModal :disabled="!active" class="gl-mt-3">{{ + <gl-button v-gl-modal.tokenModal :disabled="!active" class="gl-mt-3">{{ $options.i18n.resetKey }}</gl-button> <gl-modal - modal-id="authKeyModal" + modal-id="tokenModal" :title="$options.i18n.resetKey" :ok-title="$options.i18n.resetKey" ok-variant="danger" diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue index 7fe0a4ad2cb..0a59a5981ef 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue @@ -7,6 +7,10 @@ import createFlash, { FLASH_TYPES } from '~/flash'; import getIntegrationsQuery from '../graphql/queries/get_integrations.query.graphql'; import createHttpIntegrationMutation from '../graphql/mutations/create_http_integration.mutation.graphql'; import createPrometheusIntegrationMutation from '../graphql/mutations/create_prometheus_integration.mutation.graphql'; +import updateHttpIntegrationMutation from '../graphql/mutations/update_http_integration.mutation.graphql'; +import updatePrometheusIntegrationMutation from '../graphql/mutations/update_prometheus_integration.mutation.graphql'; +import resetHttpTokenMutation from '../graphql/mutations/reset_http_token.mutation.graphql'; +import resetPrometheusTokenMutation from '../graphql/mutations/reset_prometheus_token.mutation.graphql'; import IntegrationsList from './alerts_integrations_list.vue'; import SettingsFormOld from './alerts_settings_form_old.vue'; import SettingsFormNew from './alerts_settings_form_new.vue'; @@ -52,16 +56,16 @@ export default { list, }; }, - error() { - this.errored = true; + error(err) { + createFlash({ message: err }); }, }, }, data() { return { - errored: false, isUpdating: false, integrations: {}, + currentIntegration: null, }; }, computed: { @@ -84,7 +88,7 @@ export default { }, }, methods: { - onCreateNewIntegration({ type, variables }) { + createNewIntegration({ type, variables }) { this.isUpdating = true; this.$apollo .mutate({ @@ -109,7 +113,6 @@ export default { }); }) .catch(err => { - this.errored = true; createFlash({ message: err }); }) .finally(() => { @@ -151,6 +154,72 @@ export default { data, }); }, + updateIntegration({ type, variables }) { + this.isUpdating = true; + this.$apollo + .mutate({ + mutation: + type === this.$options.typeSet.http + ? updateHttpIntegrationMutation + : updatePrometheusIntegrationMutation, + variables: { + ...variables, + id: this.currentIntegration.id, + }, + }) + .then(({ data: { httpIntegrationUpdate, prometheusIntegrationUpdate } = {} } = {}) => { + const error = httpIntegrationUpdate?.errors[0] || prometheusIntegrationUpdate?.errors[0]; + if (error) { + return createFlash({ message: error }); + } + return createFlash({ + message: this.$options.i18n.changesSaved, + type: FLASH_TYPES.SUCCESS, + }); + }) + .catch(err => { + createFlash({ message: err }); + }) + .finally(() => { + this.isUpdating = false; + }); + }, + resetToken({ type, variables }) { + this.isUpdating = true; + this.$apollo + .mutate({ + mutation: + type === this.$options.typeSet.http + ? resetHttpTokenMutation + : resetPrometheusTokenMutation, + variables, + }) + .then( + ({ data: { httpIntegrationResetToken, prometheusIntegrationResetToken } = {} } = {}) => { + const error = + httpIntegrationResetToken?.errors[0] || prometheusIntegrationResetToken?.errors[0]; + if (error) { + return createFlash({ message: error }); + } + return createFlash({ + message: this.$options.i18n.changesSaved, + type: FLASH_TYPES.SUCCESS, + }); + }, + ) + .catch(err => { + createFlash({ message: err }); + }) + .finally(() => { + this.isUpdating = false; + }); + }, + editIntegration({ id }) { + this.currentIntegration = this.integrations.list.find(integration => integration.id === id); + }, + deleteIntegration() { + // TODO, handle delete via GraphQL + }, }, }; </script> @@ -160,11 +229,16 @@ export default { <integrations-list :integrations="glFeatures.httpIntegrationsList ? integrations.list : intergrationsOptionsOld" :loading="loading" + @edit-integration="editIntegration" + @delete-integration="deleteIntegration" /> <settings-form-new v-if="glFeatures.httpIntegrationsList" - :loading="loading" - @on-create-new-integration="onCreateNewIntegration" + :loading="isUpdating" + :current-integration="currentIntegration" + @create-new-integration="createNewIntegration" + @update-integration="updateIntegration" + @reset-token="resetToken" /> <settings-form-old v-else /> </div> diff --git a/app/assets/javascripts/alerts_settings/constants.js b/app/assets/javascripts/alerts_settings/constants.js index 7e0422c100d..4ab8d215572 100644 --- a/app/assets/javascripts/alerts_settings/constants.js +++ b/app/assets/javascripts/alerts_settings/constants.js @@ -57,6 +57,15 @@ export const typeSet = { prometheus: 'PROMETHEUS', }; +export const defaultFormState = { + name: '', + active: false, + token: '', + url: '', + apiUrl: '', + integrationTestPayload: { json: null, error: null }, +}; + export const JSON_VALIDATE_DELAY = 250; export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/'; diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql new file mode 100644 index 00000000000..178d1e13047 --- /dev/null +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql @@ -0,0 +1,10 @@ +#import "../fragments/integration_item.fragment.graphql" + +mutation resetHttpIntegrationToken($id: ID!) { + httpIntegrationResetToken(input: { id: $id }) { + errors + integration { + ...IntegrationItem + } + } +} diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_prometheus_token.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_prometheus_token.mutation.graphql new file mode 100644 index 00000000000..8f34521b9fd --- /dev/null +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_prometheus_token.mutation.graphql @@ -0,0 +1,10 @@ +#import "../fragments/integration_item.fragment.graphql" + +mutation resetPrometheusIntegrationToken($id: ID!) { + prometheusIntegrationResetToken(input: { id: $id }) { + errors + integration { + ...IntegrationItem + } + } +} diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql new file mode 100644 index 00000000000..bb5b334deeb --- /dev/null +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql @@ -0,0 +1,10 @@ +#import "../fragments/integration_item.fragment.graphql" + +mutation updateHttpIntegration($id: ID!, $name: String!, $active: Boolean!) { + httpIntegrationUpdate(input: { id: $id, name: $name, active: $active }) { + errors + integration { + ...IntegrationItem + } + } +} diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql new file mode 100644 index 00000000000..62761730bd2 --- /dev/null +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql @@ -0,0 +1,10 @@ +#import "../fragments/integration_item.fragment.graphql" + +mutation updatePrometheusIntegration($id: ID!, $apiUrl: String!, $active: Boolean!) { + prometheusIntegrationUpdate(input: { id: $id, apiUrl: $apiUrl, active: $active }) { + errors + integration { + ...IntegrationItem + } + } +} diff --git a/app/assets/javascripts/alerts_settings/index.js b/app/assets/javascripts/alerts_settings/index.js index 611148cd103..2ae0dd447a1 100644 --- a/app/assets/javascripts/alerts_settings/index.js +++ b/app/assets/javascripts/alerts_settings/index.js @@ -50,7 +50,7 @@ export default el => { prometheus: { active: parseBoolean(prometheusActivated), url: prometheusUrl, - authKey: prometheusAuthorizationKey, + token: prometheusAuthorizationKey, prometheusFormPath, prometheusResetKeyPath, prometheusApiUrl, @@ -60,7 +60,7 @@ export default el => { alertsUsageUrl, active: parseBoolean(activatedStr), formPath, - authKey: authorizationKey, + token: authorizationKey, url, }, opsgenie: { |