Merge branch 'master' into ui/misc
This commit is contained in:
commit
dddfbb653e
234 changed files with 2619 additions and 1357 deletions
|
@ -1 +1 @@
|
|||
2.1.6
|
||||
2.1.7
|
||||
|
|
15
CHANGELOG
15
CHANGELOG
|
@ -4,8 +4,20 @@ v 8.3.0 (unreleased)
|
|||
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
|
||||
- Fix 500 error when update group member permission
|
||||
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
|
||||
- Recognize issue/MR/snippet/commit links as references
|
||||
- Add ignore whitespace change option to commit view
|
||||
- Fire update hook from GitLab
|
||||
- Style warning about mentioning many people in a comment
|
||||
- Fix: sort milestones by due date once again (Greg Smethells)
|
||||
- Don't show project fork event as "imported"
|
||||
- Add API endpoint to fetch merge request commits list
|
||||
- Expose events API with comment information and author info
|
||||
- Fix: Ensure "Remove Source Branch" button is not shown when branch is being deleted. #3583
|
||||
- Run custom Git hooks when branch is created or deleted.
|
||||
|
||||
v 8.2.3
|
||||
- Fix application settings cache not expiring after changes (Stan Hu)
|
||||
- Fix Error 500s when creating global milestones with Unicode characters (Stan Hu)
|
||||
|
||||
v 8.2.2
|
||||
- Fix 404 in redirection after removing a project (Stan Hu)
|
||||
|
@ -13,6 +25,9 @@ v 8.2.2
|
|||
- Fix Error 500 when viewing user's personal projects from admin page (Stan Hu)
|
||||
- Fix: Raw private snippets access workflow
|
||||
- Prevent "413 Request entity too large" errors when pushing large files with LFS
|
||||
- Fix invalid links within projects dashboard header
|
||||
- Make current user the first user in assignee dropdown in issues detail page (Stan Hu)
|
||||
- Fix: duplicate email notifications on issue comments
|
||||
|
||||
v 8.2.1
|
||||
- Forcefully update builds that didn't want to update with state machine
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -171,6 +171,7 @@ gem "underscore-rails", "~> 1.4.4"
|
|||
|
||||
# Sanitize user input
|
||||
gem "sanitize", '~> 2.0'
|
||||
gem 'babosa', '~> 1.0.2'
|
||||
|
||||
# Protect against bruteforcing
|
||||
gem "rack-attack", '~> 4.3.0'
|
||||
|
|
|
@ -73,6 +73,7 @@ GEM
|
|||
descendants_tracker (~> 0.0.4)
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
babosa (1.0.2)
|
||||
bcrypt (3.1.10)
|
||||
benchmark-ips (2.3.0)
|
||||
better_errors (1.0.1)
|
||||
|
@ -823,6 +824,7 @@ DEPENDENCIES
|
|||
asciidoctor (~> 1.5.2)
|
||||
attr_encrypted (~> 1.3.4)
|
||||
awesome_print (~> 1.2.0)
|
||||
babosa (~> 1.0.2)
|
||||
benchmark-ips
|
||||
better_errors (~> 1.0.1)
|
||||
binding_of_caller (~> 0.7.2)
|
||||
|
|
6
Procfile
6
Procfile
|
@ -1,3 +1,7 @@
|
|||
# For DEVELOPMENT only. Production uses Runit in
|
||||
# https://gitlab.com/gitlab-org/omnibus-gitlab or the init scripts in
|
||||
# lib/support/init.d, which call scripts in bin/ .
|
||||
#
|
||||
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
|
||||
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q mailers -q default
|
||||
worker: bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default
|
||||
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
|
||||
|
|
|
@ -135,17 +135,25 @@ $ ->
|
|||
), 1
|
||||
|
||||
# Initialize tooltips
|
||||
$('body').tooltip({
|
||||
selector: '.has_tooltip, [data-toggle="tooltip"], .page-sidebar-collapsed .nav-sidebar a'
|
||||
$('body').tooltip(
|
||||
selector: '.has_tooltip, [data-toggle="tooltip"]'
|
||||
placement: (_, el) ->
|
||||
$el = $(el)
|
||||
if $el.attr('id') == 'js-shortcuts-home'
|
||||
# Place the logo tooltip on the right when collapsed, bottom when expanded
|
||||
$el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom'
|
||||
else
|
||||
# Otherwise use the data-placement attribute, or 'bottom' if undefined
|
||||
$el.data('placement') or 'bottom'
|
||||
})
|
||||
$el.data('placement') || 'bottom'
|
||||
)
|
||||
|
||||
$('.header-logo .home').tooltip(
|
||||
placement: (_, el) ->
|
||||
$el = $(el)
|
||||
if $('.page-with-sidebar').hasClass('page-sidebar-collapsed') then 'right' else 'bottom'
|
||||
container: 'body'
|
||||
)
|
||||
|
||||
$('.page-with-sidebar').tooltip(
|
||||
selector: '.sidebar-collapsed .nav-sidebar a, .sidebar-collapsed a.sidebar-user'
|
||||
placement: 'right'
|
||||
container: 'body'
|
||||
)
|
||||
|
||||
# Form submitter
|
||||
$('.trigger-submit').on 'change', ->
|
||||
|
|
|
@ -88,4 +88,9 @@ class @AwardsHandler
|
|||
callback.call()
|
||||
|
||||
findEmojiIcon: (emoji) ->
|
||||
$(".icon[data-emoji='" + emoji + "']")
|
||||
$(".icon[data-emoji='" + emoji + "']")
|
||||
|
||||
scrollToAwards: ->
|
||||
$('body, html').animate({
|
||||
scrollTop: $('.awards').offset().top - 80
|
||||
}, 200)
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
class @Flash
|
||||
constructor: (message, type)->
|
||||
flash = $(".flash-container")
|
||||
flash.html("")
|
||||
@flash = $(".flash-container")
|
||||
@flash.html("")
|
||||
|
||||
$('<div/>',
|
||||
innerDiv = $('<div/>',
|
||||
class: "flash-#{type}",
|
||||
text: message
|
||||
).appendTo(".flash-container")
|
||||
)
|
||||
innerDiv.appendTo(".flash-container")
|
||||
|
||||
flash.click -> $(@).fadeOut()
|
||||
flash.show()
|
||||
@flash.click -> $(@).fadeOut()
|
||||
@flash.show()
|
||||
|
||||
pin: ->
|
||||
@flash.addClass('flash-pinned flash-raised')
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
$('#filter_issue_search').val($('#issue_search').val())
|
||||
|
||||
initSelects: ->
|
||||
$("select#update_status").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_state_event").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_assignee_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_milestone_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#label_name").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
|
|
|
@ -10,17 +10,20 @@ class @MergeRequestWidget
|
|||
constructor: (@opts) ->
|
||||
modal = $('#modal_merge_info').modal(show: false)
|
||||
|
||||
mergeInProgress: ->
|
||||
mergeInProgress: (deleteSourceBranch = false)->
|
||||
$.ajax
|
||||
type: 'GET'
|
||||
url: $('.merge-request').data('url')
|
||||
success: (data) =>
|
||||
if data.state == "merged"
|
||||
location.reload()
|
||||
urlSuffix = if deleteSourceBranch then '?delete_source=true' else ''
|
||||
|
||||
window.location.href = window.location.href + urlSuffix
|
||||
else if data.merge_error
|
||||
$('.mr-widget-body').html("<h4>" + data.merge_error + "</h4>")
|
||||
else
|
||||
setTimeout(merge_request_widget.mergeInProgress, 2000)
|
||||
callback = -> merge_request_widget.mergeInProgress(deleteSourceBranch)
|
||||
setTimeout(callback, 2000)
|
||||
dataType: 'json'
|
||||
|
||||
getMergeStatus: ->
|
||||
|
|
|
@ -111,6 +111,12 @@ class @Notes
|
|||
Note: for rendering inline notes use renderDiscussionNote
|
||||
###
|
||||
renderNote: (note) ->
|
||||
unless note.valid
|
||||
if note.award
|
||||
flash = new Flash('You have already used this award emoji!', 'alert')
|
||||
flash.pin()
|
||||
return
|
||||
|
||||
# render note if it not present in loaded list
|
||||
# or skip if rendered
|
||||
if @isNewNote(note) && !note.award
|
||||
|
@ -122,6 +128,7 @@ class @Notes
|
|||
|
||||
if note.award
|
||||
awards_handler.addAwardToEmojiBar(note.note, note.emoji_path)
|
||||
awards_handler.scrollToAwards()
|
||||
|
||||
###
|
||||
Check if note does not exists on page
|
||||
|
|
|
@ -5,6 +5,7 @@ $(document).on("click", '.toggle-nav-collapse', (e) ->
|
|||
|
||||
$('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}")
|
||||
$('header').toggleClass("header-collapsed header-expanded")
|
||||
$('.sidebar-wrapper').toggleClass("sidebar-collapsed sidebar-expanded")
|
||||
$('.toggle-nav-collapse i').toggleClass("fa-angle-right fa-angle-left")
|
||||
$.cookie("collapsed_nav", $('.page-with-sidebar').hasClass(collapsed), { path: '/' })
|
||||
)
|
||||
|
|
|
@ -2,3 +2,9 @@ class @User
|
|||
constructor: ->
|
||||
$('.profile-groups-avatars').tooltip("placement": "top")
|
||||
new ProjectsList()
|
||||
|
||||
$('.hide-project-limit-message').on 'click', (e) ->
|
||||
path = '/'
|
||||
$.cookie('hide_project_limit_message', 'false', { path: path })
|
||||
$(@).parents('.project-limit-message').remove()
|
||||
e.preventDefault()
|
||||
|
|
|
@ -32,17 +32,15 @@ class @UsersSelect
|
|||
if showNullUser
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
id: 0
|
||||
}
|
||||
data.results.unshift(nullUser)
|
||||
|
||||
if showAnyUser
|
||||
name = showAnyUser
|
||||
name = 'Any User' if name == true
|
||||
anyUser = {
|
||||
name: 'Any',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
name: name,
|
||||
id: null
|
||||
}
|
||||
data.results.unshift(anyUser)
|
||||
|
@ -50,7 +48,6 @@ class @UsersSelect
|
|||
if showEmailUser && data.results.length == 0 && query.term.match(/^[^@]+@[^@]+$/)
|
||||
emailUser = {
|
||||
name: "Invite \"#{query.term}\"",
|
||||
avatar: null,
|
||||
username: query.term,
|
||||
id: query.term
|
||||
}
|
||||
|
@ -82,10 +79,10 @@ class @UsersSelect
|
|||
else
|
||||
avatar = gon.default_avatar_url
|
||||
|
||||
"<div class='user-result'>
|
||||
"<div class='user-result #{'no-username' unless user.username}'>
|
||||
<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
|
||||
<div class='user-name'>#{user.name}</div>
|
||||
<div class='user-username'>#{user.username}</div>
|
||||
<div class='user-username'>#{user.username || ""}</div>
|
||||
</div>"
|
||||
|
||||
formatSelection: (user) ->
|
||||
|
|
|
@ -116,6 +116,11 @@
|
|||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
|
||||
&.left {
|
||||
left: 10px;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -341,10 +341,6 @@ table {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.task-status {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#nprogress .spinner {
|
||||
top: 15px !important;
|
||||
right: 10px !important;
|
||||
|
|
|
@ -15,3 +15,13 @@
|
|||
@extend .alert-danger;
|
||||
}
|
||||
}
|
||||
|
||||
.flash-pinned {
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.flash-raised {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
|
|
@ -91,9 +91,17 @@ label {
|
|||
}
|
||||
|
||||
.input-group {
|
||||
.select2-container {
|
||||
display: table-cell;
|
||||
width: 200px !important;
|
||||
}
|
||||
.input-group-addon {
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
.input-group-addon:not(:first-child):not(:last-child) {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.help-block {
|
||||
|
|
|
@ -6,15 +6,17 @@ header {
|
|||
transition-duration: .3s;
|
||||
|
||||
&.navbar-empty {
|
||||
height: 58px;
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid #EEE;
|
||||
|
||||
.center-logo {
|
||||
margin: 8px 0;
|
||||
margin: 11px 0;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
#tanuki-logo, img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@ html {
|
|||
|
||||
body {
|
||||
background-color: #EAEBEC !important;
|
||||
|
||||
&.navless {
|
||||
background-color: white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
|
@ -18,8 +22,8 @@ body {
|
|||
}
|
||||
|
||||
.navless-container {
|
||||
padding-top: $header-height;
|
||||
margin-top: 30px;
|
||||
margin-top: $header-height;
|
||||
padding-top: $gl-padding * 2;
|
||||
}
|
||||
|
||||
.container-limited {
|
||||
|
|
|
@ -73,11 +73,8 @@
|
|||
}
|
||||
|
||||
.referenced-users {
|
||||
padding: 10px 0;
|
||||
color: #999;
|
||||
margin-left: 10px;
|
||||
margin-top: 1px;
|
||||
margin-right: 130px;
|
||||
color: #4c4e54;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.md-preview-holder {
|
||||
|
|
|
@ -15,6 +15,16 @@
|
|||
border-left: none;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.select2-chosen {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
||||
&.select2-default {
|
||||
.select2-chosen {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +33,7 @@
|
|||
border: 1px solid #e7e9ed;
|
||||
}
|
||||
|
||||
|
||||
.select2-drop {
|
||||
@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);
|
||||
|
@ -48,17 +59,38 @@
|
|||
color: #313236;
|
||||
}
|
||||
|
||||
.select2-container-multi {
|
||||
.select2-choices {
|
||||
@include border-radius(2px);
|
||||
border-color: $input-border;
|
||||
background: white;
|
||||
padding-left: $gl-padding / 2;
|
||||
|
||||
.select2-container-multi .select2-choices {
|
||||
@include border-radius(2px);
|
||||
border-color: #CCC;
|
||||
}
|
||||
.select2-search-field input {
|
||||
padding: $gl-padding / 2;
|
||||
font-size: 13px;
|
||||
height: auto;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-field input {
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
height: auto;
|
||||
.select2-search-choice {
|
||||
margin: 8px 0 0 8px;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border-color: $input-border;
|
||||
color: $gl-text-color;
|
||||
line-height: 15px;
|
||||
|
||||
.select2-search-choice-close {
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&.select2-search-choice-focus {
|
||||
border-color: $gl-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select2-drop-active {
|
||||
|
@ -123,10 +155,16 @@
|
|||
}
|
||||
|
||||
.user-result {
|
||||
min-height: 24px;
|
||||
|
||||
.user-image {
|
||||
float: left;
|
||||
}
|
||||
.user-name {
|
||||
|
||||
&.no-username {
|
||||
.user-name {
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
.page-with-sidebar {
|
||||
padding-top: $header-height;
|
||||
transition-duration: .3s;
|
||||
|
||||
.sidebar-wrapper {
|
||||
position: fixed;
|
||||
|
@ -16,7 +17,6 @@
|
|||
.sidebar-wrapper {
|
||||
z-index: 99;
|
||||
background: $background-color;
|
||||
transition-duration: .3s;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
|
@ -35,6 +35,83 @@
|
|||
}
|
||||
}
|
||||
|
||||
.sidebar-wrapper {
|
||||
.header-logo {
|
||||
border-bottom: 1px solid transparent;
|
||||
float: left;
|
||||
height: $header-height;
|
||||
width: $sidebar_width;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
transition-duration: .3s;
|
||||
|
||||
a {
|
||||
float: left;
|
||||
height: $header-height;
|
||||
width: 100%;
|
||||
padding: 11px 0 11px 22px;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
transition-duration: .3s;
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
#tanuki-logo, img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.gitlab-text-container {
|
||||
width: 230px;
|
||||
|
||||
h3 {
|
||||
width: 158px;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 14px;
|
||||
font-size: 19px;
|
||||
line-height: 41px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-user {
|
||||
padding: 9px 22px;
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
width: $sidebar_width;
|
||||
overflow: hidden;
|
||||
transition-duration: .3s;
|
||||
|
||||
.username {
|
||||
margin-left: 10px;
|
||||
width: $sidebar_width - 2 * 10px;
|
||||
font-size: 16px;
|
||||
line-height: 34px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tanuki-shape {
|
||||
transition: all 0.8s;
|
||||
|
||||
&:hover {
|
||||
fill: rgb(255, 255, 255);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.nav-sidebar {
|
||||
margin-top: 14 + $header-height;
|
||||
margin-bottom: 100px;
|
||||
|
@ -61,7 +138,7 @@
|
|||
color: $gray;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding-left: 22px;
|
||||
padding-left: 23px;
|
||||
font-weight: normal;
|
||||
outline: none;
|
||||
|
||||
|
@ -85,6 +162,10 @@
|
|||
padding: 0px 8px;
|
||||
@include border-radius(6px);
|
||||
}
|
||||
|
||||
&.back-link i {
|
||||
transition-duration: .3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +181,6 @@
|
|||
|
||||
@mixin expanded-sidebar {
|
||||
padding-left: $sidebar_width;
|
||||
transition-duration: .3s;
|
||||
|
||||
.sidebar-wrapper {
|
||||
width: $sidebar_width;
|
||||
|
@ -114,16 +194,15 @@
|
|||
|
||||
&.back-link {
|
||||
i {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin folded-sidebar {
|
||||
padding-left: 60px;
|
||||
transition-duration: .3s;
|
||||
@mixin collapsed-sidebar {
|
||||
padding-left: $sidebar_collapsed_width;
|
||||
|
||||
.sidebar-wrapper {
|
||||
width: $sidebar_collapsed_width;
|
||||
|
@ -132,7 +211,7 @@
|
|||
width: $sidebar_collapsed_width;
|
||||
|
||||
a {
|
||||
padding-left: 12px;
|
||||
padding-left: ($sidebar_collapsed_width - 36) / 2;
|
||||
|
||||
.gitlab-text-container {
|
||||
display: none;
|
||||
|
@ -143,9 +222,13 @@
|
|||
.nav-sidebar {
|
||||
width: $sidebar_collapsed_width;
|
||||
|
||||
li a {
|
||||
span {
|
||||
display: none;
|
||||
li {
|
||||
width: auto;
|
||||
|
||||
a {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +238,7 @@
|
|||
}
|
||||
|
||||
.sidebar-user {
|
||||
padding-left: 12px;
|
||||
padding-left: ($sidebar_collapsed_width - 36) / 2;
|
||||
width: $sidebar_collapsed_width;
|
||||
|
||||
.username {
|
||||
|
@ -186,11 +269,11 @@
|
|||
|
||||
@media (max-width: $screen-md-max) {
|
||||
.page-sidebar-collapsed {
|
||||
@include folded-sidebar;
|
||||
@include collapsed-sidebar;
|
||||
}
|
||||
|
||||
.page-sidebar-expanded {
|
||||
@include folded-sidebar;
|
||||
@include collapsed-sidebar;
|
||||
}
|
||||
|
||||
.collapse-nav {
|
||||
|
@ -200,83 +283,10 @@
|
|||
|
||||
@media(min-width: $screen-md-max) {
|
||||
.page-sidebar-collapsed {
|
||||
@include folded-sidebar;
|
||||
@include collapsed-sidebar;
|
||||
}
|
||||
|
||||
.page-sidebar-expanded {
|
||||
@include expanded-sidebar;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-user {
|
||||
padding: 9px 22px;
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
width: $sidebar_width;
|
||||
overflow: hidden;
|
||||
transition-duration: .3s;
|
||||
|
||||
.username {
|
||||
margin-left: 10px;
|
||||
width: $sidebar_width - 2 * 10px;
|
||||
font-size: 16px;
|
||||
line-height: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-wrapper {
|
||||
.header-logo {
|
||||
border-bottom: 1px solid transparent;
|
||||
float: left;
|
||||
height: $header-height;
|
||||
width: $sidebar_width;
|
||||
overflow: hidden;
|
||||
transition-duration: .3s;
|
||||
|
||||
a {
|
||||
float: left;
|
||||
height: $header-height;
|
||||
width: 100%;
|
||||
padding: 10px 22px;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
#tanuki-logo, img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.gitlab-text-container {
|
||||
width: 230px;
|
||||
|
||||
h3 {
|
||||
width: 158px;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 14px;
|
||||
font-size: 19px;
|
||||
line-height: 41px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tanuki-shape {
|
||||
transition: all 0.8s;
|
||||
|
||||
&:hover {
|
||||
fill: rgb(255, 255, 255);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.issuable-show-labels {
|
||||
a {
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
display: inline-block;
|
||||
.color-label {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cross-project-reference {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
@ -158,6 +169,7 @@
|
|||
min-width: 214px;
|
||||
|
||||
> li {
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,17 +56,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.issue-show-labels {
|
||||
a {
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
display: inline-block;
|
||||
.color-label {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form.edit-issue {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* Login Page */
|
||||
.login-page {
|
||||
background-color: white;
|
||||
|
||||
.container {
|
||||
max-width: 960px;
|
||||
}
|
||||
|
@ -21,6 +19,7 @@
|
|||
h1:first-child {
|
||||
font-weight: normal;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
|
|
|
@ -173,27 +173,12 @@
|
|||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.merge-request-form-info {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
// hide mr close link for inline diff comment form
|
||||
.diff-file .close-mr-link,
|
||||
.diff-file .reopen-mr-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.merge-request-show-labels {
|
||||
a {
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
display: inline-block;
|
||||
.color-label {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.merge-request-form .select2-container {
|
||||
width: 250px !important;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.no-ssh-key-message {
|
||||
.no-ssh-key-message, .project-limit-message {
|
||||
background-color: #f28d35;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@
|
|||
@extend .btn-gray;
|
||||
|
||||
color: $gray;
|
||||
cursor: auto;
|
||||
cursor: default;
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
margin-right: auto;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.wiki-last-edit-by {
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ module GlobalMilestones
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
def milestones
|
||||
epoch = DateTime.parse('1970-01-01')
|
||||
@milestones = MilestonesFinder.new.execute(@projects, params)
|
||||
@milestones = GlobalMilestone.build_collection(@milestones)
|
||||
@milestones = @milestones.sort_by { |x| x.due_date.nil? ? epoch : x.due_date }
|
||||
@milestones = Kaminari.paginate_array(@milestones).page(params[:page]).per(ApplicationController::PER_PAGE)
|
||||
end
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Groups::MilestonesController < Groups::ApplicationController
|
|||
end
|
||||
|
||||
def milestone_path(title)
|
||||
group_milestone_path(@group, title.parameterize, title: title)
|
||||
group_milestone_path(@group, title.to_slug.to_s, title: title)
|
||||
end
|
||||
|
||||
def projects
|
||||
|
|
|
@ -70,6 +70,7 @@ class ProfilesController < Profiles::ApplicationController
|
|||
:email,
|
||||
:hide_no_password,
|
||||
:hide_no_ssh_key,
|
||||
:hide_project_limit,
|
||||
:linkedin,
|
||||
:location,
|
||||
:name,
|
||||
|
|
|
@ -3,7 +3,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!
|
||||
before_action :authorize_push_code!, only: [:create, :destroy]
|
||||
before_action :authorize_push_code!, only: [:new, :create, :destroy]
|
||||
|
||||
def index
|
||||
@sort = params[:sort] || 'name'
|
||||
|
|
|
@ -131,16 +131,25 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def render_note_json(note)
|
||||
render json: {
|
||||
id: note.id,
|
||||
discussion_id: note.discussion_id,
|
||||
html: note_to_html(note),
|
||||
award: note.is_award,
|
||||
emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
|
||||
note: note.note,
|
||||
discussion_html: note_to_discussion_html(note),
|
||||
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
|
||||
}
|
||||
if note.valid?
|
||||
render json: {
|
||||
valid: true,
|
||||
id: note.id,
|
||||
discussion_id: note.discussion_id,
|
||||
html: note_to_html(note),
|
||||
award: note.is_award,
|
||||
emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
|
||||
note: note.note,
|
||||
discussion_html: note_to_discussion_html(note),
|
||||
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
|
||||
}
|
||||
else
|
||||
render json: {
|
||||
valid: false,
|
||||
award: note.is_award,
|
||||
errors: note.errors
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_admin_note!
|
||||
|
|
|
@ -2,7 +2,7 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!
|
||||
before_action :authorize_push_code!, only: [:create]
|
||||
before_action :authorize_push_code!, only: [:new, :create]
|
||||
before_action :authorize_admin_project!, only: [:destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class MilestonesFinder
|
||||
def execute(projects, params)
|
||||
milestones = Milestone.of_projects(projects)
|
||||
milestones = milestones.order("due_date ASC")
|
||||
milestones = milestones.reorder("due_date ASC")
|
||||
|
||||
case params[:state]
|
||||
when 'closed' then milestones.closed
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# For example instead of this:
|
||||
#
|
||||
# namespace_project_merge_request_path(merge_request.project.namespace, merge_request.projects, merge_request)
|
||||
# namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
|
||||
#
|
||||
# We can simply use shortcut:
|
||||
#
|
||||
|
|
|
@ -27,16 +27,20 @@ module IconsHelper
|
|||
end
|
||||
end
|
||||
|
||||
def public_icon
|
||||
icon('globe fw')
|
||||
end
|
||||
def visibility_level_icon(level, fw: true)
|
||||
name =
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
'lock'
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
'shield'
|
||||
else # Gitlab::VisibilityLevel::PUBLIC
|
||||
'globe'
|
||||
end
|
||||
|
||||
name << " fw" if fw
|
||||
|
||||
def internal_icon
|
||||
icon('shield fw')
|
||||
end
|
||||
|
||||
def private_icon
|
||||
icon('lock fw')
|
||||
icon(name)
|
||||
end
|
||||
|
||||
def file_type_icon_class(type, mode, name)
|
||||
|
|
|
@ -44,14 +44,17 @@ module IssuesHelper
|
|||
end
|
||||
|
||||
def bulk_update_milestone_options
|
||||
options_for_select([['None (backlog)', -1]]) +
|
||||
options_from_collection_for_select(project_active_milestones, 'id',
|
||||
'title', params[:milestone_id])
|
||||
milestones = project_active_milestones.to_a
|
||||
milestones.unshift(Milestone::None)
|
||||
|
||||
options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id])
|
||||
end
|
||||
|
||||
def milestone_options(object)
|
||||
options_from_collection_for_select(object.project.milestones.active,
|
||||
'id', 'title', object.milestone_id)
|
||||
milestones = object.project.milestones.active.to_a
|
||||
milestones.unshift(Milestone::None)
|
||||
|
||||
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
|
||||
end
|
||||
|
||||
def issue_box_class(item)
|
||||
|
@ -84,7 +87,11 @@ module IssuesHelper
|
|||
end
|
||||
|
||||
def merge_requests_sentence(merge_requests)
|
||||
merge_requests.map(&:to_reference).to_sentence(last_word_connector: ', or ')
|
||||
# Sorting based on the `!123` or `group/project!123` reference will sort
|
||||
# local merge requests first.
|
||||
merge_requests.map do |merge_request|
|
||||
merge_request.to_reference(@project)
|
||||
end.sort.to_sentence(last_word_connector: ', or ')
|
||||
end
|
||||
|
||||
def url_to_emoji(name)
|
||||
|
@ -96,7 +103,7 @@ module IssuesHelper
|
|||
|
||||
def emoji_author_list(notes, current_user)
|
||||
list = notes.map do |note|
|
||||
note.author == current_user ? "me" : note.author.username
|
||||
note.author == current_user ? "me" : note.author.name
|
||||
end
|
||||
|
||||
list.join(", ")
|
||||
|
|
|
@ -39,7 +39,11 @@ module MergeRequestsHelper
|
|||
end
|
||||
|
||||
def issues_sentence(issues)
|
||||
issues.map(&:to_reference).to_sentence
|
||||
# Sorting based on the `#123` or `group/project#123` reference will sort
|
||||
# local issues first.
|
||||
issues.map do |issue|
|
||||
issue.to_reference(@project)
|
||||
end.sort.to_sentence
|
||||
end
|
||||
|
||||
def mr_change_branches_path(merge_request)
|
||||
|
@ -49,18 +53,21 @@ module MergeRequestsHelper
|
|||
source_project_id: @merge_request.source_project_id,
|
||||
target_project_id: @merge_request.target_project_id,
|
||||
source_branch: @merge_request.source_branch,
|
||||
target_branch: nil
|
||||
}
|
||||
target_branch: @merge_request.target_branch,
|
||||
},
|
||||
change_branches: true
|
||||
)
|
||||
end
|
||||
|
||||
def source_branch_with_namespace(merge_request)
|
||||
branch = link_to(merge_request.source_branch, namespace_project_commits_path(merge_request.source_project.namespace, merge_request.source_project, merge_request.source_branch))
|
||||
|
||||
if merge_request.for_fork?
|
||||
namespace = link_to(merge_request.source_project_namespace,
|
||||
project_path(merge_request.source_project))
|
||||
namespace + ":#{merge_request.source_branch}"
|
||||
namespace + ":" + branch
|
||||
else
|
||||
merge_request.source_branch
|
||||
branch
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@ module MilestonesHelper
|
|||
Milestone.where(project_id: @projects)
|
||||
end.active
|
||||
|
||||
epoch = DateTime.parse('1970-01-01')
|
||||
grouped_milestones = GlobalMilestone.build_collection(milestones)
|
||||
grouped_milestones = grouped_milestones.sort_by { |x| x.due_date.nil? ? epoch : x.due_date }
|
||||
grouped_milestones.unshift(Milestone::None)
|
||||
grouped_milestones.unshift(Milestone::Any)
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
module NamespacesHelper
|
||||
def namespaces_options(selected = :current_user, scope = :default)
|
||||
def namespaces_options(selected = :current_user, display_path: false)
|
||||
groups = current_user.owned_groups + current_user.masters_groups
|
||||
users = [current_user.namespace]
|
||||
|
||||
group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [g.human_name, g.id]} ]
|
||||
users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ]
|
||||
group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [display_path ? g.path : g.human_name, g.id]} ]
|
||||
users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [display_path ? u.path : u.human_name, u.id]} ]
|
||||
|
||||
options = []
|
||||
options << group_opts
|
||||
|
|
|
@ -4,6 +4,14 @@ module NavHelper
|
|||
end
|
||||
|
||||
def nav_sidebar_class
|
||||
if nav_menu_collapsed?
|
||||
"sidebar-collapsed"
|
||||
else
|
||||
"sidebar-expanded"
|
||||
end
|
||||
end
|
||||
|
||||
def page_sidebar_class
|
||||
if nav_menu_collapsed?
|
||||
"page-sidebar-collapsed"
|
||||
else
|
||||
|
|
|
@ -21,7 +21,7 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def link_to_member(project, author, opts = {})
|
||||
default_opts = { avatar: true, name: true, size: 16, author_class: 'author' }
|
||||
default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
|
||||
opts = default_opts.merge(opts)
|
||||
|
||||
return "(deleted)" unless author
|
||||
|
@ -39,7 +39,8 @@ module ProjectsHelper
|
|||
if opts[:name]
|
||||
link_to(author_html, user_path(author), class: "author_link").html_safe
|
||||
else
|
||||
link_to(author_html, user_path(author), class: "author_link has_tooltip", data: { :'original-title' => sanitize(author.name) } ).html_safe
|
||||
title = opts[:title].sub(":name", sanitize(author.name))
|
||||
link_to(author_html, user_path(author), class: "author_link has_tooltip", data: { :'original-title' => title, container: 'body' } ).html_safe
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -15,12 +15,14 @@ module SelectsHelper
|
|||
|
||||
html = {
|
||||
class: css_class,
|
||||
'data-placeholder' => placeholder,
|
||||
'data-null-user' => null_user,
|
||||
'data-any-user' => any_user,
|
||||
'data-email-user' => email_user,
|
||||
'data-first-user' => first_user,
|
||||
'data-current-user' => current_user
|
||||
data: {
|
||||
placeholder: placeholder,
|
||||
null_user: null_user,
|
||||
any_user: any_user,
|
||||
email_user: email_user,
|
||||
first_user: first_user,
|
||||
current_user: current_user
|
||||
}
|
||||
}
|
||||
|
||||
unless opts[:scope] == :all
|
||||
|
|
|
@ -25,48 +25,24 @@ module VisibilityLevelHelper
|
|||
end
|
||||
|
||||
def project_visibility_level_description(level)
|
||||
capture_haml do
|
||||
haml_tag :span do
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
haml_concat "Project access must be granted explicitly for each user."
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
haml_concat "The project can be cloned by"
|
||||
haml_concat "any logged in user."
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
haml_concat "The project can be cloned"
|
||||
haml_concat "without any"
|
||||
haml_concat "authentication."
|
||||
end
|
||||
end
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
"Project access must be granted explicitly for each user."
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
"The project can be cloned by any logged in user."
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
"The project can be cloned without any authentication."
|
||||
end
|
||||
end
|
||||
|
||||
def snippet_visibility_level_description(level)
|
||||
capture_haml do
|
||||
haml_tag :span do
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
haml_concat "The snippet is visible only for me."
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
haml_concat "The snippet is visible for any logged in user."
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
haml_concat "The snippet can be accessed"
|
||||
haml_concat "without any"
|
||||
haml_concat "authentication."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def visibility_level_icon(level)
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
private_icon
|
||||
"The snippet is visible only for me."
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
internal_icon
|
||||
"The snippet is visible for any logged in user."
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
public_icon
|
||||
"The snippet can be accessed without any authentication."
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#
|
||||
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
CACHE_KEY = 'application_setting.last'
|
||||
|
||||
serialize :restricted_visibility_levels
|
||||
serialize :import_sources
|
||||
serialize :restricted_signup_domains, Array
|
||||
|
@ -73,21 +75,17 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
end
|
||||
|
||||
after_commit do
|
||||
Rails.cache.write(cache_key, self)
|
||||
Rails.cache.write(CACHE_KEY, self)
|
||||
end
|
||||
|
||||
def self.current
|
||||
Rails.cache.fetch(cache_key) do
|
||||
Rails.cache.fetch(CACHE_KEY) do
|
||||
ApplicationSetting.last
|
||||
end
|
||||
end
|
||||
|
||||
def self.expire
|
||||
Rails.cache.delete(cache_key)
|
||||
end
|
||||
|
||||
def self.cache_key
|
||||
'application_setting.last'
|
||||
Rails.cache.delete(CACHE_KEY)
|
||||
end
|
||||
|
||||
def self.create_from_defaults
|
||||
|
|
|
@ -12,17 +12,18 @@
|
|||
module Ci
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
CACHE_KEY = 'ci_application_setting.last'
|
||||
|
||||
after_commit do
|
||||
Rails.cache.write(cache_key, self)
|
||||
Rails.cache.write(CACHE_KEY, self)
|
||||
end
|
||||
|
||||
def self.expire
|
||||
Rails.cache.delete(cache_key)
|
||||
Rails.cache.delete(CACHE_KEY)
|
||||
end
|
||||
|
||||
def self.current
|
||||
Rails.cache.fetch(cache_key) do
|
||||
Rails.cache.fetch(CACHE_KEY) do
|
||||
Ci::ApplicationSetting.last
|
||||
end
|
||||
end
|
||||
|
@ -33,9 +34,5 @@ module Ci
|
|||
add_pusher: Settings.gitlab_ci['add_pusher'],
|
||||
)
|
||||
end
|
||||
|
||||
def self.cache_key
|
||||
'ci_application_setting.last'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -78,11 +78,23 @@ class Commit
|
|||
}x
|
||||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
super("commit", /(?<commit>\h{6,40})/)
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
if cross_project_reference?(from_project)
|
||||
"#{project.to_reference}@#{id}"
|
||||
project.to_reference + self.class.reference_prefix + self.id
|
||||
else
|
||||
id
|
||||
self.id
|
||||
end
|
||||
end
|
||||
|
||||
def reference_link_text(from_project = nil)
|
||||
if cross_project_reference?(from_project)
|
||||
project.to_reference + self.class.reference_prefix + self.short_id
|
||||
else
|
||||
self.short_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,36 +2,38 @@
|
|||
#
|
||||
# Examples:
|
||||
#
|
||||
# range = CommitRange.new('f3f85602...e86e1013')
|
||||
# range = CommitRange.new('f3f85602...e86e1013', project)
|
||||
# range.exclude_start? # => false
|
||||
# range.reference_title # => "Commits f3f85602 through e86e1013"
|
||||
# range.to_s # => "f3f85602...e86e1013"
|
||||
#
|
||||
# range = CommitRange.new('f3f856029bc5f966c5a7ee24cf7efefdd20e6019..e86e1013709735be5bb767e2b228930c543f25ae')
|
||||
# range = CommitRange.new('f3f856029bc5f966c5a7ee24cf7efefdd20e6019..e86e1013709735be5bb767e2b228930c543f25ae', project)
|
||||
# range.exclude_start? # => true
|
||||
# range.reference_title # => "Commits f3f85602^ through e86e1013"
|
||||
# range.to_param # => {from: "f3f856029bc5f966c5a7ee24cf7efefdd20e6019^", to: "e86e1013709735be5bb767e2b228930c543f25ae"}
|
||||
# range.to_s # => "f3f85602..e86e1013"
|
||||
#
|
||||
# # Assuming `project` is a Project with a repository containing both commits:
|
||||
# range.project = project
|
||||
# # Assuming the specified project has a repository containing both commits:
|
||||
# range.valid_commits? # => true
|
||||
#
|
||||
class CommitRange
|
||||
include ActiveModel::Conversion
|
||||
include Referable
|
||||
|
||||
attr_reader :sha_from, :notation, :sha_to
|
||||
attr_reader :commit_from, :notation, :commit_to
|
||||
attr_reader :ref_from, :ref_to
|
||||
|
||||
# Optional Project model
|
||||
attr_accessor :project
|
||||
|
||||
# See `exclude_start?`
|
||||
attr_reader :exclude_start
|
||||
|
||||
# The beginning and ending SHAs can be between 6 and 40 hex characters, and
|
||||
# The beginning and ending refs can be named or SHAs, and
|
||||
# the range notation can be double- or triple-dot.
|
||||
PATTERN = /\h{6,40}\.{2,3}\h{6,40}/
|
||||
REF_PATTERN = /[0-9a-zA-Z][0-9a-zA-Z_.-]*[0-9a-zA-Z\^]/
|
||||
PATTERN = /#{REF_PATTERN}\.{2,3}#{REF_PATTERN}/
|
||||
|
||||
# In text references, the beginning and ending refs can only be SHAs
|
||||
# between 6 and 40 hex characters.
|
||||
STRICT_PATTERN = /\h{6,40}\.{2,3}\h{6,40}/
|
||||
|
||||
def self.reference_prefix
|
||||
'@'
|
||||
|
@ -43,27 +45,40 @@ class CommitRange
|
|||
def self.reference_pattern
|
||||
%r{
|
||||
(?:#{Project.reference_pattern}#{reference_prefix})?
|
||||
(?<commit_range>#{PATTERN})
|
||||
(?<commit_range>#{STRICT_PATTERN})
|
||||
}x
|
||||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
super("compare", /(?<commit_range>#{PATTERN})/)
|
||||
end
|
||||
|
||||
# Initialize a CommitRange
|
||||
#
|
||||
# range_string - The String commit range.
|
||||
# project - An optional Project model.
|
||||
#
|
||||
# Raises ArgumentError if `range_string` does not match `PATTERN`.
|
||||
def initialize(range_string, project = nil)
|
||||
def initialize(range_string, project)
|
||||
@project = project
|
||||
|
||||
range_string.strip!
|
||||
|
||||
unless range_string.match(/\A#{PATTERN}\z/)
|
||||
unless range_string =~ /\A#{PATTERN}\z/
|
||||
raise ArgumentError, "invalid CommitRange string format: #{range_string}"
|
||||
end
|
||||
|
||||
@exclude_start = !range_string.include?('...')
|
||||
@sha_from, @notation, @sha_to = range_string.split(/(\.{2,3})/, 2)
|
||||
@ref_from, @notation, @ref_to = range_string.split(/(\.{2,3})/, 2)
|
||||
|
||||
@project = project
|
||||
if project.valid_repo?
|
||||
@commit_from = project.commit(@ref_from)
|
||||
@commit_to = project.commit(@ref_to)
|
||||
end
|
||||
|
||||
if valid_commits?
|
||||
@ref_from = Commit.truncate_sha(sha_from) if sha_from.start_with?(@ref_from)
|
||||
@ref_to = Commit.truncate_sha(sha_to) if sha_to.start_with?(@ref_to)
|
||||
end
|
||||
end
|
||||
|
||||
def inspect
|
||||
|
@ -71,15 +86,24 @@ class CommitRange
|
|||
end
|
||||
|
||||
def to_s
|
||||
"#{sha_from[0..7]}#{notation}#{sha_to[0..7]}"
|
||||
sha_from + notation + sha_to
|
||||
end
|
||||
|
||||
alias_method :id, :to_s
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
# Not using to_s because we want the full SHAs
|
||||
reference = sha_from + notation + sha_to
|
||||
if cross_project_reference?(from_project)
|
||||
project.to_reference + self.class.reference_prefix + self.id
|
||||
else
|
||||
self.id
|
||||
end
|
||||
end
|
||||
|
||||
def reference_link_text(from_project = nil)
|
||||
reference = ref_from + notation + ref_to
|
||||
|
||||
if cross_project_reference?(from_project)
|
||||
reference = project.to_reference + '@' + reference
|
||||
reference = project.to_reference + self.class.reference_prefix + reference
|
||||
end
|
||||
|
||||
reference
|
||||
|
@ -87,46 +111,58 @@ class CommitRange
|
|||
|
||||
# Returns a String for use in a link's title attribute
|
||||
def reference_title
|
||||
"Commits #{suffixed_sha_from} through #{sha_to}"
|
||||
"Commits #{sha_start} through #{sha_to}"
|
||||
end
|
||||
|
||||
# Return a Hash of parameters for passing to a URL helper
|
||||
#
|
||||
# See `namespace_project_compare_url`
|
||||
def to_param
|
||||
{ from: suffixed_sha_from, to: sha_to }
|
||||
{ from: sha_start, to: sha_to }
|
||||
end
|
||||
|
||||
def exclude_start?
|
||||
exclude_start
|
||||
@notation == '..'
|
||||
end
|
||||
|
||||
# Check if both the starting and ending commit IDs exist in a project's
|
||||
# repository
|
||||
#
|
||||
# project - An optional Project to check (default: `project`)
|
||||
def valid_commits?(project = project)
|
||||
return nil unless project.present?
|
||||
return false unless project.valid_repo?
|
||||
|
||||
commit_from.present? && commit_to.present?
|
||||
def valid_commits?
|
||||
commit_start.present? && commit_end.present?
|
||||
end
|
||||
|
||||
def persisted?
|
||||
true
|
||||
end
|
||||
|
||||
def commit_from
|
||||
@commit_from ||= project.repository.commit(suffixed_sha_from)
|
||||
def sha_from
|
||||
return nil unless @commit_from
|
||||
|
||||
@commit_from.id
|
||||
end
|
||||
|
||||
def commit_to
|
||||
@commit_to ||= project.repository.commit(sha_to)
|
||||
def sha_to
|
||||
return nil unless @commit_to
|
||||
|
||||
@commit_to.id
|
||||
end
|
||||
|
||||
private
|
||||
def sha_start
|
||||
return nil unless sha_from
|
||||
|
||||
def suffixed_sha_from
|
||||
sha_from + (exclude_start? ? '^' : '')
|
||||
exclude_start? ? sha_from + '^' : sha_from
|
||||
end
|
||||
|
||||
def commit_start
|
||||
return nil unless sha_start
|
||||
|
||||
if exclude_start?
|
||||
@commit_start ||= project.commit(sha_start)
|
||||
else
|
||||
commit_from
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :sha_end, :sha_to
|
||||
alias_method :commit_end, :commit_to
|
||||
end
|
||||
|
|
|
@ -62,13 +62,18 @@ module Mentionable
|
|||
return [] if text.blank?
|
||||
|
||||
refs = all_references(current_user, text, load_lazy_references: load_lazy_references)
|
||||
(refs.issues + refs.merge_requests + refs.commits) - [local_reference]
|
||||
refs = (refs.issues + refs.merge_requests + refs.commits)
|
||||
|
||||
# We're using this method instead of Array diffing because that requires
|
||||
# both of the object's `hash` values to be the same, which may not be the
|
||||
# case for otherwise identical Commit objects.
|
||||
refs.reject { |ref| ref == local_reference }
|
||||
end
|
||||
|
||||
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
|
||||
def create_cross_references!(author = self.author, without = [], text = self.mentionable_text)
|
||||
refs = referenced_mentionables(author, text)
|
||||
|
||||
|
||||
# We're using this method instead of Array diffing because that requires
|
||||
# both of the object's `hash` values to be the same, which may not be the
|
||||
# case for otherwise identical Commit objects.
|
||||
|
@ -111,7 +116,7 @@ module Mentionable
|
|||
# Only include changed fields that are mentionable
|
||||
source.select { |key, val| mentionable.include?(key) }
|
||||
end
|
||||
|
||||
|
||||
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
|
||||
# the specified target.
|
||||
def cross_reference_exists?(target)
|
||||
|
|
|
@ -21,6 +21,10 @@ module Referable
|
|||
''
|
||||
end
|
||||
|
||||
def reference_link_text(from_project = nil)
|
||||
to_reference(from_project)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# The character that prefixes the actual reference identifier
|
||||
#
|
||||
|
@ -44,6 +48,25 @@ module Referable
|
|||
def reference_pattern
|
||||
raise NotImplementedError, "#{self} does not implement #{__method__}"
|
||||
end
|
||||
|
||||
def link_reference_pattern(route, pattern)
|
||||
%r{
|
||||
(?<url>
|
||||
#{Regexp.escape(Gitlab.config.gitlab.url)}
|
||||
\/#{Project.reference_pattern}
|
||||
\/#{Regexp.escape(route)}
|
||||
\/#{pattern}
|
||||
(?<path>
|
||||
(\/[a-z0-9_=-]+)*
|
||||
)?
|
||||
(?<query>
|
||||
\?[a-z0-9_=-]+
|
||||
(&[a-z0-9_=-]+)*
|
||||
)?
|
||||
(?<anchor>\#[a-z0-9_-]+)?
|
||||
)
|
||||
}x
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -201,7 +201,7 @@ class Event < ActiveRecord::Base
|
|||
elsif commented?
|
||||
"commented on"
|
||||
elsif created_project?
|
||||
if project.import?
|
||||
if project.external_import?
|
||||
"imported"
|
||||
else
|
||||
"created"
|
||||
|
|
|
@ -16,7 +16,15 @@ class GlobalMilestone
|
|||
end
|
||||
|
||||
def safe_title
|
||||
@title.parameterize
|
||||
@title.to_slug.to_s
|
||||
end
|
||||
|
||||
def expired?
|
||||
if due_date
|
||||
due_date.past?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def projects
|
||||
|
@ -98,4 +106,25 @@ class GlobalMilestone
|
|||
def complete?
|
||||
total_items_count == closed_items_count
|
||||
end
|
||||
|
||||
def due_date
|
||||
return @due_date if defined?(@due_date)
|
||||
|
||||
@due_date =
|
||||
if @milestones.all? { |x| x.due_date == @milestones.first.due_date }
|
||||
@milestones.first.due_date
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def expires_at
|
||||
if due_date
|
||||
if due_date.past?
|
||||
"expired at #{due_date.stamp("Aug 21, 2011")}"
|
||||
else
|
||||
"expires at #{due_date.stamp("Aug 21, 2011")}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -69,6 +69,10 @@ class Issue < ActiveRecord::Base
|
|||
}x
|
||||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
super("issues", /(?<issue>\d+)/)
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{iid}"
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Label < ActiveRecord::Base
|
|||
# Requests that have no label assigned.
|
||||
LabelStruct = Struct.new(:title, :name)
|
||||
None = LabelStruct.new('No Label', 'No Label')
|
||||
Any = LabelStruct.new('Any', '')
|
||||
Any = LabelStruct.new('Any Label', '')
|
||||
|
||||
DEFAULT_COLOR = '#428BCA'
|
||||
|
||||
|
|
|
@ -151,6 +151,10 @@ class MergeRequest < ActiveRecord::Base
|
|||
}x
|
||||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
super("merge_requests", /(?<merge_request>\d+)/)
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{iid}"
|
||||
|
||||
|
@ -316,7 +320,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
issues = commits.flat_map { |c| c.closes_issues(current_user) }
|
||||
issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
|
||||
closed_by_message(description))
|
||||
issues.uniq.sort_by(&:id)
|
||||
issues.uniq
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
class Milestone < ActiveRecord::Base
|
||||
# Represents a "No Milestone" state used for filtering Issues and Merge
|
||||
# Requests that have no milestone assigned.
|
||||
MilestoneStruct = Struct.new(:title, :name)
|
||||
None = MilestoneStruct.new('No Milestone', 'No Milestone')
|
||||
Any = MilestoneStruct.new('Any', '')
|
||||
MilestoneStruct = Struct.new(:title, :name, :id)
|
||||
None = MilestoneStruct.new('No Milestone', 'No Milestone', 0)
|
||||
Any = MilestoneStruct.new('Any Milestone', '', -1)
|
||||
|
||||
include InternalId
|
||||
include Sortable
|
||||
|
|
|
@ -39,8 +39,11 @@ class Note < ActiveRecord::Base
|
|||
delegate :name, to: :project, prefix: true
|
||||
delegate :name, :email, to: :author, prefix: true
|
||||
|
||||
before_validation :set_award!
|
||||
|
||||
validates :note, :project, presence: true
|
||||
validates :note, uniqueness: { scope: [:author, :noteable_type, :noteable_id] }, if: ->(n) { n.is_award }
|
||||
validates :note, inclusion: { in: Emoji.emojis_names }, if: ->(n) { n.is_award }
|
||||
validates :line_code, format: { with: /\A[a-z0-9]+_\d+_\d+\Z/ }, allow_blank: true
|
||||
# Attachments are deprecated and are handled by Markdown uploader
|
||||
validates :attachment, file_size: { maximum: :max_attachment_size }
|
||||
|
@ -348,4 +351,31 @@ class Note < ActiveRecord::Base
|
|||
def editable?
|
||||
!system?
|
||||
end
|
||||
|
||||
# Checks if note is an award added as a comment
|
||||
#
|
||||
# If note is an award, this method sets is_award to true
|
||||
# and changes content of the note to award name.
|
||||
#
|
||||
# Method is executed as a before_validation callback.
|
||||
#
|
||||
def set_award!
|
||||
return unless awards_supported? && contains_emoji_only?
|
||||
self.is_award = true
|
||||
self.note = award_emoji_name
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def awards_supported?
|
||||
noteable.kind_of?(Issue) || noteable.is_a?(MergeRequest)
|
||||
end
|
||||
|
||||
def contains_emoji_only?
|
||||
note =~ /\A#{Gitlab::Markdown::EmojiFilter.emoji_pattern}\s?\Z/
|
||||
end
|
||||
|
||||
def award_emoji_name
|
||||
note.match(Gitlab::Markdown::EmojiFilter.emoji_pattern)[1]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
require 'securerandom'
|
||||
|
||||
class Repository
|
||||
class PreReceiveError < StandardError; end
|
||||
class CommitError < StandardError; end
|
||||
|
||||
include Gitlab::ShellAdapter
|
||||
|
@ -108,10 +107,19 @@ class Repository
|
|||
tags.find { |tag| tag.name == name }
|
||||
end
|
||||
|
||||
def add_branch(branch_name, ref)
|
||||
expire_branches_cache
|
||||
def add_branch(user, branch_name, target)
|
||||
oldrev = Gitlab::Git::BLANK_SHA
|
||||
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
|
||||
target = commit(target).try(:id)
|
||||
|
||||
gitlab_shell.add_branch(path_with_namespace, branch_name, ref)
|
||||
return false unless target
|
||||
|
||||
GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do
|
||||
rugged.branches.create(branch_name, target)
|
||||
end
|
||||
|
||||
expire_branches_cache
|
||||
find_branch(branch_name)
|
||||
end
|
||||
|
||||
def add_tag(tag_name, ref, message = nil)
|
||||
|
@ -120,10 +128,20 @@ class Repository
|
|||
gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message)
|
||||
end
|
||||
|
||||
def rm_branch(branch_name)
|
||||
def rm_branch(user, branch_name)
|
||||
expire_branches_cache
|
||||
|
||||
gitlab_shell.rm_branch(path_with_namespace, branch_name)
|
||||
branch = find_branch(branch_name)
|
||||
oldrev = branch.try(:target)
|
||||
newrev = Gitlab::Git::BLANK_SHA
|
||||
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
|
||||
|
||||
GitHooksService.new.execute(user, path_to_repo, oldrev, newrev, ref) do
|
||||
rugged.branches.delete(branch_name)
|
||||
end
|
||||
|
||||
expire_branches_cache
|
||||
true
|
||||
end
|
||||
|
||||
def rm_tag(tag_name)
|
||||
|
@ -550,7 +568,6 @@ class Repository
|
|||
def commit_with_hooks(current_user, branch)
|
||||
oldrev = Gitlab::Git::BLANK_SHA
|
||||
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch
|
||||
gl_id = Gitlab::ShellEnv.gl_id(current_user)
|
||||
was_empty = empty?
|
||||
|
||||
# Create temporary ref
|
||||
|
@ -569,15 +586,7 @@ class Repository
|
|||
raise CommitError.new('Failed to create commit')
|
||||
end
|
||||
|
||||
# Run GitLab pre-receive hook
|
||||
pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', path_to_repo)
|
||||
pre_receive_hook_status = pre_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
|
||||
# Run GitLab update hook
|
||||
update_hook = Gitlab::Git::Hook.new('update', path_to_repo)
|
||||
update_hook_status = update_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
|
||||
if pre_receive_hook_status && update_hook_status
|
||||
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
|
||||
if was_empty
|
||||
# Create branch
|
||||
rugged.references.create(ref, newrev)
|
||||
|
@ -592,16 +601,11 @@ class Repository
|
|||
raise CommitError.new('Commit was rejected because branch received new push')
|
||||
end
|
||||
end
|
||||
|
||||
# Run GitLab post receive hook
|
||||
post_receive_hook = Gitlab::Git::Hook.new('post-receive', path_to_repo)
|
||||
post_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
else
|
||||
# Remove tmp ref and return error to user
|
||||
rugged.references.delete(tmp_ref)
|
||||
|
||||
raise PreReceiveError.new('Commit was rejected by git hook')
|
||||
end
|
||||
rescue GitHooksService::PreReceiveError
|
||||
# Remove tmp ref and return error to user
|
||||
rugged.references.delete(tmp_ref)
|
||||
raise
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -65,6 +65,10 @@ class Snippet < ActiveRecord::Base
|
|||
}x
|
||||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
super("snippets", /(?<snippet>\d+)/)
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{id}"
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
|
||||
class UsersStarProject < ActiveRecord::Base
|
||||
belongs_to :project, counter_cache: :star_count
|
||||
belongs_to :project, counter_cache: :star_count, touch: true
|
||||
belongs_to :user
|
||||
|
||||
validates :user, presence: true
|
||||
|
|
|
@ -13,8 +13,7 @@ class CreateBranchService < BaseService
|
|||
return error('Branch already exists')
|
||||
end
|
||||
|
||||
repository.add_branch(branch_name, ref)
|
||||
new_branch = repository.find_branch(branch_name)
|
||||
new_branch = repository.add_branch(current_user, branch_name, ref)
|
||||
|
||||
if new_branch
|
||||
push_data = build_push_data(project, current_user, new_branch)
|
||||
|
@ -27,6 +26,8 @@ class CreateBranchService < BaseService
|
|||
else
|
||||
error('Invalid reference name')
|
||||
end
|
||||
rescue GitHooksService::PreReceiveError
|
||||
error('Branch creation was rejected by Git hook')
|
||||
end
|
||||
|
||||
def success(branch)
|
||||
|
|
|
@ -24,7 +24,7 @@ class DeleteBranchService < BaseService
|
|||
return error('You dont have push access to repo', 405)
|
||||
end
|
||||
|
||||
if repository.rm_branch(branch_name)
|
||||
if repository.rm_branch(current_user, branch_name)
|
||||
push_data = build_push_data(branch)
|
||||
|
||||
EventCreateService.new.push(project, current_user, push_data)
|
||||
|
@ -35,6 +35,8 @@ class DeleteBranchService < BaseService
|
|||
else
|
||||
error('Failed to remove branch')
|
||||
end
|
||||
rescue GitHooksService::PreReceiveError
|
||||
error('Branch deletion was rejected by Git hook')
|
||||
end
|
||||
|
||||
def error(message, return_code = 400)
|
||||
|
|
|
@ -26,7 +26,7 @@ module Files
|
|||
else
|
||||
error("Something went wrong. Your changes were not committed")
|
||||
end
|
||||
rescue Repository::CommitError, Repository::PreReceiveError, ValidationError => ex
|
||||
rescue Repository::CommitError, GitHooksService::PreReceiveError, ValidationError => ex
|
||||
error(ex.message)
|
||||
end
|
||||
|
||||
|
|
28
app/services/git_hooks_service.rb
Normal file
28
app/services/git_hooks_service.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
class GitHooksService
|
||||
PreReceiveError = Class.new(StandardError)
|
||||
|
||||
def execute(user, repo_path, oldrev, newrev, ref)
|
||||
@repo_path = repo_path
|
||||
@user = Gitlab::ShellEnv.gl_id(user)
|
||||
@oldrev = oldrev
|
||||
@newrev = newrev
|
||||
@ref = ref
|
||||
|
||||
%w(pre-receive update).each do |hook_name|
|
||||
unless run_hook(hook_name)
|
||||
raise PreReceiveError.new("Git operation was rejected by #{hook_name} hook")
|
||||
end
|
||||
end
|
||||
|
||||
yield
|
||||
|
||||
run_hook('post-receive')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_hook(name)
|
||||
hook = Gitlab::Git::Hook.new(name, @repo_path)
|
||||
hook.trigger(@user, @oldrev, @newrev, @ref)
|
||||
end
|
||||
end
|
|
@ -5,11 +5,6 @@ module Notes
|
|||
note.author = current_user
|
||||
note.system = false
|
||||
|
||||
if contains_emoji_only?(params[:note])
|
||||
note.is_award = true
|
||||
note.note = emoji_name(params[:note])
|
||||
end
|
||||
|
||||
if note.save
|
||||
notification_service.new_note(note)
|
||||
|
||||
|
@ -33,13 +28,5 @@ module Notes
|
|||
note.project.execute_hooks(note_data, :note_hooks)
|
||||
note.project.execute_services(note_data, :note_hooks)
|
||||
end
|
||||
|
||||
def contains_emoji_only?(note)
|
||||
note =~ /\A:[-_+[:alnum:]]*:\s?\z/
|
||||
end
|
||||
|
||||
def emoji_name(note)
|
||||
note.match(/\A:([-_+[:alnum:]]*):\s?/)[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -145,6 +145,7 @@ class NotificationService
|
|||
recipients = reject_unsubscribed_users(recipients, note.noteable)
|
||||
|
||||
recipients.delete(note.author)
|
||||
recipients = recipients.uniq
|
||||
|
||||
# build notify method like 'note_commit_email'
|
||||
notify_method = "note_#{note.noteable_type.underscore}_email".to_sym
|
||||
|
|
|
@ -125,7 +125,7 @@ class SystemNoteService
|
|||
# Returns the created Note object
|
||||
def self.change_status(noteable, project, author, status, source)
|
||||
body = "Status changed to #{status}"
|
||||
body += " by #{source.gfm_reference}" if source
|
||||
body += " by #{source.gfm_reference(project)}" if source
|
||||
|
||||
create_note(noteable: noteable, project: project, author: author, note: body)
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
.col-sm-10
|
||||
= f.text_field :title, class: "form-control", required: true
|
||||
.form-group
|
||||
= f.label :color, "Background Color", class: 'control-label'
|
||||
= f.label :color, "Background color", class: 'control-label'
|
||||
.col-sm-10
|
||||
.input-group
|
||||
.input-group-addon.label-color-preview
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
- page_title "Edit", @label.name, "Labels"
|
||||
%h3
|
||||
Edit label
|
||||
%span.light #{@label.name}
|
||||
.back-link
|
||||
= link_to admin_labels_path do
|
||||
← To labels list
|
||||
%h3.page-title
|
||||
Edit Label
|
||||
%hr
|
||||
= render 'form'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
- page_title "New Label"
|
||||
%h3 New label
|
||||
.back-link
|
||||
= link_to admin_labels_path do
|
||||
← To labels list
|
||||
%h3.page-title
|
||||
New Label
|
||||
%hr
|
||||
= render 'form'
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
- page_title "Edit", @user.name, "Users"
|
||||
%h3.page-title
|
||||
Edit user: #{@user.name}
|
||||
.back-link
|
||||
= link_to admin_user_path(@user) do
|
||||
← Back to user page
|
||||
%hr
|
||||
= render 'form'
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
= content_for :flash_message do
|
||||
= render 'shared/project_limit'
|
||||
|
||||
%ul.center-top-menu
|
||||
= nav_link(page: [dashboard_projects_path, root_path]) do
|
||||
= link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
= milestone_progress_bar(milestone)
|
||||
.row
|
||||
.col-sm-6
|
||||
- milestone.milestones.each do |milestone|
|
||||
= link_to milestone_path(milestone) do
|
||||
%span.label.label-gray
|
||||
= milestone.project.name_with_namespace
|
||||
.expiration
|
||||
= render 'shared/milestone_expired', milestone: milestone
|
||||
.projects
|
||||
- milestone.milestones.each do |milestone|
|
||||
= link_to milestone_path(milestone) do
|
||||
%span.label.label-gray
|
||||
= milestone.project.name_with_namespace
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
- page_title @milestone.title, "Milestones"
|
||||
%h4.page-title
|
||||
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
|
||||
- if @milestone.closed?
|
||||
Closed
|
||||
- else
|
||||
Open
|
||||
Milestone #{@milestone.title}
|
||||
- header_title "Milestones", dashboard_milestones_path
|
||||
|
||||
.issuable-details
|
||||
.page-title
|
||||
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
|
||||
- if @milestone.closed?
|
||||
Closed
|
||||
- else
|
||||
Open
|
||||
Milestone #{@milestone.title}
|
||||
|
||||
.gray-content-block.middle-block
|
||||
%h2.issue-title
|
||||
= gfm escape_once(@milestone.title)
|
||||
|
||||
%hr
|
||||
- if @milestone.complete? && @milestone.active?
|
||||
.alert.alert-success
|
||||
.alert.alert-success.prepend-top-default
|
||||
%span All issues for this milestone are closed. You may close the milestone now.
|
||||
|
||||
.description
|
||||
|
||||
.table-holder
|
||||
%table.table
|
||||
%thead
|
||||
|
@ -44,7 +48,7 @@
|
|||
#{@milestone.open_items_count} open
|
||||
= milestone_progress_bar(@milestone)
|
||||
|
||||
%ul.nav.nav-tabs
|
||||
%ul.center-top-menu.no-top.no-bottom
|
||||
%li.active
|
||||
= link_to '#tab-issues', 'data-toggle' => 'tab' do
|
||||
Issues
|
||||
|
@ -58,25 +62,39 @@
|
|||
Participants
|
||||
%span.badge= @milestone.participants.count
|
||||
|
||||
.pull-right
|
||||
= link_to 'Browse Issues', issues_dashboard_path(milestone_title: @milestone.title), class: "btn edit-milestone-link btn-grouped"
|
||||
|
||||
.tab-content
|
||||
.tab-pane.active#tab-issues
|
||||
.row
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
= link_to 'Browse Issues', issues_dashboard_path(milestone_title: @milestone.title), class: "btn btn-grouped"
|
||||
|
||||
.oneline
|
||||
All issues in this milestone
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-md-6
|
||||
= render 'issues', title: "Open", issues: @milestone.opened_issues
|
||||
.col-md-6
|
||||
= render 'issues', title: "Closed", issues: @milestone.closed_issues
|
||||
|
||||
.tab-pane#tab-merge-requests
|
||||
.row
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
= link_to 'Browse Merge Requests', merge_requests_dashboard_path(milestone_title: @milestone.title), class: "btn btn-grouped"
|
||||
|
||||
.oneline
|
||||
All merge requests in this milestone
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-md-6
|
||||
= render 'merge_requests', title: "Open", merge_requests: @milestone.opened_merge_requests
|
||||
.col-md-6
|
||||
= render 'merge_requests', title: "Closed", merge_requests: @milestone.closed_merge_requests
|
||||
|
||||
.tab-pane#tab-participants
|
||||
.gray-content-block.middle-block
|
||||
.oneline
|
||||
All participants to this milestone
|
||||
%ul.bordered-list
|
||||
- @milestone.participants.each do |user|
|
||||
%li
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= auto_discovery_link_tag(:atom, dashboard_projects_url(format: :atom, private_token: current_user.private_token), title: "All activity")
|
||||
|
||||
- page_title "Projects"
|
||||
- header_title "Projects", root_path
|
||||
- header_title "Projects", dashboard_projects_path
|
||||
|
||||
= render 'dashboard/projects_head'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- page_title "Starred Projects"
|
||||
- header_title "Projects", projects_path
|
||||
- header_title "Projects", dashboard_projects_path
|
||||
|
||||
= render 'dashboard/projects_head'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- page_title "Projects"
|
||||
- header_title "Projects", root_path
|
||||
- header_title "Projects", dashboard_projects_path
|
||||
|
||||
- if current_user
|
||||
= render 'dashboard/projects_head'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- page_title "Projects"
|
||||
- header_title "Projects", root_path
|
||||
- header_title "Projects", dashboard_projects_path
|
||||
|
||||
- if current_user
|
||||
= render 'dashboard/projects_head'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- page_title "Projects"
|
||||
- header_title "Projects", root_path
|
||||
- header_title "Projects", dashboard_projects_path
|
||||
|
||||
- if current_user
|
||||
= render 'dashboard/projects_head'
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%strong= @group.name
|
||||
group settings:
|
||||
Group settings
|
||||
.panel-body
|
||||
= form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f|
|
||||
- if @group.errors.any?
|
||||
|
@ -45,4 +44,5 @@
|
|||
%br
|
||||
%strong Removed group can not be restored!
|
||||
|
||||
= link_to 'Remove Group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
|
||||
.form-actions
|
||||
= link_to 'Remove Group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
.form-group
|
||||
= f.label :title, "Title", class: "control-label"
|
||||
.col-sm-10
|
||||
= f.text_field :title, maxlength: 255, class: "form-control js-quick-submit", required: true
|
||||
%p.hint Required
|
||||
= f.text_field :title, maxlength: 255, class: "form-control js-quick-submit", required: true, autofocus: true
|
||||
.form-group.milestone-description
|
||||
= f.label :description, "Description", class: "control-label"
|
||||
.col-sm-10
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
- page_title @milestone.title, "Milestones"
|
||||
= render "header_title"
|
||||
|
||||
%h4.page-title
|
||||
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
|
||||
- if @milestone.closed?
|
||||
Closed
|
||||
- else
|
||||
Open
|
||||
Milestone #{@milestone.title}
|
||||
.pull-right
|
||||
- if can?(current_user, :admin_milestones, @group)
|
||||
- if @milestone.active?
|
||||
= link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
|
||||
.issuable-details
|
||||
.page-title
|
||||
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
|
||||
- if @milestone.closed?
|
||||
Closed
|
||||
- else
|
||||
= link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
|
||||
Open
|
||||
Milestone #{@milestone.title}
|
||||
.pull-right
|
||||
- if can?(current_user, :admin_milestones, @group)
|
||||
- if @milestone.active?
|
||||
= link_to 'Close Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
|
||||
- else
|
||||
= link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
|
||||
|
||||
.gray-content-block.middle-block
|
||||
%h2.issue-title
|
||||
= gfm escape_once(@milestone.title)
|
||||
|
||||
%hr
|
||||
- if @milestone.complete? && @milestone.active?
|
||||
.alert.alert-success
|
||||
.alert.alert-success.prepend-top-default
|
||||
%span All issues for this milestone are closed. You may close the milestone now.
|
||||
|
||||
.description
|
||||
|
||||
.table-holder
|
||||
%table.table
|
||||
%thead
|
||||
|
@ -52,7 +54,7 @@
|
|||
#{@milestone.open_items_count} open
|
||||
= milestone_progress_bar(@milestone)
|
||||
|
||||
%ul.nav.nav-tabs
|
||||
%ul.center-top-menu.no-top.no-bottom
|
||||
%li.active
|
||||
= link_to '#tab-issues', 'data-toggle' => 'tab' do
|
||||
Issues
|
||||
|
@ -66,25 +68,40 @@
|
|||
Participants
|
||||
%span.badge= @milestone.participants.count
|
||||
|
||||
.pull-right
|
||||
= link_to 'Browse Issues', issues_group_path(@group, milestone_title: @milestone.title), class: "btn edit-milestone-link btn-grouped"
|
||||
|
||||
.tab-content
|
||||
.tab-pane.active#tab-issues
|
||||
.row
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
= link_to 'Browse Issues', issues_group_path(@group, milestone_title: @milestone.title), class: "btn btn-grouped"
|
||||
|
||||
.oneline
|
||||
All issues in this milestone
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-md-6
|
||||
= render 'issues', title: "Open", issues: @milestone.opened_issues
|
||||
.col-md-6
|
||||
= render 'issues', title: "Closed", issues: @milestone.closed_issues
|
||||
|
||||
.tab-pane#tab-merge-requests
|
||||
.row
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
= link_to 'Browse Merge Requests', merge_requests_group_path(@group, milestone_title: @milestone.title), class: "btn btn-grouped"
|
||||
|
||||
.oneline
|
||||
All merge requests in this milestone
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-md-6
|
||||
= render 'merge_requests', title: "Open", merge_requests: @milestone.opened_merge_requests
|
||||
.col-md-6
|
||||
= render 'merge_requests', title: "Closed", merge_requests: @milestone.closed_merge_requests
|
||||
|
||||
.tab-pane#tab-participants
|
||||
.gray-content-block.middle-block
|
||||
.oneline
|
||||
All participants to this milestone
|
||||
|
||||
%ul.bordered-list
|
||||
- @milestone.participants.each do |user|
|
||||
%li
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
- page_title 'New Group'
|
||||
- header_title 'New Group'
|
||||
- header_title "Groups", dashboard_groups_path
|
||||
|
||||
%h3.page-title
|
||||
New Group
|
||||
%hr
|
||||
|
||||
= form_for @group, html: { class: 'group-form form-horizontal' } do |f|
|
||||
- if @group.errors.any?
|
||||
.alert.alert-danger
|
||||
|
@ -18,3 +23,4 @@
|
|||
|
||||
.form-actions
|
||||
= f.submit 'Create group', class: "btn btn-create", tabindex: 3
|
||||
= link_to 'Cancel', dashboard_groups_path, class: 'btn btn-cancel'
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.page-with-sidebar{ class: nav_sidebar_class }
|
||||
.page-with-sidebar{ class: page_sidebar_class }
|
||||
= render "layouts/broadcast"
|
||||
.sidebar-wrapper.nicescroll
|
||||
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
|
||||
.header-logo
|
||||
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
|
||||
= brand_header_logo
|
||||
.gitlab-text-container
|
||||
%h3 GitLab
|
||||
|
@ -17,8 +17,8 @@
|
|||
.collapse-nav
|
||||
= render partial: 'layouts/collapse_button'
|
||||
- if current_user
|
||||
= link_to current_user, class: 'sidebar-user' do
|
||||
= image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
|
||||
= link_to current_user, class: 'sidebar-user', title: "Profile" do
|
||||
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36'
|
||||
.username
|
||||
= current_user.username
|
||||
.content-wrapper
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- page_title "Admin area"
|
||||
- header_title "Admin area", admin_root_path
|
||||
- page_title "Admin Area"
|
||||
- header_title "Admin Area", admin_root_path
|
||||
- sidebar "admin"
|
||||
|
||||
= render template: "layouts/application"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.page-with-sidebar{ class: nav_sidebar_class }
|
||||
.page-with-sidebar{ class: page_sidebar_class }
|
||||
= render "layouts/broadcast"
|
||||
.sidebar-wrapper.nicescroll
|
||||
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
|
||||
.header-logo
|
||||
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
|
||||
= brand_header_logo
|
||||
.gitlab-text-container
|
||||
%h3 GitLab
|
||||
|
@ -14,8 +14,8 @@
|
|||
.collapse-nav
|
||||
= render partial: 'layouts/collapse_button'
|
||||
- if current_user
|
||||
= link_to current_user, class: 'sidebar-user' do
|
||||
= image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
|
||||
= link_to current_user, class: 'sidebar-user', title: "Profile" do
|
||||
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36'
|
||||
.username
|
||||
= current_user.username
|
||||
.content-wrapper
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
!!! 5
|
||||
%html{ lang: "en"}
|
||||
= render "layouts/head"
|
||||
%body.ui_charcoal.login-page.application
|
||||
%body.ui_charcoal.login-page.application.navless
|
||||
= render "layouts/header/empty"
|
||||
= render "layouts/broadcast"
|
||||
.container.navless-container
|
||||
.content
|
||||
= render "layouts/flash"
|
||||
.row.prepend-top-20
|
||||
.row
|
||||
.col-sm-5.pull-right
|
||||
= yield
|
||||
.col-sm-7.brand-holder.pull-left
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
!!! 5
|
||||
%html{ lang: "en"}
|
||||
= render "layouts/head"
|
||||
%body{class: "#{user_application_theme} application"}
|
||||
%body{class: "#{user_application_theme} application navless"}
|
||||
= render "layouts/header/empty"
|
||||
.container.navless-container
|
||||
= render "layouts/flash"
|
||||
|
|
|
@ -11,27 +11,27 @@
|
|||
%li.hidden-sm.hidden-xs
|
||||
= render 'layouts/search'
|
||||
%li.visible-sm.visible-xs
|
||||
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('search')
|
||||
- if session[:impersonator_id]
|
||||
%li.impersonation
|
||||
= link_to stop_impersonation_admin_users_path, method: :delete, title: 'Stop impersonation', data: { toggle: 'tooltip', placement: 'bottom' } do
|
||||
= link_to stop_impersonation_admin_users_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
|
||||
= icon('user-secret fw')
|
||||
- if current_user.is_admin?
|
||||
%li
|
||||
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to admin_root_path, title: 'Admin Area', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('wrench fw')
|
||||
- if current_user.can_create_project?
|
||||
%li
|
||||
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('plus fw')
|
||||
- if Gitlab::Sherlock.enabled?
|
||||
%li
|
||||
= link_to sherlock_transactions_path, title: 'Sherlock Transactions',
|
||||
data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('tachometer fw')
|
||||
%li
|
||||
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
|
||||
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= icon('sign-out')
|
||||
|
||||
%h1.title= title
|
||||
|
|
|
@ -5,78 +5,78 @@
|
|||
%span
|
||||
Overview
|
||||
= nav_link(controller: [:admin, :projects]) do
|
||||
= link_to admin_namespaces_projects_path, title: 'Projects', data: {placement: 'right'} do
|
||||
= link_to admin_namespaces_projects_path, title: 'Projects' do
|
||||
= icon('cube fw')
|
||||
%span
|
||||
Projects
|
||||
= nav_link(controller: :users) do
|
||||
= link_to admin_users_path, title: 'Users', data: {placement: 'right'} do
|
||||
= link_to admin_users_path, title: 'Users' do
|
||||
= icon('user fw')
|
||||
%span
|
||||
Users
|
||||
= nav_link(controller: :groups) do
|
||||
= link_to admin_groups_path, title: 'Groups', data: {placement: 'right'} do
|
||||
= link_to admin_groups_path, title: 'Groups' do
|
||||
= icon('group fw')
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: :deploy_keys) do
|
||||
= link_to admin_deploy_keys_path, title: 'Deploy Keys', data: {placement: 'right'} do
|
||||
= link_to admin_deploy_keys_path, title: 'Deploy Keys' do
|
||||
= icon('key fw')
|
||||
%span
|
||||
Deploy Keys
|
||||
= nav_link do
|
||||
= link_to ci_admin_projects_path, title: 'Continuous Integration', data: {placement: 'right'} do
|
||||
= link_to ci_admin_projects_path, title: 'Continuous Integration' do
|
||||
= icon('building fw')
|
||||
%span
|
||||
Continuous Integration
|
||||
= nav_link(controller: :logs) do
|
||||
= link_to admin_logs_path, title: 'Logs', data: {placement: 'right'} do
|
||||
= link_to admin_logs_path, title: 'Logs' do
|
||||
= icon('file-text fw')
|
||||
%span
|
||||
Logs
|
||||
= nav_link(controller: :broadcast_messages) do
|
||||
= link_to admin_broadcast_messages_path, title: 'Broadcast Messages', data: {placement: 'right'} do
|
||||
= link_to admin_broadcast_messages_path, title: 'Messages' do
|
||||
= icon('bullhorn fw')
|
||||
%span
|
||||
Messages
|
||||
= nav_link(controller: :hooks) do
|
||||
= link_to admin_hooks_path, title: 'Hooks', data: {placement: 'right'} do
|
||||
= link_to admin_hooks_path, title: 'Hooks' do
|
||||
= icon('external-link fw')
|
||||
%span
|
||||
Hooks
|
||||
= nav_link(controller: :background_jobs) do
|
||||
= link_to admin_background_jobs_path, title: 'Background Jobs', data: {placement: 'right'} do
|
||||
= link_to admin_background_jobs_path, title: 'Background Jobs' do
|
||||
= icon('cog fw')
|
||||
%span
|
||||
Background Jobs
|
||||
|
||||
= nav_link(controller: :applications) do
|
||||
= link_to admin_applications_path, title: 'Applications', data: {placement: 'right'} do
|
||||
= link_to admin_applications_path, title: 'Applications' do
|
||||
= icon('cloud fw')
|
||||
%span
|
||||
Applications
|
||||
|
||||
= nav_link(controller: :services) do
|
||||
= link_to admin_application_settings_services_path, title: 'Service Templates', data: {placement: 'right'} do
|
||||
= link_to admin_application_settings_services_path, title: 'Service Templates' do
|
||||
= icon('copy fw')
|
||||
%span
|
||||
Service Templates
|
||||
|
||||
= nav_link(controller: :labels) do
|
||||
= link_to admin_labels_path, title: 'Labels', data: {placement: 'right'} do
|
||||
= link_to admin_labels_path, title: 'Labels' do
|
||||
= icon('tags fw')
|
||||
%span
|
||||
Labels
|
||||
|
||||
= nav_link(controller: :abuse_reports) do
|
||||
= link_to admin_abuse_reports_path, title: "Abuse reports" do
|
||||
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Abuse Reports
|
||||
%span.count= AbuseReport.count(:all)
|
||||
|
||||
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
|
||||
= link_to admin_application_settings_path, title: 'Settings', data: {placement: 'right'} do
|
||||
= link_to admin_application_settings_path, title: 'Settings' do
|
||||
= icon('cogs fw')
|
||||
%span
|
||||
Settings
|
||||
|
|
|
@ -1,50 +1,50 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do
|
||||
= link_to dashboard_projects_path, title: 'Projects', data: {placement: 'right'} do
|
||||
= link_to dashboard_projects_path, title: 'Projects' do
|
||||
= icon('home fw')
|
||||
%span
|
||||
Projects
|
||||
= nav_link(path: 'dashboard#activity') do
|
||||
= link_to activity_dashboard_path, class: 'shortcuts-activity', title: 'Activity', data: {placement: 'right'} do
|
||||
= link_to activity_dashboard_path, class: 'shortcuts-activity', title: 'Activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Activity
|
||||
= nav_link(controller: :groups) do
|
||||
= link_to dashboard_groups_path, title: 'Groups', data: {placement: 'right'} do
|
||||
= link_to dashboard_groups_path, title: 'Groups' do
|
||||
= icon('group fw')
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: :milestones) do
|
||||
= link_to dashboard_milestones_path, title: 'Milestones', data: {placement: 'right'} do
|
||||
= link_to dashboard_milestones_path, title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'dashboard#issues') do
|
||||
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
|
||||
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
%span.count= current_user.assigned_issues.opened.count
|
||||
= nav_link(path: 'dashboard#merge_requests') do
|
||||
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
|
||||
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
%span.count= current_user.assigned_merge_requests.opened.count
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to dashboard_snippets_path, title: 'Your snippets', data: {placement: 'right'} do
|
||||
= link_to dashboard_snippets_path, title: 'Snippets' do
|
||||
= icon('clipboard fw')
|
||||
%span
|
||||
Snippets
|
||||
= nav_link(controller: :help) do
|
||||
= link_to help_path, title: 'Help', data: {placement: 'right'} do
|
||||
= link_to help_path, title: 'Help' do
|
||||
= icon('question-circle fw')
|
||||
%span
|
||||
Help
|
||||
|
||||
%li.separate-item
|
||||
= nav_link(controller: :profile) do
|
||||
= link_to profile_path, title: 'Profile settings', data: {placement: 'bottom'} do
|
||||
= link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do
|
||||
= icon('user fw')
|
||||
%span
|
||||
Profile Settings
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
|
||||
= link_to explore_root_path, title: 'Projects', data: {placement: 'right'} do
|
||||
= link_to explore_root_path, title: 'Projects' do
|
||||
= icon('home fw')
|
||||
%span
|
||||
Projects
|
||||
= nav_link(controller: :groups) do
|
||||
= link_to explore_groups_path, title: 'Groups', data: {placement: 'right'} do
|
||||
= link_to explore_groups_path, title: 'Groups' do
|
||||
= icon('group fw')
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to explore_snippets_path, title: 'Snippets', data: {placement: 'right'} do
|
||||
= link_to explore_snippets_path, title: 'Snippets' do
|
||||
= icon('clipboard fw')
|
||||
%span
|
||||
Snippets
|
||||
= nav_link(controller: :help) do
|
||||
= link_to help_path, title: 'Help', data: {placement: 'right'} do
|
||||
= link_to help_path, title: 'Help' do
|
||||
= icon('question-circle fw')
|
||||
%span
|
||||
Help
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link do
|
||||
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to dashboard
|
||||
|
@ -8,39 +8,39 @@
|
|||
%li.separate-item
|
||||
|
||||
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
|
||||
= link_to group_path(@group), title: 'Home', data: {placement: 'right'} do
|
||||
= link_to group_path(@group), title: 'Home' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Group
|
||||
- if can?(current_user, :read_group, @group)
|
||||
- if current_user
|
||||
= nav_link(controller: [:group, :milestones]) do
|
||||
= link_to group_milestones_path(@group), title: 'Milestones', data: {placement: 'right'} do
|
||||
= link_to group_milestones_path(@group), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'groups#issues') do
|
||||
= link_to issues_group_path(@group), title: 'Issues', data: {placement: 'right'} do
|
||||
= link_to issues_group_path(@group), title: 'Issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
- if current_user
|
||||
%span.count= Issue.opened.of_group(@group).count
|
||||
= nav_link(path: 'groups#merge_requests') do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests', data: {placement: 'right'} do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
- if current_user
|
||||
%span.count= MergeRequest.opened.of_group(@group).count
|
||||
= nav_link(controller: [:group_members]) do
|
||||
= link_to group_group_members_path(@group), title: 'Members', data: {placement: 'right'} do
|
||||
= link_to group_group_members_path(@group), title: 'Members' do
|
||||
= icon('users fw')
|
||||
%span
|
||||
Members
|
||||
- if can?(current_user, :admin_group, @group)
|
||||
= nav_link(html_options: { class: "separate-item" }) do
|
||||
= link_to edit_group_path(@group), title: 'Settings', data: {placement: 'right'} do
|
||||
= link_to edit_group_path(@group), title: 'Settings' do
|
||||
= icon ('cogs fw')
|
||||
%span
|
||||
Settings
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link do
|
||||
= link_to group_path(@group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to group_path(@group), title: 'Go to group', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to group
|
||||
|
@ -9,12 +9,12 @@
|
|||
|
||||
%ul.sidebar-subnav
|
||||
= nav_link(path: 'groups#edit') do
|
||||
= link_to edit_group_path(@group), title: 'Group Settings', data: {placement: 'right'} do
|
||||
= link_to edit_group_path(@group), title: 'Group Settings' do
|
||||
= icon ('pencil-square-o fw')
|
||||
%span
|
||||
Group Settings
|
||||
= nav_link(path: 'groups#projects') do
|
||||
= link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do
|
||||
= link_to projects_group_path(@group), title: 'Projects' do
|
||||
= icon('folder fw')
|
||||
%span
|
||||
Projects
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link do
|
||||
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to dashboard
|
||||
|
@ -8,52 +8,52 @@
|
|||
%li.separate-item
|
||||
|
||||
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
|
||||
= link_to profile_path, title: 'Profile', data: {placement: 'right'} do
|
||||
= link_to profile_path, title: 'Profile Settings' do
|
||||
= icon('user fw')
|
||||
%span
|
||||
Profile Settings
|
||||
= nav_link(controller: [:accounts, :two_factor_auths]) do
|
||||
= link_to profile_account_path, title: 'Account', data: {placement: 'right'} do
|
||||
= link_to profile_account_path, title: 'Account' do
|
||||
= icon('gear fw')
|
||||
%span
|
||||
Account
|
||||
= nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new', 'applications#create']) do
|
||||
= link_to applications_profile_path, title: 'Applications', data: {placement: 'right'} do
|
||||
= link_to applications_profile_path, title: 'Applications' do
|
||||
= icon('cloud fw')
|
||||
%span
|
||||
Applications
|
||||
= nav_link(controller: :emails) do
|
||||
= link_to profile_emails_path, title: 'Emails', data: {placement: 'right'} do
|
||||
= link_to profile_emails_path, title: 'Emails' do
|
||||
= icon('envelope-o fw')
|
||||
%span
|
||||
Emails
|
||||
%span.count= current_user.emails.count + 1
|
||||
- unless current_user.ldap_user?
|
||||
= nav_link(controller: :passwords) do
|
||||
= link_to edit_profile_password_path, title: 'Password', data: {placement: 'right'} do
|
||||
= link_to edit_profile_password_path, title: 'Password' do
|
||||
= icon('lock fw')
|
||||
%span
|
||||
Password
|
||||
= nav_link(controller: :notifications) do
|
||||
= link_to profile_notifications_path, title: 'Notifications', data: {placement: 'right'} do
|
||||
= link_to profile_notifications_path, title: 'Notifications' do
|
||||
= icon('inbox fw')
|
||||
%span
|
||||
Notifications
|
||||
|
||||
= nav_link(controller: :keys) do
|
||||
= link_to profile_keys_path, title: 'SSH Keys', data: {placement: 'right'} do
|
||||
= link_to profile_keys_path, title: 'SSH Keys' do
|
||||
= icon('key fw')
|
||||
%span
|
||||
SSH Keys
|
||||
%span.count= current_user.keys.count
|
||||
= nav_link(controller: :preferences) do
|
||||
= link_to profile_preferences_path, title: 'Preferences', data: {placement: 'right'} do
|
||||
= link_to profile_preferences_path, title: 'Preferences' do
|
||||
-# TODO (rspeicher): Better icon?
|
||||
= icon('image fw')
|
||||
%span
|
||||
Preferences
|
||||
= nav_link(path: 'profiles#audit_log') do
|
||||
= link_to audit_log_profile_path, title: 'Audit Log', data: {placement: 'right'} do
|
||||
= link_to audit_log_profile_path, title: 'Audit Log' do
|
||||
= icon('history fw')
|
||||
%span
|
||||
Audit Log
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
%ul.nav.nav-sidebar
|
||||
- if @project.group
|
||||
= nav_link do
|
||||
= link_to group_path(@project.group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to group_path(@project.group), title: 'Go to group', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to group
|
||||
- else
|
||||
= nav_link do
|
||||
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to dashboard
|
||||
|
@ -15,32 +15,32 @@
|
|||
%li.separate-item
|
||||
|
||||
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
|
||||
= icon('home fw')
|
||||
%span
|
||||
Project
|
||||
= nav_link(path: 'projects#activity') do
|
||||
= link_to activity_project_path(@project), title: 'Project Activity', class: 'shortcuts-project-activity', data: {placement: 'right'} do
|
||||
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Activity
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
|
||||
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree', data: {placement: 'right'} do
|
||||
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
|
||||
= icon('files-o fw')
|
||||
%span
|
||||
Files
|
||||
|
||||
- if project_nav_tab? :commits
|
||||
= nav_link(controller: %w(commit commits compare repositories tags branches releases)) do
|
||||
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do
|
||||
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
|
||||
= icon('history fw')
|
||||
%span
|
||||
Commits
|
||||
|
||||
- if project_nav_tab? :builds
|
||||
= nav_link(controller: %w(builds)) do
|
||||
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds', data: {placement: 'right'} do
|
||||
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
|
||||
= icon('cubes fw')
|
||||
%span
|
||||
Builds
|
||||
|
@ -48,28 +48,28 @@
|
|||
|
||||
- if project_nav_tab? :network
|
||||
= nav_link(controller: %w(network)) do
|
||||
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do
|
||||
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
|
||||
= icon('code-fork fw')
|
||||
%span
|
||||
Network
|
||||
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs', data: {placement: 'right'} do
|
||||
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
|
||||
= icon('area-chart fw')
|
||||
%span
|
||||
Graphs
|
||||
|
||||
- if project_nav_tab? :milestones
|
||||
= nav_link(controller: :milestones) do
|
||||
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones', data: {placement: 'right'} do
|
||||
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
|
||||
- if project_nav_tab? :issues
|
||||
= nav_link(controller: :issues) do
|
||||
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
|
||||
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
|
@ -78,7 +78,7 @@
|
|||
|
||||
- if project_nav_tab? :merge_requests
|
||||
= nav_link(controller: :merge_requests) do
|
||||
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
|
||||
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
|
@ -86,35 +86,35 @@
|
|||
|
||||
- if project_nav_tab? :settings
|
||||
= nav_link(controller: [:project_members, :teams]) do
|
||||
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab', data: {placement: 'right'} do
|
||||
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
|
||||
= icon('users fw')
|
||||
%span
|
||||
Members
|
||||
|
||||
- if project_nav_tab? :labels
|
||||
= nav_link(controller: :labels) do
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels', data: {placement: 'right'} do
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
|
||||
= icon('tags fw')
|
||||
%span
|
||||
Labels
|
||||
|
||||
- if project_nav_tab? :wiki
|
||||
= nav_link(controller: :wikis) do
|
||||
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki', data: {placement: 'right'} do
|
||||
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
|
||||
= icon('book fw')
|
||||
%span
|
||||
Wiki
|
||||
|
||||
- if project_nav_tab? :snippets
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do
|
||||
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
|
||||
= icon('clipboard fw')
|
||||
%span
|
||||
Snippets
|
||||
|
||||
- if project_nav_tab? :settings
|
||||
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
|
||||
= link_to edit_project_path(@project), title: 'Settings', data: {placement: 'right'} do
|
||||
= link_to edit_project_path(@project), title: 'Settings' do
|
||||
= icon('cogs fw')
|
||||
%span
|
||||
Settings
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%ul.nav.nav-sidebar
|
||||
= nav_link do
|
||||
= link_to project_path(@project), title: 'Go to project', data: {placement: 'right'}, class: 'back-link' do
|
||||
= link_to project_path(@project), title: 'Go to project', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to project
|
||||
|
@ -9,59 +9,59 @@
|
|||
|
||||
%ul.sidebar-subnav
|
||||
= nav_link(path: 'projects#edit') do
|
||||
= link_to edit_project_path(@project), title: 'Project Settings', data: {placement: 'right'} do
|
||||
= link_to edit_project_path(@project), title: 'Project Settings' do
|
||||
= icon('pencil-square-o fw')
|
||||
%span
|
||||
Project Settings
|
||||
= nav_link(controller: :deploy_keys) do
|
||||
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do
|
||||
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
|
||||
= icon('key fw')
|
||||
%span
|
||||
Deploy Keys
|
||||
= nav_link(controller: :hooks) do
|
||||
= link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks', data: {placement: 'right'} do
|
||||
= link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks' do
|
||||
= icon('link fw')
|
||||
%span
|
||||
Web Hooks
|
||||
= nav_link(controller: :services) do
|
||||
= link_to namespace_project_services_path(@project.namespace, @project), title: 'Services', data: {placement: 'right'} do
|
||||
= link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
|
||||
= icon('cogs fw')
|
||||
%span
|
||||
Services
|
||||
= nav_link(controller: :protected_branches) do
|
||||
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches', data: {placement: 'right'} do
|
||||
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
|
||||
= icon('lock fw')
|
||||
%span
|
||||
Protected Branches
|
||||
|
||||
- if @project.builds_enabled?
|
||||
= nav_link(controller: :runners) do
|
||||
= link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners', data: {placement: 'right'} do
|
||||
= link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do
|
||||
= icon('cog fw')
|
||||
%span
|
||||
Runners
|
||||
= nav_link(controller: :variables) do
|
||||
= link_to namespace_project_variables_path(@project.namespace, @project) do
|
||||
= link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do
|
||||
= icon('code fw')
|
||||
%span
|
||||
Variables
|
||||
= nav_link path: 'triggers#index' do
|
||||
= link_to namespace_project_triggers_path(@project.namespace, @project) do
|
||||
= link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
|
||||
= icon('retweet fw')
|
||||
%span
|
||||
Triggers
|
||||
= nav_link path: 'ci_web_hooks#index' do
|
||||
= link_to namespace_project_ci_web_hooks_path(@project.namespace, @project) do
|
||||
= link_to namespace_project_ci_web_hooks_path(@project.namespace, @project), title: 'CI Web Hooks' do
|
||||
= icon('link fw')
|
||||
%span
|
||||
CI Web Hooks
|
||||
= nav_link path: 'ci_settings#edit' do
|
||||
= link_to edit_namespace_project_ci_settings_path(@project.namespace, @project) do
|
||||
= link_to edit_namespace_project_ci_settings_path(@project.namespace, @project), title: 'CI Settings' do
|
||||
= icon('building fw')
|
||||
%span
|
||||
CI Settings
|
||||
= nav_link controller: 'ci_services' do
|
||||
= link_to namespace_project_ci_services_path(@project.namespace, @project) do
|
||||
= link_to namespace_project_ci_services_path(@project.namespace, @project), title: 'CI Services' do
|
||||
= icon('share fw')
|
||||
%span
|
||||
CI Services
|
||||
|
|
|
@ -23,10 +23,13 @@
|
|||
%p.cgray
|
||||
- if current_user.private_token
|
||||
= text_field_tag "token", current_user.private_token, class: "form-control"
|
||||
%div
|
||||
= f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default btn-build-token"
|
||||
- else
|
||||
%span You don`t have one yet. Click generate to fix it.
|
||||
|
||||
.form-actions
|
||||
- if current_user.private_token
|
||||
= f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-default btn-build-token"
|
||||
- else
|
||||
= f.submit 'Generate', class: "btn btn-default btn-build-token"
|
||||
|
||||
- unless current_user.ldap_user?
|
||||
|
@ -54,7 +57,8 @@
|
|||
%p
|
||||
Each time you log in you’ll be required to provide your username and
|
||||
password as usual, plus a randomly-generated code from your phone.
|
||||
%div
|
||||
|
||||
.form-actions
|
||||
= link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success'
|
||||
|
||||
- if button_based_providers.any?
|
||||
|
@ -81,15 +85,16 @@
|
|||
%p
|
||||
Changing your username will change path to all personal projects!
|
||||
%div
|
||||
= f.text_field :username, required: true, class: 'form-control'
|
||||
.input-group
|
||||
.input-group-addon
|
||||
= "#{root_url}u/"
|
||||
= f.text_field :username, required: true, class: 'form-control'
|
||||
|
||||
.loading-gif.hide
|
||||
%p
|
||||
= icon('spinner spin')
|
||||
Saving new username
|
||||
%p.light
|
||||
= user_url(@user)
|
||||
%div
|
||||
.form-actions
|
||||
= f.submit 'Save username', class: "btn btn-warning"
|
||||
|
||||
- if signup_enabled?
|
||||
|
@ -104,7 +109,8 @@
|
|||
- rp = current_user.personal_projects.count
|
||||
- unless rp.zero?
|
||||
%li #{pluralize rp, 'personal project'} will be removed and cannot be restored
|
||||
= link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove"
|
||||
.form-actions
|
||||
= link_to 'Delete account', user_registration_path, data: { confirm: "REMOVE #{current_user.name}? Are you sure?" }, method: :delete, class: "btn btn-remove"
|
||||
- else
|
||||
- if @user.solo_owned_groups.present?
|
||||
%p
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue