Commit 1d3e3060 authored by Peter Hegman's avatar Peter Hegman Committed by Olena Horal-Koretska

Break "New project" and "New subgroup" buttons out of dropdown

Better UX and allows us to get rid of some legacy JS
parent 25de286a
import { visitUrl } from '../lib/utils/url_utility';
import DropLab from '../droplab/drop_lab';
import ISetter from '../droplab/plugins/input_setter';
const InputSetter = { ...ISetter };
const NEW_PROJECT = 'new-project';
const NEW_SUBGROUP = 'new-subgroup';
export default class NewGroupChild {
constructor(buttonWrapper) {
this.buttonWrapper = buttonWrapper;
this.newGroupChildButton = this.buttonWrapper.querySelector('.js-new-group-child');
this.dropdownToggle = this.buttonWrapper.querySelector('.js-dropdown-toggle');
this.dropdownList = this.buttonWrapper.querySelector('.dropdown-menu');
this.newGroupPath = this.buttonWrapper.dataset.projectPath;
this.subgroupPath = this.buttonWrapper.dataset.subgroupPath;
this.init();
}
init() {
this.initDroplab();
this.bindEvents();
}
initDroplab() {
this.droplab = new DropLab();
this.droplab.init(
this.dropdownToggle,
this.dropdownList,
[InputSetter],
this.getDroplabConfig(),
);
}
getDroplabConfig() {
return {
InputSetter: [
{
input: this.newGroupChildButton,
valueAttribute: 'data-value',
inputAttribute: 'data-action',
},
{
input: this.newGroupChildButton,
valueAttribute: 'data-text',
},
],
};
}
bindEvents() {
this.newGroupChildButton.addEventListener('click', this.onClickNewGroupChildButton.bind(this));
}
onClickNewGroupChildButton(e) {
if (e.target.dataset.action === NEW_PROJECT) {
visitUrl(this.newGroupPath);
} else if (e.target.dataset.action === NEW_SUBGROUP) {
visitUrl(this.subgroupPath);
}
}
}
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import { getPagePath, getDashPath } from '~/lib/utils/common_utils'; import { getPagePath, getDashPath } from '~/lib/utils/common_utils';
import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants'; import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown'; import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form'; import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list'; import ProjectsList from '~/projects_list';
...@@ -11,7 +10,6 @@ import GroupTabs from './group_tabs'; ...@@ -11,7 +10,6 @@ import GroupTabs from './group_tabs';
import initInviteMembersBanner from '~/groups/init_invite_members_banner'; import initInviteMembersBanner from '~/groups/init_invite_members_banner';
export default function initGroupDetails(actionName = 'show') { export default function initGroupDetails(actionName = 'show') {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED]; const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
const dashPath = getDashPath(); const dashPath = getDashPath();
let action = loadableActions.includes(dashPath) ? dashPath : getPagePath(1); let action = loadableActions.includes(dashPath) ? dashPath : getPagePath(1);
...@@ -25,8 +23,5 @@ export default function initGroupDetails(actionName = 'show') { ...@@ -25,8 +23,5 @@ export default function initGroupDetails(actionName = 'show') {
notificationsDropdown(); notificationsDropdown();
new ProjectsList(); new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
initInviteMembersBanner(); initInviteMembersBanner();
} }
...@@ -20,37 +20,16 @@ ...@@ -20,37 +20,16 @@
%span.access-request-links.gl-ml-3 %span.access-request-links.gl-ml-3
= render 'shared/members/access_request_links', source: @group = render 'shared/members/access_request_links', source: @group
.home-panel-buttons.col-md-12.col-lg-6.d-inline-flex.flex-wrap.justify-content-lg-end .home-panel-buttons.col-md-12.col-lg-6
- if current_user - if current_user
.group-buttons .gl-display-flex.gl-flex-wrap.gl-lg-justify-content-end.gl-mx-n2{ data: { testid: 'group-buttons' } }
= render 'shared/notifications/new_button', notification_setting: @notification_setting, btn_class: 'btn', emails_disabled: emails_disabled = render 'shared/notifications/new_button', notification_setting: @notification_setting, btn_class: 'btn gl-button gl-sm-w-auto gl-w-full', dropdown_container_class: 'gl-mr-0 gl-px-2 gl-sm-w-auto gl-w-full', emails_disabled: emails_disabled
- new_project_label = _("New project") - if can_create_subgroups
- new_subgroup_label = _("New subgroup") .gl-px-2.gl-sm-w-auto.gl-w-full
- if can_create_projects and can_create_subgroups = link_to _("New subgroup"), new_group_path(parent_id: @group.id), class: "btn btn-success btn-md gl-button btn-success-secondary gl-mt-3 gl-sm-w-auto gl-w-full", data: { qa_selector: 'new_subgroup_button' }
.btn-group.new-project-subgroup.droplab-dropdown.home-panel-action-button.gl-mt-3.js-new-project-subgroup.qa-new-project-or-subgroup-dropdown{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } } - if can_create_projects
%input.btn.btn-success.dropdown-primary.js-new-group-child.qa-new-in-group-button{ type: "button", value: new_project_label, data: { action: "new-project" } } .gl-px-2.gl-sm-w-auto.gl-w-full
%button.btn.btn-success.dropdown-toggle.js-dropdown-toggle.qa-new-project-or-subgroup-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } } = link_to _("New project"), new_project_path(namespace_id: @group.id), class: "btn btn-success btn-md gl-button gl-mt-3 gl-sm-w-auto gl-w-full", data: { qa_selector: 'new_project_button' }
= sprite_icon("chevron-down", css_class: "icon dropdown-btn-icon")
%ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } }
%li.droplab-item-selected.qa-new-project-option{ role: "button", data: { value: "new-project", text: new_project_label } }
.menu-item
.icon-container
= sprite_icon("check", css_class: "list-item-checkmark")
.description
%strong= new_project_label
%span= s_("GroupsTree|Create a project in this group.")
%li.divider.droplap-item-ignore
%li.qa-new-subgroup-option{ role: "button", data: { value: "new-subgroup", text: new_subgroup_label } }
.menu-item
.icon-container
= sprite_icon("check", css_class: "list-item-checkmark")
.description
%strong= new_subgroup_label
%span= s_("GroupsTree|Create a subgroup in this group.")
- elsif can_create_projects
= link_to new_project_label, new_project_path(namespace_id: @group.id), class: "btn btn-success gl-mt-3"
- elsif can_create_subgroups
= link_to new_subgroup_label, new_group_path(parent_id: @group.id), class: "btn btn-success gl-mt-3"
- if @group.description.present? - if @group.description.present?
.group-home-desc.mt-1 .group-home-desc.mt-1
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
.project-repo-buttons.col-md-12.col-lg-6.d-inline-flex.flex-wrap.justify-content-lg-end .project-repo-buttons.col-md-12.col-lg-6.d-inline-flex.flex-wrap.justify-content-lg-end
- if current_user - if current_user
.d-inline-flex .d-inline-flex
= render 'shared/notifications/new_button', notification_setting: @notification_setting, btn_class: 'btn-xs', emails_disabled: emails_disabled = render 'shared/notifications/new_button', notification_setting: @notification_setting, btn_class: 'btn-xs', dropdown_container_class: 'gl-mr-3', emails_disabled: emails_disabled
.count-buttons.d-inline-flex .count-buttons.d-inline-flex
= render 'projects/buttons/star' = render 'projects/buttons/star'
......
- btn_class = local_assigns.fetch(:btn_class, '') - btn_class = local_assigns.fetch(:btn_class, '')
- dropdown_container_class = local_assigns.fetch(:dropdown_container_class, '')
- emails_disabled = local_assigns.fetch(:emails_disabled, false) - emails_disabled = local_assigns.fetch(:emails_disabled, false)
- if notification_setting - if notification_setting
...@@ -8,8 +9,8 @@ ...@@ -8,8 +9,8 @@
- else - else
- button_title = _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) } - button_title = _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }
.js-notification-dropdown.notification-dropdown.home-panel-action-button.gl-mt-3.gl-mr-3.dropdown.inline .js-notification-dropdown.notification-dropdown.home-panel-action-button.gl-mt-3.dropdown.inline{ class: dropdown_container_class }
= form_for notification_setting, remote: true, html: { class: "inline notification-form no-label" } do |f| = form_for notification_setting, remote: true, html: { class: "notification-form no-label" } do |f|
= hidden_setting_source_input(notification_setting) = hidden_setting_source_input(notification_setting)
= hidden_field_tag "hide_label", true = hidden_field_tag "hide_label", true
= f.hidden_field :level, class: "notification_setting_level" = f.hidden_field :level, class: "notification_setting_level"
......
---
title: Move "New subgroup" and "New project" out of the dropdown into individual buttons
merge_request: 46907
author:
type: changed
...@@ -235,7 +235,7 @@ There are two different ways to add a new project to a group: ...@@ -235,7 +235,7 @@ There are two different ways to add a new project to a group:
- Select a group, and then click **New project**. You can then continue [creating your project](../../gitlab-basics/create-project.md). - Select a group, and then click **New project**. You can then continue [creating your project](../../gitlab-basics/create-project.md).
![New project](img/create_new_project_from_group.png) ![New project](img/create_new_project_from_group_v13_6.png)
- While you are creating a project, select a group namespace - While you are creating a project, select a group namespace
you've already created from the dropdown menu. you've already created from the dropdown menu.
......
...@@ -99,10 +99,9 @@ creation is disabled by an administrator in their settings. ...@@ -99,10 +99,9 @@ creation is disabled by an administrator in their settings.
To create a subgroup: To create a subgroup:
1. In the group's dashboard expand the **New project** split button, select 1. In the group's dashboard click the **New subgroup** button.
**New subgroup** and click the **New subgroup** button.
![Subgroups page](img/create_subgroup_button.png) ![Subgroups page](img/create_subgroup_button_v13_6.png)
1. Create a new group like you would normally do. Notice that the immediate parent group 1. Create a new group like you would normally do. Notice that the immediate parent group
namespace is fixed under **Group path**. The visibility level can differ from namespace is fixed under **Group path**. The visibility level can differ from
......
...@@ -13560,12 +13560,6 @@ msgstr "" ...@@ -13560,12 +13560,6 @@ msgstr ""
msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?" msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?"
msgstr "" msgstr ""
msgid "GroupsTree|Create a project in this group."
msgstr ""
msgid "GroupsTree|Create a subgroup in this group."
msgstr ""
msgid "GroupsTree|Edit group" msgid "GroupsTree|Edit group"
msgstr "" msgstr ""
......
...@@ -7,11 +7,8 @@ module QA ...@@ -7,11 +7,8 @@ module QA
include Page::Component::GroupsFilter include Page::Component::GroupsFilter
view 'app/views/groups/_home_panel.html.haml' do view 'app/views/groups/_home_panel.html.haml' do
element :new_project_or_subgroup_dropdown element :new_project_button
element :new_project_or_subgroup_dropdown_toggle element :new_subgroup_button
element :new_project_option
element :new_subgroup_option
element :new_in_group_button
end end
view 'app/assets/javascripts/groups/constants.js' do view 'app/assets/javascripts/groups/constants.js' do
...@@ -26,8 +23,9 @@ module QA ...@@ -26,8 +23,9 @@ module QA
click_link name click_link name
end end
def has_new_project_or_subgroup_dropdown? def has_new_project_and_new_subgroup_buttons?
has_element?(:new_project_or_subgroup_dropdown) has_element?(:new_project_button)
has_element?(:new_subgroup_button)
end end
def has_subgroup?(name) def has_subgroup?(name)
...@@ -35,15 +33,11 @@ module QA ...@@ -35,15 +33,11 @@ module QA
end end
def go_to_new_subgroup def go_to_new_subgroup
select_kind :new_subgroup_option click_element :new_subgroup_button
click_element :new_in_group_button
end end
def go_to_new_project def go_to_new_project
select_kind :new_project_option click_element :new_project_button
click_element :new_in_group_button
end end
def leave_group def leave_group
...@@ -51,23 +45,6 @@ module QA ...@@ -51,23 +45,6 @@ module QA
click_element :leave_group_link click_element :leave_group_link
end end
end end
private
def select_kind(kind)
QA::Support::Retrier.retry_on_exception(sleep_interval: 1.0) do
within_element(:new_project_or_subgroup_dropdown) do
# May need to click again because it is possible to click the button quicker than the JS is bound
wait_until(reload: false) do
click_element :new_project_or_subgroup_dropdown_toggle
has_element?(kind)
end
click_element kind
end
end
end
end end
end end
end end
......
...@@ -44,7 +44,7 @@ module QA ...@@ -44,7 +44,7 @@ module QA
# Ensure that the group was actually created # Ensure that the group was actually created
group_show.wait_until(sleep_interval: 1) do group_show.wait_until(sleep_interval: 1) do
group_show.has_text?(path) && group_show.has_text?(path) &&
group_show.has_new_project_or_subgroup_dropdown? group_show.has_new_project_and_new_subgroup_buttons?
end end
end end
end end
......
...@@ -81,8 +81,7 @@ RSpec.describe 'Group show page' do ...@@ -81,8 +81,7 @@ RSpec.describe 'Group show page' do
it 'allows creating subgroups' do it 'allows creating subgroups' do
visit path visit path
expect(page) expect(page).to have_link('New subgroup')
.to have_css("li[data-text='New subgroup']", visible: false)
end end
end end
end end
...@@ -102,8 +101,7 @@ RSpec.describe 'Group show page' do ...@@ -102,8 +101,7 @@ RSpec.describe 'Group show page' do
path = group_path(relaxed_group) path = group_path(relaxed_group)
visit path visit path
expect(page) expect(page).to have_link('New subgroup')
.to have_css("li[data-text='New subgroup']", visible: false)
end end
end end
...@@ -116,9 +114,7 @@ RSpec.describe 'Group show page' do ...@@ -116,9 +114,7 @@ RSpec.describe 'Group show page' do
path = group_path(restricted_group) path = group_path(restricted_group)
visit path visit path
expect(page) expect(page).not_to have_link('New subgroup')
.not_to have_selector("li[data-text='New subgroup']",
visible: false)
end end
end end
end end
......
...@@ -294,25 +294,19 @@ RSpec.describe 'Group' do ...@@ -294,25 +294,19 @@ RSpec.describe 'Group' do
describe 'new subgroup / project button' do describe 'new subgroup / project button' do
let(:group) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS, subgroup_creation_level: Gitlab::Access::OWNER_SUBGROUP_ACCESS) } let(:group) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS, subgroup_creation_level: Gitlab::Access::OWNER_SUBGROUP_ACCESS) }
it 'new subgroup button is displayed without project creation permission' do context 'when user has subgroup creation permissions but not project creation permissions' do
it 'only displays "New subgroup" button' do
visit group_path(group) visit group_path(group)
page.within '.group-buttons' do page.within '[data-testid="group-buttons"]' do
expect(page).to have_link('New subgroup') expect(page).to have_link('New subgroup')
expect(page).not_to have_link('New project')
end end
end end
it 'new subgroup button is displayed together with new project button when having project creation permission' do
group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
visit group_path(group)
page.within '.group-buttons' do
expect(page).to have_css("li[data-text='New subgroup']", visible: false)
expect(page).to have_css("li[data-text='New project']", visible: false)
end
end end
it 'new project button is displayed without subgroup creation permission' do context 'when user has project creation permissions but not subgroup creation permissions' do
it 'only displays "New project" button' do
group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
user = create(:user) user = create(:user)
...@@ -321,8 +315,22 @@ RSpec.describe 'Group' do ...@@ -321,8 +315,22 @@ RSpec.describe 'Group' do
sign_in(user) sign_in(user)
visit group_path(group) visit group_path(group)
page.within '.group-buttons' do page.within '[data-testid="group-buttons"]' do
expect(page).to have_link('New project') expect(page).to have_link('New project')
expect(page).not_to have_link('New subgroup')
end
end
end
context 'when user has project and subgroup creation permissions' do
it 'displays "New subgroup" and "New project" buttons' do
group.update!(project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
visit group_path(group)
page.within '[data-testid="group-buttons"]' do
expect(page).to have_link('New subgroup')
expect(page).to have_link('New project')
end
end end
end 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