Commit bcdde2a1 authored by Dmitry Gruzd's avatar Dmitry Gruzd

Merge branch '301143-part-3-finish-top-nav-view-model' into 'master'

TopNavRedesign: Finish migrating to top_nav_view_model

See merge request gitlab-org/gitlab!60420
parents 1c2eff2b 35926446
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
module Nav module Nav
module TopNavHelper module TopNavHelper
PROJECTS_VIEW = :projects PROJECTS_VIEW = :projects
GROUPS_VIEW = :groups
def top_nav_view_model(project:) def top_nav_view_model(project:, group:)
builder = ::Gitlab::Nav::TopNavViewModelBuilder.new builder = ::Gitlab::Nav::TopNavViewModelBuilder.new
if current_user if current_user
build_view_model(builder: builder, project: project) build_view_model(builder: builder, project: project, group: group)
else else
build_anonymous_view_model(builder: builder) build_anonymous_view_model(builder: builder)
end end
...@@ -20,32 +21,65 @@ module Nav ...@@ -20,32 +21,65 @@ module Nav
def build_anonymous_view_model(builder:) def build_anonymous_view_model(builder:)
# These come from `app/views/layouts/nav/_explore.html.ham` # These come from `app/views/layouts/nav/_explore.html.ham`
# TODO: We will move the rest of them shortly
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56587
if explore_nav_link?(:projects) if explore_nav_link?(:projects)
builder.add_primary_menu_item( builder.add_primary_menu_item(
**projects_menu_item_attrs.merge({ **projects_menu_item_attrs.merge(
active: active_nav_link?(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index']), {
href: explore_root_path active: active_nav_link?(path: %w[dashboard#show root#show projects#trending projects#starred projects#index]),
}) href: explore_root_path
})
)
end
if explore_nav_link?(:groups)
builder.add_primary_menu_item(
**groups_menu_item_attrs.merge(
{
active: active_nav_link?(controller: [:groups, 'groups/milestones', 'groups/group_members']),
href: explore_groups_path
})
)
end
if explore_nav_link?(:snippets)
builder.add_primary_menu_item(
**snippets_menu_item_attrs.merge(
{
active: active_nav_link?(controller: :snippets),
href: explore_snippets_path
})
) )
end end
end end
def build_view_model(builder:, project:) def build_view_model(builder:, project:, group:)
# These come from `app/views/layouts/nav/_dashboard.html.haml` # These come from `app/views/layouts/nav/_dashboard.html.haml`
if dashboard_nav_link?(:projects) if dashboard_nav_link?(:projects)
current_item = project ? current_project(project: project) : {} current_item = project ? current_project(project: project) : {}
builder.add_primary_menu_item( builder.add_primary_menu_item(
**projects_menu_item_attrs.merge({ **projects_menu_item_attrs.merge({
active: active_nav_link?(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index']), active: active_nav_link?(path: %w[root#index projects#trending projects#starred dashboard/projects#index]),
css_class: 'qa-projects-dropdown', css_class: 'qa-projects-dropdown',
data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" }, data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" },
view: PROJECTS_VIEW view: PROJECTS_VIEW
}) })
) )
builder.add_view(PROJECTS_VIEW, container_view_props(current_item: current_item, submenu: projects_submenu)) builder.add_view(PROJECTS_VIEW, container_view_props(namespace: 'projects', current_item: current_item, submenu: projects_submenu))
end
if dashboard_nav_link?(:groups)
current_item = group ? current_group(group: group) : {}
builder.add_primary_menu_item(
**groups_menu_item_attrs.merge({
active: active_nav_link?(path: %w[dashboard/groups explore/groups]),
css_class: 'qa-groups-dropdown',
data: { track_label: "groups_dropdown", track_event: "click_dropdown" },
view: GROUPS_VIEW
})
)
builder.add_view(GROUPS_VIEW, container_view_props(namespace: 'groups', current_item: current_item, submenu: groups_submenu))
end end
if dashboard_nav_link?(:milestones) if dashboard_nav_link?(:milestones)
...@@ -59,6 +93,27 @@ module Nav ...@@ -59,6 +93,27 @@ module Nav
) )
end end
if dashboard_nav_link?(:snippets)
builder.add_primary_menu_item(
**snippets_menu_item_attrs.merge({
active: active_nav_link?(controller: 'dashboard/snippets'),
data: { qa_selector: 'snippets_link' },
href: dashboard_snippets_path
})
)
end
if dashboard_nav_link?(:activity)
builder.add_primary_menu_item(
id: 'activity',
title: 'Activity',
active: active_nav_link?(path: 'dashboard#activity'),
icon: 'history',
data: { qa_selector: 'activity_link' },
href: activity_dashboard_path
)
end
# Using admin? is generally discouraged because it does not check for # Using admin? is generally discouraged because it does not check for
# "admin_mode". In this case we are migrating code and check both, so # "admin_mode". In this case we are migrating code and check both, so
# we should be good. # we should be good.
...@@ -95,6 +150,15 @@ module Nav ...@@ -95,6 +150,15 @@ module Nav
end end
end end
# rubocop: enable Cop/UserAdmin # rubocop: enable Cop/UserAdmin
if Gitlab::Sherlock.enabled?
builder.add_secondary_menu_item(
id: 'sherlock',
title: _('Sherlock Transactions'),
icon: 'admin',
href: sherlock_transactions_path
)
end
end end
def projects_menu_item_attrs def projects_menu_item_attrs
...@@ -105,9 +169,25 @@ module Nav ...@@ -105,9 +169,25 @@ module Nav
} }
end end
def container_view_props(current_item:, submenu:) def groups_menu_item_attrs
{ {
namespace: 'projects', id: 'groups',
title: 'Groups',
icon: 'group'
}
end
def snippets_menu_item_attrs
{
id: 'snippets',
title: _('Snippets'),
icon: 'snippet'
}
end
def container_view_props(namespace:, current_item:, submenu:)
{
namespace: namespace,
currentUserName: current_user&.username, currentUserName: current_user&.username,
currentItem: current_item, currentItem: current_item,
linksPrimary: submenu[:primary], linksPrimary: submenu[:primary],
...@@ -127,6 +207,18 @@ module Nav ...@@ -127,6 +207,18 @@ module Nav
} }
end end
def current_group(group:)
return {} unless group.persisted?
{
id: group.id,
name: group.name,
namespace: group.full_name,
webUrl: group_path(group),
avatarUrl: group.avatar_url
}
end
def projects_submenu def projects_submenu
# These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml` # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new builder = ::Gitlab::Nav::TopNavMenuBuilder.new
...@@ -136,6 +228,15 @@ module Nav ...@@ -136,6 +228,15 @@ module Nav
builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path) builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path)
builder.build builder.build
end end
def groups_submenu
# These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new
builder.add_primary_menu_item(id: 'your', title: _('Your groups'), href: dashboard_groups_path)
builder.add_primary_menu_item(id: 'explore', title: _('Explore groups'), href: explore_groups_path)
builder.add_secondary_menu_item(id: 'create', title: _('Create group'), href: new_group_path(anchor: 'create-group-pane'))
builder.build
end
end end
end end
......
...@@ -8,7 +8,7 @@ module EE ...@@ -8,7 +8,7 @@ module EE
private private
override :build_view_model override :build_view_model
def build_view_model(builder:, project:) def build_view_model(builder:, project:, group:)
super super
# These come from `ee/app/views/dashboard/_nav_link_list.html.haml` # These come from `ee/app/views/dashboard/_nav_link_list.html.haml`
......
...@@ -14,7 +14,7 @@ RSpec.describe Nav::TopNavHelper do ...@@ -14,7 +14,7 @@ RSpec.describe Nav::TopNavHelper do
let(:with_geo_secondary) { false } let(:with_geo_secondary) { false }
let(:with_geo_primary_node_configured) { false } let(:with_geo_primary_node_configured) { false }
let(:subject) { helper.top_nav_view_model(project: nil) } let(:subject) { helper.top_nav_view_model(project: nil, group: nil) }
before do before do
allow(helper).to receive(:current_user) { current_user } allow(helper).to receive(:current_user) { current_user }
......
...@@ -11,12 +11,17 @@ RSpec.describe Nav::TopNavHelper do ...@@ -11,12 +11,17 @@ RSpec.describe Nav::TopNavHelper do
let(:current_user) { nil } let(:current_user) { nil }
let(:current_project) { nil } let(:current_project) { nil }
let(:current_group) { nil }
let(:with_current_settings_admin_mode) { false } let(:with_current_settings_admin_mode) { false }
let(:with_header_link_admin_mode) { false } let(:with_header_link_admin_mode) { false }
let(:with_sherlock_enabled) { false }
let(:with_projects) { false } let(:with_projects) { false }
let(:with_groups) { false }
let(:with_milestones) { false } let(:with_milestones) { false }
let(:with_snippets) { false }
let(:with_activity) { false }
let(:subject) { helper.top_nav_view_model(project: current_project) } let(:subject) { helper.top_nav_view_model(project: current_project, group: current_group) }
let(:active_title) { 'Menu' } let(:active_title) { 'Menu' }
...@@ -24,13 +29,17 @@ RSpec.describe Nav::TopNavHelper do ...@@ -24,13 +29,17 @@ RSpec.describe Nav::TopNavHelper do
allow(helper).to receive(:current_user) { current_user } allow(helper).to receive(:current_user) { current_user }
allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode } allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode }
allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode } allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode }
allow(Gitlab::Sherlock).to receive(:enabled?) { with_sherlock_enabled }
# Defaulting all `dashboard_nav_link?` calls to false ensures the EE-specific behavior # Defaulting all `dashboard_nav_link?` calls to false ensures the EE-specific behavior
# is not enabled in this CE spec # is not enabled in this CE spec
allow(helper).to receive(:dashboard_nav_link?).with(anything) { false } allow(helper).to receive(:dashboard_nav_link?).with(anything) { false }
allow(helper).to receive(:dashboard_nav_link?).with(:projects) { with_projects } allow(helper).to receive(:dashboard_nav_link?).with(:projects) { with_projects }
allow(helper).to receive(:dashboard_nav_link?).with(:groups) { with_groups }
allow(helper).to receive(:dashboard_nav_link?).with(:milestones) { with_milestones } allow(helper).to receive(:dashboard_nav_link?).with(:milestones) { with_milestones }
allow(helper).to receive(:dashboard_nav_link?).with(:snippets) { with_snippets }
allow(helper).to receive(:dashboard_nav_link?).with(:activity) { with_activity }
end end
it 'has :activeTitle' do it 'has :activeTitle' do
...@@ -39,13 +48,30 @@ RSpec.describe Nav::TopNavHelper do ...@@ -39,13 +48,30 @@ RSpec.describe Nav::TopNavHelper do
context 'when current_user is nil (anonymous)' do context 'when current_user is nil (anonymous)' do
it 'has expected :primary' do it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build( expected_projects_item = ::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore', href: '/explore',
icon: 'project', icon: 'project',
id: 'project', id: 'project',
title: 'Projects' title: 'Projects'
) )
expect(subject[:primary]).to eq([expected_primary]) expected_groups_item = ::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore/groups',
icon: 'group',
id: 'groups',
title: 'Groups'
)
expected_snippets_item = ::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore/snippets',
icon: 'snippet',
id: 'snippets',
title: 'Snippets'
)
expect(subject[:primary])
.to eq([
expected_projects_item,
expected_groups_item,
expected_snippets_item
])
end end
end end
...@@ -124,7 +150,7 @@ RSpec.describe Nav::TopNavHelper do ...@@ -124,7 +150,7 @@ RSpec.describe Nav::TopNavHelper do
let_it_be(:project) { build_stubbed(:project) } let_it_be(:project) { build_stubbed(:project) }
let(:current_project) { project } let(:current_project) { project }
let(:avatar_url) { 'avatar_url' } let(:avatar_url) { 'project_avatar_url' }
before do before do
allow(project).to receive(:persisted?) { true } allow(project).to receive(:persisted?) { true }
...@@ -146,6 +172,87 @@ RSpec.describe Nav::TopNavHelper do ...@@ -146,6 +172,87 @@ RSpec.describe Nav::TopNavHelper do
end end
end end
context 'with groups' do
let(:with_groups) { true }
let(:groups_view) { subject[:views][:groups] }
it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
css_class: 'qa-groups-dropdown',
data: {
track_event: 'click_dropdown',
track_label: 'groups_dropdown'
},
icon: 'group',
id: 'groups',
title: 'Groups',
view: 'groups'
)
expect(subject[:primary]).to eq([expected_primary])
end
context 'groups' do
it 'has expected :currentUserName' do
expect(groups_view[:currentUserName]).to eq(current_user.username)
end
it 'has expected :namespace' do
expect(groups_view[:namespace]).to eq('groups')
end
it 'has expected :linksPrimary' do
expected_links_primary = [
::Gitlab::Nav::TopNavMenuItem.build(
href: '/dashboard/groups',
id: 'your',
title: 'Your groups'
),
::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore/groups',
id: 'explore',
title: 'Explore groups'
)
]
expect(groups_view[:linksPrimary]).to eq(expected_links_primary)
end
it 'has expected :linksSecondary' do
expected_links_secondary = [
::Gitlab::Nav::TopNavMenuItem.build(
href: '/groups/new#create-group-pane',
id: 'create',
title: 'Create group'
)
]
expect(groups_view[:linksSecondary]).to eq(expected_links_secondary)
end
context 'with persisted group' do
let_it_be(:group) { build_stubbed(:group) }
let(:current_group) { group }
let(:avatar_url) { 'group_avatar_url' }
before do
allow(group).to receive(:persisted?) { true }
allow(group).to receive(:avatar_url) { avatar_url }
end
it 'has expected :container' do
expected_container = {
avatarUrl: avatar_url,
id: group.id,
name: group.name,
namespace: group.full_name,
webUrl: group_path(group)
}
expect(groups_view[:currentItem]).to eq(expected_container)
end
end
end
end
context 'with milestones' do context 'with milestones' do
let(:with_milestones) { true } let(:with_milestones) { true }
...@@ -162,6 +269,61 @@ RSpec.describe Nav::TopNavHelper do ...@@ -162,6 +269,61 @@ RSpec.describe Nav::TopNavHelper do
expect(subject[:primary]).to eq([expected_primary]) expect(subject[:primary]).to eq([expected_primary])
end end
end end
context 'with snippets' do
let(:with_snippets) { true }
it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'snippets_link'
},
href: '/dashboard/snippets',
icon: 'snippet',
id: 'snippets',
title: 'Snippets'
)
expect(subject[:primary]).to eq([expected_primary])
end
end
context 'with activity' do
let(:with_activity) { true }
it 'has expected :primary' do
expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
data: {
qa_selector: 'activity_link'
},
href: '/dashboard/activity',
icon: 'history',
id: 'activity',
title: 'Activity'
)
expect(subject[:primary]).to eq([expected_primary])
end
end
context 'when sherlock is enabled' do
let(:with_sherlock_enabled) { true }
before do
# Note: We have to mock the sherlock route because the route is conditional on
# sherlock being enabled, but it parsed at Rails load time and can't be overridden
# in a spec.
allow(helper).to receive(:sherlock_transactions_path) { '/fake_sherlock_path' }
end
it 'has sherlock as last :secondary item' do
expected_sherlock_item = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'sherlock',
title: 'Sherlock Transactions',
icon: 'admin',
href: '/fake_sherlock_path'
)
expect(subject[:secondary].last).to eq(expected_sherlock_item)
end
end
end end
context 'when current_user is admin' do context 'when current_user is admin' do
......
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