summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pages/groups
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-06 00:06:13 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-06 00:06:13 +0000
commitb66baea97dfb652e8a143e409ab44bbd38c856f1 (patch)
tree28d3033719035cfe3dcd8b4e40ad193674185cc1 /app/assets/javascripts/pages/groups
parent82cef8dd1f48ffbc7aaa1ff7374cdb859137e01e (diff)
downloadgitlab-ce-b66baea97dfb652e8a143e409ab44bbd38c856f1.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/pages/groups')
-rw-r--r--app/assets/javascripts/pages/groups/new/fetch_group_path_availability.js7
-rw-r--r--app/assets/javascripts/pages/groups/new/group_path_validator.js91
-rw-r--r--app/assets/javascripts/pages/groups/new/index.js6
3 files changed, 104 insertions, 0 deletions
diff --git a/app/assets/javascripts/pages/groups/new/fetch_group_path_availability.js b/app/assets/javascripts/pages/groups/new/fetch_group_path_availability.js
new file mode 100644
index 00000000000..1d68ccd724d
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/new/fetch_group_path_availability.js
@@ -0,0 +1,7 @@
+import axios from '~/lib/utils/axios_utils';
+
+const rootUrl = gon.relative_url_root;
+
+export default function fetchGroupPathAvailability(groupPath) {
+ return axios.get(`${rootUrl}/users/${groupPath}/suggests`);
+}
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);
+ }
+ }
+}
diff --git a/app/assets/javascripts/pages/groups/new/index.js b/app/assets/javascripts/pages/groups/new/index.js
index 57b53eb9e5d..0710fefe70c 100644
--- a/app/assets/javascripts/pages/groups/new/index.js
+++ b/app/assets/javascripts/pages/groups/new/index.js
@@ -1,8 +1,14 @@
+import $ from 'jquery';
import BindInOut from '~/behaviors/bind_in_out';
import Group from '~/group';
import initAvatarPicker from '~/avatar_picker';
+import GroupPathValidator from './group_path_validator';
document.addEventListener('DOMContentLoaded', () => {
+ const parentId = $('#group_parent_id');
+ if (!parentId.val()) {
+ new GroupPathValidator(); // eslint-disable-line no-new
+ }
BindInOut.initAll();
new Group(); // eslint-disable-line no-new
initAvatarPicker();