Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/webhooks/components/form_url_app.vue')
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_app.vue92
1 files changed, 88 insertions, 4 deletions
diff --git a/app/assets/javascripts/webhooks/components/form_url_app.vue b/app/assets/javascripts/webhooks/components/form_url_app.vue
index 5ec16d4ba15..4fafeff8804 100644
--- a/app/assets/javascripts/webhooks/components/form_url_app.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_app.vue
@@ -1,7 +1,8 @@
<script>
-import { isEmpty } from 'lodash';
+import { cloneDeep, isEmpty } from 'lodash';
import { GlFormGroup, GlFormInput, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { __, s__ } from '~/locale';
+import { scrollToElement } from '~/lib/utils/common_utils';
import FormUrlMaskItem from './form_url_mask_item.vue';
@@ -30,10 +31,15 @@ export default {
return {
maskEnabled: !isEmpty(this.initialUrlVariables),
url: this.initialUrl,
- items: isEmpty(this.initialUrlVariables) ? [{}] : this.initialUrlVariables,
+ items: this.getInitialItems(),
+ isValidated: false,
+ formEl: null,
};
},
computed: {
+ urlState() {
+ return !this.isValidated || !isEmpty(this.url);
+ },
maskedUrl() {
if (!this.url) {
return null;
@@ -46,14 +52,83 @@ export default {
return;
}
- const replacementExpression = new RegExp(value, 'g');
- maskedUrl = maskedUrl.replace(replacementExpression, `{${key}}`);
+ maskedUrl = this.maskUrl(maskedUrl, key, value);
});
return maskedUrl;
},
},
+ mounted() {
+ this.formEl = document.querySelector('.js-webhook-form');
+
+ this.formEl?.addEventListener('submit', this.handleSubmit);
+ },
+ destroy() {
+ this.formEl?.removeEventListener('submit', this.handleSubmit);
+ },
methods: {
+ getInitialItems() {
+ return isEmpty(this.initialUrlVariables) ? [{}] : cloneDeep(this.initialUrlVariables);
+ },
+ isEditingItem(index, key) {
+ if (isEmpty(this.initialUrlVariables)) {
+ return false;
+ }
+
+ const item = this.initialUrlVariables[index];
+ return item && item.key === key;
+ },
+ keyInvalidFeedback(key) {
+ if (this.isValidated && isEmpty(key)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ return null;
+ },
+ valueInvalidFeedback(index, key, value) {
+ if (this.isEditingItem(index, key)) {
+ return null;
+ }
+
+ if (this.isValidated && isEmpty(value)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ if (!isEmpty(value) && !this.url?.includes(value)) {
+ return this.$options.i18n.valuePartOfUrl;
+ }
+
+ return null;
+ },
+ isValid() {
+ this.isValidated = true;
+
+ if (!this.urlState) {
+ return false;
+ }
+
+ if (
+ this.maskEnabled &&
+ this.items.some(
+ ({ key, value }, index) =>
+ this.keyInvalidFeedback(key) || this.valueInvalidFeedback(index, key, value),
+ )
+ ) {
+ return false;
+ }
+
+ return true;
+ },
+ handleSubmit(e) {
+ if (!this.isValid()) {
+ scrollToElement(this.$refs.formUrl.$el);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ },
+ maskUrl(url, key, value) {
+ return url.split(value).join(`{${key}}`);
+ },
onItemInput({ index, key, value }) {
this.$set(this.items, index, { key, value });
},
@@ -66,6 +141,7 @@ export default {
},
i18n: {
addItem: s__('Webhooks|+ Mask another portion of URL'),
+ inputRequired: __('This field is required.'),
radioFullUrlText: s__('Webhooks|Show full URL'),
radioMaskUrlText: s__('Webhooks|Mask portions of URL'),
radioMaskUrlHelp: s__('Webhooks|Do not show sensitive data such as tokens in the UI.'),
@@ -75,6 +151,7 @@ export default {
urlLabel: __('URL'),
urlPlaceholder: 'http://example.com/trigger-ci.json',
urlPreview: s__('Webhooks|URL preview'),
+ valuePartOfUrl: s__('Webhooks|Must match part of URL'),
},
};
</script>
@@ -82,14 +159,18 @@ export default {
<template>
<div>
<gl-form-group
+ ref="formUrl"
:label="$options.i18n.urlLabel"
label-for="webhook-url"
:description="$options.i18n.urlDescription"
+ :invalid-feedback="$options.i18n.inputRequired"
+ :state="urlState"
>
<gl-form-input
id="webhook-url"
v-model="url"
name="hook[url]"
+ :state="urlState"
:placeholder="$options.i18n.urlPlaceholder"
data-testid="form-url"
/>
@@ -112,6 +193,9 @@ export default {
:index="index"
:item-key="key"
:item-value="value"
+ :is-editing="isEditingItem(index, key)"
+ :key-invalid-feedback="keyInvalidFeedback(key)"
+ :value-invalid-feedback="valueInvalidFeedback(index, key, value)"
@input="onItemInput"
@remove="removeItem"
/>