Merge pull request #5063 from consul/refactor_layout_components

Make it easier to customize admin and main layouts
This commit is contained in:
Javi Martín
2023-01-16 19:52:00 +01:00
committed by GitHub
27 changed files with 297 additions and 257 deletions

View File

@@ -31,14 +31,6 @@ $table-header: #ecf1f6;
.admin {
@include admin-layout;
> header {
border-bottom: 1px solid #eee;
> * {
@include full-width-background($adjust-margin: false, $adjust-padding: true);
}
}
h2 {
font-weight: 100;
margin-bottom: $line-height;
@@ -60,86 +52,6 @@ $table-header: #ecf1f6;
float: none;
}
.top-links {
a {
line-height: rem-calc($line-height * 1.5);
}
}
.top-bar {
height: auto;
padding-top: $line-height / 2;
@include breakpoint(small only) {
.top-bar-left ul {
display: inline-block;
}
.top-bar-right {
> ul {
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
}
.submenu {
position: initial;
}
a {
font-weight: normal;
}
}
[class^="icon-"] {
display: none;
}
}
[class^="icon-"] {
font-size: $base-font-size;
}
h1 {
margin-top: $line-height / 2;
margin-bottom: 0;
@include breakpoint(medium) {
margin-top: 0;
}
small {
color: inherit;
text-transform: uppercase;
}
a {
color: inherit;
display: inline-block;
font-family: "Lato" !important;
font-size: rem-calc(24);
font-weight: lighter;
line-height: 1;
}
}
}
.top-bar .menu > li {
@include breakpoint(medium) {
height: auto !important;
}
}
.title-bar {
color: inherit;
position: absolute;
right: 12px;
}
.notifications.unread-notifications::after {
color: $admin-color;
}

View File

@@ -0,0 +1,89 @@
.admin {
> header {
border-bottom: 1px solid #eee;
> * {
@include full-width-background($adjust-margin: false, $adjust-padding: true);
}
}
.top-links {
a {
line-height: rem-calc($line-height * 1.5);
}
}
.top-bar {
height: auto;
padding-top: $line-height / 2;
@include breakpoint(small only) {
.top-bar-left ul {
display: inline-block;
}
.top-bar-right {
> ul {
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
}
.submenu {
position: initial;
}
a {
font-weight: normal;
}
}
[class^="icon-"] {
display: none;
}
}
[class^="icon-"] {
font-size: $base-font-size;
}
h1 {
margin-top: $line-height / 2;
margin-bottom: 0;
@include breakpoint(medium) {
margin-top: 0;
}
small {
color: inherit;
text-transform: uppercase;
}
a {
color: inherit;
display: inline-block;
font-family: "Lato" !important;
font-size: rem-calc(24);
font-weight: lighter;
line-height: 1;
}
}
}
.top-bar .menu > li {
@include breakpoint(medium) {
height: auto !important;
}
}
.title-bar {
color: inherit;
position: absolute;
right: 12px;
}
}

View File

@@ -0,0 +1,5 @@
<ul class="menu" data-responsive-menu="medium-dropdown">
<%= render Layout::AdminLoginItemsComponent.new(user) %>
<%= render Layout::NotificationItemComponent.new(user) %>
<%= render Layout::LoginItemsComponent.new(user) %>
</ul>

View File

@@ -0,0 +1,7 @@
class Layout::AccountMenuComponent < ApplicationComponent
attr_reader :user
def initialize(user)
@user = user
end
end

View File

@@ -0,0 +1,39 @@
<header class="header">
<div class="top-links">
<%= render "shared/locale_switcher" %>
<%= link_to root_path do %>
<%= t("admin.dashboard.index.back", org: setting["org_name"]) %>
<% end %>
</div>
<div class="expanded row admin-top-bar">
<% if show_account_menu? %>
<div class="title-bar" data-responsive-toggle="responsive_menu" data-hide-for="medium">
<button class="menu-button" type="button" data-toggle="responsive_menu">
<span class="menu-icon"></span>
<span class="title-bar-title"><%= t("application.menu") %></span>
</button>
</div>
<% end %>
<div class="top-bar">
<div class="top-bar-left">
<h1>
<%= link_to namespace_path do %>
<%= setting["org_name"] %>
<br><small><%= namespaced_header_title %></small>
<% end %>
</h1>
</div>
<% if show_account_menu? %>
<div id="responsive_menu">
<div class="top-bar-right">
<%= render Layout::AccountMenuComponent.new(user) %>
</div>
</div>
<% end %>
</div>
</div>
</header>

View File

@@ -0,0 +1,32 @@
class Layout::AdminHeaderComponent < ApplicationComponent
attr_reader :user
delegate :namespace, :namespaced_root_path, :show_admin_menu?, to: :helpers
def initialize(user)
@user = user
end
private
def namespaced_header_title
if namespace == "moderation/budgets"
t("moderation.header.title")
elsif namespace == "management"
t("management.dashboard.index.title")
else
t("#{namespace}.header.title")
end
end
def namespace_path
if namespace == "officing"
"#"
else
namespaced_root_path
end
end
def show_account_menu?
show_admin_menu?(user) || namespace != "management"
end
end

View File

@@ -0,0 +1,4 @@
<li class="has-submenu">
<%= link_to t("layouts.header.administration_menu"), "#", rel: "nofollow", class: "hide-for-small-only" %>
<%= link_list(*admin_links, class: "submenu menu", data: { submenu: true }) %>
</li>

View File

@@ -0,0 +1,49 @@
class Layout::AdminLoginItemsComponent < ApplicationComponent
attr_reader :user
delegate :link_list, :show_admin_menu?, to: :helpers
def initialize(user)
@user = user
end
def render?
show_admin_menu?(user)
end
private
def admin_links
[
(admin_link if user.administrator?),
(moderation_link if user.administrator? || user.moderator?),
(valuation_link if feature?(:budgets) && (user.administrator? || user.valuator?)),
(management_link if user.administrator? || user.manager?),
(officing_link if user.poll_officer? && Poll.current.any?),
(sdg_management_link if feature?(:sdg) && (user.administrator? || user.sdg_manager?))
]
end
def admin_link
[t("layouts.header.administration"), admin_root_path]
end
def moderation_link
[t("layouts.header.moderation"), moderation_root_path]
end
def valuation_link
[t("layouts.header.valuation"), valuation_root_path]
end
def management_link
[t("layouts.header.management"), management_sign_in_path]
end
def officing_link
[t("layouts.header.officing"), officing_root_path]
end
def sdg_management_link
[t("sdg_management.header.title"), sdg_management_root_path]
end
end

View File

@@ -0,0 +1,2 @@
class Layout::FooterComponent < ApplicationComponent
end

View File

@@ -1,7 +1,7 @@
<% if user_signed_in? %>
<% if user %>
<li>
<%= layout_menu_link_to t("layouts.header.my_activity_link"),
user_path(current_user),
user_path(user),
controller_name == "users",
rel: "nofollow",
title: t("shared.go_to_page") +

View File

@@ -0,0 +1,8 @@
class Layout::LoginItemsComponent < ApplicationComponent
attr_reader :user
delegate :layout_menu_link_to, to: :helpers
def initialize(user)
@user = user
end
end

View File

@@ -0,0 +1,3 @@
class Layout::SubnavigationComponent < ApplicationComponent
delegate :content_block, :layout_menu_link_to, to: :helpers
end

View File

@@ -3,16 +3,6 @@ module AdminHelper
"/#{namespace}"
end
def namespaced_header_title
if namespace == "moderation/budgets"
t("moderation.header.title")
elsif namespace == "management"
t("management.dashboard.index.title")
else
t("#{namespace}.header.title")
end
end
def official_level_options
options = [["", 0]]
(1..5).each do |i|

View File

@@ -35,34 +35,10 @@ module UsersHelper
end
end
def current_administrator?
current_user&.administrator?
end
def current_moderator?
current_user&.moderator?
end
def current_valuator?
current_user&.valuator?
end
def current_manager?
current_user&.manager?
end
def current_sdg_manager?
current_user&.sdg_manager?
end
def current_poll_officer?
current_user&.poll_officer?
end
def show_admin_menu?(user = nil)
def show_admin_menu?(user)
unless namespace == "officing"
current_administrator? || current_moderator? || current_valuator? || current_manager? ||
user&.administrator? || current_poll_officer? || current_sdg_manager?
user&.administrator? || user&.moderator? || user&.valuator? ||
(user&.manager? && namespace != "management") || user&.poll_officer? || user&.sdg_manager?
end
end

View File

@@ -1,50 +0,0 @@
<header class="header">
<div class="top-links">
<%= render "shared/locale_switcher" %>
<%= link_to root_path do %>
<%= t("admin.dashboard.index.back", org: setting["org_name"]) %>
<% end %>
</div>
<div class="expanded row admin-top-bar">
<div class="title-bar" data-responsive-toggle="responsive_menu" data-hide-for="medium">
<button class="menu-button" type="button" data-toggle="responsive_menu">
<span class="menu-icon"></span>
<span class="title-bar-title"><%= t("application.menu") %></span>
</button>
</div>
<div class="top-bar">
<div class="top-bar-left">
<% if namespace == "officing" %>
<h1>
<%= link_to "#" do %>
<%= setting["org_name"] %>
<br><small><%= namespaced_header_title %></small>
<% end %>
</h1>
<% else %>
<h1>
<%= link_to namespaced_root_path do %>
<%= setting["org_name"] %>
<br><small><%= namespaced_header_title %></small>
<% end %>
</h1>
<% end %>
</div>
<% if show_admin_menu?(current_user) || namespace != "management" %>
<div id="responsive_menu">
<div class="top-bar-right">
<ul class="menu" data-responsive-menu="medium-dropdown">
<%= render "shared/admin_login_items", current_user: current_user %>
<%= render "layouts/notification_item", current_user: current_user %>
<%= render "devise/menu/login_items", current_user: current_user %>
</ul>
</div>
</div>
<% end %>
</div>
</div>
</header>

View File

@@ -26,15 +26,11 @@
<div id="responsive-menu">
<div class="top-bar-right">
<ul class="menu" data-responsive-menu="medium-dropdown">
<%= render "shared/admin_login_items" %>
<%= render "layouts/notification_item" %>
<%= render "devise/menu/login_items" %>
</ul>
<%= render Layout::AccountMenuComponent.new(current_user) %>
<div class="show-for-small-only">
<div class="subnavigation subnavigation-with-top-links">
<%= render "shared/subnavigation" %>
<%= render Layout::SubnavigationComponent.new %>
<%= render "shared/top_links" %>
</div>
</div>
@@ -44,7 +40,7 @@
<div id="navigation_bar" class="subnavigation">
<div class="hide-for-small-only">
<%= render "shared/subnavigation" %>
<%= render Layout::SubnavigationComponent.new %>
</div>
<%= yield :header_addon %>

View File

@@ -1 +0,0 @@
<%= render Layout::NotificationItemComponent.new(current_user) %>

View File

@@ -6,7 +6,7 @@
</head>
<body class="admin">
<%= render "layouts/admin_header" %>
<%= render Layout::AdminHeaderComponent.new(current_user) %>
<div class="menu-and-content">
<%= check_box_tag :show_menu, nil, false, role: "switch" %>

View File

@@ -43,7 +43,7 @@
<%= yield %>
</div>
<div class="footer">
<%= render "layouts/footer" %>
<%= render Layout::FooterComponent.new %>
</div>
</body>
</html>

View File

@@ -32,7 +32,7 @@
</div>
<div class="footer">
<%= render "layouts/footer" %>
<%= render Layout::FooterComponent.new %>
</div>
</body>
</html>

View File

@@ -7,7 +7,7 @@
</head>
<body class="admin">
<%= render "layouts/admin_header", current_user: manager_logged_in %>
<%= render Layout::AdminHeaderComponent.new(manager_logged_in) %>
<div class="menu-and-content">
<%= check_box_tag :show_menu, nil, false, role: "switch" %>

View File

@@ -1,43 +0,0 @@
<% if show_admin_menu?(current_user) %>
<li class="has-submenu">
<%= link_to t("layouts.header.administration_menu"), "#", rel: "nofollow", class: "hide-for-small-only" %>
<ul class="submenu menu" data-submenu>
<% if current_user.administrator? %>
<li>
<%= link_to t("layouts.header.administration"), admin_root_path %>
</li>
<% end %>
<% if current_user.administrator? || current_user.moderator? %>
<li>
<%= link_to t("layouts.header.moderation"), moderation_root_path %>
</li>
<% end %>
<% if feature?(:budgets) &&
(current_user.administrator? || current_user.valuator?) %>
<li>
<%= link_to t("layouts.header.valuation"), valuation_root_path %>
</li>
<% end %>
<% if current_user.administrator? || current_user.manager? %>
<li>
<%= link_to t("layouts.header.management"), management_sign_in_path %>
</li>
<% end %>
<% if current_user.poll_officer? && Poll.current.any? %>
<li>
<%= link_to t("layouts.header.officing"), officing_root_path %>
</li>
<% end %>
<% if feature?(:sdg) && (current_user.administrator? || current_user.sdg_manager?) %>
<li>
<%= link_to t("sdg_management.header.title"), sdg_management_root_path %>
</li>
<% end %>
</ul>
</li>
<% end %>

View File

@@ -17,7 +17,7 @@
<h2 class="inline-block">
<%= avatar_image(@user, seed: @user.id, size: 60) %>
<%= @user.name %>
<% if current_administrator? %>
<% if current_user&.administrator? %>
<small><%= @user.email %></small>
<% end %>
</h2>

View File

@@ -0,0 +1,38 @@
require "rails_helper"
describe Layout::AdminHeaderComponent do
let(:user) { create(:user) }
before { Setting["org_name"] = "CONSUL" }
around do |example|
with_request_url("/") { example.run }
end
context "management section", controller: Management::BaseController do
it "shows the menu button and menu for administrators" do
create(:administrator, user: user)
render_inline Layout::AdminHeaderComponent.new(user)
expect(page).to have_link "Go back to CONSUL"
expect(page).to have_link "You don't have new notifications"
expect(page).to have_link "My content"
expect(page).to have_link "My account"
expect(page).to have_link "Sign out"
expect(page).to have_css "[data-toggle]"
end
it "does not show the menu button and menu for managers" do
create(:manager, user: user)
render_inline Layout::AdminHeaderComponent.new(user)
expect(page).to have_link "Go back to CONSUL"
expect(page).not_to have_content "You don't have new notifications"
expect(page).not_to have_content "My content"
expect(page).not_to have_content "My account"
expect(page).not_to have_content "Sign out"
expect(page).not_to have_css "[data-toggle]"
end
end
end

View File

@@ -2,34 +2,18 @@ require "rails_helper"
describe "Management" do
let(:user) { create(:user) }
before { Setting["org_name"] = "CONSUL" }
scenario "Should show admin menu if logged user is admin" do
create(:administrator, user: user)
login_as(user)
visit root_path
click_link "Menu"
click_link "Management"
expect(page).to have_link "Go back to CONSUL"
expect(page).to have_link "You don't have new notifications"
expect(page).to have_link "My content"
expect(page).to have_link "My account"
expect(page).to have_link "Sign out"
end
scenario "Should not show admin menu if logged user is manager" do
scenario "Does not show the admin menu when managing users having the admin menu" do
create(:manager, user: user)
create(:moderator, user: create(:user, :in_census, document_number: "12345678M"))
login_as(user)
visit root_path
click_link "Menu"
click_link "Management"
expect(page).to have_link "Go back to CONSUL"
visit management_sign_in_path
click_link "Select user"
fill_in "Document number", with: "12345678M"
click_button "Check document"
expect(page).to have_content "This user account is already verified"
expect(page).not_to have_content "You don't have new notifications"
expect(page).not_to have_content "My content"
expect(page).not_to have_content "My account"