BigW Consortium Gitlab

Commit 9c10683b by Grzegorz Bizon

Merge branch 'master' into backstage/gb/migrate-stages-statuses

* master: Fix background migration cleanup specs Fix JS; make buttons sr accessibile; fix overlay Isolate stage_id reference clean up migration Fix eslint Make sidebar accessible on mobile Add mobile navigation on project page Fix database schema version number Fix background migrations module specs Remove migration dependency from stage_id migration Remove obsolete argument from bg migrations code Add specs for stage_id reference cleanup migration Add pending set of specs for stage_id cleanup migration Rename stage_id reference clean up migration Implement build stage_id reference migration clean up
parents 54efa041 001dd56e
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, no-unused-vars, one-var, one-var-declaration-per-line, vars-on-top, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, no-unused-vars, one-var, one-var-declaration-per-line, vars-on-top, max-len */
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie';
import NewNavSidebar from './new_sidebar';
(function() { (function() {
var hideEndFade; var hideEndFade;
...@@ -53,6 +55,11 @@ import _ from 'underscore'; ...@@ -53,6 +55,11 @@ import _ from 'underscore';
} }
$(() => { $(() => {
if (Cookies.get('new_nav') === 'true') {
const newNavSidebar = new NewNavSidebar();
newNavSidebar.bindEvents();
}
$(window).on('scroll', _.throttle(applyScrollNavClass, 100)); $(window).on('scroll', _.throttle(applyScrollNavClass, 100));
}); });
}).call(window); }).call(window);
export default class NewNavSidebar {
constructor() {
this.initDomElements();
}
initDomElements() {
this.$sidebar = $('.nav-sidebar');
this.$overlay = $('.mobile-overlay');
this.$openSidebar = $('.toggle-mobile-nav');
this.$closeSidebar = $('.close-nav-button');
}
bindEvents() {
this.$openSidebar.on('click', () => this.toggleSidebarNav(true));
this.$closeSidebar.on('click', () => this.toggleSidebarNav(false));
this.$overlay.on('click', () => this.toggleSidebarNav(false));
}
toggleSidebarNav(show) {
this.$sidebar.toggleClass('nav-sidebar-expanded', show);
this.$overlay.toggleClass('mobile-nav-open', show);
}
}
...@@ -275,8 +275,6 @@ header.navbar-gitlab-new { ...@@ -275,8 +275,6 @@ header.navbar-gitlab-new {
.breadcrumbs { .breadcrumbs {
display: flex; display: flex;
min-height: 60px; min-height: 60px;
padding-top: $gl-padding-top;
padding-bottom: $gl-padding-top;
color: $gl-text-color; color: $gl-text-color;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
...@@ -300,6 +298,7 @@ header.navbar-gitlab-new { ...@@ -300,6 +298,7 @@ header.navbar-gitlab-new {
display: flex; display: flex;
width: 100%; width: 100%;
position: relative; position: relative;
align-items: center;
.dropdown-menu-projects { .dropdown-menu-projects {
margin-top: -$gl-padding; margin-top: -$gl-padding;
......
...@@ -26,41 +26,75 @@ $new-sidebar-width: 220px; ...@@ -26,41 +26,75 @@ $new-sidebar-width: 220px;
} }
.context-header { .context-header {
border-bottom: 1px solid $border-color; position: relative;
font-weight: 600;
display: flex;
align-items: center;
padding: 10px 16px 10px 10px;
color: $gl-text-color;
.avatar-container { a {
flex: 0 0 40px; border-bottom: 1px solid $border-color;
background-color: $white-light; font-weight: 600;
} display: flex;
align-items: center;
&:hover { padding: 10px 16px 10px 10px;
background-color: $hover-background; color: $gl-text-color;
color: $hover-color;
border-color: $hover-background;
.avatar-container { @media (max-width: $screen-xs-max) {
border-color: transparent; padding-right: 30px;
} }
.settings-avatar { &:hover {
background-color: $indigo-500; background-color: $hover-background;
color: $hover-color;
border-color: $hover-background;
i { .avatar-container {
color: $hover-color; border-color: transparent;
}
.settings-avatar {
background-color: $indigo-500;
i {
color: $hover-color;
}
} }
} }
} }
.avatar-container {
flex: 0 0 40px;
background-color: $white-light;
}
.project-title, .project-title,
.group-title { .group-title {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
&:hover {
.close-nav-button {
color: $white-light;
}
}
.close-nav-button {
display: none;
position: absolute;
top: 0;
right: 0;
height: 100%;
background-color: transparent;
border: 0;
padding: 0 10px;
@media (max-width: $screen-xs-max) {
display: block;
}
&:hover {
color: $gl-text-color;
}
}
} }
.settings-avatar { .settings-avatar {
...@@ -79,7 +113,7 @@ $new-sidebar-width: 220px; ...@@ -79,7 +113,7 @@ $new-sidebar-width: 220px;
position: fixed; position: fixed;
z-index: 400; z-index: 400;
width: $new-sidebar-width; width: $new-sidebar-width;
transition: width $sidebar-transition-duration; transition: left $sidebar-transition-duration;
top: 50px; top: 50px;
bottom: 0; bottom: 0;
left: 0; left: 0;
...@@ -87,6 +121,10 @@ $new-sidebar-width: 220px; ...@@ -87,6 +121,10 @@ $new-sidebar-width: 220px;
background-color: $gray-normal; background-color: $gray-normal;
box-shadow: inset -2px 0 0 $border-color; box-shadow: inset -2px 0 0 $border-color;
&.nav-sidebar-expanded {
left: 0;
}
a { a {
transition: none; transition: none;
text-decoration: none; text-decoration: none;
...@@ -117,7 +155,7 @@ $new-sidebar-width: 220px; ...@@ -117,7 +155,7 @@ $new-sidebar-width: 220px;
} }
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
width: 0; left: (-$new-sidebar-width);
} }
} }
...@@ -183,6 +221,38 @@ $new-sidebar-width: 220px; ...@@ -183,6 +221,38 @@ $new-sidebar-width: 220px;
} }
} }
.toggle-mobile-nav {
display: none;
background-color: transparent;
border: 0;
padding: 6px 16px;
margin: 0 16px 0 -15px;
height: 46px;
border-right: 1px solid $gl-text-color-quaternary;
i {
font-size: 20px;
color: $gl-text-color-secondary;
}
@media (max-width: $screen-xs-max) {
display: inline-block;
}
}
.mobile-overlay {
display: none;
&.mobile-nav-open {
display: block;
position: fixed;
background-color: $black-transparent;
height: 100%;
width: 100%;
z-index: 300;
}
}
// Make issue boards full-height now that sub-nav is gone // Make issue boards full-height now that sub-nav is gone
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
- if content_for?(:sub_nav) - if content_for?(:sub_nav)
= yield :sub_nav = yield :sub_nav
.content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" } .content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" }
- if show_new_nav?
.mobile-overlay
.alert-wrapper .alert-wrapper
= render "layouts/broadcast" = render "layouts/broadcast"
- if show_new_nav? - if show_new_nav?
......
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
%nav.breadcrumbs{ role: "navigation" } %nav.breadcrumbs{ role: "navigation" }
.breadcrumbs-container{ class: [container_class, @content_class] } .breadcrumbs-container{ class: [container_class, @content_class] }
- if defined?(@new_sidebar)
= button_tag class: 'toggle-mobile-nav', type: 'button' do
%span.sr-only Open sidebar
= icon ('bars')
.breadcrumbs-links.js-title-container .breadcrumbs-links.js-title-container
- unless hide_top_links - unless hide_top_links
.title .title
......
.nav-sidebar .nav-sidebar
= link_to admin_root_path, title: 'Admin Overview', class: 'context-header' do .context-header
.avatar-container.s40.settings-avatar = link_to admin_root_path, title: 'Admin Overview' do
= icon('wrench') .avatar-container.s40.settings-avatar
.project-title Admin Area = icon('wrench')
.project-title Admin Area
= button_tag class: 'close-nav-button', type: 'button' do
%span.sr-only Close sidebar
= icon ('times')
%ul.sidebar-top-level-items %ul.sidebar-top-level-items
= nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts), html_options: {class: 'home'}) do = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts), html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do = link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
......
.nav-sidebar .nav-sidebar
= link_to group_path(@group), title: @group.name, class: 'context-header' do .context-header
.avatar-container.s40.group-avatar = link_to group_path(@group), title: @group.name do
= image_tag group_icon(@group), class: "avatar s40 avatar-tile" .avatar-container.s40.group-avatar
.group-title = image_tag group_icon(@group), class: "avatar s40 avatar-tile"
= @group.name .group-title
= @group.name
= button_tag class: 'close-nav-button', type: 'button' do
%span.sr-only Close sidebar
= icon ('times')
%ul.sidebar-top-level-items %ul.sidebar-top-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do = nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'About group' do = link_to group_path(@group), title: 'About group' do
......
.nav-sidebar .nav-sidebar
= link_to profile_path, title: 'Profile Settings', class: 'context-header' do .context-header
.avatar-container.s40.settings-avatar = link_to profile_path, title: 'Profile Settings' do
= icon('user') .avatar-container.s40.settings-avatar
.project-title User Settings = icon('user')
.project-title User Settings
= button_tag class: 'close-nav-button', type: 'button' do
%span.sr-only Close sidebar
= icon ('times')
%ul.sidebar-top-level-items %ul.sidebar-top-level-items
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile Settings' do = link_to profile_path, title: 'Profile Settings' do
......
.nav-sidebar .nav-sidebar
- can_edit = can?(current_user, :admin_project, @project) - can_edit = can?(current_user, :admin_project, @project)
= link_to project_path(@project), title: @project.name, class: 'context-header' do .context-header
.avatar-container.s40.project-avatar = link_to project_path(@project), title: @project.name do
= project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile') .avatar-container.s40.project-avatar
.project-title = project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile')
= @project.name .project-title
= @project.name
= button_tag class: 'close-nav-button', type: 'button' do
%span.sr-only Close sidebar
= icon ('times')
%ul.sidebar-top-level-items %ul.sidebar-top-level-items
= nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do = nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
= link_to project_path(@project), title: 'About project', class: 'shortcuts-project' do = link_to project_path(@project), title: 'About project', class: 'shortcuts-project' do
......
class CleanStageIdReferenceMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
##
# `MigrateStageIdReferenceInBackground` background migration cleanup.
#
def up
Gitlab::BackgroundMigration.steal('MigrateBuildStageIdReference')
end
def down
# noop
end
end
...@@ -26,7 +26,7 @@ module Gitlab ...@@ -26,7 +26,7 @@ module Gitlab
next unless migration_class == steal_class next unless migration_class == steal_class
begin begin
perform(migration_class, migration_args, retries: 3) if job.delete perform(migration_class, migration_args) if job.delete
rescue Exception # rubocop:disable Lint/RescueException rescue Exception # rubocop:disable Lint/RescueException
BackgroundMigrationWorker # enqueue this migration again BackgroundMigrationWorker # enqueue this migration again
.perform_async(migration_class, migration_args) .perform_async(migration_class, migration_args)
......
...@@ -25,7 +25,7 @@ describe Gitlab::BackgroundMigration do ...@@ -25,7 +25,7 @@ describe Gitlab::BackgroundMigration do
expect(queue[0]).to receive(:delete).and_return(true) expect(queue[0]).to receive(:delete).and_return(true)
expect(described_class).to receive(:perform) expect(described_class).to receive(:perform)
.with('Foo', [10, 20], anything) .with('Foo', [10, 20])
described_class.steal('Foo') described_class.steal('Foo')
end end
...@@ -93,9 +93,9 @@ describe Gitlab::BackgroundMigration do ...@@ -93,9 +93,9 @@ describe Gitlab::BackgroundMigration do
it 'steals from the scheduled sets queue first' do it 'steals from the scheduled sets queue first' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
expect(described_class).to receive(:perform) expect(described_class).to receive(:perform)
.with('Object', [1], anything).ordered .with('Object', [1]).ordered
expect(described_class).to receive(:perform) expect(described_class).to receive(:perform)
.with('Object', [2], anything).ordered .with('Object', [2]).ordered
BackgroundMigrationWorker.perform_async('Object', [2]) BackgroundMigrationWorker.perform_async('Object', [2])
BackgroundMigrationWorker.perform_in(10.minutes, 'Object', [1]) BackgroundMigrationWorker.perform_in(10.minutes, 'Object', [1])
......
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20170710083355_clean_stage_id_reference_migration.rb')
describe CleanStageIdReferenceMigration, :migration, :sidekiq, :redis do
let(:migration_class) { 'MigrateBuildStageIdReference' }
let(:migration) { spy('migration') }
before do
allow(Gitlab::BackgroundMigration.const_get(migration_class))
.to receive(:new).and_return(migration)
end
context 'when there are pending background migrations' do
it 'processes pending jobs synchronously' do
Sidekiq::Testing.disable! do
BackgroundMigrationWorker.perform_in(2.minutes, migration_class, [1, 1])
BackgroundMigrationWorker.perform_async(migration_class, [1, 1])
migrate!
expect(migration).to have_received(:perform).with(1, 1).twice
end
end
end
context 'when there are no background migrations pending' do
it 'does nothing' do
Sidekiq::Testing.disable! do
migrate!
expect(migration).not_to have_received(:perform)
end
end
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