Commit 086052d3 authored by Douwe Maan's avatar Douwe Maan

Merge branch '5023-add-system-header-and-footer' into 'master'

Resolve "Add system header and footer"

Closes #5023

See merge request gitlab-org/gitlab-ee!4972
parents 47f94d9a 54aa4bff
......@@ -88,7 +88,6 @@
.right-sidebar {
border-left: 1px solid $border-color;
height: calc(100% - #{$header-height});
}
.with-performance-bar .right-sidebar.affix {
......
......@@ -261,6 +261,8 @@ $general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232);
$performance-bar-height: 35px;
$system-header-height: 35px;
$system-footer-height: $system-header-height;
$flash-height: 52px;
$context-header-height: 60px;
$breadcrumb-min-height: 48px;
......
......@@ -523,10 +523,6 @@
.with-performance-bar .right-sidebar {
top: $header-height + $performance-bar-height;
.issuable-sidebar {
height: calc(100% - #{$performance-bar-height});
}
}
.sidebar-move-issue-confirmation-button {
......
......@@ -19,7 +19,7 @@
.ide-view {
display: flex;
height: calc(100vh - #{$header-height});
margin-top: 40px;
margin-top: 0;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
......@@ -457,6 +457,8 @@
display: flex;
flex-direction: column;
flex: 1;
max-height: 100%;
overflow: auto;
}
.multi-file-commit-empty-state-container {
......@@ -467,7 +469,7 @@
.multi-file-commit-panel-header {
display: flex;
align-items: center;
margin-bottom: 12px;
margin-bottom: 0;
border-bottom: 1px solid $white-dark;
padding: $gl-btn-padding 0;
......@@ -674,8 +676,14 @@
overflow: hidden;
&.nav-only {
padding-top: $header-height;
.with-performance-bar & {
padding-top: $header-height + $performance-bar-height;
}
.flash-container {
margin-top: $header-height;
margin-top: 0;
margin-bottom: 0;
}
......@@ -685,7 +693,7 @@
}
.content-wrapper {
margin-top: $header-height;
margin-top: 0;
padding-bottom: 0;
}
......@@ -709,11 +717,11 @@
.with-performance-bar .ide.nav-only {
.flash-container {
margin-top: #{$header-height + $performance-bar-height};
margin-top: 0;
}
.content-wrapper {
margin-top: #{$header-height + $performance-bar-height};
margin-top: 0;
padding-bottom: 0;
}
......@@ -722,10 +730,6 @@
}
&.flash-shown {
.content-wrapper {
margin-top: 0;
}
.ide-view {
height: calc(100vh - #{$header-height + $performance-bar-height + $flash-height});
}
......
class Admin::AppearancesController < Admin::ApplicationController
prepend EE::Admin::AppearancesController
before_action :set_appearance, except: :create
def show
......@@ -50,9 +52,19 @@ class Admin::AppearancesController < Admin::ApplicationController
# Only allow a trusted parameter "white list" through.
def appearance_params
params.require(:appearance).permit(
:title, :description, :logo, :logo_cache, :header_logo, :header_logo_cache,
:new_project_guidelines, :updated_by
)
params.require(:appearance).permit(allowed_appearance_params)
end
def allowed_appearance_params
%i[
title
description
logo
logo_cache
header_logo
header_logo_cache
new_project_guidelines
updated_by
]
end
end
module AppearancesHelper
prepend EE::AppearancesHelper
def brand_title
brand_item&.title.presence || 'GitLab Enterprise Edition'
current_appearance&.title.presence || 'GitLab Enterprise Edition'
end
def brand_image
image_tag(brand_item.logo) if brand_item&.logo?
image_tag(current_appearance.logo) if current_appearance&.logo?
end
def brand_text
markdown_field(brand_item, :description)
markdown_field(current_appearance, :description)
end
def brand_new_project_guidelines
markdown_field(brand_item, :new_project_guidelines)
markdown_field(current_appearance, :new_project_guidelines)
end
def brand_item
def current_appearance
@appearance ||= Appearance.current
end
def brand_header_logo
if brand_item&.header_logo?
image_tag brand_item.header_logo
if current_appearance&.header_logo?
image_tag current_appearance.header_logo
else
render 'shared/logo.svg'
end
......@@ -29,7 +31,7 @@ module AppearancesHelper
# Skip the 'GitLab' type logo when custom brand logo is set
def brand_header_logo_type
unless brand_item&.header_logo?
unless current_appearance&.header_logo?
render 'shared/logo_type.svg'
end
end
......
......@@ -54,9 +54,9 @@ module EmailsHelper
end
def header_logo
if brand_item && brand_item.header_logo?
if current_appearance&.header_logo?
image_tag(
brand_item.header_logo,
current_appearance.header_logo,
style: 'height: 50px'
)
else
......
......@@ -3,6 +3,8 @@ class Appearance < ActiveRecord::Base
include AfterCommitQueue
include ObjectStorage::BackgroundMove
prepend EE::Appearance
cache_markdown_field :description
cache_markdown_field :new_project_guidelines
......
......@@ -18,6 +18,8 @@
.hint
Maximum file size is 1MB. Pages are optimized for a 28px tall header logo
= render partial: 'admin/appearances/system_header_footer_form', locals: { form: f }
%fieldset.sign-in
%legend
Sign in/Sign up pages:
......
......@@ -4,7 +4,9 @@
%body{ class: "#{user_application_theme} #{@body_class}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
= header_message
= render "layouts/header/default"
= render 'layouts/page', sidebar: sidebar, nav: nav
= footer_message
= yield :scripts_body
!!! 5
%html.devise-layout-html
%html.devise-layout-html{ class: system_message_class }
= render "layouts/head"
%body.ui_indigo.login-page.application.navless{ data: { page: body_data_page } }
= header_message
.page-wrap
= render "layouts/header/empty"
.login-page-broadcast
......@@ -16,7 +17,7 @@
%h1
= brand_title
= brand_image
- if brand_item&.description?
- if current_appearance&.description?
= brand_text
- else
%h3 Open source software to collaborate on code
......@@ -40,3 +41,4 @@
= link_to "Explore", explore_root_path
= link_to "Help", help_path
= link_to "About GitLab", "https://about.gitlab.com/"
= footer_message
!!! 5
%html{ lang: "en" }
%html{ lang: "en", class: system_message_class }
= render "layouts/head"
%body.ui_indigo.login-page.application.navless
= header_message
= render "layouts/header/empty"
= render "layouts/broadcast"
.container.navless-container
......@@ -15,3 +16,4 @@
= link_to "Explore", explore_root_path
= link_to "Help", help_path
= link_to "About GitLab", "https://about.gitlab.com/"
= footer_message
......@@ -3,6 +3,7 @@
= render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class} nav-only", data: { page: body_data_page } }
= render 'peek/bar'
= header_message
= render "layouts/header/default"
= render 'shared/outdated_browser'
.mobile-overlay
......@@ -12,3 +13,4 @@
= render "layouts/flash"
.content-wrapper{ id: "content-body" }
= yield
= footer_message
......@@ -39,6 +39,12 @@ ActiveRecord::Schema.define(version: 20180327101207) do
t.integer "cached_markdown_version"
t.text "new_project_guidelines"
t.text "new_project_guidelines_html"
t.text "header_message"
t.text "header_message_html"
t.text "footer_message"
t.text "footer_message_html"
t.text "message_background_color"
t.text "message_font_color"
end
create_table "application_settings", force: :cascade do |t|
......
# Adding a system message to every page
Navigate to the **Admin** area and go to the **Appearance** page.
Under **System header and footer** insert your header message and/or footer message.
Both background and font color of the header and footer are customizable.
![appearance](system_header_and_footer_messages/appearance.png)
After saving, all GitLab pages will contain the custom system header and/or footer messages:
![custom_header_footer](system_header_and_footer_messages/custom_header_footer.png)
The GitLab sign in page will also show the header and the footer messages:
![sign_up_custom_header_and_footer](system_header_and_footer_messages/sign_up_custom_header_and_footer.png)
.header-message,
.footer-message {
padding: 0 15px;
border: 1px solid transparent;
border-radius: 0;
position: fixed;
left: 0;
width: 100%;
text-align: center;
margin: 0;
z-index: 1000;
p {
@include str-truncated(100%);
margin-top: 0;
margin-bottom: 0;
}
}
.header-message {
top: 0;
height: $system-header-height;
line-height: $system-header-height;
}
.footer-message {
bottom: 0;
height: $system-footer-height;
line-height: $system-footer-height;
}
.with-performance-bar {
.header-message {
top: $performance-bar-height;
}
}
// System Header
.with-system-header {
// main navigation
// login page
.navbar-gitlab,
.navbar-fixed-top {
top: $system-header-height;
}
// left sidebar eg: project page
// right sidebar eg: MR page
.nav-sidebar,
.right-sidebar {
top: $system-header-height + $header-height;
}
.ide.nav-only {
// body element on WebIDE page
padding-top: $header-height + $system-header-height;
.ide-view {
height: calc(100vh - #{$header-height + $system-header-height});
}
}
}
// System Footer
.with-system-footer {
// left sidebar eg: project page
// right sidebar eg: mr page
.nav-sidebar,
.right-sidebar,
// navless pages' footer eg: login page
// navless pages' footer border eg: login page
&.devise-layout-html body .footer-container,
&.devise-layout-html body hr.footer-fixed {
bottom: $system-footer-height;
}
}
// Performance Bar
// System Header
.with-system-header.with-performance-bar {
// main navigation
header.navbar-gitlab {
top: $performance-bar-height + $system-header-height;
}
.layout-page {
margin-top: $header-height + $performance-bar-height + $system-header-height;
}
// left sidebar eg: project page
// right sidebar eg: MR page
.nav-sidebar,
.right-sidebar {
top: $header-height + $performance-bar-height + $system-header-height;
}
// IDE adjustments
// body element on WebIDe view
.ide.nav-only {
padding-top: $header-height + $performance-bar-height + $system-header-height;
}
}
@mixin ide-height-with($map) {
$height: 0;
$height: $height + $header-height; // header is always present
@if (map-get($map, performance) == true) {
$height: $height + $performance-bar-height;
}
@if (map-get($map, system-header) == true) {
$height: $height + $system-header-height;
}
@if (map-get($map, system-footer) == true) {
$height: $height + $system-footer-height;
}
@if (map-get($map, flash) == true) {
$height: $height + $flash-height;
}
height: calc(100vh - #{$height});
}
// Space adjustments for the IDE UI
.ide.nav-only {
.ide-view {
.with-system-header & {
@include ide-height-with((system-header: true));
}
.with-system-footer & {
@include ide-height-with((system-footer: true));
}
.with-system-header.with-system-footer & {
@include ide-height-with((system-header: true, system-footer: true));
}
.with-performance-bar.with-system-header & {
@include ide-height-with((system-header: true, performance: true));
}
.with-performance-bar.with-system-footer & {
@include ide-height-with((system-footer: true, performance: true));
}
.with-performance-bar.with-system-header.with-system-footer & {
@include ide-height-with((system-header: true, system-footer: true, performance: true));
}
}
// Repeat previous block of selectors but with addition of Flash
&.flash-shown .ide-view {
.with-system-header & {
@include ide-height-with((system-header: true, flash: true));
}
.with-system-footer & {
@include ide-height-with((system-footer: true, flash: true));
}
.with-system-header.with-system-footer & {
@include ide-height-with((system-header: true, system-footer: true, flash: true));
}
.with-performance-bar.with-system-header & {
@include ide-height-with((system-header: true, performance: true, flash: true));
}
.with-performance-bar.with-system-footer & {
@include ide-height-with((system-footer: true, performance: true, flash: true));
}
.with-performance-bar.with-system-header.with-system-footer & {
@include ide-height-with((system-header: true, system-footer: true, performance: true, flash: true));
}
}
}
module EE
module Admin
module AppearancesController
def allowed_appearance_params
super + %i[
header_message
footer_message
message_background_color
message_font_color
]
end
end
end
end
module EE
module AppearancesHelper
def header_message
return unless current_appearance&.show_header?
class_names = []
class_names << 'with-performance-bar' if performance_bar_enabled?
render_message(:header_message, class_names)
end
def footer_message
return unless current_appearance&.show_footer?
render_message(:footer_message)
end
private
def render_message(field_sym, class_names = [])
class_names << field_sym.to_s.dasherize
content_tag :div, class: class_names, style: message_style do
markdown_field(current_appearance, field_sym)
end
end
def message_style
style = ''
style << "background-color: #{current_appearance.message_background_color};"
style << "color: #{current_appearance.message_font_color}"
style
end
end
end
......@@ -9,5 +9,29 @@ module EE
(_('You are on a secondary (read-only) Geo node. If you want to make any changes, you must visit the %{primary_node}.') %
{ primary_node: link_to('primary node', ::Gitlab::Geo.primary_node.url) }).html_safe
end
def page_class
class_names = super
class_names += system_message_class
class_names
end
def system_message_class
class_names = []
return class_names unless appearance
class_names << 'with-system-header' if appearance.show_header?
class_names << 'with-system-footer' if appearance.show_footer?
class_names
end
private
def appearance
::Appearance.current
end
end
end
module EE
module Appearance
extend ActiveSupport::Concern
prepended do
cache_markdown_field :header_message, pipeline: :broadcast_message
cache_markdown_field :footer_message, pipeline: :broadcast_message
validates :message_background_color, allow_blank: true, color: true
validates :message_font_color, allow_blank: true, color: true
default_value_for :message_background_color, '#E75E40'
default_value_for :message_font_color, '#FFFFFF'
end
def show_header?
header_message.present?
end
def show_footer?
footer_message.present?
end
end
end
- form = local_assigns.fetch(:form)
%fieldset.system_header_footer
%legend
= _('System header and footer:')
.form-group
= form.label :header_message, _('Header message'), class: 'control-label'
.col-sm-10
= form.text_area :header_message, placeholder: _('State your message to activate'), class: "form-control js-autosize"
.form-group
= form.label :footer_message, _('Footer message'), class: 'control-label'
.col-sm-10
= form.text_area :footer_message, placeholder: _('State your message to activate'), class: "form-control js-autosize"
.form-group.js-toggle-colors-container
.col-sm-10.col-sm-offset-2
= link_to _('Customize colors'), '#', class: 'js-toggle-colors-link'
.form-group.js-toggle-colors-container.hide
= form.label :message_background_color, _('Background Color'), class: 'control-label'
.col-sm-10
= form.color_field :message_background_color, class: "form-control"
.form-group.js-toggle-colors-container.hide
= form.label :message_font_color, _('Font Color'), class: 'control-label'
.col-sm-10
= form.color_field :message_font_color, class: "form-control"
---
title: Add system header and footer as new appearance options
merge_request: 4972
author:
type: added
class AddHeaderAndFooterBannersToAppearancesTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :appearances, :header_message, :text
add_column :appearances, :header_message_html, :text
add_column :appearances, :footer_message, :text
add_column :appearances, :footer_message_html, :text
add_column :appearances, :message_background_color, :text
add_column :appearances, :message_font_color, :text
end
end
require 'rails_helper'
describe 'Display system header and footer bar' do
let(:header_message) { "Foo" }
let(:footer_message) { "Bar" }
shared_examples 'system header is configured' do
it 'shows system header' do
expect(page).to have_css('.header-message')
end
it 'shows the correct content' do
page.within('.header-message') do
expect(page).to have_content(header_message)
end
end
end
shared_examples 'system footer is configured' do
it 'shows system footer' do
expect(page).to have_css('.footer-message')
end
it 'shows the correct content' do
page.within('.footer-message') do
expect(page).to have_content(footer_message)
end
end
end
shared_examples 'system header is not configured' do
it 'does not show system header' do
expect(page).not_to have_css('.header-message')
end
end
shared_examples 'system footer is not configured' do
it 'does not show system footer' do
expect(page).not_to have_css('.footer-message')
end
end
context 'when authenticated' do
context 'when system header and footer are not configured' do
before do
sign_in(create(:user))
visit root_path
end
it_behaves_like 'system header is not configured'
it_behaves_like 'system footer is not configured'
end
context 'when only system header is defined' do
before do
create(:appearance, header_message: header_message)
sign_in(create(:user))
visit root_path
end
it_behaves_like 'system header is configured'
it_behaves_like 'system footer is not configured'
end
context 'when only system footer is defined' do
before do
create(:appearance, footer_message: footer_message)
sign_in(create(:user))
visit root_path
end
it_behaves_like 'system header is not configured'
it_behaves_like 'system footer is configured'
end
context 'when system header and footer are defined' do
before do
create(:appearance, header_message: header_message, footer_message: footer_message)
sign_in(create(:user))
visit root_path
end
it_behaves_like 'system header is configured'
it_behaves_like 'system footer is configured'
end
end
context 'when not authenticated' do
context 'when system header and footer are not configured' do
before do
visit root_path
end
it_behaves_like 'system header is not configured'
it_behaves_like 'system footer is not configured'
end
context 'when only system header is defined' do
before do
create(:appearance, header_message: header_message)
visit root_path
end
it_behaves_like 'system header is configured'
it_behaves_like 'system footer is not configured'
end
context 'when only system footer is defined' do
before do
create(:appearance, footer_message: footer_message)
visit root_path
end
it_behaves_like 'system header is not configured'
it_behaves_like 'system footer is configured'
end
context 'when system header and footer are defined' do
before do
create(:appearance, header_message: header_message, footer_message: footer_message)
visit root_path
end
it_behaves_like 'system header is configured'
it_behaves_like 'system footer is configured'
end
end
end
require 'spec_helper'
describe AppearancesHelper do
before do
user = create(:user)
allow(helper).to receive(:current_user).and_return(user)
end
describe '#header_message' do
it 'returns nil when header message field is not set' do
create(:appearance)
expect(helper.header_message).to be_nil
end
context 'when header message is set' do
it 'includes current message' do
message = "Foo bar"
create(:appearance, header_message: message)
expect(helper.header_message).to include(message)
end
end
end
describe '#footer_message' do
it 'returns nil when footer message field is not set' do
create(:appearance)
expect(helper.footer_message).to be_nil
end
context 'when footer message is set' do
it 'includes current message' do
message = "Foo bar"
create(:appearance, footer_message: message)
expect(helper.footer_message).to include(message)
end
end
end
end
require 'spec_helper'
describe Appearance do
subject { build(:appearance) }
describe 'validations' do
let(:triplet) { '#000' }
let(:hex) { '#AABBCC' }
it { is_expected.to allow_value(nil).for(:message_background_color) }
it { is_expected.to allow_value(triplet).for(:message_background_color) }
it { is_expected.to allow_value(hex).for(:message_background_color) }
it { is_expected.not_to allow_value('000').for(:message_background_color) }
it { is_expected.to allow_value(nil).for(:message_font_color) }
it { is_expected.to allow_value(triplet).for(:message_font_color) }
it { is_expected.to allow_value(hex).for(:message_font_color) }
it { is_expected.not_to allow_value('000').for(:message_font_color) }
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