Commit 31ecdedd authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '328504-fj-add-epics-menu' into 'master'

Add Epics menu

See merge request gitlab-org/gitlab!65829
parents 36a4862b 437db4bf
- issues_count = cached_issuables_count(@group, type: :issues) - issues_count = cached_issuables_count(@group, type: :issues)
- merge_requests_count = cached_issuables_count(@group, type: :merge_requests) - merge_requests_count = cached_issuables_count(@group, type: :merge_requests)
= render_if_exists "layouts/nav/ee/epic_link", group: @group
- if group_sidebar_link?(:issues) - if group_sidebar_link?(:issues)
= nav_link(path: group_issues_sub_menu_items, unless: -> { current_path?('issues_analytics#show') }) do = nav_link(path: group_issues_sub_menu_items, unless: -> { current_path?('issues_analytics#show') }) do
= link_to issues_group_path(@group), data: { qa_selector: 'group_issues_item' }, class: 'has-sub-items' do = link_to issues_group_path(@group), data: { qa_selector: 'group_issues_item' }, class: 'has-sub-items' do
......
- return unless group_sidebar_link?(:epics)
- epics_count = cached_issuables_count(group, type: :epics)
- epics_items = ['epics#show', 'epics#index', 'epic_boards#index', 'epic_boards#show', 'roadmap#show']
= nav_link(path: epics_items) do
= link_to group_epics_path(group), class: 'qa-group-epics-link has-sub-items' do
.nav-icon-container
= sprite_icon('epic')
%span.nav-item-name
= _('Epics')
%span.badge.badge-pill.count= number_with_delimiter(epics_count)
%ul.sidebar-sub-level-items
= nav_link(path: epics_items, html_options: { class: "fly-out-top-item" } ) do
= link_to group_epics_path(group) do
%strong.fly-out-top-item-name= _('Epics')
%span.badge.badge-pill.count.epic_counter.fly-out-badge= number_with_delimiter(epics_count)
%li.divider.fly-out-top-item
= nav_link(path: 'epics#index', html_options: { class: 'home' }) do
= link_to group_epics_path(group), title: 'List' do
%span= _('List')
= nav_link(path: ['epic_boards#index', 'epic_boards#show'], html_options: { class: "home" }) do
= link_to group_epic_boards_path(group), title: 'Boards' do
%span= _('Boards')
= nav_link(path: 'roadmap#show', html_options: { class: 'home' }) do
= link_to group_roadmap_path(group), title: 'Roadmap' do
%span= _('Roadmap')
...@@ -11,6 +11,7 @@ module EE ...@@ -11,6 +11,7 @@ module EE
super super
insert_menu_before(::Sidebars::Groups::Menus::GroupInformationMenu, ::Sidebars::Groups::Menus::TrialExperimentMenu.new(context)) insert_menu_before(::Sidebars::Groups::Menus::GroupInformationMenu, ::Sidebars::Groups::Menus::TrialExperimentMenu.new(context))
insert_menu_after(::Sidebars::Groups::Menus::GroupInformationMenu, ::Sidebars::Groups::Menus::EpicsMenu.new(context))
end end
end end
end end
......
# frozen_string_literal: true
module Sidebars
module Groups
module Menus
class EpicsMenu < ::Sidebars::Menu
include Gitlab::Utils::StrongMemoize
override :configure_menu_items
def configure_menu_items
return false unless can?(context.current_user, :read_epic, context.group)
add_item(epic_list_menu_item)
add_item(boards_menu_item)
add_item(roadmap_menu_item)
true
end
override :link
def link
renderable_items.first.link
end
override :title
def title
_('Epics')
end
override :sprite_icon
def sprite_icon
'epic'
end
override :active_routes
def active_routes
{ controller: :epics }
end
override :has_pill?
def has_pill?
true
end
override :pill_count
def pill_count
strong_memoize(:pill_count) do
count_service = ::Groups::EpicsCountService
count = count_service.new(context.group, context.current_user).count
format_cached_count(count_service, count)
end
end
private
def epic_list_menu_item
::Sidebars::MenuItem.new(
title: _('List'),
link: group_epics_path(context.group),
active_routes: { path: 'epics#index' },
container_html_options: { class: 'home' },
item_id: :epic_list
)
end
def boards_menu_item
::Sidebars::MenuItem.new(
title: _('Boards'),
link: group_epic_boards_path(context.group),
active_routes: { path: %w[epic_boards#index epic_boards#show] },
container_html_options: { class: 'home' },
item_id: :boards
)
end
def roadmap_menu_item
::Sidebars::MenuItem.new(
title: _('Roadmap'),
link: group_roadmap_path(context.group),
active_routes: { path: 'roadmap#show' },
container_html_options: { class: 'home' },
item_id: :roadmap
)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Groups::Menus::EpicsMenu do
let_it_be(:owner) { create(:user) }
let_it_be(:group) do
build(:group, :private).tap do |g|
g.add_owner(owner)
end
end
let(:user) { owner }
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
let(:menu) { described_class.new(context) }
describe 'Menu Items' do
subject { menu.renderable_items }
before do
stub_licensed_features(epics: true)
end
describe 'when the user has access to epics' do
it 'has all the menus' do
expect(subject.map(&:item_id)).to include(:epic_list, :boards, :roadmap)
end
end
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_empty }
end
end
it_behaves_like 'pill_count formatted results' do
let(:count_service) { ::Groups::EpicsCountService }
end
end
...@@ -76,6 +76,51 @@ RSpec.describe 'layouts/nav/sidebar/_group' do ...@@ -76,6 +76,51 @@ RSpec.describe 'layouts/nav/sidebar/_group' do
end end
end end
describe 'Epics menu' do
let_it_be(:user) { create(:user) }
let_it_be(:group) do
create(:group).tap do |g|
g.add_maintainer(user)
end
end
before do
stub_licensed_features(epics: true)
allow(view).to receive(:current_user).and_return(user)
end
it 'has a link to the epic list path' do
render
expect(rendered).to have_link('Epics', href: group_epics_path(group))
end
describe 'List' do
it 'has a link to the epic list path' do
render
expect(rendered).to have_link('List', href: group_epics_path(group))
end
end
describe 'Boards' do
it 'has a link to the epic boards path' do
render
expect(rendered).to have_link('Boards', href: group_epic_boards_path(group))
end
end
describe 'Roadmap' do
it 'has a link to the epic roadmap path' do
render
expect(rendered).to have_link('Roadmap', href: group_roadmap_path(group))
end
end
end
describe 'DevOps adoption link' do describe 'DevOps adoption link' do
let!(:current_user) { create(:user) } let!(:current_user) { create(:user) }
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
module Sidebars module Sidebars
module Concerns module Concerns
module HasPill module HasPill
include ActionView::Helpers::NumberHelper
def has_pill? def has_pill?
false false
end end
...@@ -18,6 +20,17 @@ module Sidebars ...@@ -18,6 +20,17 @@ module Sidebars
def pill_html_options def pill_html_options
{} {}
end end
def format_cached_count(count_service, count)
if count > count_service::CACHED_COUNT_THRESHOLD
number_to_human(
count,
units: { thousand: 'k', million: 'm' }, precision: 1, significant: false, format: '%n%u'
)
else
number_with_delimiter(count)
end
end
end end
end end
end end
...@@ -34,9 +34,6 @@ module QA ...@@ -34,9 +34,6 @@ module QA
element :ldap_synchronization_link element :ldap_synchronization_link
element :billing_link element :billing_link
end end
view 'ee/app/views/layouts/nav/ee/_epic_link.html.haml' do
element :group_epics_link
end
view 'ee/app/views/layouts/nav/ee/_security_link.html.haml' do view 'ee/app/views/layouts/nav/ee/_security_link.html.haml' do
element :security_compliance_link element :security_compliance_link
...@@ -120,7 +117,7 @@ module QA ...@@ -120,7 +117,7 @@ module QA
def click_group_epics_link def click_group_epics_link
within_sidebar do within_sidebar do
click_element(:group_epics_link) click_element(:sidebar_menu_link, menu_item: 'Epics')
end end
end end
......
# frozen_string_literal: true
RSpec.shared_examples_for 'pill_count formatted results' do
let(:count_service) { raise NotImplementedError }
subject(:pill_count) { menu.pill_count }
it 'returns all digits for count value under 1000' do
allow_next_instance_of(count_service) do |service|
allow(service).to receive(:count).and_return(999)
end
expect(pill_count).to eq('999')
end
it 'returns truncated digits for count value over 1000' do
allow_next_instance_of(count_service) do |service|
allow(service).to receive(:count).and_return(2300)
end
expect(pill_count).to eq('2.3k')
end
it 'returns truncated digits for count value over 10000' do
allow_next_instance_of(count_service) do |service|
allow(service).to receive(:count).and_return(12560)
end
expect(pill_count).to eq('12.6k')
end
it 'returns truncated digits for count value over 100000' do
allow_next_instance_of(count_service) do |service|
allow(service).to receive(:count).and_return(112560)
end
expect(pill_count).to eq('112.6k')
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