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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-08 15:09:27 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-08 15:09:27 +0300
commit81f062b841f6062601662061850934a51e77ceea (patch)
tree0851038895c34776af8603f13b546b50df511e36 /app/assets/javascripts/webhooks
parente40061efd4c68576da944254567d0b3fbc233ae4 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/webhooks')
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_app.vue70
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_mask_item.vue26
2 files changed, 93 insertions, 3 deletions
diff --git a/app/assets/javascripts/webhooks/components/form_url_app.vue b/app/assets/javascripts/webhooks/components/form_url_app.vue
index 45526ff9080..a156b638e21 100644
--- a/app/assets/javascripts/webhooks/components/form_url_app.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_app.vue
@@ -2,6 +2,7 @@
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';
@@ -31,9 +32,14 @@ export default {
maskEnabled: !isEmpty(this.initialUrlVariables),
url: this.initialUrl,
items: this.getInitialItems(),
+ isValidated: false,
+ formEl: null,
};
},
computed: {
+ urlState() {
+ return !this.isValidated || !isEmpty(this.url);
+ },
maskedUrl() {
if (!this.url) {
return null;
@@ -46,13 +52,20 @@ 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);
@@ -64,6 +77,52 @@ export default {
return this.initialUrlVariables.some((item) => item.key === key);
},
+ keyInvalidFeedback(key) {
+ if (this.isValidated && isEmpty(key)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ return null;
+ },
+ valueInvalidFeedback(key, value) {
+ if (this.isEditingItem(key)) {
+ return null;
+ }
+
+ if (this.isValidated && isEmpty(value)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ return null;
+ },
+ isValid() {
+ this.isValidated = true;
+
+ if (!this.urlState) {
+ return false;
+ }
+
+ if (
+ this.maskEnabled &&
+ this.items.some(
+ ({ key, value }) => this.keyInvalidFeedback(key) || this.valueInvalidFeedback(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 });
},
@@ -76,6 +135,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.'),
@@ -92,14 +152,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"
/>
@@ -123,6 +187,8 @@ export default {
:item-key="key"
:item-value="value"
:is-editing="isEditingItem(key)"
+ :key-invalid-feedback="keyInvalidFeedback(key)"
+ :value-invalid-feedback="valueInvalidFeedback(key, value)"
@input="onItemInput"
@remove="removeItem"
/>
diff --git a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
index aa5d9ce57f4..f5f81759719 100644
--- a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
@@ -1,4 +1,5 @@
<script>
+import { isEmpty } from 'lodash';
import { GlButton, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { s__ } from '~/locale';
import { MASK_ITEM_VALUE_HIDDEN } from '../constants';
@@ -30,6 +31,16 @@ export default {
required: false,
default: false,
},
+ keyInvalidFeedback: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ valueInvalidFeedback: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
computed: {
keyInputId() {
@@ -38,6 +49,12 @@ export default {
valueInputId() {
return this.inputId('value');
},
+ keyState() {
+ return isEmpty(this.keyInvalidFeedback);
+ },
+ valueState() {
+ return isEmpty(this.valueInvalidFeedback);
+ },
displayValue() {
return this.isEditing ? MASK_ITEM_VALUE_HIDDEN : this.itemValue;
},
@@ -67,10 +84,12 @@ export default {
</script>
<template>
- <div class="gl-display-flex gl-align-items-flex-end gl-gap-3 gl-mb-3">
+ <div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-mb-3">
<gl-form-group
:label="$options.i18n.valueLabel"
:label-for="valueInputId"
+ :invalid-feedback="valueInvalidFeedback"
+ :state="valueState"
class="gl-flex-grow-1 gl-mb-0"
data-testid="mask-item-value"
>
@@ -79,12 +98,15 @@ export default {
:name="inputName('value')"
:value="displayValue"
:disabled="isEditing"
+ :state="valueState"
@input="onValueInput"
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.keyLabel"
:label-for="keyInputId"
+ :invalid-feedback="keyInvalidFeedback"
+ :state="keyState"
class="gl-flex-grow-1 gl-mb-0"
data-testid="mask-item-key"
>
@@ -93,6 +115,7 @@ export default {
:name="inputName('key')"
:value="itemKey"
:disabled="isEditing"
+ :state="keyState"
@input="onKeyInput"
/>
</gl-form-group>
@@ -100,6 +123,7 @@ export default {
icon="remove"
:aria-label="__('Remove')"
:disabled="isEditing"
+ class="gl-mt-6"
@click="onRemoveClick"
/>
</div>