Commit fd91b48f authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into milestone-ref

parents 7dedd997 7c3c901a
......@@ -12,6 +12,7 @@ before_script:
spec:feature:
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
tags:
- ruby
......
Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Implement new UI for group page
- Implement search inside emoji picker
- Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note
- Expose Git's version in the admin area
- Only allow group/project members to mention `@all`
- Expose Git's version in the admin area (Trey Davis)
- Add "Frequently used" category to emoji picker
- Add CAS support (tduehr)
- Add link to merge request on build detail page.
v 8.3.2 (unreleased)
- Enable "Add key" button when user fills in a proper key
- Add link to merge request on build detail page
- Revert back upvote and downvote button to the issue and MR pages
- Swap position of Assignee and Author selector on Issuables (Zeger-Jan van de Weg)
- Add system hook messages for project rename and transfer (Steve Norman)
- Fix version check image in Safari
- Show 'All' tab by default in the builds page
- Fix API project lookups when querying with a namespace with dots (Stan Hu)
v 8.3.3 (unreleased)
- Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu)
- Enable "Add key" button when user fills in a proper key (Stan Hu)
v 8.3.2
- Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu)
- Add support for Google reCAPTCHA in user registration
v 8.3.1
- Fix Error 500 when global milestones have slashes (Stan Hu)
......@@ -83,6 +98,8 @@ v 8.3.0
- Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
- Persist runners registration token in database
- Fix online editor should not remove newlines at the end of the file
- Expose Git's version in the admin area
- Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye)
v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu)
......
......@@ -155,6 +155,28 @@ sudo -u git -H bundle exec rake gitlab:env:info)
```
### Issue weight
Issue weight allows us to get an idea of the amount of work required to solve
one or multiple issues. This makes it possible to schedule work more accurately.
You are encouraged to set the weight of any issue. Following the guidelines
below will make it easy to manage this, without unnecessary overhead.
1. Set weight for any issue at the earliest possible convenience
1. If you don't agree with a set weight, discuss with other developers until
consensus is reached about the weight
1. Issue weights are an abstract measurement of complexity of the issue. Do not
relate issue weight directly to time. This is called [anchoring](https://en.wikipedia.org/wiki/Anchoring)
and something you want to avoid.
1. Something that has a weight of 1 (or no weight) is really small and simple.
Something that is 9 is rewriting a large fundamental part of GitLab,
which might lead to many hard problems to solve. Changing some text in GitLab
is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9.
1. If something is very large, it should probably be split up in multiple
issues or chunks. You can simply not set the weight of a parent issue and set
weights to children issues.
## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests,
......
......@@ -35,6 +35,9 @@ gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd'
gem 'rack-oauth2', '~> 1.2.1'
# reCAPTCHA protection
gem 'recaptcha', require: 'recaptcha/rails'
# Two-factor authentication
gem 'devise-two-factor', '~> 2.0.0'
gem 'rqrcode-rails3', '~> 0.1.7'
......@@ -166,10 +169,10 @@ gem 'asana', '~> 0.4.0'
gem 'ruby-fogbugz', '~> 0.2.1'
# d3
gem 'd3_rails', '~> 3.5.5'
gem 'd3_rails', '~> 3.5.0'
#cal-heatmap
gem "cal-heatmap-rails", "~> 0.0.1"
gem 'cal-heatmap-rails', '~> 3.5.0'
# underscore-rails
gem "underscore-rails", "~> 1.8.0"
......@@ -197,7 +200,7 @@ gem 'turbolinks', '~> 2.5.0'
gem 'jquery-turbolinks', '~> 2.1.0'
gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.0'
gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.2.0'
gem 'gon', '~> 6.0.1'
......@@ -212,9 +215,17 @@ gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1'
# Metrics
group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri
gem 'method_source', '~> 0.8', require: false
gem 'influxdb', '~> 0.2', require: false
gem 'connection_pool', '~> 2.0', require: false
end
group :development do
gem "foreman"
gem 'brakeman', '3.0.1', require: false
gem 'brakeman', '~> 3.1.0', require: false
gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2'
......
......@@ -49,6 +49,7 @@ GEM
addressable (2.3.8)
after_commit_queue (1.3.0)
activerecord (>= 3.0)
allocations (1.0.3)
annotate (2.6.10)
activerecord (>= 3.2, <= 4.3)
rake (~> 10.4)
......@@ -65,7 +66,7 @@ GEM
attr_encrypted (1.3.4)
encryptor (>= 1.3.0)
attr_required (1.0.0)
autoprefixer-rails (6.1.1)
autoprefixer-rails (6.2.3)
execjs
json
awesome_print (1.2.0)
......@@ -81,18 +82,20 @@ GEM
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bootstrap-sass (3.3.5)
autoprefixer-rails (>= 5.0.0.1)
sass (>= 3.2.19)
brakeman (3.0.1)
bootstrap-sass (3.3.6)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
brakeman (3.1.4)
erubis (~> 2.6)
fastercsv (~> 1.5)
haml (>= 3.0, < 5.0)
highline (~> 1.6.20)
highline (>= 1.6.20, < 2.0)
multi_json (~> 1.2)
ruby2ruby (~> 2.1.1)
ruby_parser (~> 3.5.0)
ruby2ruby (>= 2.1.1, < 2.3.0)
ruby_parser (~> 3.7.0)
safe_yaml (>= 1.0)
sass (~> 3.0)
slim (>= 1.3.6, < 4.0)
terminal-table (~> 1.4)
browser (1.0.1)
builder (3.2.2)
......@@ -102,8 +105,8 @@ GEM
bundler-audit (0.4.0)
bundler (~> 1.2)
thor (~> 0.18)
byebug (8.2.0)
cal-heatmap-rails (0.0.1)
byebug (8.2.1)
cal-heatmap-rails (3.5.1)
capybara (2.4.4)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
......@@ -117,6 +120,7 @@ GEM
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
json (>= 1.7)
cause (0.1)
charlock_holmes (0.7.3)
chunky_png (1.3.5)
cliver (0.3.2)
......@@ -140,10 +144,10 @@ GEM
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
tins (~> 1.6.0)
crack (0.4.2)
crack (0.4.3)
safe_yaml (~> 1.0.0)
creole (0.5.0)
d3_rails (3.5.6)
d3_rails (3.5.11)
railties (>= 3.1.0)
daemons (1.2.3)
database_cleaner (1.4.1)
......@@ -230,7 +234,7 @@ GEM
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
opennebula
fog-brightbox (0.9.0)
fog-brightbox (0.10.1)
fog-core (~> 1.22)
fog-json
inflecto (~> 0.0.2)
......@@ -249,7 +253,7 @@ GEM
fog-core (>= 1.21.0)
fog-json
fog-xml (>= 0.0.1)
fog-sakuracloud (1.4.0)
fog-sakuracloud (1.5.0)
fog-core
fog-json
fog-softlayer (1.0.2)
......@@ -277,11 +281,11 @@ GEM
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (2.1.0)
gemojione (2.1.1)
json
get_process_mem (0.2.0)
gherkin-ruby (0.3.2)
github-linguist (4.7.2)
github-linguist (4.7.3)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
......@@ -298,7 +302,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.2.0)
gemojione (~> 2.1)
gitlab_git (7.2.21)
gitlab_git (7.2.22)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -347,7 +351,7 @@ GEM
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashie (3.4.3)
highline (1.6.21)
highline (1.7.8)
hike (1.2.3)
hipchat (1.5.2)
httparty
......@@ -370,6 +374,9 @@ GEM
i18n (0.7.0)
ice_nine (0.11.1)
inflecto (0.0.2)
influxdb (0.2.3)
cause
json
ipaddress (0.8.0)
jquery-atwho-rails (1.3.2)
jquery-rails (4.0.5)
......@@ -417,7 +424,7 @@ GEM
net-ldap (0.12.1)
net-ssh (3.0.1)
netrc (0.11.0)
newrelic-grape (2.0.0)
newrelic-grape (2.1.0)
grape
newrelic_rpm
newrelic_rpm (3.9.4.245)
......@@ -566,6 +573,8 @@ GEM
trollop
rdoc (3.12.2)
json (~> 1.4)
recaptcha (1.0.2)
json
redcarpet (3.3.3)
redis (3.2.2)
redis-actionpack (4.0.1)
......@@ -636,10 +645,10 @@ GEM
ruby-saml (1.0.0)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
ruby2ruby (2.1.4)
ruby2ruby (2.2.0)
ruby_parser (~> 3.1)
sexp_processor (~> 4.0)
ruby_parser (3.5.0)
ruby_parser (3.7.2)
sexp_processor (~> 4.1)
rubyntlm (0.5.2)
rubypants (0.2.0)
......@@ -693,6 +702,9 @@ GEM
tilt (>= 1.3, < 3)
six (0.2.0)
slack-notifier (1.2.1)
slim (3.0.6)
temple (~> 0.7.3)
tilt (>= 1.3.3, < 2.1)
slop (3.6.0)
spinach (0.8.10)
colorize
......@@ -734,6 +746,7 @@ GEM
railties (>= 3.2.5, < 5)
teaspoon-jasmine (2.2.0)
teaspoon (>= 1.0.0)
temple (0.7.6)
term-ansicolor (1.3.2)
tins (~> 1.0)
terminal-table (1.5.2)
......@@ -789,7 +802,7 @@ GEM
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
web-console (2.2.1)
activemodel (>= 4.0)
......@@ -820,6 +833,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
allocations (~> 1.0)
annotate (~> 2.6.0)
asana (~> 0.4.0)
asciidoctor (~> 1.5.2)
......@@ -829,22 +843,23 @@ DEPENDENCIES
benchmark-ips
better_errors (~> 1.0.1)
binding_of_caller (~> 0.7.2)
bootstrap-sass (~> 3.0)
brakeman (= 3.0.1)
bootstrap-sass (~> 3.3.0)
brakeman (~> 3.1.0)
browser (~> 1.0.0)
bullet
bundler-audit
byebug
cal-heatmap-rails (~> 0.0.1)
cal-heatmap-rails (~> 3.5.0)
capybara (~> 2.4.0)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.9.0)
charlock_holmes (~> 0.7.3)
coffee-rails (~> 4.1.0)
colorize (~> 0.7.0)
connection_pool (~> 2.0)
coveralls (~> 0.8.2)
creole (~> 0.5.0)
d3_rails (~> 3.5.5)
d3_rails (~> 3.5.0)
database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0)
devise (~> 3.5.3)
......@@ -879,6 +894,7 @@ DEPENDENCIES
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
influxdb (~> 0.2)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.0.0)
jquery-scrollto-rails (~> 1.4.3)
......@@ -887,6 +903,7 @@ DEPENDENCIES
kaminari (~> 0.16.3)
letter_opener (~> 1.1.2)
mail_room (~> 0.6.1)
method_source (~> 0.8)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.3.16)
......@@ -924,6 +941,7 @@ DEPENDENCIES
raphael-rails (~> 2.1.2)
rblineprof
rdoc (~> 3.6)
recaptcha
redcarpet (~> 3.3.3)
redis-namespace
redis-rails (~> 4.0.0)
......
Copyright (c) 2011-2015 GitLab B.V.
Copyright (c) 2011-2016 GitLab B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -10,12 +10,12 @@
#= require jquery.cookie
#= require jquery.endless-scroll
#= require jquery.highlight
#= require jquery.history
#= require jquery.waitforimages
#= require jquery.atwho
#= require jquery.scrollTo
#= require jquery.blockUI
#= require jquery.turbolinks
#= require d3
#= require cal-heatmap
#= require turbolinks
#= require autosave
#= require bootstrap
......@@ -27,7 +27,6 @@
#= require branch-graph
#= require ace/ace
#= require ace/ext-searchbox
#= require d3
#= require underscore
#= require nprogress
#= require nprogress-turbolinks
......@@ -39,7 +38,6 @@
#= require shortcuts_dashboard_navigation
#= require shortcuts_issuable
#= require shortcuts_network
#= require cal-heatmap
#= require jquery.nicescroll.min
#= require_tree .
......
......@@ -43,15 +43,19 @@ class @AwardsHandler
decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter")
emojiIcon = counter.parent()
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
counter.parent().removeClass("active")
emojiIcon.removeClass("active")
@removeMeFromAuthorList(emoji)
else if emoji =="thumbsup" || emoji == "thumbsdown"
emojiIcon.tooltip("destroy")
counter.text(0)
emojiIcon.removeClass("active")
else
award = counter.parent()
award.tooltip("destroy")
award.remove()
emojiIcon.tooltip("destroy")
emojiIcon.remove()
removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
......@@ -127,21 +131,19 @@ class @AwardsHandler
getFrequentlyUsedEmojis: ->
frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",")
frequently_used_emojis = ["thumbsup", "thumbsdown"].concat(frequently_used_emojis)
_.compact(_.uniq(frequently_used_emojis))
renderFrequentlyUsedBlock: ->
frequently_used_emojis = @getFrequentlyUsedEmojis()
if $.cookie('frequently_used_emojis')
frequently_used_emojis = @getFrequentlyUsedEmojis()
ul = $("<ul>")
ul = $("<ul>")
for emoji in frequently_used_emojis
do (emoji) ->
$(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul)
for emoji in frequently_used_emojis
do (emoji) ->
$(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul)
$("input.emoji-search").after(ul).after($("<h5>").text("Frequently used"))
$("input.emoji-search").after(ul).after($("<h5>").text("Frequently used"))
setupSearch: ->
$("input.emoji-search").keyup (ev) =>
......
class @Calendar
options =
month: "short"
day: "numeric"
year: "numeric"
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
cal = new CalHeatMap()
cal.init
......
......@@ -49,7 +49,7 @@ class Dispatcher
new DropzoneInput($('.release-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssuable()
shortcut_handler = new ShortcutsIssuable(true)
new ZenMode()
when "projects:merge_requests:diffs"
new Diff()
......
#= require flash
#= require jquery.waitforimages
#= require task_list
......@@ -6,13 +7,44 @@ class @Issue
# Prevent duplicate event bindings
@disableTaskList()
if $("a.btn-close").length
if $('a.btn-close').length
@initTaskList()
@initIssueBtnEventListeners()
initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
initIssueBtnEventListeners: ->
issueFailMessage = 'Unable to update this issue at this time.'
$('a.btn-close, a.btn-reopen').on 'click', (e) ->
e.preventDefault()
e.stopImmediatePropagation()
$this = $(this)
isClose = $this.hasClass('btn-close')
$this.prop('disabled', true)
url = $this.attr('href')
$.ajax
type: 'PUT'
url: url,
error: (jqXHR, textStatus, errorThrown) ->
issueStatus = if isClose then 'close' else 'open'
new Flash(issueFailMessage, 'alert')
success: (data, textStatus, jqXHR) ->
if data.saved
$this.addClass('hidden')
if isClose
$('a.btn-reopen').removeClass('hidden')
$('div.status-box-closed').removeClass('hidden')
$('div.status-box-open').addClass('hidden')
else
$('a.btn-close').removeClass('hidden')
$('div.status-box-closed').addClass('hidden')
$('div.status-box-open').removeClass('hidden')
else
new Flash(issueFailMessage, 'alert')
$this.prop('disabled', false)
disableTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
......
......@@ -15,13 +15,6 @@
$(this).html totalIssues + 1
else
$(this).html totalIssues - 1
$("body").on "click", ".issues-other-filters .dropdown-menu a", ->
$('.issues-list').block(
message: null,
overlayCSS:
backgroundColor: '#DDD'
opacity: .4
)
reload: ->
Issues.initSelects()
......@@ -54,7 +47,7 @@
form = $("#issue_search_form")
search = $("#issue_search").val()
$('.issues-holder').css("opacity", '0.5')
issues_url = form.attr('action') + '? '+ form.serialize()
issues_url = form.attr('action') + '?' + form.serialize()
$.ajax
type: "GET"
......@@ -65,7 +58,7 @@
success: (data) ->
$('.issues-holder').html(data.html)
# Change url so if user reload a page - search results are saved
History.replaceState {page: issues_url}, document.title, issues_url
history.replaceState {page: issues_url}, document.title, issues_url
Issues.reload()
dataType: "json"
......
NProgress.configure(showSpinner: false)
defaultClass = 'tanuki-shape'
pieces = [
'path#tanuki-right-cheek',
'path#tanuki-right-eye, path#tanuki-right-ear',
'path#tanuki-nose',
'path#tanuki-left-eye, path#tanuki-left-ear',
'path#tanuki-left-cheek',
]
pieceIndex = 0
firstPiece = pieces[0]
currentTimer = null
delay = 150
clearHighlights = ->
$(".#{defaultClass}.highlight").attr('class', defaultClass)
start = ->
clearHighlights()
pieceIndex = 0
pieces.reverse() unless pieces[0] == firstPiece
currentTimer = setInterval(work, delay)
stop = ->
clearInterval(currentTimer)
clearHighlights()
work = ->
clearHighlights()
$(pieces[pieceIndex]).attr('class', "#{defaultClass} highlight")
# If we hit the last piece, reset the index and then reverse the array to
# get a nice back-and-forth sweeping look
if pieceIndex == pieces.length - 1
pieceIndex = 0
pieces.reverse()
else
pieceIndex++
$(document).on('page:fetch', start)
$(document).on('page:change', stop)
......@@ -16,7 +16,7 @@
form = $("#issue_search_form")
search = $("#issue_search").val()
$('.merge-requests-holder').css("opacity", '0.5')
issues_url = form.attr('action') + '? '+ form.serialize()
issues_url = form.attr('action') + '?' + form.serialize()
$.ajax
type: "GET"
......@@ -27,7 +27,7 @@
success: (data) ->
$('.merge-requests-holder').html(data.html)
# Change url so if user reload a page - search results are saved
History.replaceState {page: issues_url}, document.title, issues_url
history.replaceState {page: issues_url}, document.title, issues_url
MergeRequests.reload()
dataType: "json"
......
......@@ -7,7 +7,7 @@ class @Shortcuts
selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp)
@showHelp: (e, location) ->
if $('#modal-shortcuts').length > 0
$('#modal-shortcuts').modal('show')
......@@ -17,8 +17,7 @@ class @Shortcuts
dataType: 'script',
success: (e) ->
if location and location.length > 0
for l in location
$(l).show()
$(l).show() for l in location
else
$('.hidden-shortcut').show()
$('.js-more-help-button').remove()
......@@ -28,3 +27,8 @@ class @Shortcuts
@focusSearch: (e) ->
$('#search').focus()
e.preventDefault()
$(document).on 'click.more_help', '.js-more-help-button', (e) ->
$(@).remove()
$('.hidden-shortcut').show()
e.preventDefault()
......@@ -117,5 +117,5 @@ class @UsersSelect
callback(users)
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
url = gon.relative_url_root.replace(/\/$/, '') + url if gon.relative_url_root?
return url
......@@ -19,38 +19,33 @@
}
}
}
/**
* This overwrites the default values of the cal-heatmap gem
*/
.calendar {
.qi {
background-color: #999;
fill: #fff;
}
.q1 {
background-color: #dae289;
fill: #ededed;
fill: #ededed !important;
}
.q2 {
background-color: #cedb9c;
fill: #ACD5F2;
fill: #ACD5F2 !important;
}
.q3 {
background-color: #b5cf6b;
fill: #7FA8D1;
fill: #7FA8D1 !important;
}
.q4 {
background-color: #637939;
fill: #49729B;
fill: #49729B !important;
}
.q5 {
background-color: #3b6427;
fill: #254E77;
fill: #254E77 !important;
}
.domain-background {
......@@ -59,32 +54,7 @@
}
.ch-tooltip {
position: absolute;
display: none;
margin-top: 22px;
margin-left: 1px;
font-size: 13px;
padding: 3px;
font-weight: 550;
background-color: #222;
span {
position: absolute;
width: 200px;
text-align: center;
visibility: hidden;
border-radius: 10px;
&:after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -8px;
width: 0;
height: 0;
border-top: 8px solid #000000;
border-right: 8px solid transparent;
border-left: 8px solid transparent;
}
}
}
}
......@@ -105,7 +105,7 @@
.tanuki-shape {
transition: all 0.8s;
&:hover {
&:hover, &.highlight {
fill: rgb(255, 255, 255);
transition: all 0.1s;
}
......
......@@ -54,17 +54,17 @@
h3 {
margin: 24px 0 12px 0;
font-size: 1.25em;
font-size: 1.1em;
}
h4 {
margin: 24px 0 12px 0;
font-size: 1.1em;
font-size: 0.98em;
}
h5 {
margin: 24px 0 12px 0;
font-size: 1em;
font-size: 0.95em;
}
h6 {
......
......@@ -26,6 +26,13 @@
}
.project-home-panel {
.cover-controls {
.project-settings-dropdown {
margin-left: 10px;
}
}
.project-identicon-holder {
margin-bottom: 16px;
......
......@@ -9,12 +9,10 @@ class AbuseReportsController < ApplicationController
@abuse_report.reporter = current_user
if @abuse_report.save
if current_application_settings.admin_notification_email.present?
AbuseReportMailer.notify(@abuse_report.id).deliver_later
end
@abuse_report.notify
message = "Thank you for your report. A GitLab administrator will look into it shortly."
redirect_to root_path, notice: message
redirect_to @abuse_report.user, notice: message
else
render :new
end
......@@ -23,6 +21,9 @@ class AbuseReportsController < ApplicationController
private
def report_params
params.require(:abuse_report).permit(:user_id, :message)
params.require(:abuse_report).permit(%i(
message
user_id
))
end
end
......@@ -67,6 +67,17 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:user_oauth_applications,
:shared_runners_enabled,
:max_artifacts_size,
:metrics_enabled,
:metrics_host,
:metrics_port,
:metrics_username,
:metrics_password,
:metrics_pool_size,
:metrics_timeout,
:metrics_method_call_threshold,
:recaptcha_enabled,
:recaptcha_site_key,
:recaptcha_private_key,
restricted_visibility_levels: [],
import_sources: []
)
......
......@@ -5,12 +5,12 @@ class Admin::BuildsController < Admin::ApplicationController
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'all'
@builds
when 'running'
@builds.running_or_pending.reverse_order
when 'finished'
@builds.finished
else
@builds.running_or_pending.reverse_order
@builds
end
@builds = @builds.page(params[:page]).per(30)
end
......
class Explore::GroupsController < Explore::ApplicationController
def index
@groups = GroupsFinder.new.execute(current_user)
@groups = Group.order_id_desc
@groups = @groups.search(params[:search]) if params[:search].present?
@groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page]).per(PER_PAGE)
......
......@@ -12,12 +12,12 @@ class Projects::BuildsController < Projects::ApplicationController
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'all'
@builds
when 'running'
@builds.running_or_pending.reverse_order
when 'finished'
@builds.finished
else
@builds.running_or_pending.reverse_order
@builds
end
@builds = @builds.page(params[:page]).per(30)
end
......
......@@ -9,7 +9,7 @@ class Projects::CommitsController < Projects::ApplicationController
def show
@repo = @project.repository
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i
@commits = @repo.commits(@ref, @path, @limit, @offset)
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
......
......@@ -178,7 +178,7 @@ class ProjectsController < ApplicationController
def markdown_preview
text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user)
ext = Gitlab::ReferenceExtractor.new(@project, current_user, current_user)
ext.analyze(text)
render json: {
......
class RegistrationsController < Devise::RegistrationsController
before_action :signup_enabled?
include Recaptcha::Verify
def new
redirect_to(new_user_session_path)
end
def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
super
else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
flash.delete :recaptcha_error
render action: 'new'
end
end
def destroy
DeleteUserService.new(current_user).execute(current_user)
......@@ -38,4 +49,16 @@ class RegistrationsController < Devise::RegistrationsController
def sign_up_params
params.require(:user).permit(:username, :email, :name, :password, :password_confirmation)
end
def resource_name
:user
end
def resource
@resource ||= User.new(sign_up_params)
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
end
class SessionsController < Devise::SessionsController
include AuthenticatesWithTwoFactor
include Recaptcha::ClientHelper
prepend_before_action :authenticate_with_two_factor, only: [:create]
prepend_before_action :store_redirect_path, only: [:new]
before_action :auto_sign_in_with_provider, only: [:new]
before_action :load_recaptcha
def new
if Gitlab.config.ldap.enabled
......@@ -40,7 +42,7 @@ class SessionsController < Devise::SessionsController
User.find(session[:otp_user_id])
end
end
def store_redirect_path
redirect_path =
if request.referer.present? && (params['redirect_to_referer'] == 'yes')
......@@ -87,14 +89,14 @@ class SessionsController < Devise::SessionsController
provider = Gitlab.config.omniauth.auto_sign_in_with_provider
return unless provider.present?
# Auto sign in with an Omniauth provider only if the standard "you need to sign-in" alert is
# registered or no alert at all. In case of another alert (such as a blocked user), it is safer
# Auto sign in with an Omniauth provider only if the standard "you need to sign-in" alert is
# registered or no alert at all. In case of another alert (such as a blocked user), it is safer
# to do nothing to prevent redirection loops with certain Omniauth providers.
return unless flash[:alert].blank? || flash[:alert] == I18n.t('devise.failure.unauthenticated')
# Prevent alert from popping up on the first page shown after authentication.
flash[:alert] = nil
flash[:alert] = nil
redirect_to user_omniauth_authorize_path(provider.to_sym)
end
......@@ -107,4 +109,8 @@ class SessionsController < Devise::SessionsController
AuditEventService.new(user, user, options).
for_authentication.security_event
end
def load_recaptcha
Gitlab::Recaptcha.load_configurations!
end
end
......@@ -7,7 +7,7 @@ class UsersController < ApplicationController
@projects = PersonalProjectsFinder.new(@user).execute(current_user)
@groups = JoinedGroupsFinder.new(@user).execute(current_user)
@groups = @user.groups.order_id_desc
respond_to do |format|
format.html
......
class GroupsFinder
# Finds the groups available to the given user.
#
# current_user - The user to find the groups for.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = groups_visible_to_user(current_user)
else
relation = public_groups
end
relation.order_id_desc
end
private
# This method returns the groups "current_user" can see.
def groups_visible_to_user(current_user)
base = groups_for_projects(public_and_internal_projects)
union = Gitlab::SQL::Union.
new([base.select(:id), current_user.authorized_groups.select(:id)])
Group.where("namespaces.id IN (#{union.to_sql})")
end
def public_groups
groups_for_projects(public_projects)
end
def groups_for_projects(projects)
Group.public_and_given_groups(projects.select(:namespace_id))
end
def public_projects
Project.unscoped.public_only
end
def public_and_internal_projects
Project.unscoped.public_and_internal_only
end
end
# Class for finding the groups a user is a member of.
class JoinedGroupsFinder
def initialize(user = nil)
@user = user
end
# Finds the groups of the source user, optionally limited to those visible to
# the current user.
#
# current_user - If given the groups of "@user" will only include the groups
# "current_user" can also see.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = groups_visible_to_user(current_user)
else
relation = public_groups
end
relation.order_id_desc
end
private
# Returns the groups the user in "current_user" can see.
#
# This list includes all public/internal projects as well as the projects of
# "@user" that "current_user" also has access to.
def groups_visible_to_user(current_user)
base = @user.authorized_groups.visible_to_user(current_user)
extra = public_and_internal_groups
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
Group.where("namespaces.id IN (#{union.to_sql})")
end
def public_groups
groups_for_projects(@user.authorized_projects.public_only)
end
def public_and_internal_groups
groups_for_projects(@user.authorized_projects.public_and_internal_only)
end
def groups_for_projects(projects)
@user.groups.public_and_given_groups(projects.select(:namespace_id))
end
end
......@@ -72,7 +72,7 @@ module ApplicationHelper
if user_or_email.is_a?(User)
user = user_or_email
else
user = User.find_by(email: user_or_email)
user = User.find_by(email: user_or_email.downcase)
end
if user
......
......@@ -69,6 +69,10 @@ module IssuesHelper
end
end
def issue_button_visibility(issue, closed)
return 'hidden' if issue.closed? == closed
end
def issue_to_atom(xml, issue)
xml.entry do
xml.id namespace_project_issue_url(issue.project.namespace,
......@@ -95,7 +99,7 @@ module IssuesHelper
end
def emoji_icon(name, unicode = nil, aliases = [])
unicode ||= Emoji.emoji_filename(name)
unicode ||= Emoji.emoji_filename(name) rescue ""
content_tag :div, "",
class: "icon emoji-icon emoji-#{unicode}",
......@@ -120,6 +124,18 @@ module IssuesHelper
end
end
def awards_sort(awards)
awards.sort_by do |award, notes|
if award == "thumbsup"
0
elsif award == "thumbsdown"
1
else
2
end
end.to_h
end
# Required for Banzai::Filter::IssueReferenceFilter
module_function :url_for_issue
end
......@@ -8,6 +8,80 @@ module PageLayoutHelper
@page_title.join(" \u00b7 ")
end
# Define or get a description for the current page
#
# description - String (default: nil)
#
# If this helper is called multiple times with an argument, only the last
# description will be returned when called without an argument. Descriptions
# have newlines replaced with spaces and all HTML tags are sanitized.
#
# Examples:
#
# page_description # => "GitLab Community Edition"
# page_description("Foo")
# page_description # => "Foo"
#
# page_description("<b>Bar</b>\nBaz")
# page_description # => "Bar Baz"
#
# Returns an HTML-safe String.
def page_description(description = nil)
@page_description ||= page_description_default
if description.present?
@page_description = description.squish
else
sanitize(@page_description, tags: []).truncate_words(30)
end
end
# Default value for page_description when one hasn't been defined manually by
# a view
def page_description_default
if @project
@project.description || brand_title
else
brand_title
end
end
def page_image
default = image_url('gitlab_logo.png')
if @project
@project.avatar_url || default
elsif @user
avatar_icon(@user)
else
default
end
end
# Define or get attributes to be used as Twitter card metadata
#
# map - Hash of label => data pairs. Keys become labels, values become data
#
# Raises ArgumentError if given more than two attributes
def page_card_attributes(map = {})
raise ArgumentError, 'cannot provide more than two attributes' if map.length > 2
@page_card_attributes ||= {}
@page_card_attributes = map.reject { |_,v| v.blank? } if map.present?
@page_card_attributes
end
def page_card_meta_tags
tags = ''
page_card_attributes.each_with_index do |pair, i|
tags << tag(:meta, property: "twitter:label#{i + 1}", content: pair[0])
tags << tag(:meta, property: "twitter:data#{i + 1}", content: pair[1])
end
tags.html_safe
end
def header_title(title = nil, title_url = nil)
if title
@header_title = title
......
......@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5)
GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
Group.search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group)
......
......@@ -2,11 +2,19 @@ class AbuseReportMailer < BaseMailer
include Gitlab::CurrentSettings
def notify(abuse_report_id)
return unless deliverable?
@abuse_report = AbuseReport.find(abuse_report_id)
mail(
to: current_application_settings.admin_notification_email,
to: current_application_settings.admin_notification_email,
subject: "#{@abuse_report.user.name} (#{@abuse_report.user.username}) was reported for abuse"
)
end
private
def deliverable?
current_application_settings.admin_notification_email.present?
end
end
......@@ -48,7 +48,7 @@ module Emails
yield
SentNotification.record(@note, recipient_id, reply_key)
SentNotification.record_note(@note, recipient_id, reply_key)
end
end
end
......@@ -69,7 +69,7 @@ class Ability
subject.group
end
if group && group.public_profile?
if group && group.projects.public_only.any?
[:read_group]
else
[]
......
......@@ -18,4 +18,10 @@ class AbuseReport < ActiveRecord::Base
validates :user, presence: true
validates :message, presence: true
validates :user_id, uniqueness: true
def notify
return unless self.persisted?
AbuseReportMailer.notify(self.id).deliver_later
end
end
......@@ -44,24 +44,32 @@ class ApplicationSetting < ActiveRecord::Base
attr_accessor :restricted_signup_domains_raw
validates :session_expire_delay,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :home_page_url,
allow_blank: true,
url: true,
if: :home_page_url_column_exist
allow_blank: true,
url: true,
if: :home_page_url_column_exist
validates :after_sign_out_path,
allow_blank: true,
url: true
allow_blank: true,
url: true
validates :admin_notification_email,
allow_blank: true,
email: true
allow_blank: true,
email: true
validates :two_factor_grace_period,
numericality: { greater_than_or_equal_to: 0 }
numericality: { greater_than_or_equal_to: 0 }
validates :recaptcha_site_key,
presence: true,
if: :recaptcha_enabled
validates :recaptcha_private_key,
presence: true,
if: :recaptcha_enabled
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
......
......@@ -194,8 +194,11 @@ module Ci
end
def raw_trace
if File.exist?(path_to_trace)
if File.file?(path_to_trace)
File.read(path_to_trace)
elsif project.ci_id && File.file?(old_path_to_trace)
# Temporary fix for build trace data integrity
File.read(old_path_to_trace)
else
# backward compatibility
read_attribute :trace
......@@ -212,8 +215,8 @@ module Ci
end
def trace=(trace)
unless Dir.exists? dir_to_trace
FileUtils.mkdir_p dir_to_trace
unless Dir.exists?(dir_to_trace)
FileUtils.mkdir_p(dir_to_trace)
end
File.write(path_to_trace, trace)
......@@ -231,6 +234,55 @@ module Ci
"#{dir_to_trace}/#{id}.log"
end
##
# Deprecated
#
# This is a hotfix for CI build data integrity, see #4246
# Should be removed in 8.4, after CI files migration has been done.
#
def old_dir_to_trace
File.join(
Settings.gitlab_ci.builds_path,
created_at.utc.strftime("%Y_%m"),
project.ci_id.to_s
)
end
##
# Deprecated
#
# This is a hotfix for CI build data integrity, see #4246
# Should be removed in 8.4, after CI files migration has been done.
#
def old_path_to_trace
"#{old_dir_to_trace}/#{id}.log"
end
##
# Deprecated
#
# This contains a hotfix for CI build data integrity, see #4246
#
# This method is used by `ArtifactUploader` to create a store_dir.
# Warning: Uploader uses it after AND before file has been stored.
#
# This method returns old path to artifacts only if it already exists.
#
def artifacts_path
old = File.join(created_at.utc.strftime('%Y_%m'),
project.ci_id.to_s,
id.to_s)
old_store = File.join(ArtifactUploader.artifacts_path, old)
return old if project.ci_id && File.directory?(old_store)
File.join(
created_at.utc.strftime('%Y_%m'),
project.id.to_s,
id.to_s
)
end
def token
project.runners_token
end
......
......@@ -95,14 +95,12 @@ module Issuable
opened? || reopened?
end
# Deprecated. Still exists to preserve API compatibility.
def downvotes
0
notes.awards.where(note: "thumbsdown").count
end
# Deprecated. Still exists to preserve API compatibility.
def upvotes
0
notes.awards.where(note: "thumbsup").count
end
def subscribed?(user)
......@@ -161,6 +159,14 @@ module Issuable
self.class.to_s.underscore
end
# Returns a Hash of attributes to be used for Twitter card metadata
def card_attributes
{
'Author' => author.try(:name),
'Assignee' => assignee.try(:name)
}
end
def notes_with_associations
notes.includes(:author, :project)
end
......
......@@ -44,7 +44,7 @@ module Mentionable
end
def all_references(current_user = self.author, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, self.author)
if text
ext.analyze(text)
......
......@@ -50,10 +50,6 @@ class Group < Namespace
User.reference_pattern
end
def public_and_given_groups(ids)
where('public IS TRUE OR namespaces.id IN (?)', ids)
end
def visible_to_user(user)
where(id: user.authorized_groups.select(:id).reorder(nil))
end
......@@ -125,10 +121,6 @@ class Group < Namespace
end
end
def public_profile?
self.public || projects.public_only.any?
end
def post_create_hook
Gitlab::AppLogger.info("Group \"#{name}\" was created")
......
......@@ -107,9 +107,16 @@ class Note < ActiveRecord::Base
end
def grouped_awards
notes = {}
awards.select(:note).distinct.map do |note|
[ note.note, where(note: note.note) ]
notes[note.note] = where(note: note.note)
end
notes["thumbsup"] ||= Note.none
notes["thumbsdown"] ||= Note.none
notes
end
end
......@@ -339,14 +346,12 @@ class Note < ActiveRecord::Base
read_attribute(:system)
end
# Deprecated. Still exists to preserve API compatibility.
def downvote?
false
is_award && note == "thumbsdown"
end
# Deprecated. Still exists to preserve API compatibility.
def upvote?
false
is_award && note == "thumbsup"
end
def editable?
......
......@@ -81,6 +81,7 @@ class Project < ActiveRecord::Base
acts_as_taggable_on :tags
attr_accessor :new_default_branch
attr_accessor :old_path_with_namespace
# Relations
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
......@@ -555,7 +556,9 @@ class Project < ActiveRecord::Base
end
def send_move_instructions(old_path_with_namespace)
NotificationService.new.project_was_moved(self, old_path_with_namespace)
# New project path needs to be committed to the DB or notification will
# retrieve stale information
run_after_commit { NotificationService.new.project_was_moved(self, old_path_with_namespace) }
end
def owner
......@@ -699,6 +702,11 @@ class Project < ActiveRecord::Base
gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
send_move_instructions(old_path_with_namespace)
reset_events_cache
@old_path_with_namespace = old_path_with_namespace
SystemHooksService.new.execute_hooks_for(self, :rename)
@repository = nil
rescue
# Returning false does not rollback after_* transaction but gives
......
......@@ -76,7 +76,9 @@ class Repository
path: path,
limit: limit,
offset: offset,
follow: path.present?
# --follow doesn't play well with --skip. See:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
follow: false
}
commits = Gitlab::Git::Commit.where(options)
......
......@@ -352,10 +352,13 @@ class User < ActiveRecord::Base
end
def namespace_uniq
# Return early if username already failed the first uniqueness validation
return if self.errors[:username].include?('has already been taken')
namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name)
if existing_namespace && existing_namespace != self.namespace
self.errors.add :username, "already exists"
self.errors.add(:username, 'has already been taken')
end
end
......
......@@ -413,6 +413,7 @@ class NotificationService
recipients = reject_unsubscribed_users(recipients, target)
recipients.delete(current_user)
recipients = recipients.uniq
recipients
end
......
......@@ -55,6 +55,9 @@ module Projects
# Move uploads
Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path)
project.old_path_with_namespace = old_path
SystemHooksService.new.execute_hooks_for(project, :transfer)
true
end
end
......
......@@ -18,7 +18,8 @@ class SystemHooksService
def build_event_data(model, event)
data = {
event_name: build_event_name(model, event),
created_at: model.created_at.xmlschema
created_at: model.created_at.xmlschema,
updated_at: model.updated_at.xmlschema
}
case model
......@@ -34,6 +35,14 @@ class SystemHooksService
end
when Project
data.merge!(project_data(model))
if event == :rename || event == :transfer
data.merge!({
old_path_with_namespace: model.old_path_with_namespace
})
end
data
when User
data.merge!({
name: model.name,
......
......@@ -20,16 +20,12 @@ class ArtifactUploader < CarrierWave::Uploader::Base
@build, @field = build, field
end
def artifacts_path
File.join(build.created_at.utc.strftime('%Y_%m'), build.project.id.to_s, build.id.to_s)
end
def store_dir
File.join(ArtifactUploader.artifacts_path, artifacts_path)
File.join(self.class.artifacts_path, @build.artifacts_path)
end
def cache_dir
File.join(ArtifactUploader.artifacts_cache_path, artifacts_path)
File.join(self.class.artifacts_cache_path, @build.artifacts_path)
end
def file_storage?
......
......@@ -2,7 +2,7 @@
%h3.page-title Report abuse
%p Please use this form to report users who create spam issues, comments or behave inappropriately.
%hr
= form_for @abuse_report, html: { class: 'form-horizontal'} do |f|
= form_for @abuse_report, html: { class: 'form-horizontal js-requires-input'} do |f|
= f.hidden_field :user_id
- if @abuse_report.errors.any?
.alert.alert-danger
......@@ -16,7 +16,7 @@
.form-group
= f.label :message, class: 'control-label'
.col-sm-10
= f.text_area :message, class: "form-control", rows: 2, required: true
= f.text_area :message, class: "form-control js-quick-submit", rows: 2, required: true
.help-block
Explain the problem with this user. If appropriate, provide a link to the relevant issue or comment.
......
......@@ -2,19 +2,21 @@
- user = abuse_report.user
%tr
%td
- if reporter
= link_to reporter.name, reporter
- if user
= link_to user.name, [:admin, user]
.light.small
Joined #{time_ago_with_tooltip(user.created_at)}
- else
(removed)
%td
= abuse_report.created_at.to_s(:short)
%td
= abuse_report.message
%td
- if user
= link_to user.name, user
- if reporter
= link_to reporter.name, [:admin, reporter]
- else
(removed)
.light.small
= time_ago_with_tooltip(abuse_report.created_at)
%td
= markdown(abuse_report.message.squish!, pipeline: :single_line)
%td
- if user
= link_to 'Remove user & report', admin_abuse_report_path(abuse_report, remove_user: true),
......
......@@ -6,10 +6,9 @@
%table.table
%thead
%tr
%th User
%th Reported by
%th Reported at
%th Message
%th User
%th Primary action
%th
= render @abuse_reports
......
......@@ -149,12 +149,89 @@
.checkbox
= f.label :shared_runners_enabled do
= f.check_box :shared_runners_enabled
Enable shared runners for a new projects
Enable shared runners for new projects
.form-group
= f.label :max_artifacts_size, 'Maximum artifacts size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_artifacts_size, class: 'form-control'
%fieldset
%legend Metrics
%p
These settings require a restart to take effect.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :metrics_enabled do
= f.check_box :metrics_enabled
Enable InfluxDB Metrics
.form-group
= f.label :metrics_host, 'InfluxDB host', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :metrics_host, class: 'form-control', placeholder: 'influxdb.example.com'
.form-group
= f.label :metrics_port, 'InfluxDB port', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :metrics_port, class: 'form-control', placeholder: '8089'
.help-block
The UDP port to use for connecting to InfluxDB. InfluxDB requires that
your server configuration specifies a database to store data in when
sending messages to this port, without it metrics data will not be
saved.
.form-group
= f.label :metrics_username, 'InfluxDB username', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :metrics_username, class: 'form-control'
.form-group
= f.label :metrics_password, 'InfluxDB password', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :metrics_password, class: 'form-control'
.form-group
= f.label :metrics_pool_size, 'Connection pool size', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :metrics_pool_size, class: 'form-control'
.help-block
The amount of InfluxDB connections to open. Connections are opened
lazily. Users using multi-threaded application servers should ensure
enough connections are available (at minimum the amount of application
server threads).
.form-group
= f.label :metrics_timeout, 'Connection timeout', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :metrics_timeout, class: 'form-control'
.help-block
The amount of seconds after which an InfluxDB connection will time
out.
.form-group
= f.label :metrics_method_call_threshold, 'Method Call Threshold (ms)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :metrics_method_call_threshold, class: 'form-control'
.help-block
A method call is only tracked when it takes longer to complete than
the given amount of milliseconds.
%fieldset
%legend Spam and Anti-bot Protection
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :recaptcha_enabled do
= f.check_box :recaptcha_enabled
Enable reCAPTCHA
%span.help-block#recaptcha_help_block Helps preventing bots from creating accounts
.form-group
= f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :recaptcha_site_key, class: 'form-control'
.help-block
Generate site and private keys here:
%a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha
.form-group
= f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :recaptcha_private_key, class: 'form-control'
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
......@@ -7,18 +7,18 @@
%ul.center-top-menu
%li{class: ('active' if @scope.nil?)}
= link_to admin_builds_path do
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
%li{class: ('active' if @scope == 'running')}
= link_to admin_builds_path(scope: :running) do
Running
%span.badge.js-running-count= @all_builds.running_or_pending.count(:id)
%span.badge.js-running-count= number_with_delimiter(@all_builds.running_or_pending.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to admin_builds_path(scope: :finished) do
Finished
%span.badge.js-running-count= @all_builds.finished.count(:id)
%li{class: ('active' if @scope == 'all')}
= link_to admin_builds_path(scope: :all) do
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
%span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id))
.gray-content-block
#{(@scope || 'running').capitalize} builds
......
......@@ -6,35 +6,35 @@
%p
Forks
%span.light.pull-right
= ForkedProjectLink.count
= number_with_delimiter(ForkedProjectLink.count)
%p
Issues
%span.light.pull-right
= Issue.count
= number_with_delimiter(Issue.count)
%p
Merge Requests
%span.light.pull-right
= MergeRequest.count
= number_with_delimiter(MergeRequest.count)
%p
Notes
%span.light.pull-right
= Note.count
= number_with_delimiter(Note.count)
%p
Snippets
%span.light.pull-right
= Snippet.count
= number_with_delimiter(Snippet.count)
%p
SSH Keys
%span.light.pull-right
= Key.count
= number_with_delimiter(Key.count)
%p
Milestones
%span.light.pull-right
= Milestone.count
= number_with_delimiter(Milestone.count)
%p
Active Users
%span.light.pull-right
= User.active.count
= number_with_delimiter(User.active.count)
.col-md-4
%h4
Features
......@@ -99,7 +99,7 @@
%h4 Projects
.data
= link_to admin_namespaces_projects_path do
%h1= Project.count
%h1= number_with_delimiter(Project.count)
%hr
= link_to('New Project', new_project_path, class: "btn btn-new")
.col-sm-4
......@@ -107,7 +107,7 @@
%h4 Users
.data
= link_to admin_users_path do
%h1= User.count
%h1= number_with_delimiter(User.count)
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
.col-sm-4
......@@ -115,7 +115,7 @@
%h4 Groups
.data
= link_to admin_groups_path do
%h1= Group.count
%h1= number_with_delimiter(Group.count)
%hr
= link_to 'New Group', new_admin_group_path, class: "btn btn-new"
......
- page_title "Groups"
%h3.page-title
Groups (#{@groups.total_count})
Groups (#{number_with_delimiter(@groups.total_count)})
= link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right"
%p.light
......
......@@ -8,27 +8,27 @@
%li{class: "#{'active' unless params[:filter]}"}
= link_to admin_users_path do
Active
%small.pull-right= User.active.count
%small.pull-right= number_with_delimiter(User.active.count)
%li{class: "#{'active' if params[:filter] == "admins"}"}
= link_to admin_users_path(filter: "admins") do
Admins
%small.pull-right= User.admins.count
%small.pull-right= number_with_delimiter(User.admins.count)
%li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"}
= link_to admin_users_path(filter: 'two_factor_enabled') do
2FA Enabled
%small.pull-right= User.with_two_factor.count
%small.pull-right= number_with_delimiter(User.with_two_factor.count)
%li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"}
= link_to admin_users_path(filter: 'two_factor_disabled') do
2FA Disabled
%small.pull-right= User.without_two_factor.count
%small.pull-right= number_with_delimiter(User.without_two_factor.count)
%li{class: "#{'active' if params[:filter] == "blocked"}"}
= link_to admin_users_path(filter: "blocked") do
Blocked
%small.pull-right= User.blocked.count
%small.pull-right= number_with_delimiter(User.blocked.count)
%li{class: "#{'active' if params[:filter] == "wop"}"}
= link_to admin_users_path(filter: "wop") do
Without projects
%small.pull-right= User.without_projects.count
%small.pull-right= number_with_delimiter(User.without_projects.count)
%hr
= form_tag admin_users_path, method: :get, class: 'form-inline' do
.form-group
......@@ -42,7 +42,7 @@
%section.col-md-9
.panel.panel-default
.panel-heading
Users (#{@users.total_count})
Users (#{number_with_delimiter(@users.total_count)})
.panel-head-actions
.dropdown.inline
%a.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"}
......
......@@ -6,17 +6,21 @@
.login-heading
%h3 Create an account
.login-body
- user = params[:user].present? ? params[:user] : {}
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
.devise-errors
= devise_error_messages!
%div
= f.text_field :name, class: "form-control top", placeholder: "Name", required: true
= f.text_field :name, class: "form-control top", value: user[:name], placeholder: "Name", required: true
%div
= f.text_field :username, class: "form-control middle", placeholder: "Username", required: true
= f.text_field :username, class: "form-control middle", value: user[:username], placeholder: "Username", required: true
%div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
= f.email_field :email, class: "form-control middle", value: user[:email], placeholder: "Email", required: true
.form-group.append-bottom-20#password-strength
= f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true
= f.password_field :password, class: "form-control bottom", value: user[:password], id: "user_password_sign_up", placeholder: "Password", required: true
%div
- if current_application_settings.recaptcha_enabled
= recaptcha_tags
%div
= f.submit "Sign up", class: "btn-create btn"
......
......@@ -3,7 +3,7 @@
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
= cache [event, "v2.1"] do
= cache [event, current_application_settings, "v2.1"] do
= image_tag avatar_icon(event.author_email, 46), class: "avatar s46", alt:''
- if event.created_project?
= render "events/event/created_project", event: event
......
......@@ -24,15 +24,6 @@
%hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
.form-group
%hr
= f.label :public, class: 'control-label' do
Public
.col-sm-10
.checkbox
= f.check_box :public
%span.descr Make this group public (even if there is no any public project inside this group)
.form-actions
= f.submit 'Save group', class: "btn btn-save"
......
......@@ -47,5 +47,5 @@
= render "projects", projects: @projects
- else
%p
This group does not have public projects
%p.center-top-menu.no-top
No projects to show
......@@ -219,11 +219,3 @@
%td.shortcut
.key r
%td Reply (quoting selected text)
:javascript
$('.js-more-help-button').click(function (e) {
$(this).remove()l
$('.hidden-shortcut').show();
e.preventDefault();
});
- page_title "GitLab"
%head
%head{prefix: "og: http://ogp.me/ns#"}
%meta{charset: "utf-8"}
%meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'}
%meta{content: "GitLab Community Edition", name: "description"}
%meta{name: 'referrer', content: 'origin-when-cross-origin'}
%title= page_title
-# Open Graph - http://ogp.me/
%meta{property: 'og:type', content: "object"}
%meta{property: 'og:site_name', content: "GitLab"}
%meta{property: 'og:title', content: page_title}
%meta{property: 'og:description', content: page_description}
%meta{property: 'og:image', content: page_image}
%meta{property: 'og:url', content: request.base_url + request.fullpath}
-# Twitter Card - https://dev.twitter.com/cards/types/summary
%meta{property: 'twitter:card', content: "summary"}
%meta{property: 'twitter:title', content: page_title}
%meta{property: 'twitter:description', content: page_description}
%meta{property: 'twitter:image', content: page_image}
= page_card_meta_tags
%title= page_title('GitLab')
%meta{name: "description", content: page_description}
= favicon_link_tag 'favicon.ico'
......@@ -18,6 +31,8 @@
= include_gon
- unless browser.safari?
%meta{name: 'referrer', content: 'origin-when-cross-origin'}
%meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'}
%meta{name: 'theme-color', content: '#474D57'}
......
......@@ -29,13 +29,13 @@
= icon('cog fw')
%span
Runners
%span.count= Ci::Runner.count(:all)
%span.count= number_with_delimiter(Ci::Runner.count(:all))
= nav_link path: 'builds#index' do
= link_to admin_builds_path do
= icon('link fw')
%span
Builds
%span.count= Ci::Build.count(:all)
%span.count= number_with_delimiter(Ci::Build.count(:all))
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
= icon('file-text fw')
......@@ -80,7 +80,7 @@
= icon('exclamation-circle fw')
%span
Abuse Reports
%span.count= AbuseReport.count(:all)
%span.count= number_with_delimiter(AbuseReport.count(:all))
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings' do
......
......@@ -24,13 +24,13 @@
= icon('exclamation-circle fw')
%span
Issues
%span.count= current_user.assigned_issues.opened.count
%span.count= number_with_delimiter(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' do
= icon('tasks fw')
%span
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
= nav_link(controller: :snippets) do
= link_to dashboard_snippets_path, title: 'Snippets' do
= icon('clipboard fw')
......
......@@ -25,14 +25,14 @@
%span
Issues
- if current_user
%span.count= Issue.opened.of_group(@group).count
%span.count= number_with_delimiter(Issue.opened.of_group(@group).count)
= nav_link(path: 'groups#merge_requests') 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
%span.count= number_with_delimiter(MergeRequest.opened.of_group(@group).count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
......
......@@ -27,7 +27,7 @@
= icon('envelope-o fw')
%span
Emails
%span.count= current_user.emails.count + 1
%span.count= number_with_delimiter(current_user.emails.count + 1)
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= link_to edit_profile_password_path, title: 'Password' do
......@@ -45,7 +45,7 @@
= icon('key fw')
%span
SSH Keys
%span.count= current_user.keys.count
%span.count= number_with_delimiter(current_user.keys.count)
= nav_link(controller: :preferences) do
= link_to profile_preferences_path, title: 'Preferences' do
-# TODO (rspeicher): Better icon?
......
......@@ -44,7 +44,7 @@
= icon('cubes fw')
%span
Builds
%span.count.builds_counter= @project.builds.running_or_pending.count(:all)
%span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
......@@ -67,7 +67,7 @@
%span
Issues
- if @project.default_issues_tracker?
%span.count.issue_counter= @project.issues.opened.count
%span.count.issue_counter= number_with_delimiter(@project.issues.opened.count)
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
......@@ -75,7 +75,7 @@
= icon('tasks fw')
%span
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
%span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :settings
= nav_link(controller: [:project_members, :teams]) do
......
......@@ -18,13 +18,26 @@
= visibility_level_label(@project.visibility_level)
.cover-controls
- if can?(current_user, :admin_project, @project)
= link_to edit_project_path(@project), class: 'btn btn-gray' do
= icon('pencil')
- if current_user
&nbsp;
= link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), class: 'btn btn-gray' do
= icon('rss')
- access = user_max_access_in_project(current_user.id, @project)
- can_edit = can?(current_user, :admin_project, @project)
- if access || can_edit
%span.dropdown.project-settings-dropdown
%a.dropdown-new.btn.btn-gray#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
= icon('cog')
= icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right
- if can_edit
%li
= link_to edit_project_path(@project) do
Edit Project
- if access
%li
= link_to leave_namespace_project_project_members_path(@project.namespace, @project),
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
Leave Project
.project-repo-buttons
.split-one.count-buttons
......
......@@ -11,6 +11,12 @@
%ul.center-top-menu
%li{class: ('active' if @scope.nil?)}
= link_to project_builds_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@all_builds.running_or_pending.count(:id))
......@@ -21,12 +27,6 @@
%span.badge.js-running-count
= number_with_delimiter(@all_builds.finished.count(:id))
%li{class: ('active' if @scope == 'all')}
= link_to project_builds_path(@project, scope: :all) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
.gray-content-block
#{(@scope || 'running').capitalize} builds from this project
......
......@@ -8,9 +8,10 @@
= link_to url_for_new_issue(@project, only_path: true) do
= icon('exclamation-circle fw')
New issue
- if can?(current_user, :create_merge_request, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project
%li
= link_to new_namespace_project_merge_request_path(@project.namespace, @project) do
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project) do
= icon('tasks fw')
New merge request
- if can?(current_user, :create_snippet, @project)
......
......@@ -5,7 +5,7 @@
- note_count = notes.user.count
- ci_commit = project.ci_commit(commit.sha)
- cache_key = [project.path_with_namespace, commit.id, note_count]
- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count]
- cache_key.push(ci_commit.status) if ci_commit
= cache(cache_key) do
......
......@@ -7,7 +7,7 @@
- if @issues.present?
.issuable-filter-count
%span.pull-right
= @issues.total_count
= number_with_delimiter(@issues.total_count)
issues for this filter
= paginate @issues, theme: "gitlab"
- page_title "#{@issue.title} (##{@issue.iid})", "Issues"
- page_title "#{@issue.title} (##{@issue.iid})", "Issues"
- page_description @issue.description
- page_card_attributes @issue.card_attributes
= render "header_title"
.issue
.detail-page-header
.status-box{ class: status_box_class(@issue) }
- if @issue.closed?
Closed
- else
Open
.status-box{ class: "status-box-closed #{issue_button_visibility(@issue, false)}"} Closed
.status-box{ class: "status-box-open #{issue_button_visibility(@issue, true)}"} Open
%span.identifier
Issue ##{@issue.iid}
%span.creator
......@@ -27,10 +27,8 @@
= icon('plus')
New Issue
- if can?(current_user, :update_issue, @issue)
- if @issue.closed?
= link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen'
- else
= link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close Issue'
= link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue'
= link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue'
= link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-nr btn-grouped issuable-edit' do
= icon('pencil-square-o')
......
......@@ -7,7 +7,7 @@
- if @merge_requests.present?
.issuable-filter-count
%span.pull-right
= @merge_requests.total_count
= number_with_delimiter(@merge_requests.total_count)
merge requests for this filter
= paginate @merge_requests, theme: "gitlab"
......
- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
= render "header_title"
- if params[:view] == 'parallel'
......
......@@ -6,9 +6,10 @@
.controls
= render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
- if can? current_user, :create_merge_request, @project
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project
.pull-left.hidden-xs
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new", title: "New Merge Request" do
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do
%i.fa.fa-plus
New Merge Request
= render 'shared/issuable/filter', type: :merge_requests
......
- page_title @milestone.title, "Milestones"
- page_title @milestone.title, "Milestones"
- page_description @milestone.description
= render "header_title"
.detail-page-header
......
......@@ -68,15 +68,4 @@
= render 'projects/last_commit', commit: @repository.commit, project: @project
%div{class: "project-show-#{default_project_view}"}
= render default_project_view
- if current_user
- access = user_max_access_in_project(current_user.id, @project)
- if access
.prepend-top-20.project-footer
.gray-content-block.footer-block.center
You have #{access} access to this project.
- if @project.project_member_by_id(current_user)
= link_to leave_namespace_project_project_members_path(@project.namespace, @project),
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project', class: 'cred' do
Leave this project
= render default_project_view
\ No newline at end of file
......@@ -5,13 +5,13 @@
<g id="Fill-1-+-Group-24">
<g id="Group-24">
<g id="Group">
<path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
<path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
<path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
<path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
<path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
<path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
<path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
<path id="tanuki-right-ear" d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
<path id="tanuki-right-cheek" d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
<path id="tanuki-right-eye" d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
<path id="tanuki-nose" d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" fill="#E24329" class="tanuki-shape"></path>
<path id="tanuki-left-eye" d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
<path id="tanuki-left-cheek" d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
<path id="tanuki-left-ear" d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
</g>
</g>
</g>
......
......@@ -29,14 +29,14 @@
= check_box_tag "check_all_issues", nil, false,
class: "check_all_issues left"
.issues-other-filters
.filter-item.inline
= users_select_tag(:assignee_id, selected: params[:assignee_id],
placeholder: 'Assignee', class: 'trigger-submit', any_user: "Any Assignee", null_user: true, first_user: true, current_user: true)
.filter-item.inline
= users_select_tag(:author_id, selected: params[:author_id],
placeholder: 'Author', class: 'trigger-submit', any_user: "Any Author", first_user: true, current_user: true)
.filter-item.inline
= users_select_tag(:assignee_id, selected: params[:assignee_id],
placeholder: 'Assignee', class: 'trigger-submit', any_user: "Any Assignee", null_user: true, first_user: true, current_user: true)
.filter-item.inline.milestone-filter
= select_tag('milestone_title', projects_milestones_options,
class: 'select2 trigger-submit', include_blank: true,
......
......@@ -5,7 +5,7 @@
- css_class = '' unless local_assigns[:css_class]
- css_class += " no-description" unless project.description.present?
%li.project-row{ class: css_class }
= cache [project.namespace, project, controller.controller_name, controller.action_name, 'v2.2'] do
= cache [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] do
= link_to project_path(project), class: dom_class(project) do
- if avatar
.dash-project-avatar
......
- page_title @user.name
- header_title @user.name, user_path(@user)
- page_title @user.name
- page_description @user.bio
- header_title @user.name, user_path(@user)
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
......
.awards.votes-block
- votable.notes.awards.grouped_awards.each do |emoji, notes|
- awards_sort(votable.notes.awards.grouped_awards).each do |emoji, notes|
.award{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user)}
= emoji_icon(emoji)
.counter
......
<%= ENV['RAILS_ENV'] %>:
adapter: <%= ENV['GITLAB_DATABASE_ADAPTER'] || 'postgresql' %>
encoding: <%= ENV['GITLAB_DATABASE_ENCODING'] || 'unicode' %>
database: <%= ENV['GITLAB_DATABASE_DATABASE'] || "gitlab_#{ENV['RAILS_ENV']}" %>
pool: <%= ENV['GITLAB_DATABASE_POOL'] || '10' %>
username: <%= ENV['GITLAB_DATABASE_USERNAME'] || 'root' %>
password: <%= ENV['GITLAB_DATABASE_PASSWORD'] || '' %>
host: <%= ENV['GITLAB_DATABASE_HOST'] || 'localhost' %>
port: <%= ENV['GITLAB_DATABASE_PORT'] || '5432' %>
......@@ -4,8 +4,8 @@
#
########################### NOTE #####################################
# This file should not receive new settings. All configuration options #
# that do not require an application restart are being moved to #
# ApplicationSetting model! #
# * are being moved to ApplicationSetting model! #
# If a setting requires an application restart say so in that screen. #
# If you change this file in a Merge Request, please also create #
# a MR on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests #
########################################################################
......
......@@ -131,6 +131,7 @@ Settings.omniauth.cas3['session_duration'] ||= 8.hours
Settings.omniauth['session_tickets'] ||= Settingslogic.new({})
Settings.omniauth.session_tickets['cas3'] = 'ticket'
Settings['shared'] ||= Settingslogic.new({})
Settings.shared['path'] = File.expand_path(Settings.shared['path'] || "shared", Rails.root)
......@@ -144,16 +145,16 @@ Settings.gitlab['default_projects_limit'] ||= 10
Settings.gitlab['default_branch_protection'] ||= 2
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
Settings.gitlab['default_theme'] = Gitlab::Themes::APPLICATION_DEFAULT if Settings.gitlab['default_theme'].nil?
Settings.gitlab['host'] ||= 'localhost'
Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost'
Settings.gitlab['ssh_host'] ||= Settings.gitlab.host
Settings.gitlab['https'] = false if Settings.gitlab['https'].nil?
Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80
Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || ''
Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil?
Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}"
Settings.gitlab['email_display_name'] ||= "GitLab"
Settings.gitlab['email_reply_to'] ||= "noreply@#{Settings.gitlab.host}"
Settings.gitlab['email_from'] ||= ENV['GITLAB_EMAIL_FROM'] || "gitlab@#{Settings.gitlab.host}"
Settings.gitlab['email_display_name'] ||= ENV['GITLAB_EMAIL_DISPLAY_NAME'] || 'GitLab'
Settings.gitlab['email_reply_to'] ||= ENV['GITLAB_EMAIL_REPLY_TO'] || "noreply@#{Settings.gitlab.host}"
Settings.gitlab['base_url'] ||= Settings.send(:build_base_gitlab_url)
Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url)
Settings.gitlab['user'] ||= 'git'
......
if Gitlab::Metrics.enabled?
require 'influxdb'
require 'connection_pool'
require 'method_source'
# These are manually require'd so the classes are registered properly with
# ActiveSupport.
require 'gitlab/metrics/subscribers/action_view'
require 'gitlab/metrics/subscribers/active_record'
Gitlab::Application.configure do |config|
config.middleware.use(Gitlab::Metrics::RackMiddleware)
end
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add Gitlab::Metrics::SidekiqMiddleware
end
end
# This instruments all methods residing in app/models that (appear to) use any
# of the ActiveRecord methods. This has to take place _after_ initializing as
# for some unknown reason calling eager_load! earlier breaks Devise.
Gitlab::Application.config.after_initialize do
Rails.application.eager_load!
models = Rails.root.join('app', 'models').to_s
regex = Regexp.union(
ActiveRecord::Querying.public_instance_methods(false).map(&:to_s)
)
Gitlab::Metrics::Instrumentation.
instrument_class_hierarchy(ActiveRecord::Base) do |klass, method|
# Instrumenting the ApplicationSetting class can lead to an infinite
# loop. Since the data is cached any way we don't really need to
# instrument it.
if klass == ApplicationSetting
false
else
loc = method.source_location
loc && loc[0].start_with?(models) && method.source =~ regex
end
end
end
Gitlab::Metrics::Instrumentation.configure do |config|
config.instrument_instance_methods(Gitlab::Shell)
config.instrument_methods(Gitlab::Git)
Gitlab::Git.constants.each do |name|
const = Gitlab::Git.const_get(name)
config.instrument_methods(const) if const.is_a?(Module)
end
end
GC::Profiler.enable
Gitlab::Metrics::Sampler.new.start
end
# Use this file to easily define all of your cron jobs.
#
# If you make changes to this file, please create also an issue on
# https://gitlab.com/gitlab-org/omnibus-gitlab/issues . This is necessary
# because the omnibus packages manage cron jobs using Chef instead of Whenever.
every 1.hour do
rake "ci:schedule_builds"
end
# Migration type: online
class RemovePublicFromNamespace < ActiveRecord::Migration
def change
remove_column :namespaces, :public, :boolean
end
end
class InfluxdbSettings < ActiveRecord::Migration
def change
add_column :application_settings, :metrics_enabled, :boolean, default: false
add_column :application_settings, :metrics_host, :string,
default: 'localhost'
add_column :application_settings, :metrics_database, :string,
default: 'gitlab'
add_column :application_settings, :metrics_username, :string
add_column :application_settings, :metrics_password, :string
add_column :application_settings, :metrics_pool_size, :integer, default: 16
add_column :application_settings, :metrics_timeout, :integer, default: 10
add_column :application_settings, :metrics_method_call_threshold,
:integer, default: 10
end
end
class AddRecaptchaToApplicationSettings < ActiveRecord::Migration
def change
change_table :application_settings do |t|
t.boolean :recaptcha_enabled, default: false
t.string :recaptcha_site_key
t.string :recaptcha_private_key
end
end
end
class InfluxdbUdpPortSetting < ActiveRecord::Migration
def change
add_column :application_settings, :metrics_port, :integer, default: 8089
end
end
class InfluxdbRemoteDatabaseSetting < ActiveRecord::Migration
def change
remove_column :application_settings, :metrics_database
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment