Commit 86a50499 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'ek-replace-transfer-edit-jquery-with-js' into 'master'

Replace transfer group jquery with GL components

See merge request gitlab-org/gitlab!77206
parents 4ea7ecf5 9551fabd
<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: {
parentGroups: {
type: Object,
required: true,
},
isPaidGroup: {
type: Boolean,
required: true,
},
confirmationPhrase: {
type: String,
required: true,
},
confirmButtonText: {
type: String,
required: true,
},
},
data() {
return {
selectedId: null,
};
},
computed: {
selectedNamespaceId() {
return this.selectedId;
},
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"
:data="parentGroups"
:empty-namespace-title="$options.i18n.emptyNamespaceTitle"
:include-headers="false"
include-empty-namespace
@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>
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) => {
const group = JSON.parse(rawGroups).map(({ id, text: humanName }) => ({
id,
humanName,
}));
return { group };
};
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, { groupName }),
},
render(createElement) {
return createElement(TransferGroupForm, {
props: {
parentGroups: prepareGroups(parentGroups),
isPaidGroup: parseBoolean(isPaidGroup),
confirmButtonText,
confirmationPhrase: groupName,
},
on: {
confirm: () => {
document.getElementById(targetFormId)?.submit();
},
},
});
},
});
};
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();
}
}
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');
}
import { GROUP_BADGE } from '~/badges/constants'; import { GROUP_BADGE } from '~/badges/constants';
import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory'; import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory';
import initFilePickers from '~/file_pickers'; import initFilePickers from '~/file_pickers';
import TransferDropdown from '~/groups/transfer_dropdown'; import initTransferGroupForm from '~/groups/init_transfer_group_form';
import setupTransferEdit from '~/groups/transfer_edit';
import groupsSelect from '~/groups_select'; import groupsSelect from '~/groups_select';
import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings'; import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings'; import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
...@@ -15,11 +14,11 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -15,11 +14,11 @@ document.addEventListener('DOMContentLoaded', () => {
initFilePickers(); initFilePickers();
initConfirmDanger(); initConfirmDanger();
initSettingsPanels(); initSettingsPanels();
initTransferGroupForm();
dirtySubmitFactory( dirtySubmitFactory(
document.querySelectorAll('.js-general-settings-form, .js-general-permissions-form'), document.querySelectorAll('.js-general-settings-form, .js-general-permissions-form'),
); );
mountBadgeSettings(GROUP_BADGE); mountBadgeSettings(GROUP_BADGE);
setupTransferEdit('.js-group-transfer-form', '#new_parent_group_id');
// Initialize Subgroups selector // Initialize Subgroups selector
groupsSelect(); groupsSelect();
...@@ -28,6 +27,4 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -28,6 +27,4 @@ document.addEventListener('DOMContentLoaded', () => {
initSearchSettings(); initSearchSettings();
initCascadingSettingsLockPopovers(); initCascadingSettingsLockPopovers();
return new TransferDropdown();
}); });
...@@ -44,7 +44,6 @@ export default { ...@@ -44,7 +44,6 @@ export default {
<div> <div>
<gl-form-group> <gl-form-group>
<namespace-select <namespace-select
class="qa-namespaces-list"
data-testid="transfer-project-namespace" data-testid="transfer-project-namespace"
:full-width="true" :full-width="true"
:data="namespaces" :data="namespaces"
......
<script> <script>
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, GlSearchBoxByType } from '@gitlab/ui'; import {
GlDropdown,
GlDropdownDivider,
GlDropdownItem,
GlDropdownSectionHeader,
GlSearchBoxByType,
} from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
export const EMPTY_NAMESPACE_ID = -1;
export const i18n = { export const i18n = {
DEFAULT_TEXT: __('Select a new namespace'), DEFAULT_TEXT: __('Select a new namespace'),
DEFAULT_EMPTY_NAMESPACE_TEXT: __('No namespace'),
GROUPS: __('Groups'), GROUPS: __('Groups'),
USERS: __('Users'), USERS: __('Users'),
}; };
...@@ -15,6 +23,7 @@ export default { ...@@ -15,6 +23,7 @@ export default {
name: 'NamespaceSelect', name: 'NamespaceSelect',
components: { components: {
GlDropdown, GlDropdown,
GlDropdownDivider,
GlDropdownItem, GlDropdownItem,
GlDropdownSectionHeader, GlDropdownSectionHeader,
GlSearchBoxByType, GlSearchBoxByType,
...@@ -29,6 +38,26 @@ export default { ...@@ -29,6 +38,26 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
defaultText: {
type: String,
required: false,
default: i18n.DEFAULT_TEXT,
},
includeHeaders: {
type: Boolean,
required: false,
default: true,
},
emptyNamespaceTitle: {
type: String,
required: false,
default: i18n.DEFAULT_EMPTY_NAMESPACE_TEXT,
},
includeEmptyNamespace: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -52,7 +81,11 @@ export default { ...@@ -52,7 +81,11 @@ export default {
return filterByName(this.data.user, this.searchTerm); return filterByName(this.data.user, this.searchTerm);
}, },
selectedNamespaceText() { selectedNamespaceText() {
return this.selectedNamespace?.humanName || this.$options.i18n.DEFAULT_TEXT; return this.selectedNamespace?.humanName || this.defaultText;
},
filteredEmptyNamespaceTitle() {
const { includeEmptyNamespace, emptyNamespaceTitle, searchTerm } = this;
return includeEmptyNamespace && emptyNamespaceTitle.toLowerCase().includes(searchTerm);
}, },
}, },
methods: { methods: {
...@@ -60,31 +93,47 @@ export default { ...@@ -60,31 +93,47 @@ export default {
this.selectedNamespace = item; this.selectedNamespace = item;
this.$emit('select', item); this.$emit('select', item);
}, },
handleSelectEmptyNamespace() {
this.handleSelect({ id: EMPTY_NAMESPACE_ID, humanName: this.emptyNamespaceTitle });
},
}, },
i18n, i18n,
}; };
</script> </script>
<template> <template>
<gl-dropdown :text="selectedNamespaceText" :block="fullWidth"> <gl-dropdown :text="selectedNamespaceText" :block="fullWidth" data-qa-selector="namespaces_list">
<template #header> <template #header>
<gl-search-box-by-type v-model.trim="searchTerm" /> <gl-search-box-by-type v-model.trim="searchTerm" />
</template> </template>
<div v-if="hasGroupNamespaces" class="qa-namespaces-list-groups"> <div v-if="filteredEmptyNamespaceTitle">
<gl-dropdown-section-header>{{ $options.i18n.GROUPS }}</gl-dropdown-section-header> <gl-dropdown-item
data-qa-selector="namespaces_list_item"
@click="handleSelectEmptyNamespace()"
>
{{ emptyNamespaceTitle }}
</gl-dropdown-item>
<gl-dropdown-divider />
</div>
<div v-if="hasGroupNamespaces" data-qa-selector="namespaces_list_groups">
<gl-dropdown-section-header v-if="includeHeaders">{{
$options.i18n.GROUPS
}}</gl-dropdown-section-header>
<gl-dropdown-item <gl-dropdown-item
v-for="item in filteredGroupNamespaces" v-for="item in filteredGroupNamespaces"
:key="item.id" :key="item.id"
class="qa-namespaces-list-item" data-qa-selector="namespaces_list_item"
@click="handleSelect(item)" @click="handleSelect(item)"
>{{ item.humanName }}</gl-dropdown-item >{{ item.humanName }}</gl-dropdown-item
> >
</div> </div>
<div v-if="hasUserNamespaces" class="qa-namespaces-list-users"> <div v-if="hasUserNamespaces" data-qa-selector="namespaces_list_users">
<gl-dropdown-section-header>{{ $options.i18n.USERS }}</gl-dropdown-section-header> <gl-dropdown-section-header v-if="includeHeaders">{{
$options.i18n.USERS
}}</gl-dropdown-section-header>
<gl-dropdown-item <gl-dropdown-item
v-for="item in filteredUserNamespaces" v-for="item in filteredUserNamespaces"
:key="item.id" :key="item.id"
class="qa-namespaces-list-item" data-qa-selector="namespaces_list_item"
@click="handleSelect(item)" @click="handleSelect(item)"
>{{ item.humanName }}</gl-dropdown-item >{{ item.humanName }}</gl-dropdown-item
> >
......
...@@ -112,19 +112,6 @@ table.pipeline-project-metrics tr td { ...@@ -112,19 +112,6 @@ table.pipeline-project-metrics tr td {
font-weight: $gl-font-weight-normal; font-weight: $gl-font-weight-normal;
} }
.js-groups-dropdown {
width: 100%;
}
.dropdown-group-transfer {
bottom: 100%;
top: initial;
.dropdown-content {
overflow-y: unset;
}
}
.groups-list-tree-container { .groups-list-tree-container {
.has-no-search-results { .has-no-search-results {
text-align: center; text-align: center;
......
- form_id = "transfer-group-form"
- initial_data = { button_text: s_('GroupSettings|Transfer group'), group_name: @group.name, target_form_id: form_id, parent_groups: parent_group_options(group), is_paid_group: group.paid?.to_s }
.sub-section .sub-section
%h4.warning-title= s_('GroupSettings|Transfer group') %h4.warning-title= s_('GroupSettings|Transfer group')
%p= _('Transfer group to another parent group.') %p= _('Transfer group to another parent group.')
= form_for group, url: transfer_group_path(group), method: :put, html: { class: 'js-group-transfer-form' } do |f| = form_for group, url: transfer_group_path(group), method: :put, html: { id: form_id, class: 'js-group-transfer-form' } do |f|
%ul %ul
- learn_more_link_start = '<a href="https://docs.gitlab.com/ee/user/project/index.html#redirects-when-changing-repository-paths" target="_blank" rel="noopener noreferrer">'.html_safe - learn_more_link_start = '<a href="https://docs.gitlab.com/ee/user/project/index.html#redirects-when-changing-repository-paths" target="_blank" rel="noopener noreferrer">'.html_safe
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}") % { learn_more_link_start: learn_more_link_start, learn_more_link_end: '</a>'.html_safe } - warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}") % { learn_more_link_start: learn_more_link_start, learn_more_link_end: '</a>'.html_safe }
...@@ -10,14 +12,9 @@ ...@@ -10,14 +12,9 @@
%li= s_('GroupSettings|You can only transfer the group to a group you manage.') %li= s_('GroupSettings|You can only transfer the group to a group you manage.')
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.') %li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.") %li= s_("GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
.form-group
= dropdown_tag(s_('GroupSettings|Select parent group'), options: { toggle_class: 'js-groups-dropdown', title: s_('GroupSettings|Parent Group'), filter: true, dropdown_class: 'dropdown-open-top dropdown-group-transfer', placeholder: s_('GroupSettings|Search groups'), disabled: group.paid?, data: { data: parent_group_options(group), qa_selector: 'select_group_dropdown' } })
= hidden_field_tag 'new_parent_group_id'
- if group.paid? - if group.paid?
.gl-alert.gl-alert-info.gl-mb-5 .gl-alert.gl-alert-info.gl-mb-5
= sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-body .gl-alert-body
= html_escape(_("This group can't be transfered because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe } = html_escape(_("This group can't be transfered because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
.js-transfer-group-form{ data: initial_data }
= f.submit s_('GroupSettings|Transfer group'), class: 'btn gl-button btn-warning', data: { qa_selector: "transfer_group_button" }
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'groups/settings/_transfer.html.haml' do
describe 'render' do
let(:group) { create(:group) }
it 'enables the Select parent group dropdown and does not show an alert for a group' do
render 'groups/settings/transfer', group: group
expect(rendered).to have_button 'Select parent group'
expect(rendered).not_to have_button 'Select parent group', disabled: true
expect(rendered).not_to have_text "This group can't be transfered because it is linked to a subscription."
end
it 'disables the Select parent group dropdown and shows an alert for a group with a paid gitlab.com plan', :saas do
create(:gitlab_subscription, :ultimate, namespace: group)
render 'groups/settings/transfer', group: group
expect(rendered).to have_button 'Select parent group', disabled: true
expect(rendered).to have_text "This group can't be transfered because it is linked to a subscription."
end
it 'enables the Select parent group dropdown and does not show an alert for a subgroup', :saas do
create(:gitlab_subscription, :ultimate, namespace: group)
subgroup = create(:group, parent: group)
render 'groups/settings/transfer', group: subgroup
expect(rendered).to have_button 'Select parent group'
expect(rendered).not_to have_button 'Select parent group', disabled: true
expect(rendered).not_to have_text "This group can't be transfered because it is linked to a subscription."
end
end
end
...@@ -17304,9 +17304,6 @@ msgstr "" ...@@ -17304,9 +17304,6 @@ msgstr ""
msgid "GroupSettings|Overrides user notification preferences for all members of the group, subgroups, and projects." msgid "GroupSettings|Overrides user notification preferences for all members of the group, subgroups, and projects."
msgstr "" msgstr ""
msgid "GroupSettings|Parent Group"
msgstr ""
msgid "GroupSettings|Pipeline settings was updated for the group" msgid "GroupSettings|Pipeline settings was updated for the group"
msgstr "" msgstr ""
...@@ -17334,9 +17331,6 @@ msgstr "" ...@@ -17334,9 +17331,6 @@ msgstr ""
msgid "GroupSettings|Projects will be permanently deleted after a %{waiting_period}-day delay. This delay can be %{link_start}customized by an admin%{link_end} in instance settings. Inherited by subgroups." msgid "GroupSettings|Projects will be permanently deleted after a %{waiting_period}-day delay. This delay can be %{link_start}customized by an admin%{link_end} in instance settings. Inherited by subgroups."
msgstr "" msgstr ""
msgid "GroupSettings|Search groups"
msgstr ""
msgid "GroupSettings|Select a project with the %{code_start}.gitlab/insights.yml%{code_end} file" msgid "GroupSettings|Select a project with the %{code_start}.gitlab/insights.yml%{code_end} file"
msgstr "" msgstr ""
...@@ -24225,6 +24219,9 @@ msgstr "" ...@@ -24225,6 +24219,9 @@ msgstr ""
msgid "No milestones to show" msgid "No milestones to show"
msgstr "" msgstr ""
msgid "No namespace"
msgstr ""
msgid "No other labels with such name or description" msgid "No other labels with such name or description"
msgstr "" msgstr ""
...@@ -40888,6 +40885,9 @@ msgstr "" ...@@ -40888,6 +40885,9 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?" msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr "" msgstr ""
msgid "You are going to transfer %{group_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?" msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr "" msgstr ""
......
# frozen_string_literal: true
module QA
module Page
module Component
module NamespaceSelect
extend QA::Page::PageConcern
def self.included(base)
super
base.view "app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue" do
element :namespaces_list
element :namespaces_list_groups
element :namespaces_list_item
end
end
def select_namespace(item)
click_element :namespaces_list
within_element(:namespaces_list) do
find_element(:namespaces_list_item, text: item).click
end
end
end
end
end
end
...@@ -7,6 +7,8 @@ module QA ...@@ -7,6 +7,8 @@ module QA
class General < QA::Page::Base class General < QA::Page::Base
include ::QA::Page::Settings::Common include ::QA::Page::Settings::Common
include Page::Component::VisibilitySetting include Page::Component::VisibilitySetting
include Page::Component::ConfirmModal
include Page::Component::NamespaceSelect
view 'app/views/groups/edit.html.haml' do view 'app/views/groups/edit.html.haml' do
element :permission_lfs_2fa_content element :permission_lfs_2fa_content
...@@ -38,16 +40,6 @@ module QA ...@@ -38,16 +40,6 @@ module QA
element :project_creation_level_dropdown element :project_creation_level_dropdown
end end
view 'app/views/groups/settings/_transfer.html.haml' do
element :select_group_dropdown
element :transfer_group_button
end
view 'app/helpers/dropdowns_helper.rb' do
element :dropdown_input_field
element :dropdown_list_content
end
def set_group_name(name) def set_group_name(name)
find_element(:group_name_field).send_keys([:command, 'a'], :backspace) find_element(:group_name_field).send_keys([:command, 'a'], :backspace)
find_element(:group_name_field).set name find_element(:group_name_field).set name
...@@ -111,17 +103,14 @@ module QA ...@@ -111,17 +103,14 @@ module QA
click_element(:save_permissions_changes_button) click_element(:save_permissions_changes_button)
end end
def transfer_group(target_group) def transfer_group(target_group, source_group)
expand_content :advanced_settings_content expand_content :advanced_settings_content
click_element :select_group_dropdown select_namespace(target_group)
fill_element(:dropdown_input_field, target_group) click_element(:transfer_button)
within_element(:dropdown_list_content) do
click_on target_group
end
click_element :transfer_group_button fill_confirmation_text(source_group)
confirm_transfer
end end
end end
end end
......
...@@ -6,18 +6,13 @@ module QA ...@@ -6,18 +6,13 @@ module QA
module Settings module Settings
class Advanced < Page::Base class Advanced < Page::Base
include Component::ConfirmModal include Component::ConfirmModal
include Component::NamespaceSelect
view 'app/views/projects/edit.html.haml' do view 'app/views/projects/edit.html.haml' do
element :project_path_field element :project_path_field
element :change_path_button element :change_path_button
end end
view "app/assets/javascripts/vue_shared/components/namespace_select/namespace_select.vue" do
element :namespaces_list
element :namespaces_list_groups
element :namespaces_list_item
end
view 'app/views/projects/settings/_archive.html.haml' do view 'app/views/projects/settings/_archive.html.haml' do
element :archive_project_link element :archive_project_link
element :unarchive_project_link element :unarchive_project_link
...@@ -43,14 +38,6 @@ module QA ...@@ -43,14 +38,6 @@ module QA
click_element :change_path_button click_element :change_path_button
end end
def select_namespace(item)
click_element :namespaces_list
within_element(:namespaces_list) do
find_element(:namespaces_list_item, text: item).click
end
end
def transfer_project!(project_name, namespace) def transfer_project!(project_name, namespace)
QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}" QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}"
......
...@@ -31,7 +31,7 @@ module QA ...@@ -31,7 +31,7 @@ module QA
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do
Page::Group::Menu.perform(&:click_group_general_settings_item) Page::Group::Menu.perform(&:click_group_general_settings_item)
Page::Group::Settings::General.perform do |general| Page::Group::Settings::General.perform do |general|
general.transfer_group(target_group.path) general.transfer_group(target_group.path, sub_group_for_transfer.path)
sub_group_for_transfer.sandbox = target_group sub_group_for_transfer.sandbox = target_group
sub_group_for_transfer.reload! sub_group_for_transfer.reload!
......
import { GlAlert, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import Component from '~/groups/components/transfer_group_form.vue';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select.vue';
describe('Transfer group form', () => {
let wrapper;
const confirmButtonText = 'confirm';
const confirmationPhrase = 'confirmation-phrase';
const paidGroupHelpLink = 'some/fake/link';
const groups = [
{
id: 1,
humanName: 'Group 1',
},
{
id: 2,
humanName: 'Group 2',
},
];
const defaultProps = {
parentGroups: { groups },
paidGroupHelpLink,
isPaidGroup: false,
confirmationPhrase,
confirmButtonText,
};
const createComponent = (propsData = {}) =>
shallowMountExtended(Component, {
propsData: {
...defaultProps,
...propsData,
},
stubs: { GlSprintf },
});
const findAlert = () => wrapper.findComponent(GlAlert);
const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect);
const findHiddenInput = () => wrapper.find('[name="new_parent_group_id"]');
afterEach(() => {
wrapper.destroy();
});
describe('default', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('renders the namespace select component', () => {
expect(findNamespaceSelect().exists()).toBe(true);
});
it('sets the namespace select properties', () => {
expect(findNamespaceSelect().props()).toMatchObject({
defaultText: 'Select parent group',
fullWidth: false,
includeHeaders: false,
emptyNamespaceTitle: 'No parent group',
includeEmptyNamespace: true,
data: { groups },
});
});
it('renders the hidden input field', () => {
expect(findHiddenInput().exists()).toBe(true);
expect(findHiddenInput().attributes('value')).toBeUndefined();
});
it('does not render the alert message', () => {
expect(findAlert().exists()).toBe(false);
});
it('renders the confirm danger component', () => {
expect(findConfirmDanger().exists()).toBe(true);
});
it('sets the confirm danger properties', () => {
expect(findConfirmDanger().props()).toMatchObject({
buttonClass: 'qa-transfer-button',
disabled: true,
buttonText: confirmButtonText,
phrase: confirmationPhrase,
});
});
});
describe('with a selected project', () => {
const [firstGroup] = groups;
beforeEach(() => {
wrapper = createComponent();
findNamespaceSelect().vm.$emit('select', firstGroup);
});
it('sets the confirm danger disabled property to false', () => {
expect(findConfirmDanger().props()).toMatchObject({ disabled: false });
});
it('sets the hidden input field', () => {
expect(findHiddenInput().exists()).toBe(true);
expect(parseInt(findHiddenInput().attributes('value'), 10)).toBe(firstGroup.id);
});
it('emits "confirm" event when the danger modal is confirmed', () => {
expect(wrapper.emitted('confirm')).toBeUndefined();
findConfirmDanger().vm.$emit('confirm');
expect(wrapper.emitted('confirm')).toHaveLength(1);
});
});
describe('isPaidGroup = true', () => {
beforeEach(() => {
wrapper = createComponent({ isPaidGroup: true });
});
it('disables the transfer button', () => {
expect(findConfirmDanger().props()).toMatchObject({ disabled: true });
});
it('hides the namespace selector button', () => {
expect(findNamespaceSelect().exists()).toBe(false);
});
});
});
import $ from 'jquery';
import { loadHTMLFixture } from 'helpers/fixtures';
import setupTransferEdit from '~/groups/transfer_edit';
describe('setupTransferEdit', () => {
const formSelector = '.js-group-transfer-form';
const targetSelector = '#new_parent_group_id';
beforeEach(() => {
loadHTMLFixture('groups/edit.html');
setupTransferEdit(formSelector, targetSelector);
});
it('disables submit button on load', () => {
expect($(formSelector).find(':submit').prop('disabled')).toBe(true);
});
it('enables submit button when selection changes to non-empty value', () => {
const lastValue = $(formSelector).find(targetSelector).find('.dropdown-content li').last();
$(formSelector).find(targetSelector).val(lastValue).trigger('change');
expect($(formSelector).find(':submit').prop('disabled')).toBeFalsy();
});
it('disables submit button when selection changes to empty value', () => {
$(formSelector).find(targetSelector).val('').trigger('change');
expect($(formSelector).find(':submit').prop('disabled')).toBe(true);
});
});
import { nextTick } from 'vue';
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NamespaceSelect, { import NamespaceSelect, {
i18n, i18n,
EMPTY_NAMESPACE_ID,
} from '~/vue_shared/components/namespace_select/namespace_select.vue'; } from '~/vue_shared/components/namespace_select/namespace_select.vue';
import { user, group, namespaces } from './mock_data'; import { user, group, namespaces } from './mock_data';
...@@ -36,6 +38,12 @@ describe('Namespace Select', () => { ...@@ -36,6 +38,12 @@ describe('Namespace Select', () => {
expect(findDropdown().exists()).toBe(true); expect(findDropdown().exists()).toBe(true);
}); });
it('can override the default text', () => {
const textOverride = 'Select an option';
wrapper = createComponent({ defaultText: textOverride });
expect(selectedDropdownItemText()).toBe(textOverride);
});
it('renders each dropdown item', () => { it('renders each dropdown item', () => {
const items = findDropdownItems().wrappers; const items = findDropdownItems().wrappers;
expect(items).toHaveLength(flatNamespaces().length); expect(items).toHaveLength(flatNamespaces().length);
...@@ -57,6 +65,11 @@ describe('Namespace Select', () => { ...@@ -57,6 +65,11 @@ describe('Namespace Select', () => {
expect(wrappersText(headers)).toEqual([i18n.GROUPS, i18n.USERS]); expect(wrappersText(headers)).toEqual([i18n.GROUPS, i18n.USERS]);
}); });
it('can hide the group / user headers', () => {
wrapper = createComponent({ includeHeaders: false });
expect(findSectionHeaders()).toHaveLength(0);
});
it('sets the dropdown to full width', () => { it('sets the dropdown to full width', () => {
expect(findDropdownAttributes('block')).toBeUndefined(); expect(findDropdownAttributes('block')).toBeUndefined();
...@@ -83,4 +96,29 @@ describe('Namespace Select', () => { ...@@ -83,4 +96,29 @@ describe('Namespace Select', () => {
expect(wrapper.emitted('select')).toEqual([args]); expect(wrapper.emitted('select')).toEqual([args]);
}); });
}); });
describe('with an empty namespace option', () => {
const emptyNamespaceTitle = 'No namespace selected';
beforeEach(async () => {
wrapper = createComponent({
includeEmptyNamespace: true,
emptyNamespaceTitle,
});
await nextTick();
});
it('includes the empty namespace', () => {
const first = findDropdownItems().at(0);
expect(first.text()).toBe(emptyNamespaceTitle);
});
it('emits the `select` event when a namespace is selected', () => {
findDropdownItems().at(0).vm.$emit('click');
expect(wrapper.emitted('select')).toEqual([
[{ id: EMPTY_NAMESPACE_ID, humanName: emptyNamespaceTitle }],
]);
});
});
}); });
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'groups/settings/_transfer.html.haml' do
describe 'render' do
it 'enables the Select parent group dropdown and does not show an alert for a group' do
group = build(:group)
render 'groups/settings/transfer', group: group
expect(rendered).to have_button 'Select parent group'
expect(rendered).not_to have_button 'Select parent group', disabled: true
expect(rendered).not_to have_text "This group can't be transfered because it is linked to a subscription."
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment