Custom updates to the project sidebar refactor

After several discussions, we decided to make some changes to the
existing project sidebar refactor:

- Removing inheritance in menu items refactor
- Renaming the menus and moving them outside of folder
parent ced9a272
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
%span.badge.badge-pill.count.fly-out-badge{ **sidebar_menu.pill_html_options } %span.badge.badge-pill.count.fly-out-badge{ **sidebar_menu.pill_html_options }
= number_with_delimiter(sidebar_menu.pill_count) = number_with_delimiter(sidebar_menu.pill_count)
- if sidebar_menu.has_renderable_items? - if sidebar_menu.has_items?
%li.divider.fly-out-top-item %li.divider.fly-out-top-item
= render partial: 'shared/nav/sidebar_menu_item', collection: sidebar_menu.renderable_items = render partial: 'shared/nav/sidebar_menu_item', collection: sidebar_menu.items
# frozen_string_literal: true
module EE
module Sidebars
module Projects
module Menus
module Repository
module Menu
extend ::Gitlab::Utils::Override
override :configure_menu_items
def configure_menu_items
super
add_item(::Sidebars::Projects::Menus::Repository::MenuItems::FileLocks.new(context))
end
end
end
end
end
end
end
# frozen_string_literal: true
module EE
module Sidebars
module Projects
module Menus
module RepositoryMenu
extend ::Gitlab::Utils::Override
override :configure_menu_items
def configure_menu_items
return false unless super
add_item(file_locks_menu_item)
true
end
private
def file_locks_menu_item
return unless context.project.licensed_feature_available?(:file_locks)
::Sidebars::MenuItem.new(
title: _('Locked Files'),
link: project_path_locks_path(context.project),
active_routes: { controller: :path_locks },
item_id: :file_locks
)
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class FileLocks < ::Sidebars::MenuItem
override :link
def link
project_path_locks_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
data: { qa_selector: 'path_locks_link' }
}
end
override :active_routes
def active_routes
{ controller: :path_locks }
end
override :title
def title
_('Locked Files')
end
override :render?
def render?
context.project.licensed_feature_available?(:file_locks)
end
end
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::RepositoryMenu do
let_it_be(:project) { create(:project, :repository) }
let(:user) { project.owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: 'master') }
describe 'File Locks' do
subject { described_class.new(context).items.index { |e| e.item_id == :file_locks} }
context 'when licensed feature file locks is not enabled' do
it 'does not include file locks menu item' do
stub_licensed_features(file_locks: false)
is_expected.to be_nil
end
end
context 'when licensed feature file locks is enabled' do
it 'includes file locks menu item' do
stub_licensed_features(file_locks: true)
is_expected.to be_present
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::Repository::MenuItems::FileLocks do
let(:project) { build(:project) }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project) }
subject { described_class.new(context) }
describe '#render?' do
before do
stub_licensed_features(file_locks: license_feature_status)
end
context 'when project has the licensed feature' do
let(:license_feature_status) { true }
it 'returns true' do
expect(subject.render?).to eq true
end
end
context 'when project does not have the licensed feature' do
let(:license_feature_status) { false }
it 'returns false' do
expect(subject.render?).to eq false
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
# This module handles elements in a list. All elements # This module handles element positions in a list.
# must have a different class
module Sidebars module Sidebars
module Concerns module Concerns
module PositionableList module PositionableList
def add_element(list, element) def add_element(list, element)
return unless element
list << element list << element
end end
def insert_element_before(list, before_element, new_element) def insert_element_before(list, before_element, new_element)
return unless new_element
index = index_of(list, before_element) index = index_of(list, before_element)
if index if index
...@@ -20,6 +23,8 @@ module Sidebars ...@@ -20,6 +23,8 @@ module Sidebars
end end
def insert_element_after(list, after_element, new_element) def insert_element_after(list, after_element, new_element)
return unless new_element
index = index_of(list, after_element) index = index_of(list, after_element)
if index if index
...@@ -31,8 +36,10 @@ module Sidebars ...@@ -31,8 +36,10 @@ module Sidebars
private private
# Classes including this method will have to define
# the way to identify elements through this method
def index_of(list, element) def index_of(list, element)
list.index { |e| e.is_a?(element) } raise NotImplementedError
end end
end end
end end
......
...@@ -13,7 +13,7 @@ module Sidebars ...@@ -13,7 +13,7 @@ module Sidebars
include ::Sidebars::Concerns::ContainerWithHtmlOptions include ::Sidebars::Concerns::ContainerWithHtmlOptions
include ::Sidebars::Concerns::HasActiveRoutes include ::Sidebars::Concerns::HasActiveRoutes
attr_reader :context attr_reader :context, :items
delegate :current_user, :container, to: :@context delegate :current_user, :container, to: :@context
def initialize(context) def initialize(context)
...@@ -24,12 +24,12 @@ module Sidebars ...@@ -24,12 +24,12 @@ module Sidebars
end end
def configure_menu_items def configure_menu_items
# No-op true
end end
override :render? override :render?
def render? def render?
@items.empty? || renderable_items.any? has_items?
end end
# Menus might have or not a link # Menus might have or not a link
...@@ -43,7 +43,7 @@ module Sidebars ...@@ -43,7 +43,7 @@ module Sidebars
# This method filters the information and returns: { path: ['foo', 'bar'], controller: :foo } # This method filters the information and returns: { path: ['foo', 'bar'], controller: :foo }
def all_active_routes def all_active_routes
@all_active_routes ||= begin @all_active_routes ||= begin
([active_routes] + renderable_items.map(&:active_routes)).flatten.each_with_object({}) do |pairs, hash| ([active_routes] + items.map(&:active_routes)).flatten.each_with_object({}) do |pairs, hash|
pairs.each do |k, v| pairs.each do |k, v|
hash[k] ||= [] hash[k] ||= []
hash[k] += Array(v) hash[k] += Array(v)
...@@ -71,12 +71,11 @@ module Sidebars ...@@ -71,12 +71,11 @@ module Sidebars
insert_element_after(@items, after_item, new_item) insert_element_after(@items, after_item, new_item)
end end
def has_renderable_items? private
renderable_items.any?
end
def renderable_items override :index_of
@renderable_items ||= @items.select(&:render?) def index_of(list, element)
list.index { |e| e.item_id == element }
end end
end end
end end
...@@ -2,20 +2,21 @@ ...@@ -2,20 +2,21 @@
module Sidebars module Sidebars
class MenuItem class MenuItem
extend ::Gitlab::Utils::Override attr_reader :title, :link, :active_routes, :item_id, :container_html_options, :sprite_icon, :sprite_icon_html_options, :hint_html_options
include ::Gitlab::Routing
include GitlabRoutingHelper
include Gitlab::Allowable
include ::Sidebars::Concerns::HasIcon
include ::Sidebars::Concerns::HasHint
include ::Sidebars::Concerns::Renderable
include ::Sidebars::Concerns::ContainerWithHtmlOptions
include ::Sidebars::Concerns::HasActiveRoutes
attr_reader :context def initialize(title:, link:, active_routes:, item_id: nil, container_html_options: {}, sprite_icon: nil, sprite_icon_html_options: {}, hint_html_options: {})
@title = title
@link = link
@active_routes = active_routes
@item_id = item_id
@container_html_options = container_html_options
@sprite_icon = sprite_icon
@sprite_icon_html_options = sprite_icon_html_options
@hint_html_options = hint_html_options
end
def initialize(context) def show_hint?
@context = context hint_html_options.present?
end end
end end
end end
...@@ -71,5 +71,12 @@ module Sidebars ...@@ -71,5 +71,12 @@ module Sidebars
def render_raw_menus_partial def render_raw_menus_partial
# No-op # No-op
end end
private
override :index_of
def index_of(list, element)
list.index { |e| e.is_a?(element) }
end
end end
end end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module LearnGitlab
class Menu < ::Sidebars::Menu
override :link
def link
project_learn_gitlab_path(context.project)
end
override :active_routes
def active_routes
{ controller: :learn_gitlab }
end
override :title
def title
_('Learn GitLab')
end
override :extra_container_html_options
def nav_link_html_options
{ class: 'home' }
end
override :sprite_icon
def sprite_icon
'home'
end
override :render?
def render?
context.learn_gitlab_experiment_enabled
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
class LearnGitlabMenu < ::Sidebars::Menu
override :link
def link
project_learn_gitlab_path(context.project)
end
override :active_routes
def active_routes
{ controller: :learn_gitlab }
end
override :title
def title
_('Learn GitLab')
end
override :extra_container_html_options
def nav_link_html_options
{ class: 'home' }
end
override :sprite_icon
def sprite_icon
'home'
end
override :render?
def render?
context.learn_gitlab_experiment_enabled
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module ProjectOverview
class Menu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
add_item(MenuItems::Details.new(context))
add_item(MenuItems::Activity.new(context))
add_item(MenuItems::Releases.new(context))
end
override :link
def link
project_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-project rspec-project-link'
}
end
override :extra_container_html_options
def nav_link_html_options
{ class: 'home' }
end
override :title
def title
_('Project overview')
end
override :sprite_icon
def sprite_icon
'home'
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module ProjectOverview
module MenuItems
class Activity < ::Sidebars::MenuItem
override :link
def link
activity_project_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-project-activity'
}
end
override :active_routes
def active_routes
{ path: 'projects#activity' }
end
override :title
def title
_('Activity')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module ProjectOverview
module MenuItems
class Details < ::Sidebars::MenuItem
override :link
def link
project_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
aria: { label: _('Project details') },
class: 'shortcuts-project'
}
end
override :active_routes
def active_routes
{ path: 'projects#show' }
end
override :title
def title
_('Details')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module ProjectOverview
module MenuItems
class Releases < ::Sidebars::MenuItem
override :link
def link
project_releases_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-project-releases'
}
end
override :render?
def render?
can?(context.current_user, :read_release, context.project) && !context.project.empty_repo?
end
override :active_routes
def active_routes
{ controller: :releases }
end
override :title
def title
_('Releases')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
class ProjectOverviewMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
add_item(details_menu_item)
add_item(activity_menu_item)
add_item(releases_menu_item)
true
end
override :link
def link
project_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-project rspec-project-link'
}
end
override :nav_link_html_options
def nav_link_html_options
{ class: 'home' }
end
override :title
def title
_('Project overview')
end
override :sprite_icon
def sprite_icon
'home'
end
private
def details_menu_item
::Sidebars::MenuItem.new(
title: _('Details'),
link: project_path(context.project),
active_routes: { path: 'projects#show' },
item_id: :project_overview,
container_html_options: {
aria: { label: _('Project details') },
class: 'shortcuts-project'
}
)
end
def activity_menu_item
::Sidebars::MenuItem.new(
title: _('Activity'),
link: activity_project_path(context.project),
active_routes: { path: 'projects#activity' },
item_id: :activity,
container_html_options: { class: 'shortcuts-project-activity' }
)
end
def releases_menu_item
return unless can?(context.current_user, :read_release, context.project)
return if context.project.empty_repo?
::Sidebars::MenuItem.new(
title: _('Releases'),
link: project_releases_path(context.project),
item_id: :releases,
active_routes: { controller: :releases },
container_html_options: { class: 'shortcuts-project-releases' }
)
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
class Menu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
add_item(MenuItems::Files.new(context))
add_item(MenuItems::Commits.new(context))
add_item(MenuItems::Branches.new(context))
add_item(MenuItems::Tags.new(context))
add_item(MenuItems::Contributors.new(context))
add_item(MenuItems::Graphs.new(context))
add_item(MenuItems::Compare.new(context))
end
override :link
def link
project_tree_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-tree'
}
end
override :title
def title
_('Repository')
end
override :title_html_options
def title_html_options
{
id: 'js-onboarding-repo-link'
}
end
override :sprite_icon
def sprite_icon
'doc-text'
end
override :render?
def render?
can?(context.current_user, :download_code, context.project) &&
!context.project.empty_repo?
end
end
end
end
end
end
Sidebars::Projects::Menus::Repository::Menu.prepend_if_ee('EE::Sidebars::Projects::Menus::Repository::Menu')
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Branches < ::Sidebars::MenuItem
override :link
def link
project_branches_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
id: 'js-onboarding-branches-link'
}
end
override :active_routes
def active_routes
{ controller: :branches }
end
override :title
def title
_('Branches')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Commits < ::Sidebars::MenuItem
override :link
def link
project_commits_path(context.project, context.current_ref)
end
override :extra_container_html_options
def extra_container_html_options
{
id: 'js-onboarding-commits-link'
}
end
override :active_routes
def active_routes
{ controller: %w(commit commits) }
end
override :title
def title
_('Commits')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Compare < ::Sidebars::MenuItem
override :link
def link
project_compare_index_path(context.project, from: context.project.repository.root_ref, to: context.current_ref)
end
override :active_routes
def active_routes
{ controller: :compare }
end
override :title
def title
_('Compare')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Contributors < ::Sidebars::MenuItem
override :link
def link
project_graph_path(context.project, context.current_ref)
end
override :active_routes
def active_routes
{ path: 'graphs#show' }
end
override :title
def title
_('Contributors')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Files < ::Sidebars::MenuItem
override :link
def link
project_tree_path(context.project, context.current_ref)
end
override :active_routes
def active_routes
{ controller: %w[tree blob blame edit_tree new_tree find_file] }
end
override :title
def title
_('Files')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Graphs < ::Sidebars::MenuItem
override :link
def link
project_network_path(context.project, context.current_ref)
end
override :active_routes
def active_routes
{ controller: :network }
end
override :title
def title
_('Graph')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Repository
module MenuItems
class Tags < ::Sidebars::MenuItem
override :link
def link
project_tags_path(context.project)
end
override :active_routes
def active_routes
{ controller: :tags }
end
override :title
def title
_('Tags')
end
end
end
end
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
class RepositoryMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
return false unless can?(context.current_user, :download_code, context.project)
return false if context.project.empty_repo?
add_item(files_menu_item)
add_item(commits_menu_item)
add_item(branches_menu_item)
add_item(tags_menu_item)
add_item(contributors_menu_item)
add_item(graphs_menu_item)
add_item(compare_menu_item)
true
end
override :link
def link
project_tree_path(context.project)
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-tree'
}
end
override :title
def title
_('Repository')
end
override :title_html_options
def title_html_options
{
id: 'js-onboarding-repo-link'
}
end
override :sprite_icon
def sprite_icon
'doc-text'
end
private
def files_menu_item
::Sidebars::MenuItem.new(
title: _('Files'),
link: project_tree_path(context.project, context.current_ref),
active_routes: { controller: %w[tree blob blame edit_tree new_tree find_file] },
item_id: :files
)
end
def commits_menu_item
::Sidebars::MenuItem.new(
title: _('Commits'),
link: project_commits_path(context.project, context.current_ref),
active_routes: { controller: %w(commit commits) },
item_id: :commits,
container_html_options: { id: 'js-onboarding-commits-link' }
)
end
def branches_menu_item
::Sidebars::MenuItem.new(
title: _('Branches'),
link: project_branches_path(context.project),
active_routes: { controller: :branches },
item_id: :branches,
container_html_options: { id: 'js-onboarding-branches-link' }
)
end
def tags_menu_item
::Sidebars::MenuItem.new(
title: _('Tags'),
link: project_tags_path(context.project),
item_id: :tags,
active_routes: { controller: :tags }
)
end
def contributors_menu_item
::Sidebars::MenuItem.new(
title: _('Contributors'),
link: project_graph_path(context.project, context.current_ref),
active_routes: { path: 'graphs#show' },
item_id: :contributors
)
end
def graphs_menu_item
::Sidebars::MenuItem.new(
title: _('Graph'),
link: project_network_path(context.project, context.current_ref),
active_routes: { controller: :network },
item_id: :graphs
)
end
def compare_menu_item
::Sidebars::MenuItem.new(
title: _('Compare'),
link: project_compare_index_path(context.project, from: context.project.repository.root_ref, to: context.current_ref),
active_routes: { controller: :compare },
item_id: :compare
)
end
end
end
end
end
Sidebars::Projects::Menus::RepositoryMenu.prepend_if_ee('EE::Sidebars::Projects::Menus::RepositoryMenu')
...@@ -3,17 +3,15 @@ ...@@ -3,17 +3,15 @@
module Sidebars module Sidebars
module Projects module Projects
module Menus module Menus
module Scope class ScopeMenu < ::Sidebars::Menu
class Menu < ::Sidebars::Menu override :link
override :link def link
def link project_path(context.project)
project_path(context.project) end
end
override :title override :title
def title def title
context.project.name context.project.name
end
end end
end end
end end
......
...@@ -5,11 +5,11 @@ module Sidebars ...@@ -5,11 +5,11 @@ module Sidebars
class Panel < ::Sidebars::Panel class Panel < ::Sidebars::Panel
override :configure_menus override :configure_menus
def configure_menus def configure_menus
set_scope_menu(Sidebars::Projects::Menus::Scope::Menu.new(context)) set_scope_menu(Sidebars::Projects::Menus::ScopeMenu.new(context))
add_menu(Sidebars::Projects::Menus::ProjectOverview::Menu.new(context)) add_menu(Sidebars::Projects::Menus::ProjectOverviewMenu.new(context))
add_menu(Sidebars::Projects::Menus::LearnGitlab::Menu.new(context)) add_menu(Sidebars::Projects::Menus::LearnGitlabMenu.new(context))
add_menu(Sidebars::Projects::Menus::Repository::Menu.new(context)) add_menu(Sidebars::Projects::Menus::RepositoryMenu.new(context))
end end
override :render_raw_menus_partial override :render_raw_menus_partial
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Concerns::PositionableList do
subject do
Class.new do
include Sidebars::Concerns::PositionableList
end.new
end
describe '#add_element' do
it 'adds the element to the last position of the list' do
list = [1, 2]
subject.add_element(list, 3)
expect(list).to eq([1, 2, 3])
end
end
describe '#insert_element_before' do
let(:user) { build(:user) }
let(:list) { [1, user] }
it 'adds element before the specific element class' do
subject.insert_element_before(list, User, 2)
expect(list).to eq [1, 2, user]
end
context 'when reference element does not exist' do
it 'adds the element to the top of the list' do
subject.insert_element_before(list, Project, 2)
expect(list).to eq [2, 1, user]
end
end
end
describe '#insert_element_after' do
let(:user) { build(:user) }
let(:list) { [1, user] }
it 'adds element after the specific element class' do
subject.insert_element_after(list, Integer, 2)
expect(list).to eq [1, 2, user]
end
context 'when reference element does not exist' do
it 'adds the element to the end of the list' do
subject.insert_element_after(list, Project, 2)
expect(list).to eq [1, user, 2]
end
end
end
end
...@@ -8,59 +8,82 @@ RSpec.describe Sidebars::Menu do ...@@ -8,59 +8,82 @@ RSpec.describe Sidebars::Menu do
describe '#all_active_routes' do describe '#all_active_routes' do
it 'gathers all active routes of items and the current menu' do it 'gathers all active routes of items and the current menu' do
menu_item1 = Sidebars::MenuItem.new(context) menu.add_item(Sidebars::MenuItem.new(title: 'foo1', link: 'foo1', active_routes: { path: %w(bar test) }))
menu_item2 = Sidebars::MenuItem.new(context) menu.add_item(Sidebars::MenuItem.new(title: 'foo2', link: 'foo2', active_routes: { controller: 'fooc' }))
menu_item3 = Sidebars::MenuItem.new(context) menu.add_item(Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: { controller: 'barc' }))
menu.add_item(menu_item1)
menu.add_item(menu_item2)
menu.add_item(menu_item3)
allow(menu).to receive(:active_routes).and_return({ path: 'foo' }) allow(menu).to receive(:active_routes).and_return({ path: 'foo' })
allow(menu_item1).to receive(:active_routes).and_return({ path: %w(bar test) })
allow(menu_item2).to receive(:active_routes).and_return({ controller: 'fooc' })
allow(menu_item3).to receive(:active_routes).and_return({ controller: 'barc' })
expect(menu.all_active_routes).to eq({ path: %w(foo bar test), controller: %w(fooc barc) }) expect(menu.all_active_routes).to eq({ path: %w(foo bar test), controller: %w(fooc barc) })
end end
it 'does not include routes for non renderable items' do
menu_item = Sidebars::MenuItem.new(context)
menu.add_item(menu_item)
allow(menu).to receive(:active_routes).and_return({ path: 'foo' })
allow(menu_item).to receive(:render?).and_return(false)
allow(menu_item).to receive(:active_routes).and_return({ controller: 'bar' })
expect(menu.all_active_routes).to eq({ path: ['foo'] })
end
end end
describe '#render?' do describe '#render?' do
context 'when the menus has no items' do context 'when the menus has no items' do
it 'returns true' do it 'returns false' do
expect(menu.render?).to be true expect(menu.render?).to be false
end end
end end
context 'when the menu has items' do context 'when the menu has items' do
let(:menu_item) { Sidebars::MenuItem.new(context) } it 'returns true' do
menu.add_item(Sidebars::MenuItem.new(title: 'foo1', link: 'foo1', active_routes: {}))
before do expect(menu.render?).to be true
menu.add_item(menu_item)
end end
end
end
describe '#insert_element_before' do
let(:item1) { Sidebars::MenuItem.new(title: 'foo1', link: 'foo1', active_routes: {}, item_id: :foo1) }
let(:item2) { Sidebars::MenuItem.new(title: 'foo2', link: 'foo2', active_routes: {}, item_id: :foo2) }
let(:item3) { Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: {}, item_id: :foo3) }
let(:list) { [item1, item2] }
it 'adds element before the specific element class' do
menu.insert_element_before(list, :foo2, item3)
expect(list).to eq [item1, item3, item2]
end
it 'does not add nil elements' do
menu.insert_element_before(list, :foo2, nil)
expect(list).to eq [item1, item2]
end
context 'when items are not renderable' do context 'when reference element does not exist' do
it 'returns false' do it 'adds the element to the top of the list' do
allow(menu_item).to receive(:render?).and_return(false) menu.insert_element_before(list, :non_existent, item3)
expect(menu.render?).to be false expect(list).to eq [item3, item1, item2]
end
end end
end
end
describe '#insert_element_after' do
let(:item1) { Sidebars::MenuItem.new(title: 'foo1', link: 'foo1', active_routes: {}, item_id: :foo1) }
let(:item2) { Sidebars::MenuItem.new(title: 'foo2', link: 'foo2', active_routes: {}, item_id: :foo2) }
let(:item3) { Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: {}, item_id: :foo3) }
let(:list) { [item1, item2] }
it 'adds element after the specific element class' do
menu.insert_element_after(list, :foo1, item3)
expect(list).to eq [item1, item3, item2]
end
it 'does not add nil elements' do
menu.insert_element_after(list, :foo1, nil)
expect(list).to eq [item1, item2]
end
context 'when reference element does not exist' do
it 'adds the element to the end of the list' do
menu.insert_element_after(list, :non_existent, item3)
context 'when there are renderable items' do expect(list).to eq [item1, item2, item3]
it 'returns true' do
expect(menu.render?).to be true
end
end end
end end
end end
......
...@@ -26,9 +26,79 @@ RSpec.describe Sidebars::Panel do ...@@ -26,9 +26,79 @@ RSpec.describe Sidebars::Panel do
end end
it 'returns true when no renderable menus' do it 'returns true when no renderable menus' do
allow(menu1).to receive(:render?).and_return(true)
panel.add_menu(menu1) panel.add_menu(menu1)
expect(panel.has_renderable_menus?).to be true expect(panel.has_renderable_menus?).to be true
end end
end end
describe '#add_element' do
it 'adds the element to the last position of the list' do
list = [1, 2]
panel.add_element(list, 3)
expect(list).to eq([1, 2, 3])
end
it 'does not add nil elements' do
list = []
panel.add_element(list, nil)
expect(list).to be_empty
end
end
describe '#insert_element_before' do
let(:user) { build(:user) }
let(:list) { [1, user] }
it 'adds element before the specific element class' do
panel.insert_element_before(list, User, 2)
expect(list).to eq [1, 2, user]
end
it 'does not add nil elements' do
panel.insert_element_before(list, User, nil)
expect(list).to eq [1, user]
end
context 'when reference element does not exist' do
it 'adds the element to the top of the list' do
panel.insert_element_before(list, Project, 2)
expect(list).to eq [2, 1, user]
end
end
end
describe '#insert_element_after' do
let(:user) { build(:user) }
let(:list) { [1, user] }
it 'adds element after the specific element class' do
panel.insert_element_after(list, Integer, 2)
expect(list).to eq [1, 2, user]
end
it 'does not add nil elements' do
panel.insert_element_after(list, Integer, nil)
expect(list).to eq [1, user]
end
context 'when reference element does not exist' do
it 'adds the element to the end of the list' do
panel.insert_element_after(list, Project, 2)
expect(list).to eq [1, user, 2]
end
end
end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::LearnGitlab::Menu do RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do
let(:project) { build(:project) } let(:project) { build(:project) }
let(:experiment_enabled) { true } let(:experiment_enabled) { true }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project, learn_gitlab_experiment_enabled: experiment_enabled) } let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project, learn_gitlab_experiment_enabled: experiment_enabled) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::ProjectOverview::Menu do
let(:project) { build(:project) }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project) }
subject { described_class.new(context) }
it 'has the required items' do
items = subject.instance_variable_get(:@items)
expect(items[0]).to be_a(Sidebars::Projects::Menus::ProjectOverview::MenuItems::Details)
expect(items[1]).to be_a(Sidebars::Projects::Menus::ProjectOverview::MenuItems::Activity)
expect(items[2]).to be_a(Sidebars::Projects::Menus::ProjectOverview::MenuItems::Releases)
end
end
...@@ -2,35 +2,35 @@ ...@@ -2,35 +2,35 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::ProjectOverview::MenuItems::Releases do RSpec.describe Sidebars::Projects::Menus::ProjectOverviewMenu do
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
let(:user) { project.owner } let(:user) { project.owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
subject { described_class.new(context) } describe 'Releases' do
subject { described_class.new(context).items.index { |e| e.item_id == :releases } }
describe '#render?' do
context 'when project repository is empty' do context 'when project repository is empty' do
it 'returns false' do it 'does not include releases menu item' do
allow(project).to receive(:empty_repo?).and_return(true) allow(project).to receive(:empty_repo?).and_return(true)
expect(subject.render?).to eq false is_expected.to be_nil
end end
end end
context 'when project repository is not empty' do context 'when project repository is not empty' do
context 'when user can read releases' do context 'when user can download code' do
it 'returns true' do it 'includes releases menu item' do
expect(subject.render?).to eq true is_expected.to be_present
end end
end end
context 'when user cannot read releases' do context 'when user cannot download code' do
let(:user) { nil } let(:user) { nil }
it 'returns false' do it 'does not include releases menu item' do
expect(subject.render?).to eq false is_expected.to be_nil
end end
end end
end end
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::Repository::Menu do RSpec.describe Sidebars::Projects::Menus::RepositoryMenu do
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
let(:user) { project.owner } let(:user) { project.owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: 'master') }
subject { described_class.new(context) } subject { described_class.new(context) }
......
...@@ -9,6 +9,6 @@ RSpec.describe Sidebars::Projects::Panel do ...@@ -9,6 +9,6 @@ RSpec.describe Sidebars::Projects::Panel do
subject { described_class.new(context) } subject { described_class.new(context) }
it 'has a scope menu' do it 'has a scope menu' do
expect(subject.scope_menu).to be_a(Sidebars::Projects::Menus::Scope::Menu) expect(subject.scope_menu).to be_a(Sidebars::Projects::Menus::ScopeMenu)
end end
end end
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'shared/nav/_sidebar.html.haml' do RSpec.describe 'shared/nav/_sidebar.html.haml' do
let(:project) { build(:project, id: non_existing_record_id) } let(:project) { build(:project, id: non_existing_record_id) }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project)} let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project) }
let(:sidebar) { Sidebars::Projects::Panel.new(context) } let(:sidebar) { Sidebars::Projects::Panel.new(context) }
before do before 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