Commit b46ac16c authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch '28187-project-name-cut-off-with-nested-groups' into 'master'

Resolve "Project name cut off with nested groups"

Closes #28187 and #28179

See merge request !10065
parents 86e2b07a 004f3a0b
const GROUP_LIMIT = 2;
import _ from 'underscore';
export default class GroupName { export default class GroupName {
constructor() { constructor() {
this.titleContainer = document.querySelector('.title'); this.titleContainer = document.querySelector('.title-container');
this.groups = document.querySelectorAll('.group-path'); this.title = document.querySelector('.title');
this.titleWidth = this.title.offsetWidth;
this.groupTitle = document.querySelector('.group-title'); this.groupTitle = document.querySelector('.group-title');
this.groups = document.querySelectorAll('.group-path');
this.toggle = null; this.toggle = null;
this.isHidden = false; this.isHidden = false;
this.init(); this.init();
} }
init() { init() {
if (this.groups.length > GROUP_LIMIT) { if (this.groups.length > 0) {
this.groups[this.groups.length - 1].classList.remove('hidable'); this.groups[this.groups.length - 1].classList.remove('hidable');
this.addToggle(); this.toggleHandler();
window.addEventListener('resize', _.debounce(this.toggleHandler.bind(this), 100));
} }
this.render(); this.render();
} }
addToggle() { toggleHandler() {
const header = document.querySelector('.header-content'); if (this.titleWidth > this.titleContainer.offsetWidth) {
if (!this.toggle) this.createToggle();
this.showToggle();
} else if (this.toggle) {
this.hideToggle();
}
}
createToggle() {
this.toggle = document.createElement('button'); this.toggle = document.createElement('button');
this.toggle.className = 'text-expander group-name-toggle'; this.toggle.className = 'text-expander group-name-toggle';
this.toggle.setAttribute('aria-label', 'Toggle full path'); this.toggle.setAttribute('aria-label', 'Toggle full path');
this.toggle.innerHTML = '...'; this.toggle.innerHTML = '...';
this.toggle.addEventListener('click', this.toggleGroups.bind(this)); this.toggle.addEventListener('click', this.toggleGroups.bind(this));
header.insertBefore(this.toggle, this.titleContainer); this.titleContainer.insertBefore(this.toggle, this.title);
this.toggleGroups(); this.toggleGroups();
} }
showToggle() {
this.title.classList.add('wrap');
this.toggle.classList.remove('hidden');
if (this.isHidden) this.groupTitle.classList.add('is-hidden');
}
hideToggle() {
this.title.classList.remove('wrap');
this.toggle.classList.add('hidden');
if (this.isHidden) this.groupTitle.classList.remove('is-hidden');
}
toggleGroups() { toggleGroups() {
this.isHidden = !this.isHidden; this.isHidden = !this.isHidden;
this.groupTitle.classList.toggle('is-hidden'); this.groupTitle.classList.toggle('is-hidden');
} }
render() { render() {
this.titleContainer.classList.remove('initializing'); this.title.classList.remove('initializing');
} }
} }
...@@ -26,7 +26,7 @@ header { ...@@ -26,7 +26,7 @@ header {
padding: 0 16px; padding: 0 16px;
z-index: 100; z-index: 100;
margin-bottom: 0; margin-bottom: 0;
height: $header-height; min-height: $header-height;
background-color: $gray-light; background-color: $gray-light;
border: none; border: none;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
...@@ -85,7 +85,7 @@ header { ...@@ -85,7 +85,7 @@ header {
.navbar-toggle { .navbar-toggle {
color: $nav-toggle-gray; color: $nav-toggle-gray;
margin: 6px 0; margin: 7px 0;
border-radius: 0; border-radius: 0;
position: absolute; position: absolute;
right: -10px; right: -10px;
...@@ -135,12 +135,14 @@ header { ...@@ -135,12 +135,14 @@ header {
} }
.header-content { .header-content {
display: flex;
justify-content: space-between;
position: relative; position: relative;
height: $header-height; min-height: $header-height;
padding-left: 30px; padding-left: 30px;
@media (min-width: $screen-sm-min) { @media (max-width: $screen-sm-max) {
padding-right: 0; padding-right: 20px;
} }
.dropdown-menu { .dropdown-menu {
...@@ -165,8 +167,7 @@ header { ...@@ -165,8 +167,7 @@ header {
} }
.group-name-toggle { .group-name-toggle {
margin: 0 5px; margin: 3px 5px;
vertical-align: sub;
} }
.group-title { .group-title {
...@@ -177,39 +178,32 @@ header { ...@@ -177,39 +178,32 @@ header {
} }
} }
.title-container {
display: flex;
align-items: flex-start;
flex: 1 1 auto;
padding-top: (($header-height - 19) / 2);
overflow: hidden;
}
.title { .title {
position: relative; position: relative;
padding-right: 20px; padding-right: 20px;
margin: 0; margin: 0;
font-size: 18px; font-size: 18px;
max-width: 385px; line-height: 22px;
display: inline-block; display: inline-block;
line-height: $header-height;
font-weight: normal; font-weight: normal;
color: $gl-text-color; color: $gl-text-color;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top; vertical-align: top;
white-space: nowrap; white-space: nowrap;
&.initializing { &.wrap {
display: none; white-space: normal;
}
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
max-width: 300px;
}
@media (max-width: $screen-xs-max) {
max-width: 190px;
}
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
max-width: 428px;
} }
@media (min-width: $screen-lg-min) { &.initializing {
max-width: 685px; opacity: 0;
} }
a { a {
...@@ -226,10 +220,10 @@ header { ...@@ -226,10 +220,10 @@ header {
border: transparent; border: transparent;
background: transparent; background: transparent;
position: absolute; position: absolute;
top: 2px;
right: 3px; right: 3px;
width: 12px; width: 12px;
line-height: 19px; line-height: 19px;
margin-top: (($header-height - 19) / 2);
padding: 0; padding: 0;
font-size: 10px; font-size: 10px;
text-align: center; text-align: center;
...@@ -247,7 +241,7 @@ header { ...@@ -247,7 +241,7 @@ header {
} }
.navbar-collapse { .navbar-collapse {
float: right; flex: 0 0 auto;
border-top: none; border-top: none;
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
...@@ -255,7 +249,7 @@ header { ...@@ -255,7 +249,7 @@ header {
} }
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
float: none; flex: 1 1 auto;
} }
} }
} }
......
...@@ -142,7 +142,9 @@ ...@@ -142,7 +142,9 @@
border: 1px solid $border-gray-dark; border: 1px solid $border-gray-dark;
border-radius: $border-radius-default; border-radius: $border-radius-default;
margin-left: 5px; margin-left: 5px;
line-height: 1; font-size: $gl-font-size;
line-height: $gl-font-size;
outline: none;
&:hover { &:hover {
background-color: darken($gray-light, 10%); background-color: darken($gray-light, 10%);
......
...@@ -9,6 +9,13 @@ ...@@ -9,6 +9,13 @@
} }
} }
.group-root-path {
max-width: 40vw;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: nowrap;
}
.group-row { .group-row {
.stats { .stats {
float: right; float: right;
......
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
%span.sr-only Toggle navigation %span.sr-only Toggle navigation
= icon('ellipsis-v') = icon('ellipsis-v')
.header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do
= brand_header_logo
.title-container
%h1.title{ class: ('initializing' if @has_group_title) }= title
.navbar-collapse.collapse .navbar-collapse.collapse
%ul.nav.navbar-nav %ul.nav.navbar-nav
%li.hidden-sm.hidden-xs %li.hidden-sm.hidden-xs
...@@ -63,12 +70,6 @@ ...@@ -63,12 +70,6 @@
%div %div
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success' = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
.header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do
= brand_header_logo
%h1.title{ class: ('initializing' if @has_group_title) }= title
= yield :header_content = yield :header_content
= render 'shared/outdated_browser' = render 'shared/outdated_browser'
......
- parent = Group.find_by(id: params[:parent_id] || @group.parent_id) - parent = Group.find_by(id: params[:parent_id] || @group.parent_id)
- group_path = root_url
- group_path << parent.full_path + '/' if parent
- if @group.persisted? - if @group.persisted?
.form-group .form-group
= f.label :name, class: 'control-label' do = f.label :name, class: 'control-label' do
...@@ -11,7 +13,7 @@ ...@@ -11,7 +13,7 @@
Group path Group path
.col-sm-10 .col-sm-10
.input-group.gl-field-error-anchor .input-group.gl-field-error-anchor
.input-group-addon .group-root-path.input-group-addon.has-tooltip{ title: group_path, :'data-placement' => 'bottom' }
%span>= root_url %span>= root_url
- if parent - if parent
%strong= parent.full_path + '/' %strong= parent.full_path + '/'
......
...@@ -6,39 +6,46 @@ feature 'Group name toggle', feature: true, js: true do ...@@ -6,39 +6,46 @@ feature 'Group name toggle', feature: true, js: true do
let(:nested_group_2) { create(:group, parent: nested_group_1) } let(:nested_group_2) { create(:group, parent: nested_group_1) }
let(:nested_group_3) { create(:group, parent: nested_group_2) } let(:nested_group_3) { create(:group, parent: nested_group_2) }
SMALL_SCREEN = 300
before do before do
login_as :user login_as :user
end end
it 'is not present for less than 3 groups' do it 'is not present if enough horizontal space' do
visit group_path(group) visit group_path(nested_group_3)
expect(page).not_to have_css('.group-name-toggle')
visit group_path(nested_group_1) container_width = page.evaluate_script("$('.title-container')[0].offsetWidth")
title_width = page.evaluate_script("$('.title')[0].offsetWidth")
expect(container_width).to be > title_width
expect(page).not_to have_css('.group-name-toggle') expect(page).not_to have_css('.group-name-toggle')
end end
it 'is present for nested group of 3 or more in the namespace' do it 'is present if the title is longer than the container' do
visit group_path(nested_group_2)
expect(page).to have_css('.group-name-toggle')
visit group_path(nested_group_3) visit group_path(nested_group_3)
expect(page).to have_css('.group-name-toggle') title_width = page.evaluate_script("$('.title')[0].offsetWidth")
page_height = page.current_window.size[1]
page.current_window.resize_to(SMALL_SCREEN, page_height)
find('.group-name-toggle')
container_width = page.evaluate_script("$('.title-container')[0].offsetWidth")
expect(title_width).to be > container_width
end end
context 'for group with at least 3 groups' do it 'should show the full group namespace when toggled' do
before do page_height = page.current_window.size[1]
visit group_path(nested_group_2) page.current_window.resize_to(SMALL_SCREEN, page_height)
end visit group_path(nested_group_3)
it 'should show the full group namespace when toggled' do expect(page).not_to have_content(group.name)
expect(page).not_to have_content(group.name) expect(page).to have_css('.group-path.hidable', visible: false)
expect(page).to have_css('.group-path.hidable', visible: false)
click_button '...' click_button '...'
expect(page).to have_content(group.name) expect(page).to have_content(group.name)
expect(page).to have_css('.group-path.hidable', visible: true) expect(page).to have_css('.group-path.hidable', visible: true)
end
end end
end end
...@@ -18,7 +18,7 @@ feature 'toggler_behavior', js: true, feature: true do ...@@ -18,7 +18,7 @@ feature 'toggler_behavior', js: true, feature: true do
it 'should be scrolled down to fragment' do it 'should be scrolled down to fragment' do
page_height = page.current_window.size[1] page_height = page.current_window.size[1]
page_scroll_y = page.evaluate_script("window.scrollY") page_scroll_y = page.evaluate_script("window.scrollY")
fragment_position_top = page.evaluate_script("$('#{fragment_id}').offset().top") fragment_position_top = page.evaluate_script("Math.round($('#{fragment_id}').offset().top)")
expect(find('.js-toggle-content').visible?).to eq true expect(find('.js-toggle-content').visible?).to eq true
expect(find(fragment_id).visible?).to eq true expect(find(fragment_id).visible?).to eq true
expect(fragment_position_top).to be >= page_scroll_y expect(fragment_position_top).to be >= page_scroll_y
......
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