diff options
author | Rubén Dávila <ruben@gitlab.com> | 2017-08-16 18:29:04 -0500 |
---|---|---|
committer | Rubén Dávila <ruben@gitlab.com> | 2017-08-16 18:29:04 -0500 |
commit | a3fbe3fedeb700f43bfa0de7e9113b3cff943c4e (patch) | |
tree | 4075549fa4b898c1187e8adecd112cea50ee880b | |
parent | 72d5165bd57472692c77d6a9d159e65058513bf3 (diff) | |
download | gitlab-ce-revert-merge-request-9199.tar.gz |
WIP: Revert "Merge branch '26200-convert-sidebar-to-dropdown' into 'master'"revert-merge-request-9199
This reverts commit aa792b91bbddeeb61ce77f9525fcaf238a9ad331, reversing
changes made to 5d8f5328baca93b9134f10ae593e71834578a9f8.
Conflicts:
app/assets/javascripts/application.js
app/assets/javascripts/right_sidebar.js
app/assets/stylesheets/framework.scss
app/assets/stylesheets/framework/header.scss
app/assets/stylesheets/framework/sidebar.scss
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/pages/issuable.scss
app/assets/stylesheets/print.scss
app/controllers/profiles/preferences_controller.rb
app/helpers/nav_helper.rb
app/models/user.rb
app/views/layouts/_page.html.haml
app/views/layouts/application.html.haml
app/views/layouts/header/_default.html.haml
app/views/layouts/nav/_dashboard.html.haml
app/views/profiles/preferences/show.html.haml
db/schema.rb
doc/api/users.md
spec/features/dashboard/active_tab_spec.rb
spec/features/dashboard/issuables_counter_spec.rb
spec/features/dashboard/shortcuts_spec.rb
spec/features/profiles/preferences_spec.rb
spec/fixtures/api/schemas/user/public.json
spec/models/user_spec.rb
Please enter the commit message for your changes. Lines starting
with '#' will be ignored, and an empty message aborts the commit.
On branch revert-merge-request-9199
You are currently reverting commit aa792b91bb.
47 files changed, 1132 insertions, 32 deletions
diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js index 0a811627600..8365f7118d5 100644 --- a/app/assets/javascripts/project_label_subscription.js +++ b/app/assets/javascripts/project_label_subscription.js @@ -38,15 +38,13 @@ this.$buttons.attr('data-status', newStatus); this.$buttons.find('> span').text(newAction); - this.$buttons.map((button) => { + for (const button of this.$buttons) { const $button = $(button); if ($button.attr('data-original-title')) { $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); } - - return button; - }); + } }); } } diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index fa958d75fa4..668277ef111 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -23,15 +23,22 @@ import SidebarHeightManager from './sidebar_height_manager'; }; Sidebar.prototype.addEventListeners = function() { +<<<<<<< HEAD SidebarHeightManager.init(); const $document = $(document); +======= +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked); $('.dropdown').on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden); $('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading); $('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded); +<<<<<<< HEAD $document.on('click', '.js-sidebar-toggle', function(e, triggered) { +======= + $(document).on('click', '.js-sidebar-toggle', function(e, triggered) { +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' var $allGutterToggleIcons, $this, $thisIcon; e.preventDefault(); $this = $(this); diff --git a/app/assets/javascripts/sidebar.js.es6 b/app/assets/javascripts/sidebar.js.es6 new file mode 100644 index 00000000000..33e4b7db681 --- /dev/null +++ b/app/assets/javascripts/sidebar.js.es6 @@ -0,0 +1,111 @@ +/* eslint-disable arrow-parens, class-methods-use-this, no-param-reassign */ +/* global Cookies */ + +(() => { + const pinnedStateCookie = 'pin_nav'; + const sidebarBreakpoint = 1024; + + const pageSelector = '.page-with-sidebar'; + const navbarSelector = '.navbar-gitlab'; + const sidebarWrapperSelector = '.sidebar-wrapper'; + const sidebarContentSelector = '.nav-sidebar'; + + const pinnedToggleSelector = '.js-nav-pin'; + const sidebarToggleSelector = '.toggle-nav-collapse, .side-nav-toggle'; + + const pinnedPageClass = 'page-sidebar-pinned'; + const expandedPageClass = 'page-sidebar-expanded'; + + const pinnedNavbarClass = 'header-sidebar-pinned'; + const expandedNavbarClass = 'header-sidebar-expanded'; + + class Sidebar { + constructor() { + if (!Sidebar.singleton) { + Sidebar.singleton = this; + Sidebar.singleton.init(); + } + + return Sidebar.singleton; + } + + init() { + this.isPinned = Cookies.get(pinnedStateCookie) === 'true'; + this.isExpanded = ( + window.innerWidth >= sidebarBreakpoint && + $(pageSelector).hasClass(expandedPageClass) + ); + $(window).on('resize', () => this.setSidebarHeight()); + $(document) + .on('click', sidebarToggleSelector, () => this.toggleSidebar()) + .on('click', pinnedToggleSelector, () => this.togglePinnedState()) + .on('click', 'html, body, a, button', (e) => this.handleClickEvent(e)) + .on('DOMContentLoaded', () => this.renderState()) + .on('scroll', () => this.setSidebarHeight()) + .on('todo:toggle', (e, count) => this.updateTodoCount(count)); + this.renderState(); + this.setSidebarHeight(); + } + + handleClickEvent(e) { + if (this.isExpanded && (!this.isPinned || window.innerWidth < sidebarBreakpoint)) { + const $target = $(e.target); + const targetIsToggle = $target.closest(sidebarToggleSelector).length > 0; + const targetIsSidebar = $target.closest(sidebarWrapperSelector).length > 0; + if (!targetIsToggle && (!targetIsSidebar || $target.closest('a'))) { + this.toggleSidebar(); + } + } + } + + updateTodoCount(count) { + $('.js-todos-count').text(gl.text.addDelimiter(count)); + } + + toggleSidebar() { + this.isExpanded = !this.isExpanded; + this.renderState(); + } + + setSidebarHeight() { + const $navHeight = $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight(); + const diff = $navHeight - $('body').scrollTop(); + if (diff > 0) { + $('.js-right-sidebar').outerHeight($(window).height() - diff); + } else { + $('.js-right-sidebar').outerHeight('100%'); + } + } + + togglePinnedState() { + this.isPinned = !this.isPinned; + if (!this.isPinned) { + this.isExpanded = false; + } + Cookies.set(pinnedStateCookie, this.isPinned ? 'true' : 'false', { expires: 3650 }); + this.renderState(); + } + + renderState() { + $(pageSelector) + .toggleClass(pinnedPageClass, this.isPinned && this.isExpanded) + .toggleClass(expandedPageClass, this.isExpanded); + $(navbarSelector) + .toggleClass(pinnedNavbarClass, this.isPinned && this.isExpanded) + .toggleClass(expandedNavbarClass, this.isExpanded); + + const $pinnedToggle = $(pinnedToggleSelector); + const tooltipText = this.isPinned ? 'Unpin navigation' : 'Pin navigation'; + const tooltipState = $pinnedToggle.attr('aria-describedby') && this.isExpanded ? 'show' : 'hide'; + $pinnedToggle.attr('title', tooltipText).tooltip('fixTitle').tooltip(tooltipState); + + if (this.isExpanded) { + const sidebarContent = $(sidebarContentSelector); + setTimeout(() => { sidebarContent.niceScroll().updateScrollBar(); }, 200); + } + } + } + + window.gl = window.gl || {}; + gl.Sidebar = Sidebar; +})(); diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index b2b3297e880..f1df760b915 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -4,6 +4,7 @@ @import 'framework/tw_bootstrap'; @import "framework/layout"; +<<<<<<< HEAD @import "framework/animations"; @import "framework/avatar"; @import "framework/asciidoctor"; @@ -39,6 +40,42 @@ @import "framework/timeline"; @import "framework/typography"; @import "framework/zen"; +======= +@import "framework/animations.scss"; +@import "framework/avatar.scss"; +@import "framework/asciidoctor.scss"; +@import "framework/blocks.scss"; +@import "framework/buttons.scss"; +@import "framework/badges.scss"; +@import "framework/calendar.scss"; +@import "framework/callout.scss"; +@import "framework/common.scss"; +@import "framework/dropdowns.scss"; +@import "framework/files.scss"; +@import "framework/filters.scss"; +@import "framework/flash.scss"; +@import "framework/forms.scss"; +@import "framework/gfm.scss"; +@import "framework/gitlab-theme.scss"; +@import "framework/header.scss"; +@import "framework/highlight.scss"; +@import "framework/issue_box.scss"; +@import "framework/jquery.scss"; +@import "framework/lists.scss"; +@import "framework/logo.scss"; +@import "framework/markdown_area.scss"; +@import "framework/mobile.scss"; +@import "framework/modal.scss"; +@import "framework/nav.scss"; +@import "framework/pagination.scss"; +@import "framework/panels.scss"; +@import "framework/selects.scss"; +@import "framework/sidebar.scss"; +@import "framework/tables.scss"; +@import "framework/timeline.scss"; +@import "framework/typography.scss"; +@import "framework/zen.scss"; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' @import "framework/blank"; @import "framework/wells"; @import "framework/page-header"; diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss index 667b73e150d..234ca0b11a9 100644 --- a/app/assets/stylesheets/framework/animations.scss +++ b/app/assets/stylesheets/framework/animations.scss @@ -116,7 +116,7 @@ } .btn, -.global-dropdown-toggle { +.side-nav-toggle { @include transition(background-color, border-color, color, box-shadow); } @@ -140,6 +140,7 @@ a { @include transition(background-color, box-shadow); } +.nav-sidebar a, .dropdown-menu a, .dropdown-menu button, .dropdown-menu-nav a { diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss new file mode 100644 index 00000000000..d6566dc4ec9 --- /dev/null +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -0,0 +1,144 @@ +/** + * Styles the GitLab application with a specific color theme + * + * $color-light - + * $color - + * $color-darker - + * $color-dark - + */ +@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) { + .page-with-sidebar { + .toggle-nav-collapse, + .pin-nav-btn { + color: $color-light; + + &:hover { + color: $white-light; + } + } + + .sidebar-wrapper { + background: $color-darker; + } + + .sidebar-action-buttons { + color: $color-light; + background-color: lighten($color-darker, 5%); + } + + .nav-sidebar { + li { + a { + color: $color-light; + + &:hover, + &:focus, + &:active { + background: $color-dark; + } + + i { + color: $color-light; + } + + path, + polygon { + fill: $color-light; + } + + .count { + color: $color-light; + background: $color-dark; + } + + svg { + position: relative; + top: 3px; + } + } + + &.separate-item { + border-top: 1px solid $color; + } + + &.active a { + color: $white-light; + background: $color-dark; + + &.no-highlight { + border: none; + } + + i { + color: $white-light; + } + + path, + polygon { + fill: $white-light; + } + } + } + + .about-gitlab { + color: $color-light; + } + } + } +} + +$theme-charcoal-light: #b9bbbe; +$theme-charcoal: #485157; +$theme-charcoal-dark: #3d454d; +$theme-charcoal-darker: #383f45; + +$theme-blue-light: #becde9; +$theme-blue: #2980b9; +$theme-blue-dark: #1970a9; +$theme-blue-darker: #096099; + +$theme-graphite-light: #ccc; +$theme-graphite: #777; +$theme-graphite-dark: #666; +$theme-graphite-darker: #555; + +$theme-black-light: #979797; +$theme-black: #373737; +$theme-black-dark: #272727; +$theme-black-darker: #222; + +$theme-green-light: #adc; +$theme-green: #019875; +$theme-green-dark: #018865; +$theme-green-darker: #017855; + +$theme-violet-light: #98c; +$theme-violet: #548; +$theme-violet-dark: #436; +$theme-violet-darker: #325; + +body { + &.ui_blue { + @include gitlab-theme($theme-blue-light, $theme-blue, $theme-blue-dark, $theme-blue-darker); + } + + &.ui_charcoal { + @include gitlab-theme($theme-charcoal-light, $theme-charcoal, $theme-charcoal-dark, $theme-charcoal-darker); + } + + &.ui_graphite { + @include gitlab-theme($theme-graphite-light, $theme-graphite, $theme-graphite-dark, $theme-graphite-darker); + } + + &.ui_black { + @include gitlab-theme($theme-black-light, $theme-black, $theme-black-dark, $theme-black-darker); + } + + &.ui_green { + @include gitlab-theme($theme-green-light, $theme-green, $theme-green-dark, $theme-green-darker); + } + + &.ui_violet { + @include gitlab-theme($theme-violet-light, $theme-violet, $theme-violet-dark, $theme-violet-darker); + } +} diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index b677882eba4..59fb1d760e8 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -132,6 +132,7 @@ header { } } } +<<<<<<< HEAD } &.navbar-gitlab-new { @@ -161,10 +162,26 @@ header { li { &.active a { font-weight: bold; +======= + + .side-nav-toggle { + position: absolute; + left: -10px; + margin: 7px 0; + font-size: 18px; + padding: 6px 10px; + border: none; + background-color: $gray-light; + + &:hover { + background-color: $white-normal; + color: $gl-header-nav-hover-color; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' } } } +<<<<<<< HEAD .global-dropdown-toggle { margin: 7px 0; font-size: 18px; @@ -182,6 +199,8 @@ header { } } +======= +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' .header-content { display: flex; justify-content: space-between; diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 40e8a928e6e..50d8198577e 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -1,3 +1,36 @@ +.page-with-sidebar { + padding-bottom: 25px; + transition: padding $sidebar-transition-duration; + + &.page-sidebar-pinned { + .sidebar-wrapper { + box-shadow: none; + } + } + + .sidebar-wrapper { + position: fixed; + top: 0; + bottom: 0; + left: 0; + height: 100%; + width: 0; + overflow: hidden; + transition: width $sidebar-transition-duration; + box-shadow: 2px 0 16px 0 $black-transparent; + } +} + +.sidebar-wrapper { + z-index: 1000; + background: $gray-light; + + .nicescroll-rails-hr { + // TODO: Figure out why nicescroll doesn't hide horizontal bar + display: none!important; + } +} + .content-wrapper { width: 100%; transition: padding $sidebar-transition-duration; @@ -14,6 +47,105 @@ } } +.nav-sidebar { + position: absolute; + top: 50px; + bottom: 0; + width: $sidebar_width; + overflow-y: auto; + overflow-x: hidden; + + &.navbar-collapse { + padding: 0 !important; + } + + li { + &.separate-item { + padding-top: 10px; + margin-top: 10px; + } + + .icon-container { + width: 34px; + display: inline-block; + text-align: center; + } + + a { + padding: 7px $gl-sidebar-padding; + font-size: $gl-font-size; + line-height: 24px; + display: block; + text-decoration: none; + font-weight: normal; + + &:hover, + &:active, + &:focus { + text-decoration: none; + } + + i { + font-size: 16px; + } + + i, + svg { + margin-right: 13px; + } + } + } + + .count { + float: right; + padding: 0 8px; + border-radius: 6px; + } + + .about-gitlab { + padding: 7px $gl-sidebar-padding; + font-size: $gl-font-size; + line-height: 24px; + display: block; + text-decoration: none; + font-weight: normal; + position: absolute; + bottom: 10px; + } +} + +.sidebar-action-buttons { + width: $sidebar_width; + position: absolute; + top: 0; + left: 0; + min-height: 50px; + padding: 5px 0; + font-size: 18px; + line-height: 30px; + + .toggle-nav-collapse { + left: 0; + } + + .pin-nav-btn { + right: 0; + display: none; + + @media (min-width: $sidebar-breakpoint) { + display: block; + } + + .fa { + transition: transform .15s; + + .page-sidebar-pinned & { + transform: rotate(90deg); + } + } + } +} + .nav-header-btn { padding: 10px $gl-sidebar-padding; color: inherit; @@ -29,16 +161,64 @@ } } +.page-sidebar-expanded { + .sidebar-wrapper { + width: $sidebar_width; + } +} + +.page-sidebar-pinned { + .content-wrapper, + .layout-nav { + @media (min-width: $sidebar-breakpoint) { + padding-left: $sidebar_width; + } + } + + .merge-request-tabs-holder.affix { + @media (min-width: $sidebar-breakpoint) { + left: $sidebar_width; + } + } + + &.right-sidebar-expanded { + .line-resolve-all-container { + @media (min-width: $sidebar-breakpoint) { + display: none; + } + } + } +} + +header.header-sidebar-pinned { + @media (min-width: $sidebar-breakpoint) { + padding-left: ($sidebar_width + $gl-padding); + + .side-nav-toggle { + display: none; + } + + .header-content { + padding-left: 0; + } + } +} + .right-sidebar-collapsed { padding-right: 0; @media (min-width: $screen-sm-min) { +<<<<<<< HEAD &:not(.wiki-sidebar):not(.build-sidebar):not(.issuable-bulk-update-sidebar) .content-wrapper { padding-right: $gutter_collapsed_width; +======= + .content-wrapper { + padding-right: $sidebar_collapsed_width; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' } .merge-request-tabs-holder.affix { - right: $gutter_collapsed_width; + right: $sidebar_collapsed_width; } } @@ -56,8 +236,13 @@ z-index: 300; @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { +<<<<<<< HEAD &:not(.wiki-sidebar):not(.build-sidebar):not(.issuable-bulk-update-sidebar) .content-wrapper { padding-right: $gutter_collapsed_width; +======= + &:not(.build-sidebar):not(.wiki-sidebar) { + padding-right: $sidebar_collapsed_width; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' } } @@ -71,9 +256,16 @@ } &.with-overlay .merge-request-tabs-holder.affix { - right: $gutter_collapsed_width; + right: $sidebar_collapsed_width; } } +<<<<<<< HEAD +======= + + &.with-overlay { + padding-right: $sidebar_collapsed_width; + } +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' } .right-sidebar { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 3c109a5a929..f302292eaa9 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -1,6 +1,8 @@ /* * Layout */ +$sidebar_collapsed_width: 62px; +$sidebar_width: 220px; $gutter_collapsed_width: 62px; $gutter_width: 290px; $gutter_inner_width: 250px; @@ -590,6 +592,7 @@ Pipeline Graph */ $stage-hover-bg: #eaf3fc; $stage-hover-border: #d1e7fc; +<<<<<<< HEAD $action-icon-color: #d6d6d6; /* @@ -645,3 +648,6 @@ Project Templates Icons $rails: #c00; $node: #353535; $java: #70ad51; +======= +$action-icon-color: #d6d6d6; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 1dac38f2b6d..68af3ec2327 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -322,11 +322,20 @@ display: block; } +<<<<<<< HEAD width: $gutter_collapsed_width; padding: 0; .block { width: $gutter_collapsed_width - 2px; +======= + width: $sidebar_collapsed_width; + padding-top: 0; + + .block { + width: $sidebar_collapsed_width - 2px; + margin-left: -19px; +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' padding: 15px 0 0; border-bottom: none; overflow: hidden; diff --git a/app/assets/stylesheets/pages/profiles/preferences.scss b/app/assets/stylesheets/pages/profiles/preferences.scss index 305feaacaa1..100ace41f2a 100644 --- a/app/assets/stylesheets/pages/profiles/preferences.scss +++ b/app/assets/stylesheets/pages/profiles/preferences.scss @@ -1,3 +1,42 @@ +.application-theme { + label { + margin-right: 20px; + text-align: center; + + .preview { + border-radius: 4px; + + height: 80px; + margin-bottom: 10px; + width: 160px; + + &.ui_blue { + background: $theme-blue; + } + + &.ui_charcoal { + background: $theme-charcoal; + } + + &.ui_graphite { + background: $theme-graphite; + } + + &.ui_black { + background: $theme-black; + } + + &.ui_green { + background: $theme-green; + } + + &.ui_violet { + background: $theme-violet; + } + } + } +} + .syntax-theme { label { margin-right: 20px; diff --git a/app/assets/stylesheets/print.scss b/app/assets/stylesheets/print.scss index 113e6e86bb5..0570c38f6f7 100644 --- a/app/assets/stylesheets/print.scss +++ b/app/assets/stylesheets/print.scss @@ -28,6 +28,13 @@ nav.navbar-collapse.collapse, .profiler-results, .tree-ref-holder, .tree-holder .breadcrumb, +<<<<<<< HEAD +======= +.blob-commit-info, +.file-title, +.file-holder, +.sidebar-wrapper, +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' .nav, .btn, ul.notes-form, diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index fa1bc72560e..345e02e5f4b 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -204,6 +204,7 @@ class Admin::UsersController < Admin::ApplicationController :provider, :remember_me, :skype, + :theme_id, :twitter, :username, :website_url diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb index 1e557c47638..cce2a847b53 100644 --- a/app/controllers/profiles/preferences_controller.rb +++ b/app/controllers/profiles/preferences_controller.rb @@ -35,7 +35,8 @@ class Profiles::PreferencesController < Profiles::ApplicationController :color_scheme_id, :layout, :dashboard, - :project_view + :project_view, + :theme_id ) end end diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index b63b3b70903..dad4c1f666a 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -1,10 +1,17 @@ module NavHelper +<<<<<<< HEAD def page_with_sidebar_class class_name = page_gutter_class class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @new_sidebar class_name +======= + def page_sidebar_class + if pinned_nav? + "page-sidebar-expanded page-sidebar-pinned" + end +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' end def page_gutter_class @@ -34,7 +41,15 @@ module NavHelper class_names = [] class_names << 'with-horizontal-nav' if defined?(nav) && nav +<<<<<<< HEAD class_names +======= + if pinned_nav? + class_name << " header-sidebar-expanded header-sidebar-pinned" + end + + class_name +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' end def layout_nav_class @@ -50,4 +65,8 @@ module NavHelper def nav_control_class "nav-control" if current_user end + + def pinned_nav? + cookies[:pin_nav] == 'true' + end end diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index d36bb4ab074..64605908c05 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -40,6 +40,10 @@ module PreferencesHelper ] end + def user_application_theme + Gitlab::Themes.for_user(current_user).css_class + end + def user_color_scheme Gitlab::ColorSchemes.for_user(current_user).css_class end diff --git a/app/models/user.rb b/app/models/user.rb index 0e2654ff757..20341cf6f1c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,6 +31,7 @@ class User < ActiveRecord::Base default_value_for :project_view, :files default_value_for :notified_of_own_activity, false default_value_for :preferred_language, I18n.default_locale + default_value_for :theme_id, gitlab_config.default_theme attr_encrypted :otp_secret, key: Gitlab::Application.secrets.otp_key_base, diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index c4f8cd71395..ede337f084e 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -1,3 +1,4 @@ +<<<<<<< HEAD .page-with-sidebar{ class: page_with_sidebar_class } - if show_new_nav? - if defined?(nav) && nav @@ -12,6 +13,32 @@ .content-wrapper{ class: layout_nav_class } - if show_new_nav? .mobile-overlay +======= +.page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" } + .sidebar-wrapper.nicescroll + .sidebar-action-buttons + .nav-header-btn.toggle-nav-collapse{ title: "Open/Close" } + %span.sr-only Toggle navigation + = icon('bars') + + %div{ class: "nav-header-btn pin-nav-btn has-tooltip #{'is-active' if pinned_nav?} js-nav-pin", title: pinned_nav? ? "Unpin navigation" : "Pin Navigation", data: { placement: 'right', container: 'body' } } + %span.sr-only Toggle navigation pinning + = icon('fw thumb-tack') + + - if defined?(sidebar) && sidebar + = render "layouts/nav/#{sidebar}" + - elsif current_user + = render 'layouts/nav/dashboard' + - else + = render 'layouts/nav/explore' + + - if defined?(nav) && nav + .layout-nav + .container-fluid + = render "layouts/nav/#{nav}" + .content-wrapper{ class: "#{layout_nav_class}" } + = yield :sub_nav +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' .alert-wrapper = render "layouts/broadcast" - if show_new_nav? diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index b53f382fa3d..a479dddf068 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,6 +1,7 @@ !!! 5 %html{ lang: I18n.locale, class: page_class } = render "layouts/head" +<<<<<<< HEAD %body{ class: @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' @@ -8,6 +9,12 @@ = render "layouts/header/new" - else = render "layouts/header/default", title: header_title +======= + %body{ class: "#{user_application_theme}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } + = Gon::Base.render_data + + = render "layouts/header/default", title: header_title +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' = render 'layouts/page', sidebar: sidebar, nav: nav = yield :scripts_body diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index b32cfe158bb..fce3f9cb251 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -3,6 +3,7 @@ %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content .container-fluid .header-content +<<<<<<< HEAD .dropdown.global-dropdown %button.global-dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' } %span.sr-only Toggle navigation @@ -19,6 +20,14 @@ .title-container.js-title-container %h1.title{ class: ('initializing' if @has_group_title) }= title +======= + %button.side-nav-toggle{ type: 'button', "aria-label" => "Toggle global navigation" } + %span.sr-only Toggle navigation + = icon('bars') + %button.navbar-toggle{ type: 'button' } + %span.sr-only Toggle navigation + = icon('ellipsis-v') +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' .navbar-collapse.collapse %ul.nav.navbar-nav @@ -84,9 +93,18 @@ %div = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success' +<<<<<<< HEAD %button.navbar-toggle{ type: 'button' } %span.sr-only Toggle navigation = icon('ellipsis-v') +======= + + %h1.title= title + + .header-logo + = link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do + = brand_header_logo +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' = yield :header_content diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index be7d27df2a0..98bebbee103 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -1,3 +1,4 @@ +<<<<<<< HEAD %ul = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do @@ -65,3 +66,46 @@ %li.divider %li = link_to "Help", help_path, title: 'About GitLab CE', class: 'about-gitlab' +======= +.nav-sidebar + %ul.nav + = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do + = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do + %span + Projects + = nav_link(path: 'dashboard#activity') do + = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do + %span + Activity + - if koding_enabled? + = nav_link(controller: :koding) do + = link_to koding_path, title: 'Koding' do + %span + Koding + = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do + = link_to dashboard_groups_path, title: 'Groups' do + %span + Groups + = nav_link(controller: 'dashboard/milestones') do + = link_to dashboard_milestones_path, title: 'Milestones' do + %span + Milestones + = nav_link(path: 'dashboard#issues') do + = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do + %span + Issues + %span.count= number_with_delimiter(cached_assigned_issuables_count(current_user, :issues, :opened)) + = nav_link(path: 'dashboard#merge_requests') do + = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do + %span + Merge Requests + %span.count= number_with_delimiter(cached_assigned_issuables_count(current_user, :merge_requests, :opened)) + = nav_link(controller: 'dashboard/snippets') do + = link_to dashboard_snippets_path, title: 'Snippets' do + %span + Snippets + + = link_to help_path, title: 'About GitLab CE', class: 'about-gitlab' do + %span + About GitLab CE +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' diff --git a/app/views/layouts/nav/_explore.html.haml b/app/views/layouts/nav/_explore.html.haml index 0cb367452f7..572163a16b1 100644 --- a/app/views/layouts/nav/_explore.html.haml +++ b/app/views/layouts/nav/_explore.html.haml @@ -1,4 +1,4 @@ -%ul +%ul.nav.nav-sidebar = nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do = link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do .shortcut-mappings diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index f08dcc0c242..f2f8cedfe3a 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -3,7 +3,24 @@ = render 'profiles/head' = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| +<<<<<<< HEAD .col-lg-4.profile-settings-sidebar +======= + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + Application theme + %p + This setting allows you to customize the appearance of the site, e.g. the sidebar. + .col-lg-9.application-theme + - Gitlab::Themes.each do |theme| + = label_tag do + .preview{ class: theme.css_class } + = f.radio_button :theme_id, theme.id + = theme.name + .col-sm-12 + %hr + .col-lg-3.profile-settings-sidebar +>>>>>>> parent of aa792b91bb... Merge branch '26200-convert-sidebar-to-dropdown' into 'master' %h4.prepend-top-0 Syntax highlighting theme %p diff --git a/app/views/profiles/preferences/update.js.erb b/app/views/profiles/preferences/update.js.erb index 431ab9d052b..8966dd3fd86 100644 --- a/app/views/profiles/preferences/update.js.erb +++ b/app/views/profiles/preferences/update.js.erb @@ -1,3 +1,7 @@ +// Remove body class for any previous theme, re-add current one +$('body').removeClass('<%= Gitlab::Themes.body_classes %>') +$('body').addClass('<%= user_application_theme %>') + // Toggle container-fluid class if ('<%= current_user.layout %>' === 'fluid') { $('.content-wrapper .container-fluid').removeClass('container-limited') diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 25285525846..1db08b578a3 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -76,6 +76,14 @@ production: &base # default_can_create_group: false # default: true # username_changing_enabled: false # default: true - User can change her username/namespace + ## Default theme ID + ## 1 - Graphite + ## 2 - Charcoal + ## 3 - Green + ## 4 - Gray + ## 5 - Violet + ## 6 - Blue + # default_theme: 2 # default: 2 ## Automatic issue closing # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. @@ -735,4 +743,4 @@ test: admin_group: '' staging: - <<: *base + <<: *base
\ No newline at end of file diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 38ade18bdc0..bcaee8bd6ca 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -222,6 +222,7 @@ Settings['gitlab'] ||= Settingslogic.new({}) Settings.gitlab['default_projects_limit'] ||= 100000 Settings.gitlab['default_branch_protection'] ||= 2 Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil? +Settings.gitlab['default_theme'] = Gitlab::Themes::APPLICATION_DEFAULT if Settings.gitlab['default_theme'].nil? Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost' Settings.gitlab['ssh_host'] ||= Settings.gitlab.host Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? diff --git a/db/post_migrate/20170215200045_remove_theme_id_from_users.rb b/db/post_migrate/20170215200045_remove_theme_id_from_users.rb deleted file mode 100644 index c51646fbe52..00000000000 --- a/db/post_migrate/20170215200045_remove_theme_id_from_users.rb +++ /dev/null @@ -1,9 +0,0 @@ -class RemoveThemeIdFromUsers < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - def change - remove_column :users, :theme_id, :integer - end -end diff --git a/doc/api/keys.md b/doc/api/keys.md index 376ac27df3a..ddcf7830621 100644 --- a/doc/api/keys.md +++ b/doc/api/keys.md @@ -32,6 +32,7 @@ Parameters: "twitter": "", "website_url": "", "email": "john@example.com", + "theme_id": 2, "color_scheme_id": 1, "projects_limit": 10, "current_sign_in_at": null, diff --git a/doc/api/session.md b/doc/api/session.md index f79eac11689..b97e26f34a2 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -39,6 +39,7 @@ Example response: "twitter": "", "website_url": "", "email": "john@example.com", + "theme_id": 1, "color_scheme_id": 1, "projects_limit": 10, "current_sign_in_at": "2015-07-07T07:10:58.392Z", diff --git a/doc/api/users.md b/doc/api/users.md index 57a13eb477d..8c7bfa25c88 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -72,6 +72,7 @@ GET /users "organization": "", "last_sign_in_at": "2012-06-01T11:41:01Z", "confirmed_at": "2012-05-23T09:05:22Z", + "theme_id": 1, "last_activity_on": "2012-05-23", "color_scheme_id": 2, "projects_limit": 100, @@ -105,6 +106,7 @@ GET /users "organization": "", "last_sign_in_at": null, "confirmed_at": "2012-05-30T16:53:06.148Z", + "theme_id": 1, "last_activity_on": "2012-05-23", "color_scheme_id": 3, "projects_limit": 100, @@ -215,6 +217,7 @@ Parameters: "organization": "", "last_sign_in_at": "2012-06-01T11:41:01Z", "confirmed_at": "2012-05-23T09:05:22Z", + "theme_id": 1, "last_activity_on": "2012-05-23", "color_scheme_id": 2, "projects_limit": 100, @@ -344,6 +347,7 @@ GET /user "organization": "", "last_sign_in_at": "2012-06-01T11:41:01Z", "confirmed_at": "2012-05-23T09:05:22Z", + "theme_id": 1, "last_activity_on": "2012-05-23", "color_scheme_id": 2, "projects_limit": 100, @@ -390,6 +394,7 @@ GET /user "organization": "", "last_sign_in_at": "2012-06-01T11:41:01Z", "confirmed_at": "2012-05-23T09:05:22Z", + "theme_id": 1, "last_activity_on": "2012-05-23", "color_scheme_id": 2, "projects_limit": 100, diff --git a/features/project/labels.feature b/features/project/labels.feature new file mode 100644 index 00000000000..955bc3d8b1b --- /dev/null +++ b/features/project/labels.feature @@ -0,0 +1,15 @@ +@labels +Feature: Labels + Background: + Given I sign in as a user + And I own project "Shop" + And project "Shop" has labels: "bug", "feature", "enhancement" + When I visit project "Shop" labels page + + @javascript + Scenario: I can subscribe to a label + Then I should see that I am not subscribed to the "bug" label + When I click button "Subscribe" for the "bug" label + Then I should see that I am subscribed to the "bug" label + When I click button "Unsubscribe" for the "bug" label + Then I should see that I am not subscribed to the "bug" label diff --git a/features/steps/project/labels.rb b/features/steps/project/labels.rb new file mode 100644 index 00000000000..dbeb07c78db --- /dev/null +++ b/features/steps/project/labels.rb @@ -0,0 +1,32 @@ +class Spinach::Features::Labels < Spinach::FeatureSteps + include SharedAuthentication + include SharedIssuable + include SharedProject + include SharedPaths + + step 'And I visit project "Shop" labels page' do + visit namespace_project_labels_path(project.namespace, project) + end + + step 'I should see that I am subscribed to the "bug" label' do + expect(subscribe_button).to have_content 'Unsubscribe' + end + + step 'I should see that I am not subscribed to the "bug" label' do + expect(subscribe_button).to have_content 'Subscribe' + end + + step 'I click button "Unsubscribe" for the "bug" label' do + subscribe_button.click + end + + step 'I click button "Subscribe" for the "bug" label' do + subscribe_button.click + end + + private + + def subscribe_button + first('.js-subscribe-button', visible: true) + end +end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index e8dd61e493f..7d87197a270 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -35,7 +35,7 @@ module API expose :confirmed_at expose :last_activity_on expose :email - expose :color_scheme_id, :projects_limit, :current_sign_in_at + expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at expose :identities, using: Entities::Identity expose :can_create_group?, as: :can_create_group expose :can_create_project?, as: :can_create_project diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb new file mode 100644 index 00000000000..19ab76ae80f --- /dev/null +++ b/lib/gitlab/themes.rb @@ -0,0 +1,87 @@ +module Gitlab + # Module containing GitLab's application theme definitions and helper methods + # for accessing them. + module Themes + extend self + + # Theme ID used when no `default_theme` configuration setting is provided. + APPLICATION_DEFAULT = 2 + + # Struct class representing a single Theme + Theme = Struct.new(:id, :name, :css_class) + + # All available Themes + THEMES = [ + Theme.new(1, 'Graphite', 'ui_graphite'), + Theme.new(2, 'Charcoal', 'ui_charcoal'), + Theme.new(3, 'Green', 'ui_green'), + Theme.new(4, 'Black', 'ui_black'), + Theme.new(5, 'Violet', 'ui_violet'), + Theme.new(6, 'Blue', 'ui_blue') + ].freeze + + # Convenience method to get a space-separated String of all the theme + # classes that might be applied to the `body` element + # + # Returns a String + def body_classes + THEMES.collect(&:css_class).uniq.join(' ') + end + + # Get a Theme by its ID + # + # If the ID is invalid, returns the default Theme. + # + # id - Integer ID + # + # Returns a Theme + def by_id(id) + THEMES.detect { |t| t.id == id } || default + end + + # Returns the number of defined Themes + def count + THEMES.size + end + + # Get the default Theme + # + # Returns a Theme + def default + by_id(default_id) + end + + # Iterate through each Theme + # + # Yields the Theme object + def each(&block) + THEMES.each(&block) + end + + # Get the Theme for the specified user, or the default + # + # user - User record + # + # Returns a Theme + def for_user(user) + if user + by_id(user.theme_id) + else + default + end + end + + private + + def default_id + id = Gitlab.config.gitlab.default_theme.to_i + + # Prevent an invalid configuration setting from causing an infinite loop + if id < THEMES.first.id || id > THEMES.last.id + APPLICATION_DEFAULT + else + id + end + end + end +end diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb index a5f544b4f92..a66b4ab0902 100644 --- a/spec/controllers/profiles/preferences_controller_spec.rb +++ b/spec/controllers/profiles/preferences_controller_spec.rb @@ -25,7 +25,8 @@ describe Profiles::PreferencesController do def go(params: {}, format: :js) params.reverse_merge!( color_scheme_id: '1', - dashboard: 'stars' + dashboard: 'stars', + theme_id: '1' ) patch :update, user: params, format: format @@ -40,7 +41,8 @@ describe Profiles::PreferencesController do it "changes the user's preferences" do prefs = { color_scheme_id: '1', - dashboard: 'stars' + dashboard: 'stars', + theme_id: '2' }.with_indifferent_access expect(user).to receive(:assign_attributes).with(prefs) diff --git a/spec/features/dashboard/active_tab_spec.rb b/spec/features/dashboard/active_tab_spec.rb index 067e4337e6a..9bcff868756 100644 --- a/spec/features/dashboard/active_tab_spec.rb +++ b/spec/features/dashboard/active_tab_spec.rb @@ -7,9 +7,8 @@ RSpec.describe 'Dashboard Active Tab', js: true do shared_examples 'page has active tab' do |title| it "#{title} tab" do - find('.global-dropdown-toggle').trigger('click') - expect(page).to have_selector('.global-dropdown-menu li.active', count: 1) - expect(find('.global-dropdown-menu li.active')).to have_content(title) + expect(page).to have_selector('.nav-sidebar li.active', count: 1) + expect(find('.nav-sidebar li.active')).to have_content(title) end end diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index 5f1f0c10339..2f77bbde23a 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -49,7 +49,7 @@ feature 'Dashboard shortcuts', :js do end end - def check_page_title(title) - expect(find('.header-content .title')).to have_content(title) + def ensure_active_main_tab(content) + expect(find('.nav-sidebar li.active')).to have_content(content) end end diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb index c935cdfd5c4..73b14b1d338 100644 --- a/spec/features/profiles/preferences_spec.rb +++ b/spec/features/profiles/preferences_spec.rb @@ -8,7 +8,7 @@ describe 'Profile > Preferences', :js do visit profile_preferences_path end - describe 'User changes their syntax highlighting theme' do + describe 'User changes their application theme', js: true do it 'creates a flash message' do choose 'user_color_scheme_id_5' diff --git a/spec/fixtures/api/schemas/public_api/v4/user/login.json b/spec/fixtures/api/schemas/public_api/v4/user/login.json index 6181b3ccc86..e6c1d9c9d84 100644 --- a/spec/fixtures/api/schemas/public_api/v4/user/login.json +++ b/spec/fixtures/api/schemas/public_api/v4/user/login.json @@ -19,6 +19,7 @@ "organization", "last_sign_in_at", "confirmed_at", + "theme_id", "color_scheme_id", "projects_limit", "current_sign_in_at", diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index a04c87b08eb..50ac3886a36 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -26,6 +26,32 @@ describe PreferencesHelper do end end + describe 'user_application_theme' do + context 'with a user' do + it "returns user's theme's css_class" do + stub_user(theme_id: 3) + + expect(helper.user_application_theme).to eq 'ui_green' + end + + it 'returns the default when id is invalid' do + stub_user(theme_id: Gitlab::Themes.count + 5) + + allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(2) + + expect(helper.user_application_theme).to eq 'ui_charcoal' + end + end + + context 'without a user' do + it 'returns the default theme' do + stub_user + + expect(helper.user_application_theme).to eq Gitlab::Themes.default.css_class + end + end + end + describe 'user_color_scheme' do context 'with a user' do it "returns user's scheme's css_class" do diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 new file mode 100644 index 00000000000..c0bdb89ed63 --- /dev/null +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -0,0 +1,37 @@ +/* eslint-disable no-new */ + +require('~/sidebar'); +require('~/lib/utils/text_utility'); + +((global) => { + describe('Dashboard', () => { + const fixtureTemplate = 'static/dashboard.html.raw'; + + function todosCountText() { + return $('.js-todos-count').text(); + } + + function triggerToggle(newCount) { + $(document).trigger('todo:toggle', newCount); + } + + preloadFixtures(fixtureTemplate); + beforeEach(() => { + loadFixtures(fixtureTemplate); + new global.Sidebar(); + }); + + it('should update todos-count after receiving the todo:toggle event', () => { + triggerToggle(5); + expect(todosCountText()).toEqual('5'); + }); + + it('should display todos-count with delimiter', () => { + triggerToggle(1000); + expect(todosCountText()).toEqual('1,000'); + + triggerToggle(1000000); + expect(todosCountText()).toEqual('1,000,000'); + }); + }); +})(window.gl); diff --git a/spec/javascripts/fixtures/dashboard.html.haml b/spec/javascripts/fixtures/dashboard.html.haml new file mode 100644 index 00000000000..32446acfd60 --- /dev/null +++ b/spec/javascripts/fixtures/dashboard.html.haml @@ -0,0 +1,45 @@ +%ul.nav.nav-sidebar + %li.home.active + %a.dashboard-shortcuts-projects + %span + Projects + %li + %a + %span + Todos + %span.count.js-todos-count + 1 + %li + %a.dashboard-shortcuts-activity + %span + Activity + %li + %a + %span + Groups + %li + %a + %span + Milestones + %li + %a.dashboard-shortcuts-issues + %span + Issues + %span + 1 + %li + %a.dashboard-shortcuts-merge_requests + %span + Merge Requests + %li + %a + %span + Snippets + %li + %a + %span + Help + %li + %a + %span + Profile Settings diff --git a/spec/javascripts/project_dashboard_spec.js.es6 b/spec/javascripts/project_dashboard_spec.js.es6 new file mode 100644 index 00000000000..24833b4eb57 --- /dev/null +++ b/spec/javascripts/project_dashboard_spec.js.es6 @@ -0,0 +1,86 @@ +require('~/sidebar'); + +(() => { + describe('Project dashboard page', () => { + let $pageWithSidebar = null; + let $sidebarToggle = null; + let sidebar = null; + const fixtureTemplate = 'projects/dashboard.html.raw'; + + const assertSidebarStateExpanded = (shouldBeExpanded) => { + expect(sidebar.isExpanded).toBe(shouldBeExpanded); + expect($pageWithSidebar.hasClass('page-sidebar-expanded')).toBe(shouldBeExpanded); + }; + + preloadFixtures(fixtureTemplate); + beforeEach(() => { + loadFixtures(fixtureTemplate); + + $pageWithSidebar = $('.page-with-sidebar'); + $sidebarToggle = $('.toggle-nav-collapse'); + + // otherwise instantiating the Sidebar for the second time + // won't do anything, as the Sidebar is a singleton class + gl.Sidebar.singleton = null; + sidebar = new gl.Sidebar(); + }); + + it('can show the sidebar when the toggler is clicked', () => { + assertSidebarStateExpanded(false); + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + }); + + it('should dismiss the sidebar when clone button clicked', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + const cloneButton = $('.project-clone-holder a.clone-dropdown-btn'); + cloneButton.click(); + assertSidebarStateExpanded(false); + }); + + it('should dismiss the sidebar when download button clicked', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + const downloadButton = $('.project-action-button .btn:has(i.fa-download)'); + downloadButton.click(); + assertSidebarStateExpanded(false); + }); + + it('should dismiss the sidebar when add button clicked', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + const addButton = $('.project-action-button .btn:has(i.fa-plus)'); + addButton.click(); + assertSidebarStateExpanded(false); + }); + + it('should dismiss the sidebar when notification button clicked', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + const notifButton = $('.js-notification-toggle-btns .notifications-btn'); + notifButton.click(); + assertSidebarStateExpanded(false); + }); + + it('should dismiss the sidebar when clicking on the body', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + $('body').click(); + assertSidebarStateExpanded(false); + }); + + it('should dismiss the sidebar when clicking on the project description header', () => { + $sidebarToggle.click(); + assertSidebarStateExpanded(true); + + $('.project-home-panel').click(); + assertSidebarStateExpanded(false); + }); + }); +})(); diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb new file mode 100644 index 00000000000..7a140518dd2 --- /dev/null +++ b/spec/lib/gitlab/themes_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::Themes, lib: true do + describe '.body_classes' do + it 'returns a space-separated list of class names' do + css = described_class.body_classes + + expect(css).to include('ui_graphite') + expect(css).to include(' ui_charcoal ') + expect(css).to include(' ui_blue') + end + end + + describe '.by_id' do + it 'returns a Theme by its ID' do + expect(described_class.by_id(1).name).to eq 'Graphite' + expect(described_class.by_id(6).name).to eq 'Blue' + end + end + + describe '.default' do + it 'returns the default application theme' do + allow(described_class).to receive(:default_id).and_return(2) + expect(described_class.default.id).to eq 2 + end + + it 'prevents an infinite loop when configuration default is invalid' do + default = described_class::APPLICATION_DEFAULT + themes = described_class::THEMES + + config = double(default_theme: 0).as_null_object + allow(Gitlab).to receive(:config).and_return(config) + expect(described_class.default.id).to eq default + + config = double(default_theme: themes.size + 5).as_null_object + allow(Gitlab).to receive(:config).and_return(config) + expect(described_class.default.id).to eq default + end + end + + describe '.each' do + it 'passes the block to the THEMES Array' do + ids = [] + described_class.each { |theme| ids << theme.id } + expect(ids).not_to be_empty + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 97bb91a6ac8..34902cfb69d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -716,6 +716,7 @@ describe User do it "applies defaults to user" do expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit) expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group) + expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme) expect(user.external).to be_falsey end end @@ -726,6 +727,7 @@ describe User do it "applies defaults to user" do expect(user.projects_limit).to eq(123) expect(user.can_create_group).to be_falsey + expect(user.theme_id).to eq(1) end end diff --git a/spec/support/gitlab_stubs/session.json b/spec/support/gitlab_stubs/session.json index cd55d63125e..ce8dfe5ae75 100644 --- a/spec/support/gitlab_stubs/session.json +++ b/spec/support/gitlab_stubs/session.json @@ -7,7 +7,7 @@ "skype":"aertert", "linkedin":"", "twitter":"", - "color_scheme_id":2, + "theme_id":2,"color_scheme_id":2, "state":"active", "created_at":"2012-12-21T13:02:20Z", "extern_uid":null, @@ -17,4 +17,4 @@ "can_create_project":false, "private_token":"Wvjy2Krpb7y8xi93owUz", "access_token":"Wvjy2Krpb7y8xi93owUz" -} +}
\ No newline at end of file diff --git a/spec/support/gitlab_stubs/user.json b/spec/support/gitlab_stubs/user.json index cd55d63125e..ce8dfe5ae75 100644 --- a/spec/support/gitlab_stubs/user.json +++ b/spec/support/gitlab_stubs/user.json @@ -7,7 +7,7 @@ "skype":"aertert", "linkedin":"", "twitter":"", - "color_scheme_id":2, + "theme_id":2,"color_scheme_id":2, "state":"active", "created_at":"2012-12-21T13:02:20Z", "extern_uid":null, @@ -17,4 +17,4 @@ "can_create_project":false, "private_token":"Wvjy2Krpb7y8xi93owUz", "access_token":"Wvjy2Krpb7y8xi93owUz" -} +}
\ No newline at end of file |