summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pages/groups/new/group_path_validator.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/pages/groups/new/group_path_validator.js')
-rw-r--r--app/assets/javascripts/pages/groups/new/group_path_validator.js91
1 files changed, 91 insertions, 0 deletions
diff --git a/app/assets/javascripts/pages/groups/new/group_path_validator.js b/app/assets/javascripts/pages/groups/new/group_path_validator.js
new file mode 100644
index 00000000000..2021ad117e8
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/new/group_path_validator.js
@@ -0,0 +1,91 @@
+import InputValidator from '~/validators/input_validator';
+
+import _ from 'underscore';
+import fetchGroupPathAvailability from './fetch_group_path_availability';
+import flash from '~/flash';
+import { __ } from '~/locale';
+
+const debounceTimeoutDuration = 1000;
+const invalidInputClass = 'gl-field-error-outline';
+const successInputClass = 'gl-field-success-outline';
+const successMessageSelector = '.validation-success';
+const pendingMessageSelector = '.validation-pending';
+const unavailableMessageSelector = '.validation-error';
+const suggestionsMessageSelector = '.gl-path-suggestions';
+
+export default class GroupPathValidator extends InputValidator {
+ constructor(opts = {}) {
+ super();
+
+ const container = opts.container || '';
+ const validateElements = document.querySelectorAll(`${container} .js-validate-group-path`);
+
+ this.debounceValidateInput = _.debounce(inputDomElement => {
+ GroupPathValidator.validateGroupPathInput(inputDomElement);
+ }, debounceTimeoutDuration);
+
+ validateElements.forEach(element =>
+ element.addEventListener('input', this.eventHandler.bind(this)),
+ );
+ }
+
+ eventHandler(event) {
+ const inputDomElement = event.target;
+
+ GroupPathValidator.resetInputState(inputDomElement);
+ this.debounceValidateInput(inputDomElement);
+ }
+
+ static validateGroupPathInput(inputDomElement) {
+ const groupPath = inputDomElement.value;
+
+ if (inputDomElement.checkValidity() && groupPath.length > 0) {
+ GroupPathValidator.setMessageVisibility(inputDomElement, pendingMessageSelector);
+
+ fetchGroupPathAvailability(groupPath)
+ .then(({ data }) => data)
+ .then(data => {
+ GroupPathValidator.setInputState(inputDomElement, !data.exists);
+ GroupPathValidator.setMessageVisibility(inputDomElement, pendingMessageSelector, false);
+ GroupPathValidator.setMessageVisibility(
+ inputDomElement,
+ data.exists ? unavailableMessageSelector : successMessageSelector,
+ );
+
+ if (data.exists) {
+ GroupPathValidator.showSuggestions(inputDomElement, data.suggests);
+ }
+ })
+ .catch(() => flash(__('An error occurred while validating group path')));
+ }
+ }
+
+ static showSuggestions(inputDomElement, suggestions) {
+ const messageElement = inputDomElement.parentElement.parentElement.querySelector(
+ suggestionsMessageSelector,
+ );
+ const textSuggestions = suggestions && suggestions.length > 0 ? suggestions.join(', ') : 'none';
+ messageElement.textContent = textSuggestions;
+ }
+
+ static setMessageVisibility(inputDomElement, messageSelector, isVisible = true) {
+ const messageElement = inputDomElement.parentElement.parentElement.querySelector(
+ messageSelector,
+ );
+ messageElement.classList.toggle('hide', !isVisible);
+ }
+
+ static setInputState(inputDomElement, success = true) {
+ inputDomElement.classList.toggle(successInputClass, success);
+ inputDomElement.classList.toggle(invalidInputClass, !success);
+ }
+
+ static resetInputState(inputDomElement) {
+ GroupPathValidator.setMessageVisibility(inputDomElement, successMessageSelector, false);
+ GroupPathValidator.setMessageVisibility(inputDomElement, unavailableMessageSelector, false);
+
+ if (inputDomElement.checkValidity()) {
+ inputDomElement.classList.remove(successInputClass, invalidInputClass);
+ }
+ }
+}