Commit f15f0c3e authored by Arturo Herrero's avatar Arturo Herrero

Merge branch '326433-fj-add-new-operations-menu' into 'master'

Add `Operations` menu to the new sidebar

See merge request gitlab-org/gitlab!60475
parents 13cd5aa7 087d90af
......@@ -404,14 +404,6 @@ module ProjectsHelper
nav_tabs << :pipelines
end
if can_view_operations_tab?(current_user, project)
nav_tabs << :operations
end
if can_view_product_analytics?(current_user, project)
nav_tabs << :product_analytics
end
tab_ability_map.each do |tab, ability|
if can?(current_user, ability, project)
nav_tabs << tab
......@@ -470,32 +462,6 @@ module ProjectsHelper
}
end
def view_operations_tab_ability
[
:metrics_dashboard,
:read_alert_management_alert,
:read_environment,
:read_issue,
:read_sentry_issue,
:read_cluster,
:read_feature_flag,
:read_terraform_state
]
end
def can_view_operations_tab?(current_user, project)
return false unless project.feature_available?(:operations, current_user)
view_operations_tab_ability.any? do |ability|
can?(current_user, ability, project)
end
end
def can_view_product_analytics?(current_user, project)
Feature.enabled?(:product_analytics, project) &&
can?(current_user, :read_product_analytics, project)
end
def search_tab_ability_map
@search_tab_ability_map ||= tab_ability_map.merge(
blobs: :download_code,
......@@ -563,14 +529,6 @@ module ProjectsHelper
end
end
def sidebar_operations_link_path(project = @project)
if can?(current_user, :read_environment, project)
metrics_project_environments_path(project)
else
project_feature_flags_path(project)
end
end
def project_last_activity(project)
if project.last_activity_at
time_ago_with_tooltip(project.last_activity_at, placement: 'bottom', html_class: 'last_activity_time_ago')
......
......@@ -41,7 +41,8 @@ module SidebarsHelper
learn_gitlab_experiment_enabled: learn_gitlab_experiment_enabled?(project),
current_ref: current_ref,
jira_issues_integration: project_jira_issues_integration?,
can_view_pipeline_editor: can_view_pipeline_editor?(project)
can_view_pipeline_editor: can_view_pipeline_editor?(project),
show_cluster_hint: show_gke_cluster_integration_callout?(project)
}
end
end
......
- if project_nav_tab? :operations
= nav_link(controller: sidebar_operations_paths) do
= link_to sidebar_operations_link_path, class: 'shortcuts-operations', data: { qa_selector: 'operations_link' } do
.nav-icon-container
= sprite_icon('cloud-gear')
%span.nav-item-name
= _('Operations')
%ul.sidebar-sub-level-items
= nav_link(controller: sidebar_operations_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to sidebar_operations_link_path do
%strong.fly-out-top-item-name
= _('Operations')
%li.divider.fly-out-top-item
- if project_nav_tab? :metrics_dashboards
= nav_link(controller: :metrics_dashboard, action: [:show]) do
= link_to project_metrics_dashboard_path(@project), title: _('Metrics'), class: 'shortcuts-metrics', data: { qa_selector: 'operations_metrics_link' } do
%span
= _('Metrics')
- if project_nav_tab?(:environments) && can?(current_user, :read_pod_logs, @project)
= nav_link(controller: :logs, action: [:index]) do
= link_to project_logs_path(@project), title: _('Logs') do
%span
= _('Logs')
- if project_nav_tab? :environments
= render "layouts/nav/sidebar/tracing_link"
- if project_nav_tab?(:error_tracking)
= nav_link(controller: :error_tracking) do
= link_to project_error_tracking_index_path(@project), title: _('Error Tracking') do
%span
= _('Error Tracking')
- if project_nav_tab?(:alert_management)
= nav_link(controller: :alert_management) do
= link_to project_alert_management_index_path(@project), title: _('Alerts') do
%span
= _('Alerts')
- if project_nav_tab?(:incidents)
= nav_link(controller: :incidents) do
= link_to project_incidents_path(@project), title: _('Incidents'), data: { qa_selector: 'operations_incidents_link' } do
%span
= _('Incidents')
= render_if_exists 'projects/sidebar/oncall_schedules'
- if project_nav_tab? :serverless
= nav_link(controller: :functions) do
= link_to project_serverless_functions_path(@project), title: _('Serverless') do
%span
= _('Serverless')
- if project_nav_tab? :terraform
= nav_link(controller: :terraform) do
= link_to project_terraform_index_path(@project), title: _('Terraform') do
%span
= _('Terraform')
- if project_nav_tab? :clusters
- show_cluster_hint = show_gke_cluster_integration_callout?(@project)
= nav_link(controller: [:cluster_agents, :clusters]) do
= link_to project_clusters_path(@project), title: _('Kubernetes'), class: 'shortcuts-kubernetes' do
%span
= _('Kubernetes')
- if show_cluster_hint
.js-feature-highlight{ disabled: true,
data: { trigger: 'manual',
container: 'body',
placement: 'right',
highlight: UserCalloutsHelper::GKE_CLUSTER_INTEGRATION,
highlight_priority: UserCallout.feature_names[:GKE_CLUSTER_INTEGRATION],
dismiss_endpoint: user_callouts_path,
auto_devops_help_path: help_page_path('topics/autodevops/index.md') } }
- if project_nav_tab? :environments
= nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
= link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
%span
= _('Environments')
- if project_nav_tab? :feature_flags
= nav_link(controller: :feature_flags) do
= link_to project_feature_flags_path(@project), title: _('Feature Flags'), class: 'shortcuts-feature-flags' do
%span
= _('Feature Flags')
- if project_nav_tab?(:product_analytics)
= nav_link(controller: :product_analytics) do
= link_to project_product_analytics_path(@project), title: _('Product Analytics') do
%span
= _('Product Analytics')
= render_if_exists 'layouts/nav/sidebar/project_packages_link'
- if project_nav_tab? :analytics
......
- return unless can?(current_user, :read_environment, @project)
- if project_nav_tab? :settings
= nav_link(controller: :tracings, action: [:show]) do
= link_to project_tracing_path(@project), title: _('Tracing') do
%span
= _('Tracing')
......@@ -302,12 +302,5 @@ module EE
}
}
end
override :view_operations_tab_ability
def view_operations_tab_ability
super + [
:read_incident_management_oncall_schedule
]
end
end
end
- return unless project_nav_tab? :oncall_schedule
= nav_link(controller: :oncall_schedules) do
= link_to project_incident_management_oncall_schedules_path(@project), title: _('On-call Schedules') do
%span
= _('On-call Schedules')
# frozen_string_literal: true
module EE
module Sidebars
module Projects
module Menus
module OperationsMenu
extend ::Gitlab::Utils::Override
override :configure_menu_items
def configure_menu_items
return false unless super
insert_item_after(:incidents, on_call_schedules_menu_item)
true
end
private
def on_call_schedules_menu_item
return unless can?(context.current_user, :read_incident_management_oncall_schedule, context.project)
::Sidebars::MenuItem.new(
title: _('On-call Schedules'),
link: project_incident_management_oncall_schedules_path(context.project),
active_routes: { controller: :oncall_schedules },
item_id: :on_call_schedules
)
end
end
end
end
end
end
......@@ -209,41 +209,6 @@ RSpec.describe ProjectsHelper do
end
end
describe '#get_project_nav_tabs' do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
subject { helper.get_project_nav_tabs(project, user) }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:can?).with(user, ability, project).and_return(feature_available?)
end
describe 'tabs' do
where(:ability, :nav_tabs) do
:read_feature_flag | [:operations]
:read_incident_management_oncall_schedule | [:oncall_schedule]
end
with_them do
context 'when the feature is available' do
let(:feature_available?) { true }
it { is_expected.to include(*nav_tabs) }
end
context 'when the feature is not available' do
let(:feature_available?) { false }
it { is_expected.not_to include(*nav_tabs) }
end
end
end
end
describe '#show_discover_project_security?' do
using RSpec::Parameterized::TableSyntax
......@@ -308,40 +273,6 @@ RSpec.describe ProjectsHelper do
end
end
describe '#can_view_operations_tab?' do
let_it_be(:user) { create(:user) }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(false)
end
subject { helper.send(:can_view_operations_tab?, user, project) }
where(:ability) do
[
:read_incident_management_oncall_schedule
]
end
with_them do
it 'includes operations tab' do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
is_expected.to be(true)
end
context 'when operations feature is disabled' do
it 'does not include operations tab' do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
project.project_feature.update_attribute(:operations_access_level, ProjectFeature::DISABLED)
is_expected.to be(false)
end
end
end
end
describe '#project_permissions_settings' do
using RSpec::Parameterized::TableSyntax
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::OperationsMenu do
let(:project) { build(:project) }
let(:user) { project.owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: true) }
describe 'On-call Schedules' do
subject { described_class.new(context).items.index { |e| e.item_id == :on_call_schedules } }
before do
stub_licensed_features(oncall_schedules: true)
end
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
end
......@@ -180,41 +180,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'Operations > Pod logs' do
before do
allow(view).to receive(:can?).with(nil, :read_environment, project).and_return(can_read_environment)
allow(view).to receive(:can?).with(nil, :read_pod_logs, project).and_return(can_read_pod_logs)
render
end
describe 'when the user can read environments and logs' do
let(:can_read_environment) { true }
let(:can_read_pod_logs) { true }
it 'link is visible' do
expect(rendered).to have_link('Logs', href: project_logs_path(project))
end
end
describe 'when the user cannot read environment or logs' do
let(:can_read_environment) { false }
let(:can_read_pod_logs) { false }
it 'link is not visible' do
expect(rendered).not_to have_link 'Logs'
end
end
describe 'when the user can read environment but not logs' do
let(:can_read_environment) { true }
let(:can_read_pod_logs) { false }
it 'link is not visible' do
expect(rendered).not_to have_link 'Logs'
end
end
end
describe 'Security and Compliance' do
describe 'when user does not have permissions' do
before do
......@@ -296,6 +261,31 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'Operations' do
describe 'On-call schedules' do
before do
allow(view).to receive(:current_user).and_return(user)
stub_licensed_features(oncall_schedules: true)
end
it 'has a link to the on-call schedules page' do
render
expect(rendered).to have_link('On-call Schedules', href: project_incident_management_oncall_schedules_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the on-call schedules page' do
render
expect(rendered).not_to have_link('On-call Schedules')
end
end
end
end
describe 'Settings > Operations' do
it 'is not visible when no valid license' do
allow(view).to receive(:can?).and_return(true)
......
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
class OperationsMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
return false unless context.project.feature_available?(:operations, context.current_user)
add_item(metrics_dashboard_menu_item)
add_item(logs_menu_item)
add_item(tracing_menu_item)
add_item(error_tracking_menu_item)
add_item(alert_management_menu_item)
add_item(incidents_menu_item)
add_item(serverless_menu_item)
add_item(terraform_menu_item)
add_item(kubernetes_menu_item)
add_item(environments_menu_item)
add_item(feature_flags_menu_item)
add_item(product_analytics_menu_item)
true
end
override :link
def link
if can?(context.current_user, :read_environment, context.project)
metrics_project_environments_path(context.project)
else
project_feature_flags_path(context.project)
end
end
override :extra_container_html_options
def extra_container_html_options
{
class: 'shortcuts-operations'
}
end
override :title
def title
_('Operations')
end
override :sprite_icon
def sprite_icon
'cloud-gear'
end
override :active_routes
def active_routes
{ controller: [:user, :gcp] }
end
private
def metrics_dashboard_menu_item
return unless can?(context.current_user, :metrics_dashboard, context.project)
::Sidebars::MenuItem.new(
title: _('Metrics'),
link: project_metrics_dashboard_path(context.project),
active_routes: { path: 'metrics_dashboard#show' },
container_html_options: { class: 'shortcuts-metrics' },
item_id: :metrics
)
end
def logs_menu_item
return unless can?(context.current_user, :read_environment, context.project)
return unless can?(context.current_user, :read_pod_logs, context.project)
::Sidebars::MenuItem.new(
title: _('Logs'),
link: project_logs_path(context.project),
active_routes: { path: 'logs#index' },
item_id: :logs
)
end
def tracing_menu_item
return unless can?(context.current_user, :read_environment, context.project)
return unless can?(context.current_user, :admin_project, context.project)
::Sidebars::MenuItem.new(
title: _('Tracing'),
link: project_tracing_path(context.project),
active_routes: { path: 'tracings#show' },
item_id: :tracing
)
end
def error_tracking_menu_item
return unless can?(context.current_user, :read_sentry_issue, context.project)
::Sidebars::MenuItem.new(
title: _('Error Tracking'),
link: project_error_tracking_index_path(context.project),
active_routes: { controller: :error_tracking },
item_id: :error_tracking
)
end
def alert_management_menu_item
return unless can?(context.current_user, :read_alert_management_alert, context.project)
::Sidebars::MenuItem.new(
title: _('Alerts'),
link: project_alert_management_index_path(context.project),
active_routes: { controller: :alert_management },
item_id: :alert_management
)
end
def incidents_menu_item
return unless can?(context.current_user, :read_issue, context.project)
::Sidebars::MenuItem.new(
title: _('Incidents'),
link: project_incidents_path(context.project),
active_routes: { controller: [:incidents, :incident_management] },
item_id: :incidents
)
end
def serverless_menu_item
return unless can?(context.current_user, :read_cluster, context.project)
::Sidebars::MenuItem.new(
title: _('Serverless'),
link: project_serverless_functions_path(context.project),
active_routes: { controller: :functions },
item_id: :serverless
)
end
def terraform_menu_item
return unless can?(context.current_user, :read_terraform_state, context.project)
::Sidebars::MenuItem.new(
title: _('Terraform'),
link: project_terraform_index_path(context.project),
active_routes: { controller: :terraform },
item_id: :terraform
)
end
def kubernetes_menu_item
return unless can?(context.current_user, :read_cluster, context.project)
::Sidebars::MenuItem.new(
title: _('Kubernetes'),
link: project_clusters_path(context.project),
active_routes: { controller: [:cluster_agents, :clusters] },
container_html_options: { class: 'shortcuts-kubernetes' },
hint_html_options: kubernetes_hint_html_options,
item_id: :kubernetes
)
end
def kubernetes_hint_html_options
return {} unless context.show_cluster_hint
{ disabled: true,
data: { trigger: 'manual',
container: 'body',
placement: 'right',
highlight: UserCalloutsHelper::GKE_CLUSTER_INTEGRATION,
highlight_priority: UserCallout.feature_names[:GKE_CLUSTER_INTEGRATION],
dismiss_endpoint: user_callouts_path,
auto_devops_help_path: help_page_path('topics/autodevops/index.md') } }
end
def environments_menu_item
return unless can?(context.current_user, :read_environment, context.project)
::Sidebars::MenuItem.new(
title: _('Environments'),
link: project_environments_path(context.project),
active_routes: { controller: :environments },
container_html_options: { class: 'shortcuts-environments' },
item_id: :environments
)
end
def feature_flags_menu_item
return unless can?(context.current_user, :read_feature_flag, context.project)
::Sidebars::MenuItem.new(
title: _('Feature Flags'),
link: project_feature_flags_path(context.project),
active_routes: { controller: :feature_flags },
container_html_options: { class: 'shortcuts-feature-flags' },
item_id: :feature_flags
)
end
def product_analytics_menu_item
return if Feature.disabled?(:product_analytics, context.project)
return unless can?(context.current_user, :read_product_analytics, context.project)
::Sidebars::MenuItem.new(
title: _('Product Analytics'),
link: project_product_analytics_path(context.project),
active_routes: { controller: :product_analytics },
item_id: :product_analytics
)
end
end
end
end
end
Sidebars::Projects::Menus::OperationsMenu.prepend_if_ee('EE::Sidebars::Projects::Menus::OperationsMenu')
......@@ -16,6 +16,7 @@ module Sidebars
add_menu(Sidebars::Projects::Menus::MergeRequestsMenu.new(context))
add_menu(Sidebars::Projects::Menus::CiCdMenu.new(context))
add_menu(Sidebars::Projects::Menus::SecurityComplianceMenu.new(context))
add_menu(Sidebars::Projects::Menus::OperationsMenu.new(context))
end
override :render_raw_menus_partial
......
......@@ -12,20 +12,13 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :operations_link
element :operations_environments_link
element :operations_metrics_link
element :operations_incidents_link
end
end
end
def go_to_operations_environments
hover_operations do
within_submenu do
click_element(:operations_environments_link)
click_element(:sidebar_menu_item_link, menu_item: 'Environments')
end
end
end
......@@ -33,7 +26,7 @@ module QA
def go_to_operations_metrics
hover_operations do
within_submenu do
click_element(:operations_metrics_link)
click_element(:sidebar_menu_item_link, menu_item: 'Metrics')
end
end
end
......@@ -49,7 +42,7 @@ module QA
def go_to_operations_incidents
hover_operations do
within_submenu do
click_element(:operations_incidents_link)
click_element(:sidebar_menu_item_link, menu_item: 'Incidents')
end
end
end
......@@ -58,8 +51,8 @@ module QA
def hover_operations
within_sidebar do
scroll_to_element(:operations_link)
find_element(:operations_link).hover
scroll_to_element(:sidebar_menu_link, menu_item: 'Operations')
find_element(:sidebar_menu_link, menu_item: 'Operations').hover
yield
end
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
let_it_be_with_reload(:project) { create(:project, :internal, :repository) }
let(:user) { create(:user) }
let(:access_level) { ProjectFeature::PUBLIC }
let(:role) { nil }
......@@ -37,16 +38,16 @@ RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
context 'user is not a member' do
it 'has the correct `Operations` menu items', :aggregate_failures do
expect(page).to have_selector('a.shortcuts-operations', text: 'Operations')
expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
expect(page).not_to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
expect(page).not_to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project))
expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).not_to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).not_to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link('Logs', href: project_logs_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
context 'when operations project feature is PRIVATE' do
......@@ -71,16 +72,16 @@ RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
it 'has the correct `Operations` menu items' do
expect(page).to have_selector('a.shortcuts-operations', text: 'Operations')
expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
expect(page).not_to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
expect(page).not_to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project))
expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).not_to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).not_to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link('Logs', href: project_logs_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
it_behaves_like 'shows Operations menu based on the access level'
......@@ -90,16 +91,16 @@ RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
let(:role) { :reporter }
it 'has the correct `Operations` menu items' do
expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project))
expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
expect(page).to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link('Logs', href: project_logs_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
it_behaves_like 'shows Operations menu based on the access level'
......@@ -109,16 +110,16 @@ RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
let(:role) { :developer }
it 'has the correct `Operations` menu items' do
expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link(title: 'Logs', href: project_logs_path(project))
expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
expect(page).to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link('Logs', href: project_logs_path(project))
expect(page).not_to have_link('Serverless', href: project_serverless_functions_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
it_behaves_like 'shows Operations menu based on the access level'
......@@ -128,15 +129,15 @@ RSpec.describe 'Operations dropdown sidebar', :aggregate_failures do
let(:role) { :maintainer }
it 'has the correct `Operations` menu items' do
expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
expect(page).to have_link(title: 'Logs', href: project_logs_path(project))
expect(page).to have_link(title: 'Kubernetes', href: project_clusters_path(project))
expect(page).to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link('Serverless', href: project_serverless_functions_path(project))
expect(page).to have_link('Logs', href: project_logs_path(project))
expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
end
it_behaves_like 'shows Operations menu based on the access level'
......
......@@ -477,43 +477,6 @@ RSpec.describe ProjectsHelper do
end
end
describe '#can_view_operations_tab?' do
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(false)
end
subject { helper.send(:can_view_operations_tab?, user, project) }
where(:ability) do
[
:metrics_dashboard,
:read_alert_management_alert,
:read_environment,
:read_issue,
:read_sentry_issue,
:read_cluster
]
end
with_them do
it 'includes operations tab' do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
is_expected.to be(true)
end
context 'when operations feature is disabled' do
it 'does not include operations tab' do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
project.project_feature.update_attribute(:operations_access_level, ProjectFeature::DISABLED)
is_expected.to be(false)
end
end
end
end
describe '#show_projects' do
let(:projects) do
Project.all
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::OperationsMenu do
let_it_be_with_refind(:project) { create(:project) }
let(:user) { project.owner }
let(:show_cluster_hint) { true }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: show_cluster_hint) }
subject { described_class.new(context) }
describe '#render?' do
context 'when operations feature is disabled' do
it 'returns false' do
project.project_feature.update!(operations_access_level: Featurable::DISABLED)
expect(subject.render?).to be false
end
end
context 'when operation feature is enabled' do
context 'when menu does not have any menu items' do
it 'returns false' do
allow(subject).to receive(:has_items?).and_return(false)
expect(subject.render?).to be false
end
end
context 'when menu has menu items' do
it 'returns true' do
expect(subject.render?).to be true
end
end
end
end
describe '#link' do
context 'when metrics dashboard is visible' do
it 'returns link to the metrics dashboard page' do
expect(subject.link).to include('/-/environments/metrics')
end
end
context 'when metrics dashboard is not visible' do
it 'returns link to the feature flags page' do
project.project_feature.update!(operations_access_level: Featurable::DISABLED)
expect(subject.link).to include('/-/feature_flags')
end
end
end
context 'Menu items' do
subject { described_class.new(context).items.index { |e| e.item_id == item_id } }
describe 'Metrics Dashboard' do
let(:item_id) { :metrics }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Logs' do
let(:item_id) { :logs }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Tracing' do
let(:item_id) { :tracing }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Error Tracking' do
let(:item_id) { :error_tracking }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Alert Management' do
let(:item_id) { :alert_management }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Incidents' do
let(:item_id) { :incidents }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Serverless' do
let(:item_id) { :serverless }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Terraform' do
let(:item_id) { :terraform }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Kubernetes' do
let(:item_id) { :kubernetes }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Environments' do
let(:item_id) { :environments }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Feature Flags' do
let(:item_id) { :feature_flags }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'Product Analytics' do
let(:item_id) { :product_analytics }
specify { is_expected.not_to be_nil }
describe 'when feature flag :product_analytics is disabled' do
specify do
stub_feature_flags(product_analytics: false)
is_expected.to be_nil
end
end
end
end
end
......@@ -348,6 +348,238 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'Operations' do
it 'top level navigation link is visible for user with permissions' do
render
expect(rendered).to have_link('Operations')
end
describe 'Metrics Dashboard' do
it 'has a link to the metrics dashboard page' do
render
expect(rendered).to have_link('Metrics', href: project_metrics_dashboard_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the metrics page' do
render
expect(rendered).not_to have_link('Metrics')
end
end
end
describe 'Logs' do
it 'has a link to the pod logs page' do
render
expect(rendered).to have_link('Logs', href: project_logs_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the pod logs page' do
render
expect(rendered).not_to have_link('Logs')
end
end
end
describe 'Tracing' do
it 'has a link to the tracing page' do
render
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
context 'without project.tracing_external_url' do
it 'has a link to the tracing page' do
render
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the tracing page' do
render
expect(rendered).not_to have_text 'Tracing'
end
end
end
describe 'Error Tracking' do
it 'has a link to the error tracking page' do
render
expect(rendered).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the error tracking page' do
render
expect(rendered).not_to have_link('Error Tracking')
end
end
end
describe 'Alert Management' do
it 'has a link to the alert management page' do
render
expect(rendered).to have_link('Alerts', href: project_alert_management_index_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the alert management page' do
render
expect(rendered).not_to have_link('Alerts')
end
end
end
describe 'Incidents' do
it 'has a link to the incidents page' do
render
expect(rendered).to have_link('Incidents', href: project_incidents_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the incidents page' do
render
expect(rendered).not_to have_link('Incidents')
end
end
end
describe 'Serverless' do
it 'has a link to the serverless page' do
render
expect(rendered).to have_link('Serverless', href: project_serverless_functions_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the serverless page' do
render
expect(rendered).not_to have_link('Serverless')
end
end
end
describe 'Terraform' do
it 'has a link to the terraform page' do
render
expect(rendered).to have_link('Terraform', href: project_terraform_index_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the terraform page' do
render
expect(rendered).not_to have_link('Terraform')
end
end
end
describe 'Kubernetes' do
it 'has a link to the kubernetes page' do
render
expect(rendered).to have_link('Kubernetes', href: project_clusters_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the kubernetes page' do
render
expect(rendered).not_to have_link('Kubernetes')
end
end
end
describe 'Environments' do
it 'has a link to the environments page' do
render
expect(rendered).to have_link('Environments', href: project_environments_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the environments page' do
render
expect(rendered).not_to have_link('Environments')
end
end
end
describe 'Feature Flags' do
it 'has a link to the feature flags page' do
render
expect(rendered).to have_link('Feature Flags', href: project_feature_flags_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the feature flags page' do
render
expect(rendered).not_to have_link('Feature Flags')
end
end
end
describe 'Product Analytics' do
it 'has a link to the product analytics page' do
render
expect(rendered).to have_link('Product Analytics', href: project_product_analytics_path(project))
end
describe 'when feature flag :product_analytics is disabled' do
it 'does not have a link to the feature flags page' do
stub_feature_flags(product_analytics: false)
render
expect(rendered).not_to have_link('Product Analytics')
end
end
end
end
describe 'packages tab' do
before do
stub_container_registry_config(enabled: true)
......@@ -510,6 +742,32 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'value stream analytics entry' do
let(:read_cycle_analytics) { true }
before do
allow(view).to receive(:can?).with(user, :read_cycle_analytics, project).and_return(read_cycle_analytics)
end
describe 'when value stream analytics is enabled' do
it 'shows the value stream analytics entry' do
render
expect(rendered).to have_link('Value Stream', href: project_cycle_analytics_path(project))
end
end
describe 'when value stream analytics is disabled' do
let(:read_cycle_analytics) { false }
it 'does not show the value stream analytics entry' do
render
expect(rendered).not_to have_link('Value Stream', href: project_cycle_analytics_path(project))
end
end
end
describe 'operations settings tab' do
describe 'archive projects' do
before do
......@@ -536,64 +794,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
end
describe 'Tracing' do
it 'is not visible to unauthorized user' do
allow(view).to receive(:can?).and_return(false)
render
expect(rendered).not_to have_text 'Tracing'
end
it 'links to Tracing page' do
render
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
context 'without project.tracing_external_url' do
it 'links to Tracing page' do
render
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
end
end
describe 'Alert Management' do
it 'shows the Alerts sidebar entry' do
render
expect(rendered).to have_css('a[title="Alerts"]')
end
end
end
describe 'value stream analytics entry' do
let(:read_cycle_analytics) { true }
before do
allow(view).to receive(:can?).with(user, :read_cycle_analytics, project).and_return(read_cycle_analytics)
end
describe 'when value stream analytics is enabled' do
it 'shows the value stream analytics entry' do
render
expect(rendered).to have_link('Value Stream', href: project_cycle_analytics_path(project))
end
end
describe 'when value stream analytics is disabled' do
let(:read_cycle_analytics) { false }
it 'does not show the value stream analytics entry' do
render
expect(rendered).not_to have_link('Value Stream', href: project_cycle_analytics_path(project))
end
end
end
describe 'project access tokens' 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