diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-21 18:09:39 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-21 18:09:39 +0300 |
commit | b4cbe6431bf281f10d24835876e14e924d6366e8 (patch) | |
tree | ae13592cb8d57049e74c81307a0848ef7d7265a1 /app/assets/javascripts/protected_tags | |
parent | 1f2f131577d9504cc9ce96f67873de0bec6854f6 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/protected_tags')
5 files changed, 176 insertions, 173 deletions
diff --git a/app/assets/javascripts/protected_tags/constants.js b/app/assets/javascripts/protected_tags/constants.js index 758b820c4c4..d332ba1635f 100644 --- a/app/assets/javascripts/protected_tags/constants.js +++ b/app/assets/javascripts/protected_tags/constants.js @@ -1,7 +1,3 @@ -import { s__ } from '~/locale'; - -export const FAILED_TO_UPDATE_TAG_MESSAGE = s__('ProjectSettings|Failed to update tag!'); - export const ACCESS_LEVELS = { CREATE: 'create_access_levels', }; diff --git a/app/assets/javascripts/protected_tags/protected_tag_create.js b/app/assets/javascripts/protected_tags/protected_tag_create.js index 365b9a3b142..b5661af352c 100644 --- a/app/assets/javascripts/protected_tags/protected_tag_create.js +++ b/app/assets/javascripts/protected_tags/protected_tag_create.js @@ -3,8 +3,8 @@ import CreateItemDropdown from '~/create_item_dropdown'; import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { s__, __ } from '~/locale'; -import AccessDropdown from '~/projects/settings/access_dropdown'; -import { ACCESS_LEVELS, LEVEL_TYPES } from './constants'; +import { initAccessDropdown } from '~/projects/settings/init_access_dropdown'; +import { ACCESS_LEVELS } from './constants'; export default class ProtectedTagCreate { constructor({ hasLicense }) { @@ -12,6 +12,7 @@ export default class ProtectedTagCreate { this.$form = $('.js-new-protected-tag'); this.buildDropdowns(); this.bindEvents(); + this.selectedItems = []; } bindEvents() { @@ -19,20 +20,9 @@ export default class ProtectedTagCreate { } buildDropdowns() { - const $allowedToCreateDropdown = this.$form.find('.js-allowed-to-create'); - // Cache callback this.onSelectCallback = this.onSelect.bind(this); - // Allowed to Create dropdown - this.protectedTagAccessDropdown = new AccessDropdown({ - $dropdown: $allowedToCreateDropdown, - accessLevelsData: gon.create_access_levels, - onSelect: this.onSelectCallback, - accessLevel: ACCESS_LEVELS.CREATE, - hasLicense: this.hasLicense, - }); - // Protected tag dropdown this.createItemDropdown = new CreateItemDropdown({ $dropdown: this.$form.find('.js-protected-tag-select'), @@ -41,17 +31,36 @@ export default class ProtectedTagCreate { onSelect: this.onSelectCallback, getData: ProtectedTagCreate.getProtectedTags, }); + + // Allowed to Create dropdown + const createTagSelector = 'js-allowed-to-create'; + const [dropdownEl] = this.$form.find(`.${createTagSelector}`); + this.protectedTagAccessDropdown = initAccessDropdown(dropdownEl, { + toggleClass: createTagSelector, + hasLicense: this.hasLicense, + accessLevel: ACCESS_LEVELS.CREATE, + accessLevelsData: gon.create_access_levels, + searchEnabled: dropdownEl.dataset.filter !== undefined, + testId: 'allowed_to_create_dropdown', + }); + + this.protectedTagAccessDropdown.$on('select', (selected) => { + this.selectedItems = selected; + this.onSelectCallback(); + }); + + this.protectedTagAccessDropdown.$on('shown', () => { + this.createItemDropdown.close(); + }); } // This will run after clicked callback onSelect() { // Enable submit button const $tagInput = this.$form.find('input[name="protected_tag[name]"]'); - const $allowedToCreateInput = this.protectedTagAccessDropdown.getSelectedItems(); - this.$form .find('button[type="submit"]') - .prop('disabled', !($tagInput.val() && $allowedToCreateInput.length)); + .prop('disabled', !($tagInput.val() && this.selectedItems.length)); } static getProtectedTags(term, callback) { @@ -65,35 +74,7 @@ export default class ProtectedTagCreate { name: this.$form.find('input[name="protected_tag[name]"]').val(), }, }; - - Object.keys(ACCESS_LEVELS).forEach((level) => { - const accessLevel = ACCESS_LEVELS[level]; - const selectedItems = this.protectedTagAccessDropdown.getSelectedItems(); - const levelAttributes = []; - - selectedItems.forEach((item) => { - if (item.type === LEVEL_TYPES.USER) { - levelAttributes.push({ - user_id: item.user_id, - }); - } else if (item.type === LEVEL_TYPES.ROLE) { - levelAttributes.push({ - access_level: item.access_level, - }); - } else if (item.type === LEVEL_TYPES.GROUP) { - levelAttributes.push({ - group_id: item.group_id, - }); - } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) { - levelAttributes.push({ - deploy_key_id: item.deploy_key_id, - }); - } - }); - - formData.protected_tag[`${accessLevel}_attributes`] = levelAttributes; - }); - + formData.protected_tag[`${ACCESS_LEVELS.CREATE}_attributes`] = this.selectedItems; return formData; } diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js deleted file mode 100644 index 4fa3ac3be4b..00000000000 --- a/app/assets/javascripts/protected_tags/protected_tag_edit.js +++ /dev/null @@ -1,115 +0,0 @@ -import { find } from 'lodash'; -import { createAlert } from '~/alert'; -import axios from '~/lib/utils/axios_utils'; -import AccessDropdown from '~/projects/settings/access_dropdown'; -import { ACCESS_LEVELS, LEVEL_TYPES, FAILED_TO_UPDATE_TAG_MESSAGE } from './constants'; - -export default class ProtectedTagEdit { - constructor(options) { - this.hasLicense = options.hasLicense; - this.hasChanges = false; - this.$wrap = options.$wrap; - this.$allowedToCreateDropdownButton = this.$wrap.find('.js-allowed-to-create'); - - this.$allowedToCreateDropdownContainer = this.$allowedToCreateDropdownButton.closest( - '.create_access_levels-container', - ); - - this.buildDropdowns(); - } - - buildDropdowns() { - // Allowed to create dropdown - this.protectedTagAccessDropdown = new AccessDropdown({ - accessLevel: ACCESS_LEVELS.CREATE, - accessLevelsData: gon.create_access_levels, - $dropdown: this.$allowedToCreateDropdownButton, - onSelect: this.onSelectOption.bind(this), - onHide: this.onDropdownHide.bind(this), - hasLicense: this.hasLicense, - }); - } - - onSelectOption() { - this.hasChanges = true; - } - - onDropdownHide() { - if (!this.hasChanges) { - return; - } - - this.hasChanges = true; - this.updatePermissions(); - } - - updatePermissions() { - const formData = Object.keys(ACCESS_LEVELS).reduce((acc, level) => { - const accessLevelName = ACCESS_LEVELS[level]; - const inputData = this.protectedTagAccessDropdown.getInputData(accessLevelName); - acc[`${accessLevelName}_attributes`] = inputData; - - return acc; - }, {}); - - axios - .patch(this.$wrap.data('url'), { - protected_tag: formData, - }) - .then(({ data }) => { - this.hasChanges = false; - - Object.keys(ACCESS_LEVELS).forEach((level) => { - const accessLevelName = ACCESS_LEVELS[level]; - - // The data coming from server will be the new persisted *state* for each dropdown - this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`); - }); - }) - .catch(() => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - createAlert({ - message: FAILED_TO_UPDATE_TAG_MESSAGE, - }); - }); - } - - setSelectedItemsToDropdown(items = []) { - const itemsToAdd = items.map((currentItem) => { - if (currentItem.user_id) { - // Do this only for users for now - // get the current data for selected items - const selectedItems = this.protectedTagAccessDropdown.getSelectedItems(); - const currentSelectedItem = find(selectedItems, { - user_id: currentItem.user_id, - }); - - return { - id: currentItem.id, - user_id: currentItem.user_id, - type: LEVEL_TYPES.USER, - persisted: true, - name: currentSelectedItem.name, - username: currentSelectedItem.username, - avatar_url: currentSelectedItem.avatar_url, - }; - } else if (currentItem.group_id) { - return { - id: currentItem.id, - group_id: currentItem.group_id, - type: LEVEL_TYPES.GROUP, - persisted: true, - }; - } - - return { - id: currentItem.id, - access_level: currentItem.access_level, - type: LEVEL_TYPES.ROLE, - persisted: true, - }; - }); - - this.protectedTagAccessDropdown.setSelectedItems(itemsToAdd); - } -} diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.vue b/app/assets/javascripts/protected_tags/protected_tag_edit.vue new file mode 100644 index 00000000000..82b2ecc5f5c --- /dev/null +++ b/app/assets/javascripts/protected_tags/protected_tag_edit.vue @@ -0,0 +1,113 @@ +<script> +import AccessDropdown from '~/projects/settings/components/access_dropdown.vue'; +import { createAlert } from '~/alert'; +import axios from '~/lib/utils/axios_utils'; +import { s__ } from '~/locale'; +import { ACCESS_LEVELS, LEVEL_TYPES } from './constants'; + +export const i18n = { + failureMessage: s__('ProjectSettings|Failed to update tag!'), +}; + +export default { + i18n, + ACCESS_LEVELS, + name: 'ProtectedTagEdit', + components: { + AccessDropdown, + }, + props: { + url: { + type: String, + required: true, + }, + accessLevelsData: { + type: Array, + required: true, + }, + hasLicense: { + required: false, + type: Boolean, + default: true, + }, + preselectedItems: { + type: Array, + required: false, + default: () => [], + }, + searchEnabled: { + type: Boolean, + required: false, + default: true, + }, + }, + data() { + return { + selected: this.preselectedItems, + }; + }, + methods: { + hasChanges(permissions) { + return permissions.some(({ id, _destroy }) => id === undefined || _destroy); + }, + updatePermissions(permissions) { + if (!this.hasChanges(permissions)) return; + axios + .patch(this.url, { + protected_tag: { + [`${ACCESS_LEVELS.CREATE}_attributes`]: permissions, + }, + }) + .then(this.setSelected) + .catch(() => { + createAlert({ + message: i18n.failureMessage, + parent: this.parentContainer, + }); + }); + }, + setSelected({ data }) { + if (!data) return; + this.selected = data[ACCESS_LEVELS.CREATE].map( + ({ id, user_id: userId, group_id: groupId, access_level: accessLevel }) => { + if (userId) { + return { + id, + user_id: userId, + type: LEVEL_TYPES.USER, + }; + } + + if (groupId) { + return { + id, + group_id: groupId, + type: LEVEL_TYPES.GROUP, + }; + } + + return { + id, + access_level: accessLevel, + type: LEVEL_TYPES.ROLE, + }; + }, + ); + }, + }, +}; +</script> + +<template> + <access-dropdown + toggle-class="js-allowed-to-create gl-max-w-34" + test-id="allowed_to_create_dropdown" + :has-license="hasLicense" + :access-level="$options.ACCESS_LEVELS.CREATE" + :access-levels-data="accessLevelsData" + :preselected-items="selected" + :search-enabled="searchEnabled" + :block="true" + @hidden="updatePermissions" + /> +</template> diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js index 8ceb970bf03..444d6e9cf76 100644 --- a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js +++ b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js @@ -1,21 +1,49 @@ -/* eslint-disable no-new */ - -import $ from 'jquery'; -import ProtectedTagEdit from './protected_tag_edit'; +import Vue from 'vue'; +import * as Sentry from '@sentry/browser'; +import ProtectedTagEdit from './protected_tag_edit.vue'; export default class ProtectedTagEditList { constructor(options) { this.hasLicense = options.hasLicense; - this.$wrap = $('.protected-tags-list'); this.initEditForm(); } initEditForm() { - this.$wrap.find('.js-protected-tag-edit-form').each((i, el) => { - new ProtectedTagEdit({ - $wrap: $(el), - hasLicense: this.hasLicense, + document + .querySelector('.protected-tags-list') + .querySelectorAll('.js-protected-tag-edit-form') + ?.forEach((el) => { + const accessDropdownEl = el.querySelector('.js-allowed-to-create'); + this.initAccessDropdown(accessDropdownEl, { + url: el.dataset.url, + hasLicense: this.hasLicense, + accessLevelsData: gon.create_access_levels.roles, + }); }); + } + + // eslint-disable-next-line class-methods-use-this + initAccessDropdown(el, options) { + if (!el) return null; + + let preselected = []; + try { + preselected = JSON.parse(el.dataset.preselectedItems); + } catch (e) { + Sentry.captureException(e); + } + + return new Vue({ + el, + render(createElement) { + return createElement(ProtectedTagEdit, { + props: { + preselectedItems: preselected, + searchEnabled: el.dataset.filter !== undefined, + ...options, + }, + }); + }, }); } } |