diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
commit | a7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch) | |
tree | 7452bd5c3545c2fa67a28aa013835fb4fa071baf /app/assets/javascripts/groups | |
parent | ee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff) |
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'app/assets/javascripts/groups')
11 files changed, 211 insertions, 96 deletions
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index a1ec5942d64..e3147065d5c 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -41,6 +41,7 @@ export default { }, data() { return { + isModalVisible: false, isLoading: true, isSearchEmpty: false, searchEmptyMessage: '', @@ -101,6 +102,12 @@ export default { eventHub.$off(`${this.action}updateGroups`, this.updateGroups); }, methods: { + hideModal() { + this.isModalVisible = false; + }, + showModal() { + this.isModalVisible = true; + }, fetchGroups({ parentId, page, filterGroupsBy, sortBy, archived, updatePagination }) { return this.service .getGroups(parentId, page, filterGroupsBy, sortBy, archived) @@ -185,6 +192,7 @@ export default { showLeaveGroupModal(group, parentGroup) { this.targetGroup = group; this.targetParentGroup = parentGroup; + this.showModal(); }, leaveGroup() { this.targetGroup.isBeingRemoved = true; @@ -256,10 +264,12 @@ export default { /> <gl-modal modal-id="leave-group-modal" + :visible="isModalVisible" :title="__('Are you sure?')" :action-primary="primaryProps" :action-cancel="cancelProps" @primary="leaveGroup" + @hide="hideModal" > {{ groupLeaveConfirmationMessage }} </gl-modal> diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 10c45abbfa2..707008ec493 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -34,8 +34,8 @@ export default { ), itemCaret, itemTypeIcon, - itemStats, itemActions, + itemStats, }, props: { parentGroup: { @@ -92,6 +92,9 @@ export default { complianceFramework() { return this.group.complianceFramework; }, + showActionsMenu() { + return this.isGroup && (this.group.canEdit || this.group.canRemove || this.group.canLeave); + }, }, methods: { onClickRowGroup(e) { @@ -197,17 +200,19 @@ export default { <div v-if="isGroupPendingRemoval"> <gl-badge variant="warning">{{ __('pending deletion') }}</gl-badge> </div> - <div class="metadata d-flex flex-grow-1 flex-shrink-0 flex-wrap justify-content-md-between"> + <div + class="metadata gl-display-flex gl-flex-grow-1 gl-flex-shrink-0 gl-flex-wrap justify-content-md-between" + > + <item-stats + :item="group" + class="group-stats gl-mt-2 gl-display-none gl-md-display-flex gl-align-items-center" + /> <item-actions - v-if="isGroup" + v-if="showActionsMenu" :group="group" :parent-group="parentGroup" :action="action" /> - <item-stats - :item="group" - class="group-stats gl-mt-2 d-none d-md-flex gl-align-items-center" - /> </div> </div> </div> diff --git a/app/assets/javascripts/groups/components/invite_members_banner.vue b/app/assets/javascripts/groups/components/invite_members_banner.vue index dfc1549fb4a..7afea815197 100644 --- a/app/assets/javascripts/groups/components/invite_members_banner.vue +++ b/app/assets/javascripts/groups/components/invite_members_banner.vue @@ -46,7 +46,6 @@ export default { }, openModal() { eventHub.$emit('openModal', { - inviteeType: 'members', source: this.$options.openModalSource, }); this.track(this.$options.buttonClickEvent); diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index df751a3f37e..fc7cfffc22c 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -1,15 +1,17 @@ <script> -import { GlTooltipDirective, GlButton, GlModalDirective } from '@gitlab/ui'; +import { GlTooltipDirective, GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { COMMON_STR } from '../constants'; import eventHub from '../event_hub'; +const { LEAVE_BTN_TITLE, EDIT_BTN_TITLE, REMOVE_BTN_TITLE, OPTIONS_DROPDOWN_TITLE } = COMMON_STR; + export default { components: { - GlButton, + GlDropdown, + GlDropdownItem, }, directives: { GlTooltip: GlTooltipDirective, - GlModal: GlModalDirective, }, props: { parentGroup: { @@ -28,11 +30,8 @@ export default { }, }, computed: { - leaveBtnTitle() { - return COMMON_STR.LEAVE_BTN_TITLE; - }, - editBtnTitle() { - return COMMON_STR.EDIT_BTN_TITLE; + removeButtonHref() { + return `${this.group.editPath}#js-remove-group-form`; }, }, methods: { @@ -40,33 +39,51 @@ export default { eventHub.$emit(`${this.action}showLeaveGroupModal`, this.group, this.parentGroup); }, }, + i18n: { + leaveBtnTitle: LEAVE_BTN_TITLE, + editBtnTitle: EDIT_BTN_TITLE, + removeBtnTitle: REMOVE_BTN_TITLE, + optionsDropdownTitle: OPTIONS_DROPDOWN_TITLE, + }, }; </script> <template> - <div class="controls d-flex justify-content-end"> - <gl-button - v-if="group.canLeave" - v-gl-tooltip.top - v-gl-modal.leave-group-modal - :title="leaveBtnTitle" - :aria-label="leaveBtnTitle" - data-testid="leave-group-btn" - size="small" - icon="leave" - class="leave-group gl-ml-3" - @click.stop="onLeaveGroup" - /> - <gl-button - v-if="group.canEdit" - v-gl-tooltip.top - :href="group.editPath" - :title="editBtnTitle" - :aria-label="editBtnTitle" - data-testid="edit-group-btn" - size="small" - icon="pencil" - class="edit-group gl-ml-3" - /> + <div class="gl-display-flex gl-justify-content-end gl-ml-5"> + <gl-dropdown + v-gl-tooltip.hover.focus="$options.i18n.optionsDropdownTitle" + right + category="tertiary" + icon="ellipsis_v" + no-caret + :data-testid="`group-${group.id}-dropdown-button`" + data-qa-selector="group_dropdown_button" + :data-qa-group-id="group.id" + > + <gl-dropdown-item + v-if="group.canEdit" + :data-testid="`edit-group-${group.id}-btn`" + :href="group.editPath" + @click.stop + > + {{ $options.i18n.editBtnTitle }} + </gl-dropdown-item> + <gl-dropdown-item + v-if="group.canLeave" + :data-testid="`leave-group-${group.id}-btn`" + @click.stop="onLeaveGroup" + > + {{ $options.i18n.leaveBtnTitle }} + </gl-dropdown-item> + <gl-dropdown-item + v-if="group.canRemove" + :href="removeButtonHref" + :data-testid="`remove-group-${group.id}-btn`" + variant="danger" + @click.stop + > + {{ $options.i18n.removeBtnTitle }} + </gl-dropdown-item> + </gl-dropdown> </div> </template> diff --git a/app/assets/javascripts/groups/components/transfer_group_form.vue b/app/assets/javascripts/groups/components/transfer_group_form.vue new file mode 100644 index 00000000000..e848f10352d --- /dev/null +++ b/app/assets/javascripts/groups/components/transfer_group_form.vue @@ -0,0 +1,80 @@ +<script> +import { GlFormGroup } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; +import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue'; +import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue'; + +export const i18n = { + confirmationMessage: __( + 'You are going to transfer %{group_name} to another namespace. Are you ABSOLUTELY sure?', + ), + emptyNamespaceTitle: __('No parent group'), + dropdownTitle: s__('GroupSettings|Select parent group'), +}; + +export default { + name: 'TransferGroupForm', + components: { + ConfirmDanger, + GlFormGroup, + NamespaceSelect, + }, + props: { + groupNamespaces: { + type: Array, + required: true, + }, + isPaidGroup: { + type: Boolean, + required: true, + }, + confirmationPhrase: { + type: String, + required: true, + }, + confirmButtonText: { + type: String, + required: true, + }, + }, + data() { + return { + selectedId: null, + }; + }, + computed: { + disableSubmitButton() { + return this.isPaidGroup || !this.selectedId; + }, + }, + methods: { + handleSelected({ id }) { + this.selectedId = id; + }, + }, + i18n, +}; +</script> +<template> + <div> + <gl-form-group v-if="!isPaidGroup"> + <namespace-select + :default-text="$options.i18n.dropdownTitle" + :group-namespaces="groupNamespaces" + :empty-namespace-title="$options.i18n.emptyNamespaceTitle" + :include-headers="false" + include-empty-namespace + data-testid="transfer-group-namespace-select" + @select="handleSelected" + /> + <input type="hidden" name="new_parent_group_id" :value="selectedId" /> + </gl-form-group> + <confirm-danger + button-class="qa-transfer-button" + :disabled="disableSubmitButton" + :phrase="confirmationPhrase" + :button-text="confirmButtonText" + @confirm="$emit('confirm')" + /> + </div> +</template> diff --git a/app/assets/javascripts/groups/constants.js b/app/assets/javascripts/groups/constants.js index e2722d780dc..005bac1e7b5 100644 --- a/app/assets/javascripts/groups/constants.js +++ b/app/assets/javascripts/groups/constants.js @@ -15,8 +15,10 @@ export const COMMON_STR = { LEAVE_FORBIDDEN: s__( 'GroupsTree|Failed to leave the group. Please make sure you are not the only owner.', ), - LEAVE_BTN_TITLE: s__('GroupsTree|Leave this group'), - EDIT_BTN_TITLE: s__('GroupsTree|Edit group'), + LEAVE_BTN_TITLE: s__('GroupsTree|Leave group'), + EDIT_BTN_TITLE: s__('GroupsTree|Edit'), + REMOVE_BTN_TITLE: s__('GroupsTree|Delete'), + OPTIONS_DROPDOWN_TITLE: s__('GroupsTree|Options'), GROUP_SEARCH_EMPTY: s__('GroupsTree|No groups matched your search'), GROUP_PROJECT_SEARCH_EMPTY: s__('GroupsTree|No groups or projects matched your search'), }; diff --git a/app/assets/javascripts/groups/init_transfer_group_form.js b/app/assets/javascripts/groups/init_transfer_group_form.js new file mode 100644 index 00000000000..f055b926918 --- /dev/null +++ b/app/assets/javascripts/groups/init_transfer_group_form.js @@ -0,0 +1,52 @@ +import Vue from 'vue'; +import { sprintf } from '~/locale'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import TransferGroupForm, { i18n } from './components/transfer_group_form.vue'; + +const prepareGroups = (rawGroups) => { + if (!rawGroups) { + return []; + } + + return JSON.parse(rawGroups).map(({ id, text: humanName }) => ({ + id, + humanName, + })); +}; + +export default () => { + const el = document.querySelector('.js-transfer-group-form'); + if (!el) { + return false; + } + + const { + targetFormId = null, + buttonText: confirmButtonText = '', + groupName = '', + parentGroups, + isPaidGroup, + } = el.dataset; + + return new Vue({ + el, + provide: { + confirmDangerMessage: sprintf(i18n.confirmationMessage, { group_name: groupName }), + }, + render(createElement) { + return createElement(TransferGroupForm, { + props: { + groupNamespaces: prepareGroups(parentGroups), + isPaidGroup: parseBoolean(isPaidGroup), + confirmButtonText, + confirmationPhrase: groupName, + }, + on: { + confirm: () => { + document.getElementById(targetFormId)?.submit(); + }, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/groups/landing.js b/app/assets/javascripts/groups/landing.js index bfb4d9ce67b..ed76bebf843 100644 --- a/app/assets/javascripts/groups/landing.js +++ b/app/assets/javascripts/groups/landing.js @@ -1,5 +1,4 @@ -import Cookies from 'js-cookie'; -import { parseBoolean } from '~/lib/utils/common_utils'; +import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils'; class Landing { constructor(landingElement, dismissButton, cookieName) { @@ -27,11 +26,11 @@ class Landing { dismissLanding() { this.landingElement.classList.add('hidden'); - Cookies.set(this.cookieName, 'true', { expires: 365 }); + setCookie(this.cookieName, 'true'); } isDismissed() { - return parseBoolean(Cookies.get(this.cookieName)); + return parseBoolean(getCookie(this.cookieName)); } } diff --git a/app/assets/javascripts/groups/store/groups_store.js b/app/assets/javascripts/groups/store/groups_store.js index d3600bd223a..0917b9ceccf 100644 --- a/app/assets/javascripts/groups/store/groups_store.js +++ b/app/assets/javascripts/groups/store/groups_store.js @@ -83,6 +83,7 @@ export default class GroupsStore { leavePath: rawGroupItem.leave_path, canEdit: rawGroupItem.can_edit, canLeave: rawGroupItem.can_leave, + canRemove: rawGroupItem.can_remove, type: rawGroupItem.type, permission: rawGroupItem.permission, children: groupChildren, diff --git a/app/assets/javascripts/groups/transfer_dropdown.js b/app/assets/javascripts/groups/transfer_dropdown.js deleted file mode 100644 index d6343f698c0..00000000000 --- a/app/assets/javascripts/groups/transfer_dropdown.js +++ /dev/null @@ -1,39 +0,0 @@ -import $ from 'jquery'; -import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown'; -import { __ } from '~/locale'; - -export default class TransferDropdown { - constructor() { - this.groupDropdown = $('.js-groups-dropdown'); - this.parentInput = $('#new_parent_group_id'); - this.data = this.groupDropdown.data('data'); - this.init(); - } - - init() { - this.buildDropdown(); - } - - buildDropdown() { - const extraOptions = [{ id: '-1', text: __('No parent group') }, { type: 'divider' }]; - - initDeprecatedJQueryDropdown(this.groupDropdown, { - selectable: true, - filterable: true, - toggleLabel: (item) => item.text, - search: { fields: ['text'] }, - data: extraOptions.concat(this.data), - text: (item) => item.text, - clicked: (options) => { - const { e } = options; - e.preventDefault(); - this.assignSelected(options.selectedObj); - }, - }); - } - - assignSelected(selected) { - this.parentInput.val(selected.id); - this.parentInput.change(); - } -} diff --git a/app/assets/javascripts/groups/transfer_edit.js b/app/assets/javascripts/groups/transfer_edit.js deleted file mode 100644 index bb15e11fd4c..00000000000 --- a/app/assets/javascripts/groups/transfer_edit.js +++ /dev/null @@ -1,11 +0,0 @@ -import $ from 'jquery'; - -export default function setupTransferEdit(formSelector, targetSelector) { - const $transferForm = $(formSelector); - const $selectNamespace = $transferForm.find(targetSelector); - - $selectNamespace.on('change', () => { - $transferForm.find(':submit').prop('disabled', !$selectNamespace.val()); - }); - $selectNamespace.trigger('change'); -} |