Commit 894cb7df authored by Robert Speicher's avatar Robert Speicher

Merge branch 'master' into 8-4-stable

parents c7ee7eea 041ca926
......@@ -16,6 +16,7 @@ v 8.4.0 (unreleased)
- Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Remove gray background from layout in UI
- Implement new UI for group page
- Implement search inside emoji picker
- Add API support for looking up a user by username (Stan Hu)
......@@ -51,9 +52,12 @@ v 8.4.0 (unreleased)
- Add API support for managing project's build triggers
- Add API support for managing project's build variables
- Allow broadcast messages to be edited
- Autosize Markdown textareas
- Import GitHub wiki into GitLab
v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
- Add build artifacts browser
v 8.3.3
- Preserve CE behavior with JIRA integration by only calling API if URL is set
......@@ -87,6 +91,7 @@ v 8.3.0
- Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
- Add unsubscribe link in the email footer (Zeger-Jan van de Weg)
- Provide better diagnostic message upon project creation errors (Stan Hu)
- Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
- Remove api credentials from link to build_page
......
8.4.0.rc1
\ No newline at end of file
8.4.0.pre
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
......
......@@ -10,19 +10,19 @@ class @Admin
$('body').on 'click', '.js-toggle-colors-link', (e) ->
e.preventDefault()
$('.js-toggle-colors-link').hide()
$('.js-toggle-colors-container').show()
$('.js-toggle-colors-container').toggle()
$('input#broadcast_message_color').on 'input', ->
previewColor = $('input#broadcast_message_color').val()
previewColor = $(@).val()
$('div.broadcast-message-preview').css('background-color', previewColor)
$('input#broadcast_message_font').on 'input', ->
previewColor = $('input#broadcast_message_font').val()
previewColor = $(@).val()
$('div.broadcast-message-preview').css('color', previewColor)
$('textarea#broadcast_message_message').on 'input', ->
previewMessage = $('textarea#broadcast_message_message').val()
previewMessage = $(@).val()
previewMessage = "Your message here" if previewMessage.trim() == ''
$('div.broadcast-message-preview span').text(previewMessage)
$('.log-tabs a').click (e) ->
......
#= require autosize
$ ->
autosize($('.js-autosize'))
......@@ -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()
......
......@@ -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
......
#= require autosave
#= require autosize
#= require dropzone
#= require dropzone_input
#= require gfm_auto_complete
......@@ -246,6 +247,7 @@ class @Notes
else
previewButton.removeClass("turn-on").addClass "turn-off"
autosize(textarea)
new Autosave textarea, [
"Note"
form.find("#note_commit_id").val()
......@@ -521,9 +523,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()
......
#= require latinise
class @Wikis
constructor: ->
$('.build-new-wiki').bind "click", (e) ->
$('[data-error~=slug]').addClass("hidden")
$('p.hint').show()
$('.build-new-wiki').bind 'click', (e) =>
$('[data-error~=slug]').addClass('hidden')
field = $('#new_wiki_path')
valid_slug_pattern = /^[\w\/-]+$/
slug = @slugify(field.val())
slug = field.val()
if slug.match valid_slug_pattern
if (slug.length > 0)
path = field.attr('data-wikis-path')
if(slug.length > 0)
location.href = path + "/" + slug
else
e.preventDefault()
$('p.hint').hide()
$('[data-error~=slug]').removeClass("hidden")
location.href = path + '/' + slug
dasherize: (value) ->
value.replace(/[_\s]+/g, '-')
slugify: (value) =>
@dasherize(value.trim().toLowerCase().latinise())
......@@ -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";
......
......@@ -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;
}
}
@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
}
}
......@@ -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;
}
......
......@@ -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;
......
......@@ -8,10 +8,12 @@
.flash-notice {
@extend .alert;
@extend .alert-info;
margin: 0;
}
.flash-alert {
@extend .alert;
@extend .alert-danger;
margin: 0;
}
}
......@@ -3,23 +3,39 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf.woff');
src:
local('Source Sans Pro Light'),
local('SourceSansPro-Light'),
font-url('SourceSansPro-Light.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Light.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf.woff');
src:
local('Source Sans Pro'),
local('SourceSansPro-Regular'),
font-url('SourceSansPro-Regular.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Regular.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 600;
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf.woff');
src:
local('Source Sans Pro Semibold'),
local('SourceSansPro-Semibold'),
font-url('SourceSansPro-Semibold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Semibold.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf.woff');
src:
local('Source Sans Pro Bold'),
local('SourceSansPro-Bold'),
font-url('SourceSansPro-Bold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Bold.ttf.woff') format('woff');
}
......@@ -74,8 +74,10 @@ label {
.form-control {
@include box-shadow(none);
height: 42px;
padding: 8px $gl-padding;
}
.form-control-inline {
display: inline;
}
.wiki-content {
......
......@@ -28,6 +28,7 @@ header {
min-height: $header-height;
background-color: #fff;
border: none;
border-bottom: 1px solid #EEE;
.container-fluid {
width: 100% !important;
......
......@@ -5,8 +5,6 @@ html {
}
body {
background-color: #F3F3F3 !important;
&.navless {
background-color: white !important;
}
......
......@@ -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;
}
......
......@@ -65,13 +65,6 @@
position: relative;
}
.md-header {
ul {
float: left;
margin-bottom: 1px;
}
}
.referenced-users {
color: #4c4e54;
padding-top: 10px;
......@@ -85,28 +78,12 @@
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;
border: 1px solid #ddd;
min-height: 140px;
max-height: 430px;
padding: 5px;
box-shadow: none;
width: 100%;
......
......@@ -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;
}
}
}
......@@ -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;
......@@ -100,11 +100,6 @@
}
@media (max-width: $screen-sm-max) {
.page-with-sidebar .content-wrapper {
padding: 0;
padding-top: 1px;
}
.issues-filters {
.milestone-filter, .labels-filter {
display: none;
......
.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;
}
}
}
......@@ -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;
......
......@@ -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;
......
.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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -4,7 +4,7 @@
position: absolute;
top: 0px;
right: 4px;
line-height: 40px;
line-height: 56px;
}
a.js-zen-leave {
......
.branch-name{
font-weight: 600;
}
......@@ -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;
......
.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;
......
// 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;
......
......@@ -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;
......
......@@ -11,3 +11,8 @@
height: 42px;
}
}
.content-list .group-name {
font-weight: 600;
color: #4c4e54;
}
......@@ -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%;
......
......@@ -6,7 +6,7 @@
.issue-title {
margin-bottom: 5px;
font-size: $list-font-size;
font-weight: bold;
font-weight: 600;
}
.issue-info {
......
......@@ -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 {
......
......@@ -159,6 +159,7 @@
.edit_note {
.markdown-area {
min-height: 140px;
max-height: 430px;
}
.note-form-actions {
background: transparent;
......
......@@ -26,6 +26,8 @@
}
.project-home-panel {
padding-bottom: 40px;
border-bottom: 1px solid $border-color;
.cover-controls {
.project-settings-dropdown {
......@@ -77,17 +79,6 @@
}
}
.git-clone-holder {
max-width: 498px;
.form-control {
background: #FFF;
font-size: 14px;
height: 42px;
margin-left: -1px;
}
}
.visibility-level-label {
@extend .btn;
@extend .btn-gray;
......@@ -100,11 +91,6 @@
}
}
.git-clone-holder {
display: inline-table;
position: relative;
}
.project-repo-buttons {
margin-top: 12px;
margin-bottom: 0px;
......@@ -114,10 +100,22 @@
margin-bottom: 12px;
}
.clone-row {
.split-repo-buttons,
.project-clone-holder {
display: inline-block;
}
.split-repo-buttons {
margin: 0 12px;
}
}
.btn {
@include btn-gray;
text-transform: none;
}
.count-with-arrow {
display: inline-block;
position: relative;
......@@ -162,8 +160,8 @@
border-style: solid;
font-size: 13px;
font-weight: 600;
line-height: 20px;
padding: 11px 16px;
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
padding: 10px;
text-align: center;
......@@ -191,117 +189,6 @@
}
}
.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;
}
}
.input-group-btn {
.btn {
@include btn-gray;
@include btn-middle;
&:hover {
outline: none;
}
&:focus {
outline: none;
}
&:active {
outline: none;
}
&.btn-clipboard {
padding-left: 15px;
padding-right: 15px;
}
}
.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;
@include btn-default;
}
.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);
......@@ -353,28 +240,6 @@
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;
}
......@@ -401,9 +266,9 @@ ul.nav.nav-projects-tabs {
.breadcrumb.repo-breadcrumb {
padding: 0;
line-height: 42px;
background: transparent;
border: none;
line-height: 42px;
margin: 0;
> li + li:before {
......@@ -418,11 +283,8 @@ ul.nav.nav-projects-tabs {
.top-area {
border-bottom: 1px solid #EEE;
margin: 0 -16px;
padding: 0 $gl-padding;
height: 42px;
ul.left-top-menu {
ul.nav-links {
display: inline-block;
width: 50%;
margin-bottom: 0px;
......@@ -433,12 +295,12 @@ ul.nav.nav-projects-tabs {
width: 50%;
display: inline-block;
float: right;
padding-top: 7px;
padding-top: 11px;
text-align: right;
.btn-green {
margin-top: -2px;
margin-left: 10px;
float: right;
}
}
......@@ -484,11 +346,11 @@ table.table.protected-branches-list tr.no-border {
padding-top: 10px;
padding-bottom: 4px;
ul.nav-pills {
ul.nav {
display:inline-block;
}
.nav-pills li {
.nav li {
display:inline;
}
......@@ -525,8 +387,7 @@ pre.light-well {
}
.projects-search-form {
margin: -$gl-padding;
padding: $gl-padding;
padding: $gl-padding 0;
padding-bottom: 0;
margin-bottom: 0px;
......@@ -576,10 +437,8 @@ pre.light-well {
@include basic-list;
.project-row {
padding: $gl-padding;
padding: $gl-padding 0;
border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
&.no-description {
.project {
......@@ -633,8 +492,6 @@ pre.light-well {
}
.project-last-commit {
margin: 0 7px;
.ci-status {
margin-right: 16px;
}
......@@ -664,9 +521,7 @@ pre.light-well {
}
.project-show-readme .readme-holder {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
padding: ($gl-padding + 7px);
padding: $gl-padding 0;
border-top: 0;
.edit-project-readme {
......@@ -674,3 +529,32 @@ pre.light-well {
position: relative;
}
}
.git-clone-holder {
width: 498px;
.btn-clipboard {
border: 1px solid $border-color;
padding: 6px $gl-padding;
}
.project-home-dropdown + & {
margin-right: 45px;
}
.clone-options {
display: table-cell;
a.btn {
width: 100%;
}
}
.form-control {
@extend .monospace;
background: #FFF;
font-size: 14px;
margin-left: -1px;
cursor: auto;
width: 101%;
}
}
.tag-name{
font-weight: 600;
}
.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;
}
class Admin::BroadcastMessagesController < Admin::ApplicationController
before_action :broadcast_messages
before_action :finder, only: [:edit, :update, :destroy]
def index
@broadcast_message = BroadcastMessage.new
@broadcast_messages = BroadcastMessage.reorder("starts_at ASC").page(params[:page])
@broadcast_message = BroadcastMessage.new
end
def edit
end
def create
......@@ -15,8 +19,16 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end
end
def update
if @broadcast_message.update(broadcast_message_params)
redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully updated.'
else
render :edit
end
end
def destroy
BroadcastMessage.find(params[:id]).destroy
@broadcast_message.destroy
respond_to do |format|
format.html { redirect_back_or_default(default: { action: 'index' }) }
......@@ -26,14 +38,17 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
protected
def broadcast_messages
@broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page])
def finder
@broadcast_message = BroadcastMessage.find(params[:id])
end
def broadcast_message_params
params.require(:broadcast_message).permit(
:alert_type, :color, :ends_at, :font,
:message, :starts_at
)
params.require(:broadcast_message).permit(%i(
color
ends_at
font
message
starts_at
))
end
end
......@@ -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.'
......
......@@ -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")
......
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
......@@ -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
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
......@@ -181,10 +181,6 @@ module ApplicationHelper
end
end
def broadcast_message
BroadcastMessage.current
end
# Render a `time` element with Javascript-based relative date and tooltip
#
# time - Time object
......
module BroadcastMessagesHelper
def broadcast_styling(broadcast_message)
styling = ''
def broadcast_message(message = BroadcastMessage.current)
return unless message.present?
content_tag :div, class: 'broadcast-message', style: broadcast_message_style(message) do
icon('bullhorn') << ' ' << message.message
end
end
def broadcast_message_style(broadcast_message)
style = ''
if broadcast_message.color.present?
styling << "background-color: #{broadcast_message.color}"
styling << '; ' if broadcast_message.font.present?
style << "background-color: #{broadcast_message.color}"
style << '; ' if broadcast_message.font.present?
end
if broadcast_message.font.present?
styling << "color: #{broadcast_message.font}"
style << "color: #{broadcast_message.font}"
end
styling
style
end
def broadcast_message_status(broadcast_message)
if broadcast_message.active?
'Active'
elsif broadcast_message.ended?
'Expired'
else
'Pending'
end
end
end
......@@ -17,7 +17,7 @@ module ButtonHelper
def clipboard_button(data = {})
content_tag :button,
icon('clipboard'),
class: 'btn btn-xs btn-clipboard',
class: 'btn btn-clipboard',
data: data,
type: :button
end
......
......@@ -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
......
......@@ -91,7 +91,7 @@ module GitlabMarkdownHelper
def render_wiki_content(wiki_page)
case wiki_page.format
when :markdown
markdown(wiki_page.content)
markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki)
when :asciidoc
asciidoc(wiki_page.content)
else
......
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
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
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
......@@ -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
......
......@@ -175,7 +175,7 @@ class Ability
:create_merge_request,
:create_wiki,
:manage_builds,
:download_build_artifacts,
:read_build_artifacts,
:push_code
]
end
......
......@@ -6,7 +6,6 @@
# message :text not null
# starts_at :datetime
# ends_at :datetime
# alert_type :integer
# created_at :datetime
# updated_at :datetime
# color :string(255)
......@@ -23,7 +22,22 @@ class BroadcastMessage < ActiveRecord::Base
validates :color, allow_blank: true, color: true
validates :font, allow_blank: true, color: true
default_value_for :color, '#E75E40'
default_value_for :font, '#FFFFFF'
def self.current
where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last
where("ends_at > :now AND starts_at <= :now", now: Time.zone.now).last
end
def active?
started? && !ended?
end
def started?
Time.zone.now >= starts_at
end
def ended?
ends_at < Time.zone.now
end
end
......@@ -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
......
......@@ -133,7 +133,11 @@ class CommitStatus < ActiveRecord::Base
false
end
def download_url
def artifacts_download_url
nil
end
def artifacts_browse_url
nil
end
end
......@@ -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,
......
......@@ -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
......@@ -38,6 +38,10 @@ class ProjectWiki
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
end
def wiki_base_path
["/", @project.path_with_namespace, "/wikis"].join('')
end
# Returns the Gollum::Wiki object.
def wiki
@wiki ||= begin
......
......@@ -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
......@@ -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)') }
......
......@@ -169,7 +169,7 @@ class WikiPage
private
def set_attributes
attributes[:slug] = @page.escaped_url_path
attributes[:slug] = @page.url_path
attributes[:title] = @page.title
attributes[:format] = @page.format
end
......
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
.broadcast-message-preview{ style: broadcast_message_style(@broadcast_message) }
= icon('bullhorn')
%span= @broadcast_message.message || "Your message here"
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-requires-input'} do |f|
-if @broadcast_message.errors.any?
.alert.alert-danger
- @broadcast_message.errors.full_messages.each do |msg|
%p= msg
.form-group
= f.label :message, class: 'control-label'
.col-sm-10
= f.text_area :message, class: "form-control js-quick-submit", rows: 2, required: true
.form-group.js-toggle-colors-container
.col-sm-10.col-sm-offset-2
= link_to 'Customize colors', '#', class: 'js-toggle-colors-link'
.form-group.js-toggle-colors-container.hide
= f.label :color, "Background Color", class: 'control-label'
.col-sm-10
= f.color_field :color, class: "form-control"
.form-group.js-toggle-colors-container.hide
= f.label :font, "Font Color", class: 'control-label'
.col-sm-10
= f.color_field :font, class: "form-control"
.form-group
= f.label :starts_at, class: 'control-label'
.col-sm-10.datetime-controls
= f.datetime_select :starts_at, {}, class: 'form-control form-control-inline'
.form-group
= f.label :ends_at, class: 'control-label'
.col-sm-10.datetime-controls
= f.datetime_select :ends_at, {}, class: 'form-control form-control-inline'
.form-actions
- if @broadcast_message.persisted?
= f.submit "Update broadcast message", class: "btn btn-create"
- else
= f.submit "Add broadcast message", class: "btn btn-create"
- page_title "Broadcast Messages"
= render 'form'
- page_title "Broadcast Messages"
%h3.page-title
Broadcast Messages
%p.light
Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more.
.broadcast-message-preview
%i.fa.fa-bullhorn
%span Your message here
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal'} do |f|
-if @broadcast_message.errors.any?
.alert.alert-danger
- @broadcast_message.errors.full_messages.each do |msg|
%p= msg
.form-group
= f.label :message, class: 'control-label'
.col-sm-10
= f.text_area :message, class: "form-control", rows: 2, required: true
%div
= link_to '#', class: 'js-toggle-colors-link' do
Customize colors
.form-group.js-toggle-colors-container.hide
= f.label :color, "Background Color", class: 'control-label'
.col-sm-10
= f.color_field :color, value: "#eb9532", class: "form-control"
.form-group.js-toggle-colors-container.hide
= f.label :font, "Font Color", class: 'control-label'
.col-sm-10
= f.color_field :font, value: "#FFFFFF", class: "form-control"
.form-group
= f.label :starts_at, class: 'control-label'
.col-sm-10.datetime-controls
= f.datetime_select :starts_at
.form-group
= f.label :ends_at, class: 'control-label'
.col-sm-10.datetime-controls
= f.datetime_select :ends_at
.form-actions
= f.submit "Add broadcast message", class: "btn btn-create"
Broadcast messages are displayed for every user and can be used to notify
users about scheduled maintenance, recent upgrades and more.
-if @broadcast_messages.any?
%ul.bordered-list.broadcast-messages
- @broadcast_messages.each do |broadcast_message|
%li
.pull-right
- if broadcast_message.starts_at
%strong
#{broadcast_message.starts_at.to_s(:short)}
\...
- if broadcast_message.ends_at
%strong
#{broadcast_message.ends_at.to_s(:short)}
&nbsp;
= link_to [:admin, broadcast_message], method: :delete, remote: true, class: 'remove-row btn btn-xs' do
%i.fa.fa-times.cred
= render 'form'
.message= broadcast_message.message
%br.clearfix
-if @broadcast_messages.any?
%table.table
%thead
%tr
%th Status
%th Preview
%th Starts
%th Ends
%th &nbsp;
%tbody
- @broadcast_messages.each do |message|
%tr
%td
= broadcast_message_status(message)
%td
= broadcast_message(message)
%td
= message.starts_at
%td
= message.ends_at
%td
= link_to icon('pencil-square-o'), edit_admin_broadcast_message_path(message), title: 'Edit', class: 'btn btn-xs'
= link_to icon('times'), admin_broadcast_message_path(message), method: :delete, remote: true, title: 'Remove', class: 'js-remove-tr btn btn-xs btn-danger'
= paginate @broadcast_messages
......@@ -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?
......
......@@ -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
......
- 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' : ''),
......
......@@ -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
This diff is collapsed.
.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'
......
%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
......
%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
......
= 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
......
%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
......
......@@ -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
......
......@@ -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'
......@@ -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'
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment