diff options
Diffstat (limited to 'app')
124 files changed, 767 insertions, 1437 deletions
diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee index 63803747413..3b6b453ac51 100644 --- a/app/assets/javascripts/activities.js.coffee +++ b/app/assets/javascripts/activities.js.coffee @@ -1,7 +1,7 @@ class @Activities constructor: -> Pager.init 20, true - $(".event-filter .btn").bind "click", (event) => + $(".event-filter a").bind "click", (event) => event.preventDefault() @toggleFilter($(event.currentTarget)) @reloadActivities() @@ -12,7 +12,7 @@ class @Activities toggleFilter: (sender) -> - sender.toggleClass "active" + sender.closest('li').toggleClass "active" event_filters = $.cookie("event_filter") filter = sender.attr("id").split("_")[0] if event_filters diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index ed0bf2b3f48..1f46e331427 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -48,14 +48,15 @@ class @MergeRequest _this = @ $('a.btn-close, a.btn-reopen').on 'click', (e) -> $this = $(this) - if $this.data('submitted') - return - e.preventDefault() - e.stopImmediatePropagation() shouldSubmit = $this.hasClass('btn-comment') - console.log("shouldSubmit") + if shouldSubmit && $this.data('submitted') + return if shouldSubmit - _this.submitNoteForm($this.closest('form'),$this) + if $this.hasClass('btn-comment-and-close') || $this.hasClass('btn-comment-and-reopen') + e.preventDefault() + e.stopImmediatePropagation() + _this.submitNoteForm($this.closest('form'),$this) + submitNoteForm: (form, $button) => noteText = form.find("textarea.js-note-text").val() diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 9e2dc1250c9..b10e1db7f3f 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -5,7 +5,7 @@ # # ### Example Markup # -# <ul class="nav nav-tabs merge-request-tabs"> +# <ul class="nav-links merge-request-tabs"> # <li class="notes-tab active"> # <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1"> # Discussion diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 8ba00ecbbab..fcf50dd1b51 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -521,9 +521,13 @@ class @Notes if textarea.val().trim().length > 0 form.find('.js-note-target-reopen').text('Comment & reopen') form.find('.js-note-target-close').text('Comment & close') + form.find('.js-note-target-reopen').addClass('btn-comment-and-reopen') + form.find('.js-note-target-close').addClass('btn-comment-and-close') else form.find('.js-note-target-reopen').text('Reopen') form.find('.js-note-target-close').text('Close') + form.find('.js-note-target-reopen').removeClass('btn-comment-and-reopen') + form.find('.js-note-target-close').removeClass('btn-comment-and-close') initTaskList: -> @enableTaskList() diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 48a4971c8fc..fa7641b1676 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -24,6 +24,7 @@ @import "framework/lists.scss"; @import "framework/markdown_area.scss"; @import "framework/mobile.scss"; +@import "framework/nav.scss"; @import "framework/pagination.scss"; @import "framework/panels.scss"; @import "framework/selects.scss"; diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index fa0e70847f3..d0f5d33bf4d 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -18,9 +18,9 @@ line-height: 36px; } -.content-block, .gray-content-block { - margin: -$gl-padding; + margin-top: 0; + margin-bottom: -$gl-padding; background-color: $background-color; padding: $gl-padding; margin-bottom: 0px; @@ -86,10 +86,7 @@ .cover-block { text-align: center; background: $background-color; - margin: -$gl-padding; - margin-bottom: 0; - padding: 44px $gl-padding; - border-bottom: 1px solid $border-color; + padding-top: 44px; position: relative; .avatar-holder { @@ -136,3 +133,19 @@ .block-connector { margin-top: -1px; } + +.nav-block { + .controls { + float: right; + margin-top: 11px; + } +} + +.content-block { + padding: $gl-padding 0; + border-bottom: 1px solid $border-color; + + &.oneline-block { + line-height: 42px; + } +} diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 97a94638847..c99292c3f83 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -1,12 +1,8 @@ @mixin btn-default { @include border-radius(3px); - border-width: 1px; - border-style: solid; - font-size: 15px; + font-size: $gl-font-size; font-weight: 500; - line-height: 18px; - padding: 11px $gl-padding; - letter-spacing: .4px; + padding: $gl-vert-padding $gl-padding; &:focus, &:active { @@ -17,8 +13,6 @@ @mixin btn-middle { @include btn-default; - @include border-radius(3px); - padding: 11px 24px; } @mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) { @@ -74,16 +68,15 @@ @include btn-default; @include btn-white; + &.btn-small, &.btn-sm { - padding: 5px 10px; - } - - &.btn-nr { - padding: 7px 10px; + padding: 4px 10px; + font-size: 13px; + line-height: 18px; } &.btn-xs { - padding: 1px 5px; + padding: 2px 5px; } &.btn-success, @@ -131,6 +124,12 @@ &:last-child { margin-right: 0px; } + &.btn-xs { + margin-right: 3px; + } + } + &.disabled { + pointer-events: auto !important; } } @@ -153,33 +152,42 @@ } } -.btn-group-next { +.btn-clipboard { + border: none; + padding: 0 5px; +} + +.input-group-btn { .btn { - padding: 9px 0px; - font-size: 15px; - color: #7f8fa4; - border-color: #e7e9ed; - width: 140px; - - .badge { - font-weight: normal; - background-color: #eee; - color: #78a; + @include btn-gray; + @include btn-middle; + + &:hover { + outline: none; } - &.active { - border-color: $gl-info; - background: $gl-info; - color: #fff; + &:focus { + outline: none; + } + + &:active { + outline: none; + } - .badge { - color: $gl-info; - background-color: white; - } + &.btn-clipboard { + padding-left: 15px; + padding-right: 15px; } } -} -.btn-clipboard { - border: none; + .active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + border: 1px solid #c6cacf !important; + background-color: #e4e7ed !important; + } + + .btn-green { + @include btn-green + } } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 11730000f85..05645116268 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -374,75 +374,6 @@ table { } } -.center-top-menu, .left-top-menu { - @include nav-menu; - text-align: center; - margin-top: 5px; - margin-bottom: $gl-padding; - height: auto; - margin-top: -$gl-padding; - - &.no-bottom { - margin-bottom: 0; - } - - &.no-top { - margin-top: 0; - } - - li a { - display: inline-block; - padding-top: $gl-padding; - padding-bottom: 11px; - margin-bottom: -1px; - } - - &.bottom-border { - border-bottom: 1px solid $border-color; - height: 57px; - } - - &.wide { - margin-left: -$gl-padding; - margin-right: -$gl-padding; - } -} - -.left-top-menu { - text-align: left; - border-bottom: 1px solid #EEE; -} - -.center-middle-menu { - @include nav-menu; - padding: 0; - text-align: center; - margin: -$gl-padding; - margin-top: 0; - margin-bottom: 0; - height: 58px; - border-bottom: 1px solid $border-color; - - li { - &:after { - content: "|"; - color: $border-gray-light; - } - - &:last-child { - &:after { - content: none; - } - } - - > a { - display: inline-block; - text-transform: uppercase; - font-size: 13px; - } - } -} - .dropzone .dz-preview .dz-progress { border-color: $border-color !important; } diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index cbfd4bc29b6..6ee104ee31a 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -3,11 +3,8 @@ * */ .file-holder { - margin-left: -$gl-padding; - margin-right: -$gl-padding; border: none; - border-top: 1px solid #E7E9EE; - border-bottom: 1px solid #E7E9EE; + border: 1px solid $border-color; &.readme-holder { border-bottom: 0; diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index 82eb50ad4be..1bfd0213995 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -8,10 +8,12 @@ .flash-notice { @extend .alert; @extend .alert-info; + margin: 0; } .flash-alert { @extend .alert; @extend .alert-danger; + margin: 0; } } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index d0cb91a5b64..4dab806d50e 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -74,8 +74,6 @@ label { .form-control { @include box-shadow(none); - height: 42px; - padding: 8px $gl-padding; } .form-control-inline { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 4dbbb56104b..ba5e72c8c5a 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -28,6 +28,7 @@ header { min-height: $header-height; background-color: #fff; border: none; + border-bottom: 1px solid #EEE; .container-fluid { width: 100% !important; diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index a1a9990241d..e901c78d02f 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -5,8 +5,6 @@ html { } body { - background-color: #F3F3F3 !important; - &.navless { background-color: white !important; } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index bbdb1c038c5..c6bc6fb324d 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -109,10 +109,8 @@ ul.content-list { padding: 0; > li { - padding: $gl-padding; + padding: $gl-padding 0; border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; color: $gl-gray; .avatar { @@ -133,6 +131,7 @@ ul.content-list { .panel > .content-list { li { margin: 0; + padding: $gl-padding; } } @@ -148,7 +147,7 @@ ul.controls { > li { float: left; margin-right: 10px; - + &:last-child { margin-right: 0; } diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 4a00a197d9a..c540e527bed 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -65,13 +65,6 @@ position: relative; } -.md-header { - ul { - float: left; - margin-bottom: 1px; - } -} - .referenced-users { color: #4c4e54; padding-top: 10px; @@ -85,23 +78,6 @@ box-shadow: none; } -.new_note, -.edit_note, -.detail-page-description, -.milestone-description, -.wiki-content, -.merge-request-form { - .nav-tabs { - margin-bottom: 0; - border: none; - - li a, - li.active a { - border: 1px solid #DDD; - } - } -} - .markdown-area { @include border-radius(0); background: #FFF; diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 41fd890f14f..1d5000fe388 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -118,38 +118,3 @@ font-size: 16px; line-height: 24px; } - -@mixin nav-menu { - padding: 0; - margin: 0; - list-style: none; - height: 56px; - - li { - display: inline-block; - - a { - padding: 14px; - font-size: 15px; - line-height: 28px; - color: #959494; - border-bottom: 2px solid transparent; - - &:hover, &:active, &:focus { - text-decoration: none; - outline: none; - } - } - - &.active a { - color: #616060; - border-bottom: 2px solid #4688f1; - } - - .badge { - font-weight: normal; - background-color: #eee; - color: #78a; - } - } -} diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss index c00709fb6bb..28c294714ad 100644 --- a/app/assets/stylesheets/framework/mobile.scss +++ b/app/assets/stylesheets/framework/mobile.scss @@ -9,7 +9,7 @@ padding-right: 5px; } - .nav.nav-tabs > li > a { + .nav-links > li > a { padding: 10px; font-size: 12px; margin-right: 3px; @@ -81,7 +81,7 @@ display: none; } - .center-top-menu, .left-top-menu { + .nav-links, .nav-links { li a { font-size: 14px; padding: 19px 10px; diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss new file mode 100644 index 00000000000..c537d97fb24 --- /dev/null +++ b/app/assets/stylesheets/framework/nav.scss @@ -0,0 +1,39 @@ +.nav-links { + padding: 0; + margin: 0; + list-style: none; + height: auto; + border-bottom: 1px solid $border-color; + + li { + display: inline-block; + + a { + display: inline-block; + padding: 14px; + padding-top: $gl-padding; + padding-bottom: 11px; + margin-bottom: -1px; + font-size: 15px; + line-height: 28px; + color: #959494; + border-bottom: 2px solid transparent; + + &:hover, &:active, &:focus { + text-decoration: none; + outline: none; + } + } + + &.active a { + color: #000000; + border-bottom: 2px solid #4688f1; + } + + .badge { + font-weight: normal; + background-color: #eee; + color: #78a; + } + } +} diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index af145191bc8..3ee3443e349 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -3,8 +3,8 @@ .select2-choice { background: #FFF; border-color: #DDD; - height: 42px; - padding: 8px $gl-padding; + height: 36px; + padding: 6px $gl-padding; font-size: $gl-font-size; line-height: 1.42857143; diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 83243dd2457..540d0b03163 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -21,11 +21,10 @@ .content-wrapper { width: 100%; - padding: 20px; .container-fluid { background: #FFF; - padding: $gl-padding; + padding: 0 $gl-padding; &.container-blank { background: none; diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index 793ab3d9bb9..c4e9f467ce4 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -1,13 +1,11 @@ .table-holder { - margin: -$gl-padding; - margin-top: 0; - margin-bottom: 0; + margin: 0; } table { &.table { margin-bottom: $gl-padding; - + .dropdown-menu a { text-decoration: none; } @@ -32,6 +30,7 @@ table { } th { + background-color: $background-color; font-weight: normal; font-size: 15px; border-bottom: 1px solid $border-color !important; diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index ff41e26ed8a..47b843e5e3d 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -5,10 +5,8 @@ padding: 0; .timeline-entry { - padding: $gl-padding; + padding: $gl-padding 0; border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; color: $gl-gray; border-bottom: 1px solid $border-white-light; diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss index 94f0ed761df..88072606bf5 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap.scss @@ -99,47 +99,6 @@ } } -// Nav tabs -.nav.nav-tabs { - margin-bottom: 15px; - - li { - > a { - margin-right: 5px; - line-height: 20px; - border-color: #EEE; - color: #888; - border-bottom: 1px solid #ddd; - .badge { - background-color: #eee; - color: #888; - text-shadow: 0 1px 1px #fff; - } - i.fa { - line-height: 14px; - } - } - &.active { - > a { - border-color: #CCC; - border-bottom: 1px solid #fff; - color: #333; - font-weight: bold; - } - } - } -} - -.nav-tabs > li > a, -.nav-pills > li > a { - color: #666; -} - -.nav-pills > .active > a > span > .badge { - background-color: #fff; - color: $gl-primary; -} - /** * fix to keep tooltips position in top navigation bar diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index 63868a34e2a..cd0621cdbf3 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -46,7 +46,7 @@ $font-size-base: $gl-font-size; // //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). -$padding-base-vertical: 9px; +$padding-base-vertical: $gl-vert-padding; $padding-base-horizontal: $gl-padding; $component-active-color: #fff; $component-active-bg: $brand-info; diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 714369d9f15..ab4f71af039 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -177,7 +177,7 @@ body { } .page-title { - margin-top: 0px; + margin-top: $gl-padding; line-height: 1.3; font-size: 1.25em; font-weight: 600; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index d0ff3248ce1..85ecdddda79 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -22,6 +22,7 @@ $header-height: 58px; $fixed-layout-width: 1280px; $gl-gray: #5a5a5a; $gl-padding: 16px; +$gl-vert-padding: 6px; $gl-padding-top:10px; $gl-avatar-size: 46px; $secondary-text: #7f8fa4; diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index 002bd7e8ca5..c3f27333fad 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -4,7 +4,7 @@ position: absolute; top: 0px; right: 4px; - line-height: 40px; + line-height: 56px; } a.js-zen-leave { diff --git a/app/assets/stylesheets/pages/branches.scss b/app/assets/stylesheets/pages/branches.scss new file mode 100644 index 00000000000..abae5c3d0a5 --- /dev/null +++ b/app/assets/stylesheets/pages/branches.scss @@ -0,0 +1,3 @@ +.branch-name{ + font-weight: 600; +} diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss index 17245d3be7b..6ec88bdd804 100644 --- a/app/assets/stylesheets/pages/commit.scss +++ b/app/assets/stylesheets/pages/commit.scss @@ -2,6 +2,10 @@ display: block; } +.commit-row-title .commit-title { + font-weight: 600; +} + .commit-author, .commit-committer{ display: block; color: #999; @@ -35,6 +39,8 @@ } .commit-box { + border-top: 1px solid $border-color; + .commit-title { margin: 0; font-size: 23px; diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index deab805dbc2..529a43548c8 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -1,7 +1,5 @@ .detail-page-header { - margin: -$gl-padding; - padding: 7px $gl-padding; - margin-bottom: 0px; + padding: 11px 0; border-bottom: 1px solid $border-color; color: #5c5d5e; font-size: 16px; diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index afd6fb73675..1e2b8b51827 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -1,9 +1,7 @@ // Common .diff-file { - margin-left: -$gl-padding; - margin-right: -$gl-padding; - border: none; - border-bottom: 1px solid #E7E9EE; + border: 1px solid $border-color; + border-top: none; .diff-header { position: relative; @@ -23,14 +21,6 @@ } } - .diff-controls { - .btn { - padding: 0px 10px; - font-size: 13px; - line-height: 28px; - } - } - .commit-short-id { font-family: $monospace_font; font-size: smaller; diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 984b4b91216..8fa15b35748 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -4,9 +4,7 @@ */ .event-item { font-size: $gl-font-size; - padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px); - margin-left: -$gl-padding; - margin-right: -$gl-padding; + padding: $gl-padding 0 $gl-padding ($gl-avatar-size + 15px); border-bottom: 1px solid $table-border-color; color: #7f8fa4; diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 263993f59a5..3404c2631e1 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -11,3 +11,8 @@ height: 42px; } } + +.content-list .group-name { + font-weight: 600; + color: #4c4e54; +} diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index d4b44004f4f..55e834947d1 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -27,10 +27,10 @@ .project-issuable-filter { .controls { float: right; - margin-top: 7px; + margin-top: 11px; } - .center-top-menu { + .nav-links { text-align: left; } } @@ -95,7 +95,7 @@ .cross-project-reference { color: $gl-link-color; - + span { white-space: nowrap; width: 85%; diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 1e1af662850..ad92cc22815 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -6,7 +6,7 @@ .issue-title { margin-bottom: 5px; font-size: $list-font-size; - font-weight: bold; + font-weight: 600; } .issue-info { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 82effde0bf3..75f2ae80a92 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -3,9 +3,9 @@ * */ .mr-state-widget { - background: #F7F8FA; + background: $background-color; color: $gl-gray; - border: 1px solid #dce0e6; + border: 1px solid $border-color; @include border-radius(2px); form { @@ -150,7 +150,7 @@ .merge-request-title { margin-bottom: 5px; font-size: $list-font-size; - font-weight: bold; + font-weight: 600; } .merge-request-info { diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss deleted file mode 100644 index 9f719d981b4..00000000000 --- a/app/assets/stylesheets/pages/projects.scss +++ /dev/null @@ -1,681 +0,0 @@ -.alert_holder { - margin: -16px; - - .alert-link { - font-weight: normal; - } -} -.no-ssh-key-message, .project-limit-message { - background-color: #f28d35; - margin-bottom: 16px; -} -.new_project, -.edit_project { - fieldset.features { - .control-label { - font-weight: normal; - } - } -} - -.project-name-holder { - .help-inline { - vertical-align: top; - padding: 7px; - } -} - -.project-home-panel { - - .cover-controls { - .project-settings-dropdown { - margin-left: 10px; - } - } - - .project-identicon-holder { - margin-bottom: 16px; - - .avatar, .identicon { - margin: 0 auto; - float: none; - } - - .identicon { - @include border-radius(50%); - } - } - - .project-home-dropdown { - margin: 13px 0px 0; - } - - .notifications-btn { - .fa-bell { - margin-right: 6px; - } - - .fa-angle-down { - margin-left: 6px; - } - } - - .project-home-desc { - h1 { - color: #313236; - margin: 0; - margin-bottom: 6px; - font-size: 23px; - font-weight: normal; - } - - p { - padding: 0 $gl-padding; - color: #5c5d5e; - } - } - - .git-clone-holder { - max-width: 498px; - - .form-control { - background: #FFF; - font-size: 14px; - height: 34px; - margin-left: -1px; - } - } - - .visibility-level-label { - @extend .btn; - @extend .btn-gray; - - color: $gray; - cursor: default; - - i { - color: inherit; - } - } - - .git-clone-holder { - display: inline-table; - position: relative; - } - - .project-repo-buttons { - margin-top: 12px; - margin-bottom: 0px; - - .count-buttons { - display: block; - margin-bottom: 12px; - } - - .btn { - @include btn-gray; - text-transform: none; - } - .count-with-arrow { - display: inline-block; - position: relative; - margin-left: 4px; - - .arrow { - &:before { - content: ''; - display: inline-block; - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - top: 50%; - left: 0; - margin-top: -6px; - border-width: 7px 5px 7px 0; - border-right-color: #dce0e5; - } - - &:after { - content: ''; - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - top: 50%; - left: 1px; - margin-top: -9px; - border-width: 10px 7px 10px 0; - border-right-color: #FFF; - } - } - .count { - @include btn-gray; - display: inline-block; - background: white; - border-radius: 2px; - border-width: 1px; - border-style: solid; - font-size: 13px; - font-weight: 600; - line-height: 20px; - padding: 11px 16px; - letter-spacing: .4px; - padding: 10px; - text-align: center; - vertical-align: middle; - touch-action: manipulation; - cursor: pointer; - background-image: none; - white-space: nowrap; - margin: 0 11px 0px 4px; - - &:hover { - background: #FFF; - } - } - } - } -} - -.split-one { - display: inline-table; - margin-right: 12px; - - a { - margin: -1px !important; - } -} - -.git-clone-holder { - .project-home-dropdown + & { - margin-right: 45px; - } - - .clone-options { - display: table-cell; - a.btn { - width: 100%; - } - } - - .form-control { - cursor: auto; - @extend .monospace; - background: #FAFAFA; - width: 101%; - } - - .input-group-addon { - background: #f7f8fa; - - &.git-protocols { - padding: 0; - border: none; - - .input-group-btn:last-child > .btn { - @include border-radius-right(0); - - border-left: 1px solid #c6cacf; - margin-left: -2px !important; - } - } - } -} - -.projects-search-form { - - .input-group .form-control { - height: 42px; - } -} - -.dropdown-nr { - padding: 7px 0px; -} - -.input-group-btn { - .btn { - @include btn-gray; - @include btn-default; - - &:hover { - outline: none; - } - - &:focus { - outline: none; - } - - &:active { - outline: none; - } - - &.btn-clipboard { - padding-left: 15px; - padding-right: 15px; - } - &.btn-nr { - padding: 7px 10px; - } - } - - .active { - @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); - - border: 1px solid #c6cacf !important; - background-color: #e4e7ed !important; - } - - .btn-green { - @include btn-green - } - -} - -.split-repo-buttons { - display: inline-table; - margin: 0 12px 0 12px; - - .btn{ - @include btn-gray; - } - - - .dropdown-toggle { - margin: -5px; - } -} - -#notification-form { - margin-left: 5px; -} - -.dropdown-new { - margin-left: -5px; -} - -.open > .dropdown-new.btn { - @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); - - border: 1px solid #c6cacf !important; - background-color: #e4e7ed !important; - text-transform: none; - color: #313236 !important; - font-size: 15px; -} - -.dropdown-menu { - @include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px); - @include border-radius (0px); - - border: none; - padding: 16px 0; - font-size: 14px; - font-weight: 100; - - li a { - color: #5f697a; - line-height: 30px; - - &:hover { - background-color: #3084bb !important; - } - } - - i { - margin-right: 8px; - } -} - -.project-visibility-level-holder { - .radio { - margin-bottom: 10px; - - i { - margin: 2px 0; - font-size: 20px; - } - - .option-title { - font-weight: normal; - display: inline-block; - color: #313236; - } - - .option-descr { - margin-left: 29px; - color: #54565b; - } - } -} - -.save-project-loader { - margin-top: 50px; - margin-bottom: 50px; - color: #555; -} - -ul.nav.nav-projects-tabs { - @extend .nav-tabs; - - padding-left: 8px; - - li { - a { - padding: 6px 25px; - margin-top: 2px; - border-color: #DDD; - background-color: #EEE; - text-shadow: 0 1px 1px white; - color: #555; - } - &.active { - a { - font-weight: bold; - } - } - } -} - -.project_member_row form { - margin: 0px; -} - -.transfer-project .select2-container { - min-width: 200px; -} - -.deploy-project-label { - margin: 1px; -} - -.vs-public { - color: $gl-primary; -} - -.vs-internal { - color: $gl-warning; -} - -.vs-private { - color: $gl-success; -} - -.breadcrumb.repo-breadcrumb { - padding: 0; - line-height: 42px; - background: transparent; - border: none; - margin: 0; - - > li + li:before { - padding: 0 3px; - color: #999; - } -} - -.last-push-widget { - margin-top: -1px; -} - -.top-area { - border-bottom: 1px solid #EEE; - margin: 0 -16px; - padding: 0 $gl-padding; - height: 42px; - - ul.left-top-menu { - display: inline-block; - width: 50%; - margin-bottom: 0px; - border-bottom: none; - } - - .projects-search-form { - width: 50%; - display: inline-block; - float: right; - padding-top: 7px; - text-align: right; - - .btn-green { - margin-top: -2px; - margin-left: 10px; - } - } - - @media (max-width: $screen-xs-max) { - .projects-search-form { - padding-top: 15px; - } - } -} - -.fork-namespaces { - .fork-thumbnail { - text-align: center; - margin-bottom: $gl-padding; - - .caption { - padding: $gl-padding 0; - min-height: 30px; - } - - img { - @include border-radius(50%); - max-width: 100px; - } - } -} - -table.table.protected-branches-list tr.no-border { - th, td { - border: 0; - } -} - -.project-import .btn { - float: left; - margin-right: 10px; -} - -.project-stats { - text-align: center; - margin-top: $gl-padding; - margin-bottom: 0; - padding-top: 10px; - padding-bottom: 4px; - - ul.nav-pills { - display:inline-block; - } - - .nav-pills li { - display:inline; - } - - .nav > li > a { - @include btn-default; - @include btn-gray; - - background-color: transparent; - border: 1px solid #f7f8fa; - margin-left: 12px; - } - - li { - display:inline; - } - - a { - float:left; - font-size: 17px; - } - - li.missing a { - color: #5a6069; - border: 1px dashed #dce0e5; - - &:hover { - background-color: #f0f2f5; - } - } -} - -pre.light-well { - border-color: #f1f1f1; -} - -.projects-search-form { - margin: -$gl-padding; - padding: $gl-padding; - padding-bottom: 0; - margin-bottom: 0px; - - input { - display: inline-block; - width: calc(100% - 151px); - } - - .btn { - display: inline-block; - width: 135px; - } -} - -.git-empty { - margin: 0 7px 0 7px; - - h5 { - color: #5c5d5e; - } - - .light-well { - @include border-radius (2px); - - color: #5b6169; - font-size: 13px; - line-height: 1.6em; - } -} - -.project-footer { - margin-top: 20px; - - .btn-remove { - @include btn-middle; - @include btn-red; - - float: left !important; - } -} - -/* - * Projects list rendered on dashboard and user page - */ - -.projects-list { - @include basic-list; - - .project-row { - padding: $gl-padding; - border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; - - &.no-description { - .project { - line-height: 44px; - } - } - - .project-full-name { - @include str-truncated; - font-weight: 600; - color: #4c4e54; - } - - .project-controls { - float: right; - color: $gl-gray; - line-height: 45px; - color: #7f8fa4; - - a:hover { - text-decoration: none; - } - } - - .project-description { - color: #7f8fa4; - - p { - @include str-truncated; - margin-bottom: 0; - color: #7f8fa4; - } - } - } - - .bottom { - padding-top: $gl-padding; - padding-bottom: 0; - } -} - -.panel .projects-list li { - padding: 10px 15px; - margin: 0; -} - -.project-show-activity { - .activity-filter-block { - margin-top: -1px; - } -} - -.project-last-commit { - margin: 0 7px; - - .ci-status { - margin-right: 16px; - } - - .commit-row-message { - color: $gl-gray; - } - - .commit_short_id { - margin-right: 5px; - color: $gl-link-color; - font-weight: 600; - } - - .commit-author-link { - margin-left: 7px; - text-decoration: none; - .avatar { - float: none; - margin-right: 4px; - } - - .commit-author-name { - font-weight: 600; - } - } -} - -.project-show-readme .readme-holder { - margin-left: -$gl-padding; - margin-right: -$gl-padding; - padding: ($gl-padding + 7px); - border-top: 0; - - .edit-project-readme { - z-index: 100; - position: relative; - } -} diff --git a/app/assets/stylesheets/pages/tags.scss b/app/assets/stylesheets/pages/tags.scss new file mode 100644 index 00000000000..e9cd6dc6c5e --- /dev/null +++ b/app/assets/stylesheets/pages/tags.scss @@ -0,0 +1,3 @@ +.tag-name{ + font-weight: 600; +} diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 97505edeabf..6a6dd7dfc85 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -1,4 +1,7 @@ .tree-holder { + > .nav-block { + margin: 11px 0; + } .file-finder { width: 50%; @@ -13,7 +16,7 @@ tr { > td, > th { - line-height: 28px; + line-height: 26px; } &:hover { @@ -86,12 +89,14 @@ .blob-commit-info { list-style: none; + padding: $gl-padding; + background: $background-color; + border: 1px solid $border-color; + border-bottom: none; margin: 0; - padding: 0; - margin-bottom: 5px; .commit { - padding: $gl-padding 0; + padding: 0; .commit-row-title { .commit-row-message { @@ -115,3 +120,8 @@ font-weight: normal; color: $md-link-color; } + +.tree-controls { + float: right; + margin-top: 11px; +} diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb index e383fe38ea6..79a53556f0a 100644 --- a/app/controllers/admin/identities_controller.rb +++ b/app/controllers/admin/identities_controller.rb @@ -26,6 +26,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def update if @identity.update_attributes(identity_params) + RepairLdapBlockedUserService.new(@user).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully updated.' else render :edit @@ -34,6 +35,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def destroy if @identity.destroy + RepairLdapBlockedUserService.new(@user).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully removed.' else redirect_to admin_user_identities_path(@user), alert: 'Failed to remove user identity.' diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index d7c927d444c..87f4fb455b8 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -40,7 +40,9 @@ class Admin::UsersController < Admin::ApplicationController end def unblock - if user.activate + if user.ldap_blocked? + redirect_back_or_admin_user(alert: "This user cannot be unlocked manually from GitLab") + elsif user.activate redirect_back_or_admin_user(notice: "Successfully unblocked") else redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked") diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb new file mode 100644 index 00000000000..dff0732bdfe --- /dev/null +++ b/app/controllers/projects/artifacts_controller.rb @@ -0,0 +1,56 @@ +class Projects::ArtifactsController < Projects::ApplicationController + layout 'project' + before_action :authorize_read_build_artifacts! + + def download + unless artifacts_file.file_storage? + return redirect_to artifacts_file.url + end + + unless artifacts_file.exists? + return not_found! + end + + send_file artifacts_file.path, disposition: 'attachment' + end + + def browse + return render_404 unless build.artifacts? + + directory = params[:path] ? "#{params[:path]}/" : '' + @entry = build.artifacts_metadata_entry(directory) + + return render_404 unless @entry.exists? + end + + def file + entry = build.artifacts_metadata_entry(params[:path]) + + if entry.exists? + render json: { archive: build.artifacts_file.path, + entry: Base64.encode64(entry.path) } + else + render json: {}, status: 404 + end + end + + private + + def build + @build ||= project.builds.unscoped.find_by!(id: params[:build_id]) + end + + def artifacts_file + @artifacts_file ||= build.artifacts_file + end + + def authorize_read_build_artifacts! + unless can?(current_user, :read_build_artifacts, @project) + if current_user.nil? + return authenticate_user! + else + return render_404 + end + end + end +end diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index 39d3ba26ba2..0e965966ffa 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -2,7 +2,6 @@ class Projects::BuildsController < Projects::ApplicationController before_action :build, except: [:index, :cancel_all] before_action :authorize_manage_builds!, except: [:index, :show, :status] - before_action :authorize_download_build_artifacts!, only: [:download] layout "project" @@ -51,18 +50,6 @@ class Projects::BuildsController < Projects::ApplicationController redirect_to build_path(build) end - def download - unless artifacts_file.file_storage? - return redirect_to artifacts_file.url - end - - unless artifacts_file.exists? - return not_found! - end - - send_file artifacts_file.path, disposition: 'attachment' - end - def status render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha) end @@ -79,10 +66,6 @@ class Projects::BuildsController < Projects::ApplicationController @build ||= project.builds.unscoped.find_by!(id: params[:id]) end - def artifacts_file - build.artifacts_file - end - def build_path(build) namespace_project_build_path(build.project.namespace, build.project, build) end @@ -92,14 +75,4 @@ class Projects::BuildsController < Projects::ApplicationController return page_404 end end - - def authorize_download_build_artifacts! - unless can?(current_user, :download_build_artifacts, @project) - if current_user.nil? - return authenticate_user! - else - return render_404 - end - end - end end diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb new file mode 100644 index 00000000000..7271c933b9b --- /dev/null +++ b/app/controllers/sent_notifications_controller.rb @@ -0,0 +1,25 @@ +class SentNotificationsController < ApplicationController + skip_before_action :authenticate_user! + + def unsubscribe + @sent_notification = SentNotification.for(params[:id]) + return render_404 unless @sent_notification && @sent_notification.unsubscribable? + + noteable = @sent_notification.noteable + noteable.unsubscribe(@sent_notification.recipient) + + flash[:notice] = "You have been unsubscribed from this thread." + if current_user + case noteable + when Issue + redirect_to issue_path(noteable) + when MergeRequest + redirect_to merge_request_path(noteable) + else + redirect_to root_path + end + else + redirect_to new_user_session_path + end + end +end diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb deleted file mode 100644 index 80c7090d91e..00000000000 --- a/app/helpers/button_helper.rb +++ /dev/null @@ -1,58 +0,0 @@ -module ButtonHelper - # Output a "Copy to Clipboard" button - # - # data - Data attributes passed to `content_tag` - # - # Examples: - # - # # Define the clipboard's text - # clipboard_button(clipboard_text: "Foo") - # # => "<button class='...' data-clipboard-text='Foo'>...</button>" - # - # # Define the target element - # clipboard_button(clipboard_target: "div#foo") - # # => "<button class='...' data-clipboard-target='div#foo'>...</button>" - # - # See http://clipboardjs.com/#usage - def clipboard_button(data = {}) - content_tag :button, - icon('clipboard'), - class: 'btn btn-xs btn-nr btn-clipboard', - data: data, - type: :button - end - - def http_clone_button(project) - klass = 'btn js-protocol-switch' - klass << ' active' if default_clone_protocol == 'http' - klass << ' has_tooltip' if current_user.try(:require_password?) - - protocol = gitlab_config.protocol.upcase - - content_tag :button, protocol, - class: klass, - data: { - clone: project.http_url_to_repo, - container: 'body', - html: 'true', - title: "Set a password on your account<br>to pull or push via #{protocol}" - }, - type: :button - end - - def ssh_clone_button(project) - klass = 'btn js-protocol-switch' - klass << ' active' if default_clone_protocol == 'ssh' - klass << ' has_tooltip' if current_user.try(:require_ssh_key?) - - content_tag :button, 'SSH', - class: klass, - data: { - clone: project.ssh_url_to_repo, - container: 'body', - html: 'true', - title: 'Add an SSH key to your profile<br>to pull or push via SSH.' - }, - type: :button - end -end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index dde83ff36b5..31bf45baeb7 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -27,13 +27,15 @@ module EventsHelper key = key.to_s active = 'active' if @event_filter.active?(key) link_opts = { - class: "event-filter-link btn btn-default #{active}", + class: "event-filter-link", id: "#{key}_event_filter", title: "Filter by #{tooltip.downcase}", } - link_to request.path, link_opts do - content_tag(:span, ' ' + tooltip) + content_tag :li, class: active do + link_to request.path, link_opts do + content_tag(:span, ' ' + tooltip) + end end end diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index abdeefed5ef..4a88cb61132 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -1,31 +1,31 @@ module Emails module Issues def new_issue_email(recipient_id, issue_id) - issue_mail_with_notification(issue_id, recipient_id) do - mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id)) end def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end def closed_issue_email(recipient_id, issue_id, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @updated_by = User.find updated_by_user_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @updated_by = User.find updated_by_user_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @issue_status = status - @updated_by = User.find updated_by_user_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @issue_status = status + @updated_by = User.find updated_by_user_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end private @@ -38,14 +38,12 @@ module Emails } end - def issue_mail_with_notification(issue_id, recipient_id) + def setup_issue_mail(issue_id, recipient_id) @issue = Issue.find(issue_id) @project = @issue.project @target_url = namespace_project_issue_url(@project.namespace, @project, @issue) - yield - - SentNotification.record(@issue, recipient_id, reply_key) + @sent_notification = SentNotification.record(@issue, recipient_id, reply_key) end end end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 7923fb770d0..325996e2e16 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -1,77 +1,64 @@ module Emails module MergeRequests def new_merge_request_email(recipient_id, merge_request_id) - @merge_request = MergeRequest.find(merge_request_id) - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) + setup_merge_request_mail(merge_request_id, recipient_id) + mail_new_thread(@merge_request, from: sender(@merge_request.author_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @updated_by = User.find updated_by_user_id - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) + setup_merge_request_mail(merge_request_id, recipient_id) + mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @mr_status = status - @project = @merge_request.project @updated_by = User.find updated_by_user_id - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) + end + + private + + def setup_merge_request_mail(merge_request_id, recipient_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + @target_url = namespace_project_merge_request_url(@project.namespace, + @project, + @merge_request) - SentNotification.record(@merge_request, recipient_id, reply_key) + @sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key) end end end diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index e1382d2da12..f9650df9a74 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -1,31 +1,31 @@ module Emails module Notes def note_commit_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @commit = @note.noteable - @target_url = namespace_project_commit_url(*note_target_url_options) - - mail_answer_thread(@commit, - from: sender(@note.author_id), - to: recipient(recipient_id), - subject: subject("#{@commit.title} (#{@commit.short_id})")) - end + setup_note_mail(note_id, recipient_id) + + @commit = @note.noteable + @target_url = namespace_project_commit_url(*note_target_url_options) + + mail_answer_thread(@commit, + from: sender(@note.author_id), + to: recipient(recipient_id), + subject: subject("#{@commit.title} (#{@commit.short_id})")) end def note_issue_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @issue = @note.noteable - @target_url = namespace_project_issue_url(*note_target_url_options) - mail_answer_thread(@issue, note_thread_options(recipient_id)) - end + setup_note_mail(note_id, recipient_id) + + @issue = @note.noteable + @target_url = namespace_project_issue_url(*note_target_url_options) + mail_answer_thread(@issue, note_thread_options(recipient_id)) end def note_merge_request_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @merge_request = @note.noteable - @target_url = namespace_project_merge_request_url(*note_target_url_options) - mail_answer_thread(@merge_request, note_thread_options(recipient_id)) - end + setup_note_mail(note_id, recipient_id) + + @merge_request = @note.noteable + @target_url = namespace_project_merge_request_url(*note_target_url_options) + mail_answer_thread(@merge_request, note_thread_options(recipient_id)) end private @@ -42,13 +42,11 @@ module Emails } end - def note_mail_with_notification(note_id, recipient_id) + def setup_note_mail(note_id, recipient_id) @note = Note.find(note_id) @project = @note.project - yield - - SentNotification.record_note(@note, recipient_id, reply_key) + @sent_notification = SentNotification.record_note(@note, recipient_id, reply_key) end end end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 3bbdd9cee76..e1cd075a978 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -107,10 +107,9 @@ class Notify < BaseMailer end headers["X-GitLab-#{model.class.name}-ID"] = model.id + headers['X-GitLab-Reply-Key'] = reply_key - if reply_key - headers['X-GitLab-Reply-Key'] = reply_key - + if Gitlab::IncomingEmail.enabled? address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key)) address.display_name = @project.name_with_namespace diff --git a/app/models/ability.rb b/app/models/ability.rb index 5a1a67db8e1..5375148a654 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -175,7 +175,7 @@ class Ability :create_merge_request, :create_wiki, :manage_builds, - :download_build_artifacts, + :read_build_artifacts, :push_code ] end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index a4779d06de8..6cc26abce66 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -30,10 +30,12 @@ # description :string(255) # artifacts_file :text # gl_project_id :integer +# artifacts_metadata :text # module Ci class Build < CommitStatus + include Gitlab::Application.routes.url_helpers LAZY_ATTRIBUTES = ['trace'] belongs_to :runner, class_name: 'Ci::Runner' @@ -49,6 +51,7 @@ module Ci scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) } mount_uploader :artifacts_file, ArtifactUploader + mount_uploader :artifacts_metadata, ArtifactUploader acts_as_taggable @@ -291,21 +294,18 @@ module Ci end def target_url - Gitlab::Application.routes.url_helpers. - namespace_project_build_url(project.namespace, project, self) + namespace_project_build_url(project.namespace, project, self) end def cancel_url if active? - Gitlab::Application.routes.url_helpers. - cancel_namespace_project_build_path(project.namespace, project, self) + cancel_namespace_project_build_path(project.namespace, project, self) end end def retry_url if retryable? - Gitlab::Application.routes.url_helpers. - retry_namespace_project_build_path(project.namespace, project, self) + retry_namespace_project_build_path(project.namespace, project, self) end end @@ -321,20 +321,35 @@ module Ci pending? && !any_runners_online? end - def download_url - if artifacts_file.exists? - Gitlab::Application.routes.url_helpers. - download_namespace_project_build_path(project.namespace, project, self) - end - end - def execute_hooks build_data = Gitlab::BuildDataBuilder.build(self) project.execute_hooks(build_data.dup, :build_hooks) project.execute_services(build_data.dup, :build_hooks) end + def artifacts? + artifacts_file.exists? + end + + def artifacts_download_url + if artifacts? + download_namespace_project_build_artifacts_path(project.namespace, project, self) + end + end + def artifacts_browse_url + if artifacts_browser_supported? + browse_namespace_project_build_artifacts_path(project.namespace, project, self) + end + end + + def artifacts_browser_supported? + artifacts? && artifacts_metadata.exists? + end + + def artifacts_metadata_entry(path) + Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry + end private diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index 7f6f497f325..e786bd7dd93 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -18,8 +18,12 @@ module Ci belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id - validates_presence_of :key validates_uniqueness_of :key, scope: :gl_project_id + validates :key, + presence: true, + length: { within: 0..255 }, + format: { with: /\A[a-zA-Z0-9_]+\z/, + message: "can contain only letters, digits and '_'." } attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index ff479493474..4ce9b998dfc 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -131,7 +131,11 @@ class CommitStatus < ActiveRecord::Base false end - def download_url + def artifacts_download_url + nil + end + + def artifacts_browse_url nil end end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 18a00f95b48..04650a9e67a 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -119,6 +119,12 @@ module Issuable update(subscribed: !subscribed?(user)) end + def unsubscribe(user) + subscriptions. + find_or_initialize_by(user_id: user.id). + update(subscribed: false) + end + def to_hook_data(user) { object_kind: self.class.name.underscore, diff --git a/app/models/identity.rb b/app/models/identity.rb index 8bcdc194953..e1915b079d4 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -18,4 +18,8 @@ class Identity < ActiveRecord::Base validates :provider, presence: true validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :user_id, uniqueness: { scope: :provider } + + def ldap? + provider.starts_with?('ldap') + end end diff --git a/app/models/project.rb b/app/models/project.rb index 31990485f7d..7e131151513 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -397,7 +397,7 @@ class Project < ActiveRecord::Base result.password = '*****' unless result.password.nil? result.to_s rescue - original_url + self.import_url end def check_limit diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index f36eda1531b..77115597d71 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -25,8 +25,6 @@ class SentNotification < ActiveRecord::Base class << self def reply_key - return nil unless Gitlab::IncomingEmail.enabled? - SecureRandom.hex(16) end @@ -59,11 +57,15 @@ class SentNotification < ActiveRecord::Base def record_note(note, recipient_id, reply_key, params = {}) params[:line_code] = note.line_code - + record(note.noteable, recipient_id, reply_key, params) end end + def unsubscribable? + !for_commit? + end + def for_commit? noteable_type == "Commit" end @@ -75,4 +77,8 @@ class SentNotification < ActiveRecord::Base super end end + + def to_param + self.reply_key + end end diff --git a/app/models/user.rb b/app/models/user.rb index 46b36c605b0..592468933ed 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -196,10 +196,22 @@ class User < ActiveRecord::Base state_machine :state, initial: :active do event :block do transition active: :blocked + transition ldap_blocked: :blocked + end + + event :ldap_block do + transition active: :ldap_blocked end event :activate do transition blocked: :active + transition ldap_blocked: :active + end + + state :blocked, :ldap_blocked do + def blocked? + true + end end end @@ -207,7 +219,7 @@ class User < ActiveRecord::Base # Scopes scope :admins, -> { where(admin: true) } - scope :blocked, -> { with_state(:blocked) } + scope :blocked, -> { with_states(:blocked, :ldap_blocked) } scope :active, -> { with_state(:active) } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') } diff --git a/app/services/repair_ldap_blocked_user_service.rb b/app/services/repair_ldap_blocked_user_service.rb new file mode 100644 index 00000000000..863cef7ff61 --- /dev/null +++ b/app/services/repair_ldap_blocked_user_service.rb @@ -0,0 +1,17 @@ +class RepairLdapBlockedUserService + attr_accessor :user + + def initialize(user) + @user = user + end + + def execute + user.block if ldap_hard_blocked? + end + + private + + def ldap_hard_blocked? + user.ldap_blocked? && !user.ldap_user? + end +end diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml index 6936e614346..c395bd908c3 100644 --- a/app/views/admin/builds/_build.html.haml +++ b/app/views/admin/builds/_build.html.haml @@ -60,8 +60,8 @@ %td .pull-right - - if current_user && can?(current_user, :download_build_artifacts, project) && build.download_url - = link_to build.download_url, title: 'Download artifacts' do + - if current_user && can?(current_user, :read_build_artifacts, project) && build.artifacts? + = link_to build.artifacts_download_url, title: 'Download artifacts' do %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, build.project) - if build.active? diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index ddd4e1481eb..ebf2b7b60e7 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -4,7 +4,7 @@ - if @all_builds.running_or_pending.any? = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - %ul.center-top-menu + %ul.nav-links %li{class: ('active' if @scope.nil?)} = link_to admin_builds_path do All diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 1484baa78e0..af9fdeb0734 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,12 +1,13 @@ - page_title "Logs" - loggers = [Gitlab::GitLogger, Gitlab::AppLogger, Gitlab::ProductionLogger, Gitlab::SidekiqLogger] -%ul.nav.nav-tabs.log-tabs +%ul.nav-links.log-tabs - loggers.each do |klass| %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') } = link_to klass::file_name, "##{klass::file_name_noext}", 'data-toggle' => 'tab' -%p.light To prevent performance issues admin logs output the last 2000 lines +.gray-content-block + To prevent performance issues admin logs output the last 2000 lines .tab-content - loggers.each do |klass| .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''), diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index bc44b1b1d8e..ce5e21e54cc 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -12,7 +12,7 @@ %i.fa.fa-pencil-square-o Edit %hr -%ul.nav.nav-tabs +%ul.nav-links = nav_link(path: 'users#show') do = link_to "Account", admin_user_path(@user) = nav_link(path: 'users#groups') do @@ -23,3 +23,4 @@ = link_to "SSH keys", keys_admin_user_path(@user) = nav_link(controller: :identities) do = link_to "Identities", admin_user_identities_path(@user) +.append-bottom-default diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index a92c9c152b9..b050a4d01c3 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,101 +1,101 @@ - page_title "Users" = render 'shared/show_aside' -.row - %aside.col-md-3 - .admin-filter - %ul.nav.nav-pills.nav-stacked - %li{class: "#{'active' unless params[:filter]}"} - = link_to admin_users_path do - Active - %small.pull-right= number_with_delimiter(User.active.count) - %li{class: "#{'active' if params[:filter] == "admins"}"} - = link_to admin_users_path(filter: "admins") do - Admins - %small.pull-right= number_with_delimiter(User.admins.count) - %li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"} - = link_to admin_users_path(filter: 'two_factor_enabled') do - 2FA Enabled - %small.pull-right= number_with_delimiter(User.with_two_factor.count) - %li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"} - = link_to admin_users_path(filter: 'two_factor_disabled') do - 2FA Disabled - %small.pull-right= number_with_delimiter(User.without_two_factor.count) - %li{class: "#{'active' if params[:filter] == "blocked"}"} - = link_to admin_users_path(filter: "blocked") do - Blocked - %small.pull-right= number_with_delimiter(User.blocked.count) - %li{class: "#{'active' if params[:filter] == "wop"}"} - = link_to admin_users_path(filter: "wop") do - Without projects - %small.pull-right= number_with_delimiter(User.without_projects.count) - %hr - = form_tag admin_users_path, method: :get, class: 'form-inline' do - .form-group - = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control', spellcheck: false - = hidden_field_tag "filter", params[:filter] - = button_tag class: 'btn btn-primary' do - %i.fa.fa-search - %hr - = link_to 'Reset', admin_users_path, class: "btn btn-cancel" +.admin-filter + %ul.nav-links + %li{class: "#{'active' unless params[:filter]}"} + = link_to admin_users_path do + Active + %small.badge= number_with_delimiter(User.active.count) + %li{class: "#{'active' if params[:filter] == "admins"}"} + = link_to admin_users_path(filter: "admins") do + Admins + %small.badge= number_with_delimiter(User.admins.count) + %li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"} + = link_to admin_users_path(filter: 'two_factor_enabled') do + 2FA Enabled + %small.badge= number_with_delimiter(User.with_two_factor.count) + %li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"} + = link_to admin_users_path(filter: 'two_factor_disabled') do + 2FA Disabled + %small.badge= number_with_delimiter(User.without_two_factor.count) + %li{class: "#{'active' if params[:filter] == "blocked"}"} + = link_to admin_users_path(filter: "blocked") do + Blocked + %small.badge= number_with_delimiter(User.blocked.count) + %li{class: "#{'active' if params[:filter] == "wop"}"} + = link_to admin_users_path(filter: "wop") do + Without projects + %small.badge= number_with_delimiter(User.without_projects.count) - %section.col-md-9 - .panel.panel-default - .panel-heading - Users (#{number_with_delimiter(@users.total_count)}) - .panel-head-actions - .dropdown.inline - %a.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"} - %span.light sort: - - if @sort.present? - = sort_options_hash[@sort] - - else - = sort_title_name - %b.caret - %ul.dropdown-menu - %li - = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do - = sort_title_name - = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do - = sort_title_recently_signin - = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do - = sort_title_oldest_signin - = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do - = sort_title_recently_created - = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do - = sort_title_oldest_created - = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do - = sort_title_recently_updated - = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do - = sort_title_oldest_updated - - = link_to 'New User', new_admin_user_path, class: "btn btn-new btn-sm" - %ul.well-list - - @users.each do |user| + .gray-content-block.second-block + .pull-right + .dropdown.inline + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %span.light sort: + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_name + %b.caret + %ul.dropdown-menu %li - .list-item-name - - if user.blocked? - %i.fa.fa-lock.cred + = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do + = sort_title_name + = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do + = sort_title_recently_signin + = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do + = sort_title_oldest_signin + = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do + = sort_title_recently_created + = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do + = sort_title_oldest_created + = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do + = sort_title_recently_updated + = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do + = sort_title_oldest_updated + + = link_to 'New User', new_admin_user_path, class: "btn btn-new" + = form_tag admin_users_path, method: :get, class: 'form-inline' do + .form-group + = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control', spellcheck: false + = hidden_field_tag "filter", params[:filter] + = button_tag class: 'btn btn-primary' do + %i.fa.fa-search + + +.panel.panel-default + %ul.well-list + - @users.each do |user| + %li + .list-item-name + - if user.blocked? + %i.fa.fa-lock.cred + - else + %i.fa.fa-user.cgreen + = link_to user.name, [:admin, user] + - if user.admin? + %strong.cred (Admin) + - if user == current_user + %span.cred It's you! + .pull-right + %span.light + %i.fa.fa-envelope + = mail_to user.email, user.email, class: 'light' + + .pull-right + = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn-grouped btn btn-xs' + - unless user == current_user + - if user.ldap_blocked? + = link_to '#', title: 'Cannot unblock LDAP blocked users', data: {toggle: 'tooltip'}, class: 'btn-grouped btn btn-xs btn-success disabled' do + %i.fa.fa-lock + Unblock + - elsif user.blocked? + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success' - else - %i.fa.fa-user.cgreen - = link_to user.name, [:admin, user] - - if user.admin? - %strong.cred (Admin) - - if user == current_user - %span.cred It's you! - .pull-right - %span.light - %i.fa.fa-envelope - = mail_to user.email, user.email, class: 'light' - - = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-xs" - - unless user == current_user - - if user.blocked? - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-xs btn-success" - - else - = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs btn-warning" - - if user.access_locked? - = link_to 'Unlock', unlock_admin_user_path(user), method: :put, class: "btn btn-xs btn-success", data: { confirm: 'Are you sure?' } - - if user.can_be_removed? - = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: "btn btn-xs btn-remove" - = paginate @users, theme: "gitlab" + = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: 'btn-grouped btn btn-xs btn-warning' + - if user.access_locked? + = link_to 'Unlock', unlock_admin_user_path(user), method: :put, class: 'btn-grouped btn btn-xs btn-success', data: { confirm: 'Are you sure?' } + - if user.can_be_removed? + = link_to 'Destroy', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! All issues, merge requests and groups linked to this user will also be removed! Maybe block the user instead? Are you sure?" }, method: :delete, class: 'btn-grouped btn btn-xs btn-remove' += paginate @users, theme: "gitlab" diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index f98fd9f06ba..dc76599b776 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -1,9 +1,9 @@ .hidden-xs = render "events/event_last_push", event: @last_push -.gray-content-block +.nav-block - if current_user - .pull-right + .controls = link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn' do %i.fa.fa-rss = render 'shared/event_filter' diff --git a/app/views/dashboard/_activity_head.html.haml b/app/views/dashboard/_activity_head.html.haml index 9f4be025bf2..b78e70ebc1e 100644 --- a/app/views/dashboard/_activity_head.html.haml +++ b/app/views/dashboard/_activity_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links %li{ class: ("active" unless params[:filter]) } = link_to activity_dashboard_path, class: 'shortcuts-activity', data: {placement: 'right'} do Your Projects diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml index 64bd356f546..6ca97a692b4 100644 --- a/app/views/dashboard/_groups_head.html.haml +++ b/app/views/dashboard/_groups_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(page: dashboard_groups_path) do = link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do Your Groups diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index f4a3e3162bf..5c4b58cd688 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -1,7 +1,7 @@ = content_for :flash_message do = render 'shared/project_limit' .top-area - %ul.left-top-menu + %ul.nav-links = nav_link(page: [dashboard_projects_path, root_path]) do = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do Your Projects diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml index 0ae62d6f1b6..b25e8ea1f0c 100644 --- a/app/views/dashboard/_snippets_head.html.haml +++ b/app/views/dashboard/_snippets_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(page: dashboard_snippets_path, html_options: {class: 'home'}) do = link_to dashboard_snippets_path, title: 'Your snippets', data: {placement: 'right'} do Your Snippets diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 49a558e8ac9..3810267577c 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -48,7 +48,7 @@ #{@milestone.open_items_count} open = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 07b6d57932e..d4e7862981c 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -3,32 +3,36 @@ = render 'dashboard/snippets_head' -.gray-content-block - .pull-right +.nav-block + .controls = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do = icon('plus') New Snippet - .btn-group.btn-group-next.snippet-scope-menu - = link_to dashboard_snippets_path, class: "btn btn-default #{"active" unless params[:scope]}" do - All - %span.badge - = current_user.snippets.count - - = link_to dashboard_snippets_path(scope: 'are_private'), class: "btn btn-default #{"active" if params[:scope] == "are_private"}" do - Private - %span.badge - = current_user.snippets.are_private.count - - = link_to dashboard_snippets_path(scope: 'are_internal'), class: "btn btn-default #{"active" if params[:scope] == "are_internal"}" do - Internal - %span.badge - = current_user.snippets.are_internal.count - - = link_to dashboard_snippets_path(scope: 'are_public'), class: "btn btn-default #{"active" if params[:scope] == "are_public"}" do - Public - %span.badge - = current_user.snippets.are_public.count + .nav-links.snippet-scope-menu + %li{ class: ("active" unless params[:scope]) } + = link_to dashboard_snippets_path do + All + %span.badge + = current_user.snippets.count + + %li{ class: ("active" if params[:scope] == "are_private") } + = link_to dashboard_snippets_path(scope: 'are_private') do + Private + %span.badge + = current_user.snippets.are_private.count + + %li{ class: ("active" if params[:scope] == "are_internal") } + = link_to dashboard_snippets_path(scope: 'are_internal') do + Internal + %span.badge + = current_user.snippets.are_internal.count + + %li{ class: ("active" if params[:scope] == "are_public") } + = link_to dashboard_snippets_path(scope: 'are_public') do + Public + %span.badge + = current_user.snippets.are_public.count = render 'snippets/snippets' diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml index 41ad2c231d4..2c15e2c4891 100644 --- a/app/views/devise/shared/_signin_box.html.haml +++ b/app/views/devise/shared/_signin_box.html.haml @@ -7,7 +7,7 @@ %h3 Sign in .login-body - if form_based_providers.any? - %ul.nav.nav-tabs + %ul.nav-links - if crowd_enabled? %li.active = link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab' diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 7e3e2e28bc9..e2f97fd9337 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,7 +1,7 @@ - header_title group_title(@group, "Settings", edit_group_path(@group)) - @blank_container = true -.panel.panel-default +.panel.panel-default.prepend-top-default .panel-heading Group settings .panel-body diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 335bf036074..6a8acc42af9 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -2,7 +2,7 @@ - header_title group_title(@group, "Members", group_group_members_path(@group)) - @blank_container = true -.group-members-page +.group-members-page.prepend-top-default - if current_user && current_user.can?(:admin_group_member, @group) .panel.panel-default .panel-heading diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index d063b257b5e..1233da85524 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -54,7 +54,7 @@ #{@milestone.open_items_count} open = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index f1d507a50c7..9ca11ed1177 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -1,7 +1,7 @@ - page_title "Projects" - header_title group_title(@group, "Projects", projects_group_path(@group)) -.panel.panel-default +.panel.panel-default.prepend-top-default .panel-heading %strong= @group.name projects: diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 48a544fc834..5e39d3ab601 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,3 +1,6 @@ +- @no_container = true +- @blank_container = true + - unless can?(current_user, :read_group, @group) - @disable_search_panel = true @@ -25,8 +28,8 @@ .cover-desc.description = markdown(@group.description, pipeline: :description) -- if can?(current_user, :read_group, @group) - %ul.center-top-menu.no-top + + %ul.nav-links %li.active = link_to "#activity", 'data-toggle' => 'tab' do Activity @@ -35,20 +38,22 @@ = link_to "#projects", 'data-toggle' => 'tab' do Projects - .tab-content - .tab-pane.active#activity - .gray-content-block.activity-filter-block - - if current_user - = render "events/event_last_push", event: @last_push +- if can?(current_user, :read_group, @group) + %div{ class: container_class } + .tab-content + .tab-pane.active#activity + .activity-filter-block + - if current_user + = render "events/event_last_push", event: @last_push - = render 'shared/event_filter' + = render 'shared/event_filter' - .content_list - = spinner + .content_list + = spinner - .tab-pane#projects - = render "projects", projects: @projects + .tab-pane#projects + = render "projects", projects: @projects - else - %p.center-top-menu.no-top + %p.nav-links.no-top No projects to show diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index d9ffda884c8..7b45bd09050 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -139,26 +139,9 @@ %h2#navs Navigation %h4 - %code .center-top-menu + %code .nav-links .example - %ul.center-top-menu - %li.active - %a Open - %li - %a Closed - - %h4 - %code .btn-group.btn-group-next - .example - %div.btn-group.btn-group-next - %a.btn.active Open - %a.btn Closed - - - %h4 - %code .nav.nav-tabs - .example - %ul.nav.nav-tabs + %ul.nav-links %li.active %a Open %li diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index ec7cd79bc54..26159989777 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -24,7 +24,7 @@ .content-wrapper = render "layouts/flash" = yield :flash_message - %div{ class: container_class } + %div{ class: (container_class unless @no_container) } .content .clearfix = yield diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 3ca4c340406..325c68c69dc 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -44,6 +44,10 @@ %br -# Don't link the host is the line below, one link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. - If you'd like to receive fewer emails, you can adjust your notification settings. + If you'd like to receive fewer emails, you can + - if @sent_notification && @sent_notification.unsubscribable? + = link_to "unsubscribe", unsubscribe_sent_notification_url(@sent_notification) + from this thread or + adjust your notification settings. - = email_action @target_url
\ No newline at end of file + = email_action @target_url diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 17e47c622ce..a42fd38de3a 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -6,7 +6,7 @@ .alert.alert-info Some options are unavailable for LDAP accounts -.account-page +.account-page.prepend-top-default .panel.panel-default.update-token .panel-heading Reset Private token diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index 101880bd105..961b61d2e76 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -1,6 +1,6 @@ -.gray-content-block.activity-filter-block +.nav-block.activity-filter-block - if current_user - .pull-right + .controls = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'btn rss-btn' do %i.fa.fa-rss diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml index fa978325ddd..96c2fa87f45 100644 --- a/app/views/projects/_files.html.haml +++ b/app/views/projects/_files.html.haml @@ -1,5 +1,5 @@ #tree-holder.tree-holder.clearfix - .gray-content-block.second-block + .nav-block = render 'projects/tree/tree_header', tree: @tree = render 'projects/tree/tree_content', tree: @tree diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index 54c818baaf4..1fb37ef6621 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -1,6 +1,6 @@ .md-area .md-header.clearfix - %ul.center-top-menu + %ul.nav-links %li.active %a.js-md-write-button(href="#md-write-holder" tabindex="-1") Write diff --git a/app/views/projects/artifacts/_tree_directory.html.haml b/app/views/projects/artifacts/_tree_directory.html.haml new file mode 100644 index 00000000000..5b87d55efd5 --- /dev/null +++ b/app/views/projects/artifacts/_tree_directory.html.haml @@ -0,0 +1,7 @@ +%tr{ class: 'tree-item' } + %td.tree-item-file-name + = tree_icon('folder', '755', directory.name) + %span.str-truncated + = link_to directory.name, browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: directory.path) + %td + %td diff --git a/app/views/projects/artifacts/_tree_file.html.haml b/app/views/projects/artifacts/_tree_file.html.haml new file mode 100644 index 00000000000..92c1648f726 --- /dev/null +++ b/app/views/projects/artifacts/_tree_file.html.haml @@ -0,0 +1,11 @@ +%tr{ class: 'tree-item' } + %td.tree-item-file-name + = tree_icon('file', '664', file.name) + %span.str-truncated + = file.name + %td + = number_to_human_size(file.metadata[:size], precision: 2) + %td + = link_to file_namespace_project_build_artifacts_path(@project.namespace, @project, @build, path: file.path), + class: 'btn btn-xs btn-default artifact-download' do + = icon('download') diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml new file mode 100644 index 00000000000..1add7ef6bfb --- /dev/null +++ b/app/views/projects/artifacts/browse.html.haml @@ -0,0 +1,24 @@ +- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Builds' += render 'projects/builds/header_title' + +#tree-holder.tree-holder + .gray-content-block.top-block.clearfix + .pull-right + = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), + class: 'btn btn-default' do + = icon('download') + Download artifacts archive + +%div.tree-content-holder + .table-holder + %table.table.tree-table.table-striped + %thead + %tr + %th Name + %th Size + %th Download + = render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory + = render partial: 'tree_file', collection: @entry.files, as: :file + +- if @entry.empty? + .center Empty diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 2a3315da3db..3d8d88834e2 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -1,4 +1,4 @@ -.gray-content-block.top-block +.nav-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'blob', path: @path diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 09fa148b129..a279e6eda55 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -2,7 +2,7 @@ = render "header_title" .file-editor - %ul.center-top-menu.no-bottom.js-edit-mode + %ul.nav-links.no-bottom.js-edit-mode %li.active = link_to '#editor' do = icon('edit') diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index a234536723e..d276e5932d1 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -6,7 +6,7 @@ %li(class="js-branch-#{branch.name}") %div = link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do - %strong.str-truncated= branch.name + .branch-name.str-truncated= branch.name - if branch.name == @repository.root_ref %span.label.label-primary default diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 3bbfdb1e3b0..5d18c0d803a 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -8,7 +8,7 @@ - if @all_builds.running_or_pending.any? = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - %ul.center-top-menu + %ul.nav-links %li{class: ('active' if @scope.nil?)} = link_to project_builds_path(@project) do All diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 5b7ecce86ab..2be572d3b10 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -14,7 +14,7 @@ #up-build-trace - if @commit.matrix_for_ref?(@build.ref) - %ul.center-top-menu.no-top.no-bottom + %ul.nav-links.no-top.no-bottom - @commit.latest_builds_for_ref(@build.ref).each do |build| %li{class: ('active' if build == @build) } = link_to namespace_project_build_path(@project.namespace, @project, build) do @@ -89,9 +89,15 @@ Test coverage %h1 #{@build.coverage}% - - if current_user && can?(current_user, :download_build_artifacts, @project) && @build.download_url - .build-widget.center - = link_to "Download artifacts", @build.download_url, class: 'btn btn-sm btn-primary' + - if current_user && can?(current_user, :read_build_artifacts, @project) && @build.artifacts? + + .build-widget.artifacts + %h4.title Build artifacts + .center + .btn-group{ role: :group } + = link_to "Download", @build.artifacts_download_url, class: 'btn btn-sm btn-primary' + - if @build.artifacts_browser_supported? + = link_to "Browse", @build.artifacts_browse_url, class: 'btn btn-sm btn-primary' .build-widget %h4.title diff --git a/app/views/projects/commit/_ci_menu.html.haml b/app/views/projects/commit/_ci_menu.html.haml index f74f8b427ec..ea33aa472a6 100644 --- a/app/views/projects/commit/_ci_menu.html.haml +++ b/app/views/projects/commit/_ci_menu.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu.no-top.no-bottom.commit-ci-menu +%ul.nav-links.no-top.no-bottom.commit-ci-menu = nav_link(path: 'commit#show') do = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do Changes diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index ddb77fd796b..bbe820b8842 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -50,7 +50,7 @@ .commit-info-row.branches %i.fa.fa-spinner.fa-spin -.commit-box.gray-content-block.middle-block +.commit-box.content-block %h3.commit-title = markdown escape_once(@commit.title), pipeline: :single_line - if @commit.description.present? diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 58aa45e8d2c..02297158dec 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -2,7 +2,9 @@ - page_description @commit.description = render "projects/commits/header_title" -= render "commit_box" + +.prepend-top-default + = render "commit_box" - if @ci_commit = render "ci_menu" - else diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index 74a05df24d3..1736dccaf3c 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -66,8 +66,8 @@ %td .pull-right - - if current_user && can?(current_user, :download_build_artifacts, commit_status.project) && commit_status.download_url - = link_to commit_status.download_url, title: 'Download artifacts' do + - if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts? + = link_to commit_status.artifacts_download_url, title: 'Download artifacts' do %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, commit_status.project) - if commit_status.active? diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 012825f0fdb..4d4b410ee29 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -11,7 +11,7 @@ = cache(cache_key) do %li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" } .commit-row-title - %strong.str-truncated + .commit-title.str-truncated = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" - if commit.description? %a.text-expander.js-toggle-button ... diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index fcccb002d7e..498c5e05b32 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(controller: [:commit, :commits]) do = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do Commits diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 034057da42e..ede64d47ab3 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -6,7 +6,7 @@ = render "head" -.gray-content-block +.gray-content-block.second-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'commits' diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index f9d661d59d2..f67058ae0ba 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -3,7 +3,7 @@ - diff_files = safe_diff_files(diffs) -.gray-content-block.middle-block.oneline-block +.content-block.oneline-block .inline-parallel-buttons .btn-group = inline_diff_btn diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 31e752c6649..8a99aceef7f 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -1,6 +1,6 @@ - @blank_container = true -.project-edit-container +.project-edit-container.prepend-top-default .project-edit-errors .project-edit-content .panel.panel-default diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml index a47643bd09c..79a56647c53 100644 --- a/app/views/projects/graphs/_head.html.haml +++ b/app/views/projects/graphs/_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(action: :show) do = link_to 'Contributors', namespace_project_graph_path = nav_link(action: :commits) do diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index a14943b15d3..dd2c59e112a 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -18,7 +18,7 @@ = f.hidden_field :target_branch .mr-compare.merge-request - %ul.merge-request-tabs.center-top-menu.no-top.no-bottom + %ul.merge-request-tabs.nav-links.no-top.no-bottom %li.commits-tab = link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do Commits diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 095876450a0..200bfa5ac4f 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -45,7 +45,7 @@ = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - if @commits.present? - %ul.merge-request-tabs.center-top-menu.no-top.no-bottom + %ul.merge-request-tabs.nav-links.no-top.no-bottom %li.notes-tab = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do Discussion diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index d1db0f64f88..1142c584592 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -57,7 +57,7 @@ %span.pull-right= @milestone.expires_at = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 29225a36364..6239a148905 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -2,7 +2,7 @@ = render "header_title" - @blank_container = true -.project-members-page +.project-members-page.prepend-top-default - if can?(current_user, :admin_project_member, @project) .panel.panel-default .panel-heading diff --git a/app/views/projects/runners/index.html.haml b/app/views/projects/runners/index.html.haml index 315afe4a764..2d5b9f43c24 100644 --- a/app/views/projects/runners/index.html.haml +++ b/app/views/projects/runners/index.html.haml @@ -1,5 +1,6 @@ - page_title "Runners" -.light + +.light.prepend-top-default %p A 'runner' is a process which runs a build. You can setup as many runners as you need. diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 8436be433b1..797bee708bd 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,3 +1,6 @@ +- @no_container = true +- @blank_container = true + = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity") @@ -8,11 +11,10 @@ = render 'shared/no_password' = render 'projects/last_push' - = render "home_panel" .project-stats.gray-content-block.second-block - %ul.nav.nav-pills + %ul.nav %li = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do = pluralize(number_with_delimiter(@project.commit_count), 'commit') @@ -57,15 +59,17 @@ = link_to add_contribution_guide_path(@project) do Add Contribution guide -- if @project.archived? - .text-warning.center.prepend-top-20 - %p - = icon("exclamation-triangle fw") - Archived project! Repository is read-only - - if @repository.commit .content-block.second-block.white - = render 'projects/last_commit', commit: @repository.commit, project: @project + %div{ class: container_class } + = render 'projects/last_commit', commit: @repository.commit, project: @project + +%div{ class: container_class } + - if @project.archived? + .text-warning.center.prepend-top-20 + %p + = icon("exclamation-triangle fw") + Archived project! Repository is read-only -%div{class: "project-show-#{default_project_view}"} - = render default_project_view + %div{class: "project-show-#{default_project_view}"} + = render default_project_view diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 28b706c5c7e..56a7ced1236 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -3,7 +3,7 @@ %li %div = link_to namespace_project_tag_path(@project.namespace, @project, tag.name) do - %strong + .tag-name = icon('tag') = tag.name - if tag.message.present? diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index b594d4f1f27..dbb20347860 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -17,8 +17,8 @@ .pull-right = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has_tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do %i.fa.fa-trash-o - .title - %strong= @tag.name + .tag-name.title + = @tag.name - if @tag.message.present? %span.light diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index 1927883513a..558e6146ae9 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,6 +1,6 @@ %div.tree-content-holder .table-holder - %table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" } + %table.table#tree-slider{class: "table_#{@hex_path} tree-table" } %thead %tr %th Name diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index c57570afa09..91fb2a44594 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -5,13 +5,13 @@ = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits") = render 'projects/last_push' -.pull-right +.tree-controls = render 'projects/find_file_link' - if can? current_user, :download_code, @project = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true #tree-holder.tree-holder.clearfix - .gray-content-block.top-block + .nav-block = render 'projects/tree/tree_header', tree: @tree = render 'projects/tree/tree_content', tree: @tree diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml index e6e6ad5bc4b..69ba301e231 100644 --- a/app/views/projects/wikis/_nav.html.haml +++ b/app/views/projects/wikis/_nav.html.haml @@ -7,7 +7,7 @@ = render 'projects/wikis/new' - %ul.center-top-menu + %ul.nav-links = nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do = link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home) diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index 481451edb23..2c3fca439f3 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.search-filter +%ul.nav-links.search-filter - if @project %li{class: ("active" if @scope == 'blobs')} = link_to search_filter_path(scope: 'blobs') do diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml index 2a38c98dcfc..d0e64537621 100644 --- a/app/views/search/_results.html.haml +++ b/app/views/search/_results.html.haml @@ -1,7 +1,7 @@ - if @search_results.empty? = render partial: "search/results/empty" - else - %p.light + .gray-content-block Search results for %code = @search_term diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index f4f3dcfc29f..215dbb3909e 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -1,5 +1,7 @@ - page_title @search_term -= render 'search/form' + +.prepend-top-default + = render 'search/form' - if @search_term = render 'search/category' = render 'search/results' diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml index 8495774accc..c38d9313dba 100644 --- a/app/views/shared/_event_filter.html.haml +++ b/app/views/shared/_event_filter.html.haml @@ -1,4 +1,4 @@ -.btn-group.btn-group-next.event-filter +%ul.nav-links.event-filter = event_filter_link EventFilter.push, 'Push events' = event_filter_link EventFilter.merged, 'Merge events' = event_filter_link EventFilter.comments, 'Comments' diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index cbdecda4fff..f77feeb79cd 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,5 +1,5 @@ .milestones-filters - %ul.center-top-menu + %ul.nav-links %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} = link_to milestones_filter_path(state: 'opened') do Open diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index a54c5fa8c33..f4cfa29ae56 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -10,8 +10,7 @@ %i.fa.fa-sign-out = image_tag group_icon(group), class: "avatar s46 hidden-xs" - = link_to group, class: 'group-name' do - %strong= group.name + = link_to group.name, group, class: 'group-name' - if group_member as diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index 0e3e9275fc1..8d6f47b38ef 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -1,6 +1,6 @@ .issues-filters .issues-state-filters - %ul.center-top-menu + %ul.nav-links - if defined?(type) && type == :merge_requests - page_context_word = 'merge requests' - else diff --git a/app/views/sherlock/queries/show.html.haml b/app/views/sherlock/queries/show.html.haml index 4a84348ac82..83f61ce4b07 100644 --- a/app/views/sherlock/queries/show.html.haml +++ b/app/views/sherlock/queries/show.html.haml @@ -1,7 +1,7 @@ - page_title t('sherlock.title'), t('sherlock.transaction'), t('sherlock.query') - header_title t('sherlock.title'), sherlock_transactions_path -%ul.center-top-menu +%ul.nav-links %li.active %a(href="#tab-general" data-toggle="tab") = t('sherlock.general') diff --git a/app/views/sherlock/transactions/show.html.haml b/app/views/sherlock/transactions/show.html.haml index 3c8ffb06648..9d4b0b2724c 100644 --- a/app/views/sherlock/transactions/show.html.haml +++ b/app/views/sherlock/transactions/show.html.haml @@ -1,7 +1,7 @@ - page_title t('sherlock.title'), t('sherlock.transaction') - header_title t('sherlock.title'), sherlock_transactions_path -%ul.center-top-menu +%ul.nav-links %li.active %a(href="#tab-general" data-toggle="tab") = t('sherlock.general') diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ce17fc7bca1..284a62e6f47 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,6 +1,8 @@ - page_title @user.name - page_description @user.bio - header_title @user.name, user_path(@user) +- @no_container = true +- @blank_container = true = content_for :meta_tags do = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") @@ -8,6 +10,25 @@ = render 'shared/show_aside' .cover-block + .cover-controls + - if @user == current_user + = link_to profile_path, class: 'btn btn-gray' do + = icon('pencil') + - elsif current_user + %span.report-abuse + - if @user.abuse_report + %button.btn.btn-danger{ title: 'Already reported for abuse', + data: { toggle: 'tooltip', placement: 'left', container: 'body' }} + = icon('exclamation-circle') + - else + = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray', + title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do + = icon('exclamation-circle') + - if current_user + + = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do + = icon('rss') + .avatar-holder = link_to avatar_icon(@user, 400), target: '_blank' do = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: '' @@ -47,74 +68,56 @@ = icon('map-marker') = @user.location + %ul.nav-links.center + %li.active + = link_to "#activity", 'data-toggle' => 'tab' do + Activity + - if @groups.any? + %li + = link_to "#groups", 'data-toggle' => 'tab' do + Groups + - if @contributed_projects.present? + %li + = link_to "#contributed", 'data-toggle' => 'tab' do + Contributed projects + - if @projects.present? + %li + = link_to "#personal", 'data-toggle' => 'tab' do + Personal projects - .cover-controls - - if @user == current_user - = link_to profile_path, class: 'btn btn-gray' do - = icon('pencil') - - elsif current_user - %span.report-abuse - - if @user.abuse_report - %button.btn.btn-danger{ title: 'Already reported for abuse', - data: { toggle: 'tooltip', placement: 'left', container: 'body' }} - = icon('exclamation-circle') - - else - = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray', - title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do - = icon('exclamation-circle') - - if current_user - - = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do - = icon('rss') - -.gray-content-block.second-block - .user-calendar - %h4.center.light - %i.fa.fa-spinner.fa-spin - .user-calendar-activities - +%div{ class: container_class } + .tab-content + .tab-pane.active#activity + .gray-content-block.white.second-block + %div{ class: container_class } + .user-calendar + %h4.center.light + %i.fa.fa-spinner.fa-spin + .user-calendar-activities -%ul.center-top-menu.no-top.no-bottom.bottom-border.wide - %li.active - = link_to "#activity", 'data-toggle' => 'tab' do - Activity - - if @groups.any? - %li - = link_to "#groups", 'data-toggle' => 'tab' do - Groups - - if @contributed_projects.present? - %li - = link_to "#contributed", 'data-toggle' => 'tab' do - Contributed projects - - if @projects.present? - %li - = link_to "#personal", 'data-toggle' => 'tab' do - Personal projects -.tab-content - .tab-pane.active#activity - .content_list - = spinner + .content_list + = spinner - - if @groups.any? - .tab-pane#groups - %ul.content-list - - @groups.each do |group| - = render 'shared/groups/group', group: group + - if @groups.any? + .tab-pane#groups + %ul.content-list + - @groups.each do |group| + = render 'shared/groups/group', group: group - - if @contributed_projects.present? - .tab-pane#contributed - .contributed-projects - = render 'shared/projects/list', - projects: @contributed_projects.sort_by(&:star_count).reverse, - projects_limit: 5, stars: true, avatar: true + - if @contributed_projects.present? + .tab-pane#contributed + .contributed-projects + = render 'shared/projects/list', + projects: @contributed_projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: true - - if @projects.present? - .tab-pane#personal - .personal-projects - = render 'shared/projects/list', - projects: @projects.sort_by(&:star_count).reverse, - projects_limit: 10, stars: true, avatar: true + - if @projects.present? + .tab-pane#personal + .personal-projects + = render 'shared/projects/list', + projects: @projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: true :javascript $(".user-calendar").load("#{user_calendar_path}"); |