diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-06 00:06:13 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-06 00:06:13 +0000 |
commit | b66baea97dfb652e8a143e409ab44bbd38c856f1 (patch) | |
tree | 28d3033719035cfe3dcd8b4e40ad193674185cc1 /app/assets/javascripts/pages/groups | |
parent | 82cef8dd1f48ffbc7aaa1ff7374cdb859137e01e (diff) | |
download | gitlab-ce-b66baea97dfb652e8a143e409ab44bbd38c856f1.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/pages/groups')
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(); |