Skip to content
Snippets Groups Projects
Commit 110d4736 authored by Coung Ngo's avatar Coung Ngo
Browse files

Merge branch '385744-super-sidebar-create-menu' into 'master'

parents f8326195 ccb5100f
No related branches found
No related tags found
1 merge request!109246Create "Create new" menu in the super sidebar
Pipeline #755075661 passed
Showing
with 209 additions and 40 deletions
<script>
import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
components: {
GlDisclosureDropdown,
},
i18n: {
createNew: __('Create new...'),
},
props: {
groups: {
type: Array,
required: true,
},
},
};
</script>
<template>
<gl-disclosure-dropdown
v-gl-tooltip:super-sidebar.bottom="$options.i18n.createNew"
category="tertiary"
icon="plus"
:items="groups"
no-caret
text-sr-only
:toggle-text="$options.i18n.createNew"
/>
</template>
......@@ -31,6 +31,7 @@ export default {
<template>
<aside
id="super-sidebar"
class="super-sidebar gl-fixed gl-bottom-0 gl-left-0 gl-display-flex gl-flex-direction-column gl-bg-gray-10 gl-border-r gl-border-gray-a-08 gl-z-index-9999"
data-testid="super-sidebar"
>
......
......@@ -4,6 +4,7 @@ import { __ } from '~/locale';
import SafeHtml from '~/vue_shared/directives/safe_html';
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
import logo from '../../../../views/shared/_logo.svg';
import CreateMenu from './create_menu.vue';
import Counter from './counter.vue';
export default {
......@@ -12,10 +13,12 @@ export default {
GlAvatar,
GlDropdown,
GlIcon,
CreateMenu,
NewNavToggle,
Counter,
},
i18n: {
createNew: __('Create new...'),
issues: __('Issues'),
mergeRequests: __('Merge requests'),
todoList: __('To-Do list'),
......@@ -39,11 +42,7 @@ export default {
<div class="gl-flex-grow-1">
<a v-safe-html="$options.logo" :href="rootPath"></a>
</div>
<gl-dropdown variant="link" no-caret>
<template #button-content>
<gl-icon name="plus" class="gl-vertical-align-middle gl-text-black-normal" />
</template>
</gl-dropdown>
<create-menu :groups="sidebarData.create_new_menu_groups" />
<button class="gl-border-none">
<gl-icon name="search" class="gl-vertical-align-middle" />
</button>
......
......@@ -59,7 +59,7 @@ def group_menu_section(group)
end
{
title: _('This group'),
title: _('In this group'),
menu_items: menu_items.compact
}
end
......@@ -110,7 +110,7 @@ def project_menu_section(project)
end
{
title: _('This project'),
title: _('In this project'),
menu_items: menu_items
}
end
......@@ -152,7 +152,7 @@ def general_menu_section
end
{
title: _('GitLab'),
title: _('In GitLab'),
menu_items: menu_items
}
end
......
# frozen_string_literal: true
module SidebarsHelper
include Nav::NewDropdownHelper
def sidebar_tracking_attributes_by_object(object)
sidebar_attributes_for_object(object).fetch(:tracking_attrs, {})
end
......@@ -31,7 +33,7 @@ def group_sidebar_context(group, user)
Sidebars::Groups::Context.new(**context_data)
end
def super_sidebar_context(user)
def super_sidebar_context(user, group:, project:)
{
name: user.name,
username: user.username,
......@@ -39,12 +41,29 @@ def super_sidebar_context(user)
assigned_open_issues_count: user.assigned_open_issues_count,
assigned_open_merge_requests_count: user.assigned_open_merge_requests_count,
todos_pending_count: user.todos_pending_count,
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username)
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
create_new_menu_groups: create_new_menu_groups(group: group, project: project)
}
end
private
def create_new_menu_groups(group:, project:)
new_dropdown_sections = new_dropdown_view_model(group: group, project: project)[:menu_sections]
show_headers = new_dropdown_sections.length > 1
new_dropdown_sections.map do |section|
{
name: show_headers ? section[:title] : '',
items: section[:menu_items].map do |item|
{
text: item[:title],
href: item[:href]
}
end
}
end
end
def sidebar_attributes_for_object(object)
case object
when Project
......
......@@ -2,7 +2,7 @@
- @left_sidebar = true
.layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
- if show_super_sidebar?
- sidebar_data = super_sidebar_context(current_user).to_json
- sidebar_data = super_sidebar_context(current_user, group: @group, project: @project).to_json
%aside.js-super-sidebar.nav-sidebar{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
- elsif defined?(nav) && nav
= render "layouts/nav/sidebar/#{nav}"
......
......@@ -18,7 +18,7 @@
context 'with group and can create_epic' do
it 'shows create epic menu item' do
expect(subject[:menu_sections][0]).to eq({
title: 'This group',
title: 'In this group',
menu_items: [
::Gitlab::Nav::TopNavMenuItem.build(
id: 'create_epic',
......
......@@ -21378,6 +21378,9 @@ msgstr ""
msgid "Improve quality with test cases"
msgstr ""
 
msgid "In GitLab"
msgstr ""
msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
 
......@@ -21390,9 +21393,15 @@ msgstr ""
msgid "In the background, we're attempting to connect you again."
msgstr ""
 
msgid "In this group"
msgstr ""
msgid "In this page you will find information about the settings that are used in your current instance."
msgstr ""
 
msgid "In this project"
msgstr ""
msgid "In use"
msgstr ""
 
......@@ -43370,9 +43379,6 @@ msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr ""
 
msgid "This project"
msgstr ""
msgid "This project can be restored until %{date}."
msgstr ""
 
......@@ -13,10 +13,6 @@ describe('Counter component', () => {
label: __('Issues'),
};
afterEach(() => {
wrapper.destroy();
});
const findButton = () => wrapper.find('button');
const findIcon = () => wrapper.getComponent(GlIcon);
const findLink = () => wrapper.find('a');
......
import { GlDisclosureDropdown } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
import { createNewMenuGroups } from '../mock_data';
describe('CreateMenu component', () => {
let wrapper;
const findGlDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const createWrapper = () => {
wrapper = shallowMountExtended(CreateMenu, {
propsData: {
groups: createNewMenuGroups,
},
});
};
describe('default', () => {
beforeEach(() => {
createWrapper();
});
it("sets the toggle's label", () => {
expect(findGlDisclosureDropdown().props('toggleText')).toBe(__('Create new...'));
});
it('passes the groups to the disclosure dropdown', () => {
expect(findGlDisclosureDropdown().props('items')).toBe(createNewMenuGroups);
});
});
});
......@@ -8,10 +8,6 @@ describe('SuperSidebar component', () => {
const findUserBar = () => wrapper.findComponent(UserBar);
afterEach(() => {
wrapper.destroy();
});
const createWrapper = (props = {}) => {
wrapper = shallowMountExtended(SuperSidebar, {
propsData: {
......
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
import Counter from '~/super_sidebar/components/counter.vue';
import UserBar from '~/super_sidebar/components/user_bar.vue';
import { sidebarData } from '../mock_data';
......@@ -7,12 +8,9 @@ import { sidebarData } from '../mock_data';
describe('UserBar component', () => {
let wrapper;
const findCreateMenu = () => wrapper.findComponent(CreateMenu);
const findCounter = (at) => wrapper.findAllComponents(Counter).at(at);
afterEach(() => {
wrapper.destroy();
});
const createWrapper = (props = {}) => {
wrapper = shallowMountExtended(UserBar, {
propsData: {
......@@ -31,6 +29,10 @@ describe('UserBar component', () => {
createWrapper();
});
it('passes the "Create new..." menu groups to the create-menu component', () => {
expect(findCreateMenu().props('groups')).toBe(sidebarData.create_new_menu_groups);
});
it('renders issues counter', () => {
expect(findCounter(0).props('count')).toBe(sidebarData.assigned_open_issues_count);
expect(findCounter(0).props('href')).toBe(sidebarData.issues_dashboard_path);
......
export const createNewMenuGroups = [
{
name: 'This group',
items: [
{
text: 'New project/repository',
href: '/projects/new?namespace_id=22',
},
{
text: 'New subgroup',
href: '/groups/new?parent_id=22#create-group-pane',
},
{
text: 'New epic',
href: '/groups/gitlab-org/-/epics/new',
},
{
text: 'Invite members',
href: '/groups/gitlab-org/-/group_members',
},
],
},
{
name: 'GitLab',
items: [
{
text: 'New project/repository',
href: '/projects/new',
},
{
text: 'New group',
href: '/groups/new',
},
{
text: 'New snippet',
href: '/-/snippets/new',
},
],
},
];
export const sidebarData = {
name: 'Administrator',
username: 'root',
......@@ -6,4 +47,5 @@ export const sidebarData = {
assigned_open_merge_requests_count: 2,
todos_pending_count: 3,
issues_dashboard_path: 'path/to/issues',
create_new_menu_groups: createNewMenuGroups,
};
......@@ -77,7 +77,7 @@ def expected_menu_section(title:, menu_item:)
it 'has project menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: _('GitLab'),
title: _('In GitLab'),
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'general_new_project',
title: 'New project/repository',
......@@ -95,7 +95,7 @@ def expected_menu_section(title:, menu_item:)
it 'has group menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: _('GitLab'),
title: _('In GitLab'),
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'general_new_group',
title: 'New group',
......@@ -113,7 +113,7 @@ def expected_menu_section(title:, menu_item:)
it 'has new snippet menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: _('GitLab'),
title: _('In GitLab'),
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'general_new_snippet',
title: 'New snippet',
......@@ -151,7 +151,7 @@ def expected_menu_section(title:, menu_item:)
it 'has new project menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: 'This group',
title: 'In this group',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_project',
title: 'New project/repository',
......@@ -169,7 +169,7 @@ def expected_menu_section(title:, menu_item:)
it 'has new subgroup menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: 'This group',
title: 'In this group',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_subgroup',
title: 'New subgroup',
......@@ -184,7 +184,7 @@ def expected_menu_section(title:, menu_item:)
context 'when can invite members' do
let(:with_can_admin_in_group) { true }
let(:with_invite_members_experiment) { true }
let(:expected_title) { 'This group' }
let(:expected_title) { 'In this group' }
let(:expected_href) { "/groups/#{group.full_path}/-/group_members" }
it_behaves_like 'invite member link shared example'
......@@ -218,7 +218,7 @@ def expected_menu_section(title:, menu_item:)
it 'shows new issue menu item' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: 'This project',
title: 'In this project',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_issue',
title: 'New issue',
......@@ -236,7 +236,7 @@ def expected_menu_section(title:, menu_item:)
it 'shows merge project' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: 'This project',
title: 'In this project',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_mr',
title: 'New merge request',
......@@ -254,7 +254,7 @@ def expected_menu_section(title:, menu_item:)
it 'shows new snippet' do
expect(subject[:menu_sections]).to eq(
expected_menu_section(
title: 'This project',
title: 'In this project',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_snippet',
title: 'New snippet',
......@@ -269,7 +269,7 @@ def expected_menu_section(title:, menu_item:)
context 'when invite members experiment' do
let(:with_invite_members_experiment) { true }
let(:with_can_admin_project_member) { true }
let(:expected_title) { 'This project' }
let(:expected_title) { 'In this project' }
let(:expected_href) { "/#{project.path_with_namespace}/-/project_members" }
it_behaves_like 'invite member link shared example'
......
......@@ -47,15 +47,19 @@
describe '#super_sidebar_context' do
let(:user) { build(:user) }
let(:group) { build(:group) }
subject { helper.super_sidebar_context(user) }
subject { helper.super_sidebar_context(user, group: group, project: nil) }
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
before do
allow(helper).to receive(:current_user) { user }
Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1)
Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 2)
Rails.cache.write(['users', user.id, 'todos_pending_count'], 3)
end
expect(subject).to eq({
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
expect(subject).to include({
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
......@@ -65,5 +69,42 @@
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username)
})
end
it 'returns "Create new" menu groups without headers', :use_clean_rails_memory_store_caching do
expect(subject[:create_new_menu_groups]).to eq([
{
name: "",
items: [
{ href: "/projects/new", text: "New project/repository" },
{ href: "/groups/new", text: "New group" },
{ href: "/-/snippets/new", text: "New snippet" }
]
}
])
end
it 'returns "Create new" menu groups with headers', :use_clean_rails_memory_store_caching do
allow(group).to receive(:persisted?).and_return(true)
allow(helper).to receive(:can?).and_return(true)
expect(subject[:create_new_menu_groups]).to contain_exactly(
a_hash_including(
name: "In this group",
items: array_including(
{ href: "/projects/new", text: "New project/repository" },
{ href: "/groups/new#create-group-pane", text: "New subgroup" },
{ href: "/groups/#{group.full_path}/-/group_members", text: "Invite members" }
)
),
a_hash_including(
name: "In GitLab",
items: array_including(
{ href: "/projects/new", text: "New project/repository" },
{ href: "/groups/new", text: "New group" },
{ href: "/-/snippets/new", text: "New snippet" }
)
)
)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment