Commit cae84aa2 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into category-search-dropdown

parents 57ec290f 53498e42
This diff is collapsed.
...@@ -2,10 +2,14 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,10 +2,14 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.9.0 (unreleased) v 8.9.0 (unreleased)
- Bulk assign/unassign labels to issues. - Bulk assign/unassign labels to issues.
- Ability to prioritize labels !4009 / !3205 (Thijs Wouters)
- Fix endless redirections when accessing user OAuth applications when they are disabled
- Allow enabling wiki page events from Webhook management UI - Allow enabling wiki page events from Webhook management UI
- Bump rouge to 1.11.0
- Make EmailsOnPushWorker use Sidekiq mailers queue - Make EmailsOnPushWorker use Sidekiq mailers queue
- Fix wiki page events' webhook to point to the wiki repository - Fix wiki page events' webhook to point to the wiki repository
- Fix issue todo not remove when leave project !4150 (Long Nguyen) - Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Bump recaptcha gem to 3.0.0 to remove deprecated stoken support
- Allow forking projects with restricted visibility level - Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API - Improve note validation to prevent errors when creating invalid note via API
- Reduce number of fog gem dependencies - Reduce number of fog gem dependencies
...@@ -14,7 +18,9 @@ v 8.9.0 (unreleased) ...@@ -14,7 +18,9 @@ v 8.9.0 (unreleased)
- Redesign navigation for project pages - Redesign navigation for project pages
- Fix groups API to list only user's accessible projects - Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails - Redesign account and email confirmation emails
- Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0 - Use gitlab-shell v3.0.0
- Use Knapsack to evenly distribute tests across multiple nodes
- Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged - Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged
- Don't allow MRs to be merged when commits were added since the last review / page load - Don't allow MRs to be merged when commits were added since the last review / page load
- Add DB index on users.state - Add DB index on users.state
...@@ -33,7 +39,9 @@ v 8.9.0 (unreleased) ...@@ -33,7 +39,9 @@ v 8.9.0 (unreleased)
- Make authentication service for Container Registry to be compatible with < Docker 1.11 - Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min) - Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav - Cache assigned issue and merge request counts in sidebar nav
- Use Knapsack only in CI environment
- Cache project build count in sidebar nav - Cache project build count in sidebar nav
- Fix markdown_spec to use before instead of before(:all) to properly cleanup database after testing
- Reduce number of queries needed to render issue labels in the sidebar - Reduce number of queries needed to render issue labels in the sidebar
- Improve error handling importing projects - Improve error handling importing projects
- Remove duplicated notification settings - Remove duplicated notification settings
...@@ -41,6 +49,7 @@ v 8.9.0 (unreleased) ...@@ -41,6 +49,7 @@ v 8.9.0 (unreleased)
- Replace Colorize with Rainbow for coloring console output in Rake tasks. - Replace Colorize with Rainbow for coloring console output in Rake tasks.
- An indicator is now displayed at the top of the comment field for confidential issues. - An indicator is now displayed at the top of the comment field for confidential issues.
- Show categorised search queries in the search autocomplete - Show categorised search queries in the search autocomplete
- RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented
v 8.8.4 (unreleased) v 8.8.4 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds - Ensure branch cleanup regardless of whether the GitHub import process succeeds
...@@ -49,6 +58,10 @@ v 8.8.4 (unreleased) ...@@ -49,6 +58,10 @@ v 8.8.4 (unreleased)
- Reduce number of SQL queries when rendering user references - Reduce number of SQL queries when rendering user references
- Upgrade to jQuery 2 - Upgrade to jQuery 2
- Remove prev/next buttons on issues and merge requests - Remove prev/next buttons on issues and merge requests
- Import GitHub repositories respecting the API rate limit
- Fix importer for GitHub comments on diff
- Disable Webhooks before proceeding with the GitHub import
- Added descriptions to notification settings dropdown
v 8.8.3 v 8.8.3
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312 - Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
...@@ -169,6 +182,7 @@ v 8.7.6 ...@@ -169,6 +182,7 @@ v 8.7.6
- Fix import from GitLab.com to a private instance failure. !4181 - Fix import from GitLab.com to a private instance failure. !4181
- Fix external imports not finding the import data. !4106 - Fix external imports not finding the import data. !4106
- Fix notification delay when changing status of an issue - Fix notification delay when changing status of an issue
- Bump Workhorse to 0.7.5 so it can serve raw diffs
v 8.7.5 v 8.7.5
- Fix relative links in wiki pages. !4050 - Fix relative links in wiki pages. !4050
......
...@@ -405,6 +405,7 @@ description area. Copy-paste it to retain the markdown format. ...@@ -405,6 +405,7 @@ description area. Copy-paste it to retain the markdown format.
entire line to follow it. This prevents linting tools from generating warnings. entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass - Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant. refactoring modifications may leave style non-compliant.
1. If the merge request adds any new libraries (gems, JavaScript libraries, etc.), they should conform to our [Licensing guidelines][license-finder-doc]. See the instructions in that document for help if your MR fails the "license-finder" test with a "Dependencies that need approval" error.
## Changes for Stable Releases ## Changes for Stable Releases
...@@ -531,3 +532,4 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -531,3 +532,4 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design [gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12 [free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/ [`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[license-finder-doc]: doc/development/licensing.md
...@@ -38,7 +38,7 @@ gem 'rack-oauth2', '~> 1.2.1' ...@@ -38,7 +38,7 @@ gem 'rack-oauth2', '~> 1.2.1'
gem 'jwt' gem 'jwt'
# Spam and anti-bot protection # Spam and anti-bot protection
gem 'recaptcha', require: 'recaptcha/rails' gem 'recaptcha', '~> 3.0', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0' gem 'akismet', '~> 2.0'
# Two-factor authentication # Two-factor authentication
...@@ -86,6 +86,7 @@ gem 'dropzonejs-rails', '~> 0.7.1' ...@@ -86,6 +86,7 @@ gem 'dropzonejs-rails', '~> 0.7.1'
# for backups # for backups
gem 'fog-aws', '~> 0.9' gem 'fog-aws', '~> 0.9'
gem 'fog-azure', '~> 0.0'
gem 'fog-core', '~> 1.40' gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3' gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3' gem 'fog-google', '~> 0.3'
...@@ -111,7 +112,7 @@ gem 'org-ruby', '~> 0.9.12' ...@@ -111,7 +112,7 @@ gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0' gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1' gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2' gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1' gem 'rouge', '~> 1.11'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
...@@ -306,6 +307,9 @@ group :development, :test do ...@@ -306,6 +307,9 @@ group :development, :test do
gem 'bundler-audit', require: false gem 'bundler-audit', require: false
gem 'benchmark-ips', require: false gem 'benchmark-ips', require: false
gem "license_finder", require: false
gem 'knapsack'
end end
group :test do group :test do
......
...@@ -70,6 +70,21 @@ GEM ...@@ -70,6 +70,21 @@ GEM
descendants_tracker (~> 0.0.4) descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0) ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
azure (0.7.5)
addressable (~> 2.3)
azure-core (~> 0.1)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
json (~> 1.8)
mime-types (>= 1, < 3.0)
nokogiri (~> 1.6)
systemu (~> 2.6)
thor (~> 0.19)
uuid (~> 2.0)
azure-core (0.1.2)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6)
babosa (1.0.2) babosa (1.0.2)
base32 (0.3.2) base32 (0.3.2)
bcrypt (3.1.11) bcrypt (3.1.11)
...@@ -213,6 +228,11 @@ GEM ...@@ -213,6 +228,11 @@ GEM
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
ipaddress (~> 0.8) ipaddress (~> 0.8)
fog-azure (0.0.2)
azure (~> 0.6)
fog-core (~> 1.27)
fog-json (~> 1.0)
fog-xml (~> 0.1)
fog-core (1.40.0) fog-core (1.40.0)
builder builder
excon (~> 0.49) excon (~> 0.49)
...@@ -358,6 +378,9 @@ GEM ...@@ -358,6 +378,9 @@ GEM
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
kgio (2.10.0) kgio (2.10.0)
knapsack (1.11.0)
rake
timecop (>= 0.1.0)
launchy (2.4.3) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.4.1) letter_opener (1.4.1)
...@@ -366,6 +389,12 @@ GEM ...@@ -366,6 +389,12 @@ GEM
actionmailer (>= 3.2) actionmailer (>= 3.2)
letter_opener (~> 1.0) letter_opener (~> 1.0)
railties (>= 3.2) railties (>= 3.2)
license_finder (2.1.0)
bundler
httparty
rubyzip
thor
xml-simple
licensee (8.0.0) licensee (8.0.0)
rugged (>= 0.24b) rugged (>= 0.24b)
listen (3.0.5) listen (3.0.5)
...@@ -381,7 +410,7 @@ GEM ...@@ -381,7 +410,7 @@ GEM
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.1) mime-types (2.99.1)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile2 (2.0.0) mini_portile2 (2.1.0)
minitest (5.7.0) minitest (5.7.0)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.11.2) multi_json (1.11.2)
...@@ -392,8 +421,9 @@ GEM ...@@ -392,8 +421,9 @@ GEM
net-ldap (0.12.1) net-ldap (0.12.1)
net-ssh (3.0.1) net-ssh (3.0.1)
newrelic_rpm (3.14.1.311) newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2) nokogiri (1.6.8)
mini_portile2 (~> 2.0.0.rc2) mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
oauth (0.4.7) oauth (0.4.7)
oauth2 (1.0.0) oauth2 (1.0.0)
faraday (>= 0.8, < 0.10) faraday (>= 0.8, < 0.10)
...@@ -465,6 +495,7 @@ GEM ...@@ -465,6 +495,7 @@ GEM
parser (2.3.1.0) parser (2.3.1.0)
ast (~> 2.2) ast (~> 2.2)
pg (0.18.4) pg (0.18.4)
pkg-config (1.1.7)
poltergeist (1.9.0) poltergeist (1.9.0)
capybara (~> 2.1) capybara (~> 2.1)
cliver (~> 0.3.1) cliver (~> 0.3.1)
...@@ -540,7 +571,7 @@ GEM ...@@ -540,7 +571,7 @@ GEM
debugger-ruby_core_source (~> 1.3) debugger-ruby_core_source (~> 1.3)
rdoc (3.12.2) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
recaptcha (1.0.2) recaptcha (3.0.0)
json json
redcarpet (3.3.3) redcarpet (3.3.3)
redis (3.3.0) redis (3.3.0)
...@@ -569,7 +600,7 @@ GEM ...@@ -569,7 +600,7 @@ GEM
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
rinku (1.7.3) rinku (1.7.3)
rotp (2.1.2) rotp (2.1.2)
rouge (1.10.1) rouge (1.11.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
...@@ -618,6 +649,7 @@ GEM ...@@ -618,6 +649,7 @@ GEM
sexp_processor (~> 4.1) sexp_processor (~> 4.1)
rubyntlm (0.5.2) rubyntlm (0.5.2)
rubypants (0.2.0) rubypants (0.2.0)
rubyzip (1.2.0)
rufus-scheduler (3.1.10) rufus-scheduler (3.1.10)
rugged (0.24.0) rugged (0.24.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
...@@ -728,6 +760,7 @@ GEM ...@@ -728,6 +760,7 @@ GEM
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (2.0.2) tilt (2.0.2)
timecop (0.8.1)
timfel-krb5-auth (0.8.3) timfel-krb5-auth (0.8.3)
tinder (1.10.1) tinder (1.10.1)
eventmachine (~> 1.0) eventmachine (~> 1.0)
...@@ -789,6 +822,7 @@ GEM ...@@ -789,6 +822,7 @@ GEM
builder builder
expression_parser expression_parser
rinku rinku
xml-simple (1.1.5)
xpath (2.0.0) xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
...@@ -842,6 +876,7 @@ DEPENDENCIES ...@@ -842,6 +876,7 @@ DEPENDENCIES
flay flay
flog flog
fog-aws (~> 0.9) fog-aws (~> 0.9)
fog-azure (~> 0.0)
fog-core (~> 1.40) fog-core (~> 1.40)
fog-google (~> 0.3) fog-google (~> 0.3)
fog-local (~> 0.3) fog-local (~> 0.3)
...@@ -874,7 +909,9 @@ DEPENDENCIES ...@@ -874,7 +909,9 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0) jquery-ui-rails (~> 5.0.0)
jwt jwt
kaminari (~> 0.17.0) kaminari (~> 0.17.0)
knapsack
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.0)
license_finder
licensee (~> 8.0.0) licensee (~> 8.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.7) mail_room (~> 0.7)
...@@ -918,7 +955,7 @@ DEPENDENCIES ...@@ -918,7 +955,7 @@ DEPENDENCIES
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof rblineprof
rdoc (~> 3.6) rdoc (~> 3.6)
recaptcha recaptcha (~> 3.0)
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis (~> 3.2) redis (~> 3.2)
redis-namespace redis-namespace
...@@ -926,7 +963,7 @@ DEPENDENCIES ...@@ -926,7 +963,7 @@ DEPENDENCIES
request_store (~> 1.3.0) request_store (~> 1.3.0)
rerun (~> 0.11.0) rerun (~> 0.11.0)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 1.10.1) rouge (~> 1.11)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0) rspec-rails (~> 3.4.0)
rspec-retry rspec-retry
......
...@@ -8,3 +8,5 @@ relative_url_conf = File.expand_path('../config/initializers/relative_url', __FI ...@@ -8,3 +8,5 @@ relative_url_conf = File.expand_path('../config/initializers/relative_url', __FI
require relative_url_conf if File.exist?("#{relative_url_conf}.rb") require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
Gitlab::Application.load_tasks Gitlab::Application.load_tasks
Knapsack.load_tasks if defined?(Knapsack)
class @LabelManager
errorMessage: 'Unable to update label prioritization at this time'
constructor: (opts = {}) ->
# Defaults
{
@togglePriorityButton = $('.js-toggle-priority')
@prioritizedLabels = $('.js-prioritized-labels')
@otherLabels = $('.js-other-labels')
} = opts
@prioritizedLabels.sortable(
items: 'li'
placeholder: 'list-placeholder'
axis: 'y'
update: @onPrioritySortUpdate.bind(@)
)
@bindEvents()
bindEvents: ->
@togglePriorityButton.on 'click', @, @onTogglePriorityClick
onTogglePriorityClick: (e) ->
e.preventDefault()
_this = e.data
$btn = $(e.currentTarget)
$label = $("##{$btn.data('domId')}")
action = if $btn.parents('.js-prioritized-labels').length then 'remove' else 'add'
_this.toggleLabelPriority($label, action)
toggleLabelPriority: ($label, action, persistState = true) ->
_this = @
url = $label.find('.js-toggle-priority').data 'url'
$target = @prioritizedLabels
$from = @otherLabels
# Optimistic update
if action is 'remove'
$target = @otherLabels
$from = @prioritizedLabels
if $from.find('li').length is 1
$from.find('.empty-message').show()
if not $target.find('li').length
$target.find('.empty-message').hide()
$label.detach().appendTo($target)
# Return if we are not persisting state
return unless persistState
if action is 'remove'
xhr = $.ajax url: url, type: 'DELETE'
else
xhr = @savePrioritySort($label, action)
xhr.fail @rollbackLabelPosition.bind(@, $label, action)
onPrioritySortUpdate: ->
xhr = @savePrioritySort()
xhr.fail ->
new Flash(@errorMessage, 'alert')
savePrioritySort: () ->
$.post
url: @prioritizedLabels.data('url')
data:
label_ids: @getSortedLabelsIds()
rollbackLabelPosition: ($label, originalAction)->
action = if originalAction is 'remove' then 'add' else 'remove'
@toggleLabelPriority($label, action, false)
new Flash(@errorMessage, 'alert')
getSortedLabelsIds: ->
sortedIds = []
@prioritizedLabels.find('li').each ->
sortedIds.push $(@).data 'id'
sortedIds
...@@ -100,6 +100,8 @@ class Dispatcher ...@@ -100,6 +100,8 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:labels:new', 'projects:labels:edit' when 'projects:labels:new', 'projects:labels:edit'
new Labels() new Labels()
when 'projects:labels:index'
new LabelManager() if $('.prioritized-labels').length
when 'projects:network:show' when 'projects:network:show'
# Ensure we don't create a particular shortcut handler here. This is # Ensure we don't create a particular shortcut handler here. This is
# already created, where the network graph is created. # already created, where the network graph is created.
......
...@@ -211,6 +211,7 @@ class GitLabDropdown ...@@ -211,6 +211,7 @@ class GitLabDropdown
@dropdown.on "shown.bs.dropdown", @opened @dropdown.on "shown.bs.dropdown", @opened
@dropdown.on "hidden.bs.dropdown", @hidden @dropdown.on "hidden.bs.dropdown", @hidden
$(@el).on "update.label", @updateLabel
@dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate @dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate
@dropdown.on 'keyup', (e) => @dropdown.on 'keyup', (e) =>
if e.which is 27 # Escape key if e.which is 27 # Escape key
...@@ -453,7 +454,7 @@ class GitLabDropdown ...@@ -453,7 +454,7 @@ class GitLabDropdown
# Toggle the dropdown label # Toggle the dropdown label
if @options.toggleLabel if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel @updateLabel()
else else
selectedObject selectedObject
else if el.hasClass(INDETERMINATE_CLASS) else if el.hasClass(INDETERMINATE_CLASS)
...@@ -480,7 +481,7 @@ class GitLabDropdown ...@@ -480,7 +481,7 @@ class GitLabDropdown
# Toggle the dropdown label # Toggle the dropdown label
if @options.toggleLabel if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject, el) @updateLabel(selectedObject, el)
if value? if value?
if !field.length and fieldName if !field.length and fieldName
@addInput(fieldName, value) @addInput(fieldName, value)
...@@ -579,6 +580,9 @@ class GitLabDropdown ...@@ -579,6 +580,9 @@ class GitLabDropdown
# Scroll the dropdown content up # Scroll the dropdown content up
$dropdownContent.scrollTop(listItemTop - dropdownContentTop) $dropdownContent.scrollTop(listItemTop - dropdownContentTop)
updateLabel: (selected = null, el = null) =>
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selected, el)
$.fn.glDropdown = (opts) -> $.fn.glDropdown = (opts) ->
return @.each -> return @.each ->
if (!$.data @, 'glDropdown') if (!$.data @, 'glDropdown')
......
...@@ -6,12 +6,18 @@ issuable_created = false ...@@ -6,12 +6,18 @@ issuable_created = false
Issuable.initTemplates() Issuable.initTemplates()
Issuable.initSearch() Issuable.initSearch()
Issuable.initChecks() Issuable.initChecks()
Issuable.initLabelFilterRemove()
initTemplates: -> initTemplates: ->
Issuable.labelRow = _.template( Issuable.labelRow = _.template(
'<% _.each(labels, function(label){ %> '<% _.each(labels, function(label){ %>
<span class="label-row"> <span class="label-row btn-group" role="group" aria-label="<%= _.escape(label.title) %>" style="color: <%= label.text_color %>;">
<a href="#"><span class="label color-label has-tooltip" style="background-color: <%= label.color %>; color: <%= label.text_color %>" title="<%= _.escape(label.description) %>" data-container="body"><%= _.escape(label.title) %></span></a> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%= label.color %>;" title="<%= _.escape(label.description) %>" data-container="body">
<%= _.escape(label.title) %>
</a>
<button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%= label.color %>;" data-label="<%= _.escape(label.title) %>">
<i class="fa fa-times"></i>
</button>
</span> </span>
<% }); %>' <% }); %>'
) )
...@@ -35,6 +41,21 @@ issuable_created = false ...@@ -35,6 +41,21 @@ issuable_created = false
Issuable.filterResults $form Issuable.filterResults $form
, 500) , 500)
initLabelFilterRemove: ->
$(document)
.off 'click', '.js-label-filter-remove'
.on 'click', '.js-label-filter-remove', (e) ->
$button = $(@)
# Remove the label input box
$('input[name="label_name[]"]')
.filter -> @value is $button.data('label')
.remove()
# Submit the form to get new data
Issuable.filterResults $('.filter-form')
$('.js-label-select').trigger('update.label')
toggleLabelFilters: -> toggleLabelFilters: ->
$filteredLabels = $('.filtered-labels') $filteredLabels = $('.filtered-labels')
if $filteredLabels.find('.label-row').length > 0 if $filteredLabels.find('.label-row').length > 0
......
...@@ -61,6 +61,11 @@ ...@@ -61,6 +61,11 @@
margin-bottom: -$gl-padding; margin-bottom: -$gl-padding;
} }
&.content-component-block {
padding: 11px 0;
background-color: $white-light;
}
.title { .title {
color: $gl-text-color; color: $gl-text-color;
} }
......
...@@ -122,10 +122,8 @@ ...@@ -122,10 +122,8 @@
a { a {
display: block; display: block;
position: relative; position: relative;
padding-left: 10px; padding: 5px 10px;
padding-right: 10px;
color: $dropdown-link-color; color: $dropdown-link-color;
line-height: 34px;
text-overflow: ellipsis; text-overflow: ellipsis;
border-radius: 2px; border-radius: 2px;
white-space: nowrap; white-space: nowrap;
...@@ -162,6 +160,16 @@ ...@@ -162,6 +160,16 @@
} }
} }
.dropdown-menu-large {
width: 340px;
}
.dropdown-menu-no-wrap {
a {
white-space: normal;
}
}
.dropdown-menu-full-width { .dropdown-menu-full-width {
width: 100%; width: 100%;
} }
...@@ -236,8 +244,7 @@ ...@@ -236,8 +244,7 @@
&::before { &::before {
position: absolute; position: absolute;
left: 5px; left: 5px;
top: 50%; top: 8px;
margin-top: -7px;
font: normal normal normal 14px/1 FontAwesome; font: normal normal normal 14px/1 FontAwesome;
font-size: inherit; font-size: inherit;
text-rendering: auto; text-rendering: auto;
...@@ -532,3 +539,14 @@ ...@@ -532,3 +539,14 @@
background-color: $calendar-unselectable-bg; background-color: $calendar-unselectable-bg;
} }
} }
.dropdown-menu-inner-title {
display: block;
color: $gl-title-color;
font-weight: 600;
}
.dropdown-menu-inner-content {
display: block;
color: $gl-placeholder-color;
}
...@@ -89,8 +89,11 @@ ...@@ -89,8 +89,11 @@
} }
} }
$theme-blue: #2980b9;
$theme-charcoal: #3d454d; $theme-charcoal: #3d454d;
$theme-charcoal-dark: #383f45;
$theme-charcoal-text: #b9bbbe;
$theme-blue: #2980b9;
$theme-graphite: #666; $theme-graphite: #666;
$theme-gray: #373737; $theme-gray: #373737;
$theme-green: #019875; $theme-green: #019875;
...@@ -102,7 +105,7 @@ body { ...@@ -102,7 +105,7 @@ body {
} }
&.ui_charcoal { &.ui_charcoal {
@include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41); @include gitlab-theme($theme-charcoal-text, #485157, $theme-charcoal, $theme-charcoal-dark);
} }
&.ui_graphite { &.ui_graphite {
......
...@@ -79,6 +79,10 @@ header { ...@@ -79,6 +79,10 @@ header {
&.header-collapsed { &.header-collapsed {
padding: 0 16px; padding: 0 16px;
.side-nav-toggle {
display: block;
}
} }
.side-nav-toggle { .side-nav-toggle {
...@@ -86,6 +90,7 @@ header { ...@@ -86,6 +90,7 @@ header {
position: absolute; position: absolute;
left: -10px; left: -10px;
margin: 6px 0; margin: 6px 0;
font-size: 18px;
padding: 6px 10px; padding: 6px 10px;
border: none; border: none;
background-color: $background-color; background-color: $background-color;
...@@ -97,10 +102,6 @@ header { ...@@ -97,10 +102,6 @@ header {
&:focus { &:focus {
outline: none; outline: none;
} }
@media (max-width: $screen-xs-min) {
display: block;
}
} }
} }
...@@ -171,31 +172,21 @@ header { ...@@ -171,31 +172,21 @@ header {
} }
} }
@mixin collapsed-header {
margin-left: $sidebar_collapsed_width;
}
.header-collapsed { .header-collapsed {
margin-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
@include collapsed-header;
}
@media (max-width: $screen-xs-min) {
margin-left: 0; margin-left: 0;
.header-content {
padding-left: 30px;
transition-duration: .3s;
} }
} }
.header-expanded { .header-expanded {
margin-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
margin-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
margin-left: 0; margin-left: 0;
.header-content {
padding-left: $sidebar_width;
transition-duration: .3s;
} }
} }
......
...@@ -141,6 +141,18 @@ ul.content-list { ...@@ -141,6 +141,18 @@ ul.content-list {
padding: 10px 14px; padding: 10px 14px;
} }
} }
// When dragging a list item
&.ui-sortable-helper {
border-bottom: none;
}
&.list-placeholder {
background-color: $gray-light;
border: dotted 1px $gray-dark;
margin: 1px 0;
min-height: 30px;
}
} }
} }
......
...@@ -41,8 +41,7 @@ ...@@ -41,8 +41,7 @@
a { a {
display: inline-block; display: inline-block;
padding: 14px; padding: $gl-btn-padding;
padding-top: $gl-padding;
padding-bottom: 11px; padding-bottom: 11px;
margin-bottom: -1px; margin-bottom: -1px;
font-size: 15px; font-size: 15px;
...@@ -67,6 +66,27 @@ ...@@ -67,6 +66,27 @@
color: #78a; color: #78a;
} }
} }
&.sub-nav {
background-color: $background-color;
.container-fluid {
background-color: $background-color;
}
li {
a {
margin: 0;
padding: 11px 10px 9px;
}
&.active a {
border-bottom: none;
color: $link-underline-blue;
}
}
}
} }
.top-area { .top-area {
...@@ -81,6 +101,10 @@ ...@@ -81,6 +101,10 @@
width: 50%; width: 50%;
line-height: 28px; line-height: 28px;
&.wiki-page {
padding: 16px 10px 11px;
}
/* Small devices (phones, tablets, 768px and lower) */ /* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) { @media (max-width: $screen-sm-min) {
width: 100%; width: 100%;
...@@ -104,6 +128,10 @@ ...@@ -104,6 +128,10 @@
margin-bottom: 0; margin-bottom: 0;
border-bottom: none; border-bottom: none;
li a {
padding: 16px 10px 11px;
}
/* Small devices (phones, tablets, 768px and lower) */ /* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-max) { @media (max-width: $screen-sm-max) {
width: 100%; width: 100%;
...@@ -309,8 +337,8 @@ ...@@ -309,8 +337,8 @@
} }
.nav-control { .nav-control {
.fade-right {
.fade-right {
@media (min-width: $screen-xs-max) { @media (min-width: $screen-xs-max) {
right: 67px; right: 67px;
} }
...@@ -321,6 +349,24 @@ ...@@ -321,6 +349,24 @@
} }
} }
.scrolling-tabs-container {
position: relative;
.nav-links {
@include scrolling-links();
.fade-right {
@include fade(left, rgba(255, 255, 255, 0.4), $background-color);
right: 0;
}
.fade-left {
@include fade(right, rgba(255, 255, 255, 0.4), $background-color);
left: 0;
}
}
}
.nav-block { .nav-block {
position: relative; position: relative;
......
#logo {
z-index: 2;
position: absolute;
width: 58px;
cursor: pointer;
margin-top: 8px;
}
.page-with-sidebar { .page-with-sidebar {
padding-top: $header-height; padding-top: $header-height;
transition-duration: .3s; transition-duration: .3s;
...@@ -20,12 +12,6 @@ ...@@ -20,12 +12,6 @@
height: 100%; height: 100%;
transition-duration: .3s; transition-duration: .3s;
} }
.gitlab-text-container-link {
z-index: 1;
position: absolute;
left: 0;
}
} }
.sidebar-wrapper { .sidebar-wrapper {
...@@ -50,47 +36,8 @@ ...@@ -50,47 +36,8 @@
.sidebar-wrapper { .sidebar-wrapper {
.header-logo { .header-logo {
border-bottom: 1px solid transparent;
float: left;
height: $header-height; height: $header-height;
width: $sidebar_width; padding: 8px 26px;
position: fixed;
z-index: 999;
overflow: hidden;
transition-duration: .3s;
a {
float: left;
height: $header-height;
width: 100%;
padding-left: 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: 50px;
font-size: 19px;
line-height: 50px;
font-weight: normal;
}
}
}
&:hover { &:hover {
background-color: #eee; background-color: #eee;
...@@ -98,7 +45,7 @@ ...@@ -98,7 +45,7 @@
} }
.sidebar-user { .sidebar-user {
padding: 7px 22px; padding: 15px 22px;
position: fixed; position: fixed;
bottom: 40px; bottom: 40px;
width: $sidebar_width; width: $sidebar_width;
...@@ -126,8 +73,7 @@ ...@@ -126,8 +73,7 @@
.nav-sidebar { .nav-sidebar {
margin-top: 14 + $header-height; margin: 22px 0;
margin-bottom: 100px;
transition-duration: .3s; transition-duration: .3s;
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
...@@ -145,13 +91,12 @@ ...@@ -145,13 +91,12 @@
} }
a { a {
padding: 7px 15px; text-align: center;
padding: 8px;
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 24px;
color: $gray; color: $gray;
display: block; display: block;
text-decoration: none; text-decoration: none;
padding-left: 23px;
font-weight: normal; font-weight: normal;
outline: none; outline: none;
...@@ -166,14 +111,12 @@ ...@@ -166,14 +111,12 @@
i { i {
width: 16px; width: 16px;
color: $gray-light; color: $gray-light;
margin-right: 13px;
} }
.count { .nav-link-text {
float: right; margin-top: 3px;
background: #eee; font-size: 13px;
padding: 0 8px; line-height: 18px;
@include border-radius(6px);
} }
&.back-link i { &.back-link i {
...@@ -217,25 +160,13 @@ ...@@ -217,25 +160,13 @@
} }
.page-sidebar-collapsed { .page-sidebar-collapsed {
padding-left: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-left: 0; padding-left: 0;
}
.sidebar-wrapper { .sidebar-wrapper {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0; width: 0;
}
.header-logo { .header-logo {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0; width: 0;
}
a { a {
padding-left: ($sidebar_collapsed_width - 36) / 2; padding-left: ($sidebar_collapsed_width - 36) / 2;
...@@ -246,6 +177,10 @@ ...@@ -246,6 +177,10 @@
} }
} }
#logo {
display: none;
}
.nav-sidebar { .nav-sidebar {
width: $sidebar_collapsed_width; width: $sidebar_collapsed_width;
...@@ -261,44 +196,23 @@ ...@@ -261,44 +196,23 @@
} }
.collapse-nav a { .collapse-nav a {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0; width: 0;
} }
}
.sidebar-user { .sidebar-user {
padding-left: ($sidebar_collapsed_width - 36) / 2;
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0; width: 0;
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
}
.username { .username {
display: none; display: none;
} }
} }
} }
.layout-nav {
padding-right: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
}
} }
.page-sidebar-expanded { .page-sidebar-expanded {
padding-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
padding-left: $sidebar_width; padding-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) { @media (max-width: $screen-xs-min) {
padding-left: 0; padding-left: 0;
...@@ -328,7 +242,7 @@ ...@@ -328,7 +242,7 @@
} }
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) { @media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
padding-right: 62px; padding-right: 90px;
} }
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Layout * Layout
*/ */
$sidebar_collapsed_width: 62px; $sidebar_collapsed_width: 62px;
$sidebar_width: 220px; $sidebar_width: 90px;
$gutter_collapsed_width: 62px; $gutter_collapsed_width: 62px;
$gutter_width: 290px; $gutter_width: 290px;
$gutter_inner_width: 258px; $gutter_inner_width: 258px;
......
@import "framework/variables"; @import "framework/variables";
// This file is largely copied from `highlight/white.scss`, but modified to
// avoid all descendant selectors (`table td`). This is because the CSS inlining
// we use performs dramatically worse on descendant selectors than the
// alternatives.
// <https://gitlab.com/gitlab-org/gitlab-ee/issues/490#note_12283632>
//
// DO NOT ADD ANY DESCENDANT SELECTORS TO THIS FILE. Instead, use (in order of
// preference): plain class selectors, type (element name) selectors, or
// explicit child selectors.
table.code { table.code {
width: 100%; width: 100%;
font-family: monospace; font-family: monospace;
...@@ -11,33 +21,162 @@ table.code { ...@@ -11,33 +21,162 @@ table.code {
-premailer-cellspacing: 0; -premailer-cellspacing: 0;
-premailer-width: 100%; -premailer-width: 100%;
td { > tr > td {
line-height: $code_line_height; line-height: $code_line_height;
font-family: monospace; font-family: monospace;
font-size: $code_font_size; font-size: $code_font_size;
}
td.diff-line-num { &.diff-line-num {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: none; border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0 5px; padding: 0 5px;
border-right: 1px solid $border-color; border-right: 1px solid;
text-align: right; text-align: right;
min-width: 35px; min-width: 35px;
max-width: 50px; max-width: 50px;
width: 35px; width: 35px;
} }
td.line_content { &.line_content {
display: block; display: block;
margin: 0; margin: 0;
padding: 0 0.5em; padding: 0 0.5em;
border: none; border: none;
white-space: pre; white-space: pre;
} }
}
}
.line-numbers, .diff-line-num {
background-color: $background-color;
}
.diff-line-num, .diff-line-num a {
color: $black-transparent;
}
pre.code, .diff-line-num {
border-color: $table-border-gray;
}
.code.white, pre.code, .line_content {
background-color: #fff;
color: #333;
}
.diff-line-num {
&.old {
background-color: $line-number-old;
border-color: $line-removed-dark;
}
&.new {
background-color: $line-number-new;
border-color: $line-added-dark;
}
&.hll:not(.empty-cell) {
background-color: $line-number-select;
border-color: $line-select-yellow-dark;
}
}
.line_content {
&.old {
background-color: $line-removed;
> .line > span.idiff, > .line > span > span.idiff {
background-color: $line-removed-dark;
}
}
&.new {
background-color: $line-added;
> .line > span.idiff, > .line > span > span.idiff {
background-color: $line-added-dark;
}
}
&.match {
color: $black-transparent;
background-color: $match-line;
}
&.hll:not(.empty-cell) {
background-color: $line-select-yellow;
}
}
pre > .hll {
background-color: #f8eec7 !important;
}
span.highlight_word {
background-color: #fafe3d !important;
} }
@import "highlight/white"; .hll { background-color: #f8f8f8 }
.c { color: #998; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; }
.o { font-weight: bold; }
.cm { color: #998; font-style: italic; }
.cp { color: #999; font-weight: bold; }
.c1 { color: #998; font-style: italic; }
.cs { color: #999; font-weight: bold; font-style: italic; }
.gd { color: #000; background-color: #fdd; }
.gd .x { color: #000; background-color: #faa; }
.ge { font-style: italic; }
.gr { color: #a00; }
.gh { color: #999; }
.gi { color: #000; background-color: #dfd; }
.gi .x { color: #000; background-color: #afa; }
.go { color: #888; }
.gp { color: #555; }
.gs { font-weight: bold; }
.gu { color: #800080; font-weight: bold; }
.gt { color: #a00; }
.kc { font-weight: bold; }
.kd { font-weight: bold; }
.kn { font-weight: bold; }
.kp { font-weight: bold; }
.kr { font-weight: bold; }
.kt { color: #458; font-weight: bold; }
.m { color: #099; }
.s { color: #d14; }
.n { color: #333; }
.na { color: teal; }
.nb { color: #0086b3; }
.nc { color: #458; font-weight: bold; }
.no { color: teal; }
.ni { color: purple; }
.ne { color: #900; font-weight: bold; }
.nf { color: #900; font-weight: bold; }
.nn { color: #555; }
.nt { color: navy; }
.nv { color: teal; }
.ow { font-weight: bold; }
.w { color: #bbb; }
.mf { color: #099; }
.mh { color: #099; }
.mi { color: #099; }
.mo { color: #099; }
.sb { color: #d14; }
.sc { color: #d14; }
.sd { color: #d14; }
.s2 { color: #d14; }
.se { color: #d14; }
.sh { color: #d14; }
.si { color: #d14; }
.sx { color: #d14; }
.sr { color: #009926; }
.s1 { color: #d14; }
.ss { color: #990073; }
.bp { color: #999; }
.vc { color: teal; }
.vg { color: teal; }
.vi { color: teal; }
.il { color: #099; }
.gc { color: #999; background-color: #eaf2f5; }
...@@ -6,19 +6,19 @@ p.details { ...@@ -6,19 +6,19 @@ p.details {
font-style: italic; font-style: italic;
color: #777 color: #777
} }
.footer p { .footer > p {
font-size: small; font-size: small;
color: #777 color: #777
} }
pre.commit-message { pre.commit-message {
white-space: pre-wrap; white-space: pre-wrap;
} }
.file-stats a { .file-stats > a {
text-decoration: none; text-decoration: none;
} > .new-file {
.file-stats .new-file {
color: #090; color: #090;
} }
.file-stats .deleted-file { > .deleted-file {
color: #b00; color: #b00;
}
} }
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
.label-row { .label-row {
.label-name { .label-name {
display: inline-block; display: inline-block;
width: 200px; width: 170px;
@media (max-width: $screen-xs-min) { @media (max-width: $screen-xs-min) {
display: block; display: block;
...@@ -138,3 +138,51 @@ ...@@ -138,3 +138,51 @@
} }
} }
} }
.prioritized-labels {
margin-bottom: 30px;
.add-priority {
display: none;
color: $gray-light;
}
}
.other-labels {
.remove-priority {
display: none;
}
}
.toggle-priority {
display: inline-block;
vertical-align: middle;
button {
border-color: transparent;
padding: 5px 8px;
vertical-align: top;
font-size: 14px;
&:hover {
border-color: transparent;
}
}
}
.filtered-labels {
.label-row {
&:not(:last-child) {
margin-right: 5px;
}
}
.label-remove {
border-left: 1px solid rgba(0, 0, 0, .1);
z-index: 3;
}
.btn {
color: inherit;
}
}
...@@ -79,11 +79,14 @@ ...@@ -79,11 +79,14 @@
} }
&.ci-failed, &.ci-failed,
&.ci-canceled,
&.ci-error { &.ci-error {
color: $gl-danger; color: $gl-danger;
} }
&.ci-canceled {
color: $gl-gray;
}
a.monospace { a.monospace {
color: inherit; color: inherit;
} }
......
...@@ -32,6 +32,15 @@ ...@@ -32,6 +32,15 @@
.container-fluid { .container-fluid {
position: relative; position: relative;
@media (min-width: $screen-md-max) {
.row {
display: flex;
-ms-flex-align: center;
-webkit-align-items: center;
-webkit-box-align: center;
}
}
} }
.cover-controls { .cover-controls {
...@@ -57,7 +66,6 @@ ...@@ -57,7 +66,6 @@
max-width: 86px; max-width: 86px;
min-width: 86px; min-width: 86px;
padding-right: 0; padding-right: 0;
margin: 11px 0;
@media (max-width: $screen-md-max) { @media (max-width: $screen-md-max) {
padding-left: 0; padding-left: 0;
...@@ -489,9 +497,11 @@ pre.light-well { ...@@ -489,9 +497,11 @@ pre.light-well {
margin: 0; margin: 0;
} }
.project-show-activity {
.activity-filter-block { .activity-filter-block {
margin-top: -1px; .controls {
padding-bottom: 10px;
border-bottom: 1px solid $border-color;
} }
} }
......
...@@ -42,46 +42,8 @@ class JwtController < ApplicationController ...@@ -42,46 +42,8 @@ class JwtController < ApplicationController
end end
def authenticate_user(login, password) def authenticate_user(login, password)
# TODO: this is a copy and paste from grack_auth, user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password)
# it should be refactored in the future Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login)
user = Gitlab::Auth.new.find(login, password)
# If the user authenticated successfully, we reset the auth failure count
# from Rack::Attack for that IP. A client may attempt to authenticate
# with a username and blank password first, and only after it receives
# a 401 error does it present a password. Resetting the count prevents
# false positives from occurring.
#
# Otherwise, we let Rack::Attack know there was a failed authentication
# attempt from this IP. This information is stored in the Rails cache
# (Redis) and will be used by the Rack::Attack middleware to decide
# whether to block requests from this IP.
config = Gitlab.config.rack_attack.git_basic_auth
if config.enabled
if user
# A successful login will reset the auth failure count from this IP
Rack::Attack::Allow2Ban.reset(request.ip, config)
else
banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
# Unless the IP is whitelisted, return true so that Allow2Ban
# increments the counter (stored in Rails.cache) for the IP
if config.ip_whitelist.include?(request.ip)
false
else
true
end
end
if banned
Rails.logger.info "IP #{request.ip} failed to login " \
"as #{login} but has been temporarily banned from Git auth"
return
end
end
end
user user
end end
end end
...@@ -32,7 +32,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController ...@@ -32,7 +32,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
def verify_user_oauth_applications_enabled def verify_user_oauth_applications_enabled
return if current_application_settings.user_oauth_applications? return if current_application_settings.user_oauth_applications?
redirect_to applications_profile_url redirect_to profile_path
end end
def set_index_vars def set_index_vars
......
...@@ -26,9 +26,9 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -26,9 +26,9 @@ class Projects::BuildsController < Projects::ApplicationController
end end
def show def show
@builds = @project.ci_commits.find_by_sha(@build.sha).builds.order('id DESC') @builds = @project.pipelines.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id) @builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit @pipeline = @build.pipeline
respond_to do |format| respond_to do |format|
format.html format.html
......
...@@ -99,12 +99,12 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -99,12 +99,12 @@ class Projects::CommitController < Projects::ApplicationController
@commit ||= @project.commit(params[:id]) @commit ||= @project.commit(params[:id])
end end
def ci_commits def pipelines
@ci_commits ||= project.ci_commits.where(sha: commit.sha) @pipelines ||= project.pipelines.where(sha: commit.sha)
end end
def ci_builds def ci_builds
@ci_builds ||= Ci::Build.where(commit: ci_commits) @ci_builds ||= Ci::Build.where(pipeline: pipelines)
end end
def define_show_vars def define_show_vars
...@@ -117,8 +117,8 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -117,8 +117,8 @@ class Projects::CommitController < Projects::ApplicationController
@diff_refs = [commit.parent || commit, commit] @diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count @notes_count = commit.notes.count
@statuses = CommitStatus.where(commit: ci_commits) @statuses = CommitStatus.where(pipeline: pipelines)
@builds = Ci::Build.where(commit: ci_commits) @builds = Ci::Build.where(pipeline: pipelines)
end end
def assign_change_commit_vars(mr_source_branch) def assign_change_commit_vars(mr_source_branch)
......
class Projects::GitHttpController < Projects::ApplicationController
attr_reader :user
skip_before_action :repository
before_action :authenticate_user
before_action :ensure_project_found!
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs
if upload_pack? && upload_pack_allowed?
render_ok
elsif receive_pack? && receive_pack_allowed?
render_ok
else
render_not_found
end
end
# POST /foo/bar.git/git-upload-pack (git pull)
def git_upload_pack
if upload_pack? && upload_pack_allowed?
render_ok
else
render_not_found
end
end
# POST /foo/bar.git/git-receive-pack" (git push)
def git_receive_pack
if receive_pack? && receive_pack_allowed?
render_ok
else
render_not_found
end
end
private
def authenticate_user
return if project && project.public? && upload_pack?
authenticate_or_request_with_http_basic do |login, password|
auth_result = Gitlab::Auth.find(login, password, project: project, ip: request.ip)
if auth_result.type == :ci && upload_pack?
@ci = true
elsif auth_result.type == :oauth && !upload_pack?
# Not allowed
else
@user = auth_result.user
end
ci? || user
end
end
def ensure_project_found!
render_not_found if project.blank?
end
def project
return @project if defined?(@project)
project_id, _ = project_id_with_suffix
if project_id.blank?
@project = nil
else
@project = Project.find_with_namespace("#{params[:namespace_id]}/#{project_id}")
end
end
# This method returns two values so that we can parse
# params[:project_id] (untrusted input!) in exactly one place.
def project_id_with_suffix
id = params[:project_id] || ''
%w[.wiki.git .git].each do |suffix|
if id.end_with?(suffix)
# Be careful to only remove the suffix from the end of 'id'.
# Accidentally removing it from the middle is how security
# vulnerabilities happen!
return [id.slice(0, id.length - suffix.length), suffix]
end
end
# Something is wrong with params[:project_id]; do not pass it on.
[nil, nil]
end
def upload_pack?
git_command == 'git-upload-pack'
end
def receive_pack?
git_command == 'git-receive-pack'
end
def git_command
if action_name == 'info_refs'
params[:service]
else
action_name.dasherize
end
end
def render_ok
render json: Gitlab::Workhorse.git_http_ok(repository, user)
end
def repository
_, suffix = project_id_with_suffix
if suffix == '.wiki.git'
project.wiki.repository
else
project.repository
end
end
def render_not_found
render text: 'Not Found', status: :not_found
end
def ci?
@ci.present?
end
def upload_pack_allowed?
return false unless Gitlab.config.gitlab_shell.upload_pack
if user
Gitlab::GitAccess.new(user, project).download_access_check.allowed?
else
ci? || project.public?
end
end
def receive_pack_allowed?
return false unless Gitlab.config.gitlab_shell.receive_pack
# Skip user authorization on upload request.
# It will be done by the pre-receive hook in the repository.
user.present?
end
end
...@@ -5,13 +5,14 @@ class Projects::LabelsController < Projects::ApplicationController ...@@ -5,13 +5,14 @@ class Projects::LabelsController < Projects::ApplicationController
before_action :label, only: [:edit, :update, :destroy] before_action :label, only: [:edit, :update, :destroy]
before_action :authorize_read_label! before_action :authorize_read_label!
before_action :authorize_admin_labels!, only: [ before_action :authorize_admin_labels!, only: [
:new, :create, :edit, :update, :generate, :destroy :new, :create, :edit, :update, :generate, :destroy, :remove_priority, :set_priorities
] ]
respond_to :js, :html respond_to :js, :html
def index def index
@labels = @project.labels.page(params[:page]) @labels = @project.labels.unprioritized.page(params[:page])
@prioritized_labels = @project.labels.prioritized
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -71,6 +72,30 @@ class Projects::LabelsController < Projects::ApplicationController ...@@ -71,6 +72,30 @@ class Projects::LabelsController < Projects::ApplicationController
end end
end end
def remove_priority
respond_to do |format|
if label.update_attribute(:priority, nil)
format.json { render json: label }
else
message = label.errors.full_messages.uniq.join('. ')
format.json { render json: { message: message }, status: :unprocessable_entity }
end
end
end
def set_priorities
Label.transaction do
params[:label_ids].each_with_index do |label_id, index|
label = @project.labels.find_by_id(label_id)
label.update_attribute(:priority, index) if label
end
end
respond_to do |format|
format.json { render json: { message: 'success' } }
end
end
protected protected
def module_enabled def module_enabled
......
...@@ -59,8 +59,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -59,8 +59,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json { render json: @merge_request } format.json { render json: @merge_request }
format.diff { render text: @merge_request.to_diff }
format.patch { render text: @merge_request.to_patch } format.patch { render text: @merge_request.to_patch }
format.diff do
headers.store(*Gitlab::Workhorse.send_git_diff(@project.repository,
@merge_request.diff_base_commit.id,
@merge_request.last_commit.id))
headers['Content-Disposition'] = 'inline'
head :ok
end
end end
end end
...@@ -120,8 +127,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -120,8 +127,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
@diff_notes_disabled = true @diff_notes_disabled = true
@ci_commit = @merge_request.ci_commit @pipeline = @merge_request.pipeline
@statuses = @ci_commit.statuses if @ci_commit @statuses = @pipeline.statuses if @pipeline
@note_counts = Note.where(commit_id: @commits.map(&:id)). @note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count group(:commit_id).count
...@@ -200,7 +207,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -200,7 +207,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil) @merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active? if params[:merge_when_build_succeeds].present? && @merge_request.pipeline && @merge_request.pipeline.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request) .execute(@merge_request)
@status = :merge_when_build_succeeds @status = :merge_when_build_succeeds
...@@ -231,10 +238,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -231,10 +238,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def ci_status def ci_status
ci_commit = @merge_request.ci_commit pipeline = @merge_request.pipeline
if ci_commit if pipeline
status = ci_commit.status status = pipeline.status
coverage = ci_commit.try(:coverage) coverage = pipeline.try(:coverage)
status ||= "preparing" status ||= "preparing"
else else
...@@ -317,8 +324,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -317,8 +324,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request_diff = @merge_request.merge_request_diff @merge_request_diff = @merge_request.merge_request_diff
@ci_commit = @merge_request.ci_commit @pipeline = @merge_request.pipeline
@statuses = @ci_commit.statuses if @ci_commit @statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago? if @merge_request.locked_long_ago?
@merge_request.unlock_mr @merge_request.unlock_mr
...@@ -327,8 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -327,8 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def define_widget_vars def define_widget_vars
@ci_commit = @merge_request.ci_commit @pipeline = @merge_request.pipeline
@ci_commits = [@ci_commit].compact @pipelines = [@pipeline].compact
closes_issues closes_issues
end end
......
...@@ -7,7 +7,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -7,7 +7,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def index def index
@scope = params[:scope] @scope = params[:scope]
all_pipelines = project.ci_commits all_pipelines = project.pipelines
@pipelines_count = all_pipelines.count @pipelines_count = all_pipelines.count
@running_or_pending_count = all_pipelines.running_or_pending.count @running_or_pending_count = all_pipelines.running_or_pending.count
@pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope) @pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope)
...@@ -15,7 +15,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -15,7 +15,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end end
def new def new
@pipeline = project.ci_commits.new(ref: @project.default_branch) @pipeline = project.pipelines.new(ref: @project.default_branch)
end end
def create def create
...@@ -50,7 +50,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -50,7 +50,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end end
def pipeline def pipeline
@pipeline ||= project.ci_commits.find_by!(id: params[:id]) @pipeline ||= project.pipelines.find_by!(id: params[:id])
end end
def commit def commit
......
...@@ -224,7 +224,7 @@ class IssuableFinder ...@@ -224,7 +224,7 @@ class IssuableFinder
def sort(items) def sort(items)
# Ensure we always have an explicit sort order (instead of inheriting # Ensure we always have an explicit sort order (instead of inheriting
# multiple orders when combining ActiveRecord::Relation objects). # multiple orders when combining ActiveRecord::Relation objects).
params[:sort] ? items.sort(params[:sort]) : items.reorder(id: :desc) params[:sort] ? items.sort(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
end end
def by_assignee(items) def by_assignee(items)
...@@ -318,7 +318,11 @@ class IssuableFinder ...@@ -318,7 +318,11 @@ class IssuableFinder
end end
def label_names def label_names
if labels?
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name] params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
else
[]
end
end end
def current_user_related? def current_user_related?
......
module CiStatusHelper module CiStatusHelper
def ci_status_path(ci_commit) def ci_status_path(pipeline)
project = ci_commit.project project = pipeline.project
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha) builds_namespace_project_commit_path(project.namespace, project, pipeline.sha)
end end
def ci_status_with_icon(status, target = nil) def ci_status_with_icon(status, target = nil)
......
...@@ -31,6 +31,21 @@ module NotificationsHelper ...@@ -31,6 +31,21 @@ module NotificationsHelper
end end
end end
def notification_description(level)
case level.to_sym
when :participating
'You will only receive notifications from related resources'
when :mention
'You will receive notifications only for comments in which you were @mentioned'
when :watch
'You will receive notifications for any activity'
when :disabled
'You will not get any notifications via email'
when :global
'Use your global notification setting'
end
end
def notification_list_item(level, setting) def notification_list_item(level, setting)
title = notification_title(level) title = notification_title(level)
...@@ -39,9 +54,10 @@ module NotificationsHelper ...@@ -39,9 +54,10 @@ module NotificationsHelper
notification_title: title notification_title: title
} }
content_tag(:li, class: ('active' if setting.level == level)) do content_tag(:li, role: "menuitem") do
link_to '#', class: 'update-notification', data: data do link_to '#', class: "update-notification #{('is-active' if setting.level == level)}", data: data do
notification_icon(level, title) link_output = content_tag(:strong, title, class: 'dropdown-menu-inner-title')
link_output << content_tag(:span, notification_description(level), class: 'dropdown-menu-inner-content')
end end
end end
end end
......
...@@ -14,7 +14,8 @@ module SortingHelper ...@@ -14,7 +14,8 @@ module SortingHelper
sort_value_recently_signin => sort_title_recently_signin, sort_value_recently_signin => sort_title_recently_signin,
sort_value_oldest_signin => sort_title_oldest_signin, sort_value_oldest_signin => sort_title_oldest_signin,
sort_value_downvotes => sort_title_downvotes, sort_value_downvotes => sort_title_downvotes,
sort_value_upvotes => sort_title_upvotes sort_value_upvotes => sort_title_upvotes,
sort_value_priority => sort_title_priority
} }
end end
...@@ -28,6 +29,10 @@ module SortingHelper ...@@ -28,6 +29,10 @@ module SortingHelper
} }
end end
def sort_title_priority
'Priority'
end
def sort_title_oldest_updated def sort_title_oldest_updated
'Oldest updated' 'Oldest updated'
end end
...@@ -84,6 +89,10 @@ module SortingHelper ...@@ -84,6 +89,10 @@ module SortingHelper
'Most popular' 'Most popular'
end end
def sort_value_priority
'priority'
end
def sort_value_oldest_updated def sort_value_oldest_updated
'updated_asc' 'updated_asc'
end end
......
...@@ -45,8 +45,8 @@ module Ci ...@@ -45,8 +45,8 @@ module Ci
new_build.options = build.options new_build.options = build.options
new_build.commands = build.commands new_build.commands = build.commands
new_build.tag_list = build.tag_list new_build.tag_list = build.tag_list
new_build.gl_project_id = build.gl_project_id new_build.project = build.project
new_build.commit_id = build.commit_id new_build.pipeline = build.pipeline
new_build.name = build.name new_build.name = build.name
new_build.allow_failure = build.allow_failure new_build.allow_failure = build.allow_failure
new_build.stage = build.stage new_build.stage = build.stage
...@@ -66,7 +66,7 @@ module Ci ...@@ -66,7 +66,7 @@ module Ci
# We use around_transition to create builds for next stage as soon as possible, before the `after_*` is executed # We use around_transition to create builds for next stage as soon as possible, before the `after_*` is executed
around_transition any => [:success, :failed, :canceled] do |build, block| around_transition any => [:success, :failed, :canceled] do |build, block|
block.call block.call
build.commit.create_next_builds(build) if build.commit build.pipeline.create_next_builds(build) if build.pipeline
end end
after_transition any => [:success, :failed, :canceled] do |build| after_transition any => [:success, :failed, :canceled] do |build|
...@@ -80,7 +80,7 @@ module Ci ...@@ -80,7 +80,7 @@ module Ci
end end
def retried? def retried?
!self.commit.statuses.latest.include?(self) !self.pipeline.statuses.latest.include?(self)
end end
def retry def retry
...@@ -89,7 +89,7 @@ module Ci ...@@ -89,7 +89,7 @@ module Ci
def depends_on_builds def depends_on_builds
# Get builds of the same type # Get builds of the same type
latest_builds = self.commit.builds.latest latest_builds = self.pipeline.builds.latest
# Return builds from previous stages # Return builds from previous stages
latest_builds.where('stage_idx < ?', stage_idx) latest_builds.where('stage_idx < ?', stage_idx)
...@@ -114,16 +114,16 @@ module Ci ...@@ -114,16 +114,16 @@ module Ci
def merge_request def merge_request
merge_requests = MergeRequest.includes(:merge_request_diff) merge_requests = MergeRequest.includes(:merge_request_diff)
.where(source_branch: ref, source_project_id: commit.gl_project_id) .where(source_branch: ref, source_project_id: pipeline.gl_project_id)
.reorder(iid: :asc) .reorder(iid: :asc)
merge_requests.find do |merge_request| merge_requests.find do |merge_request|
merge_request.commits.any? { |ci| ci.id == commit.sha } merge_request.commits.any? { |ci| ci.id == pipeline.sha }
end end
end end
def project_id def project_id
commit.project.id pipeline.project_id
end end
def project_name def project_name
...@@ -360,8 +360,8 @@ module Ci ...@@ -360,8 +360,8 @@ module Ci
end end
def global_yaml_variables def global_yaml_variables
if commit.config_processor if pipeline.config_processor
commit.config_processor.global_variables.map do |key, value| pipeline.config_processor.global_variables.map do |key, value|
{ key: key, value: value, public: true } { key: key, value: value, public: true }
end end
else else
...@@ -370,8 +370,8 @@ module Ci ...@@ -370,8 +370,8 @@ module Ci
end end
def job_yaml_variables def job_yaml_variables
if commit.config_processor if pipeline.config_processor
commit.config_processor.job_variables(name).map do |key, value| pipeline.config_processor.job_variables(name).map do |key, value|
{ key: key, value: value, public: true } { key: key, value: value, public: true }
end end
else else
......
module Ci module Ci
class Commit < ActiveRecord::Base class Pipeline < ActiveRecord::Base
extend Ci::Model extend Ci::Model
include Statuseable include Statuseable
self.table_name = 'ci_commits'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
has_many :statuses, class_name: 'CommitStatus' has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build' has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest' has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id
validates_presence_of :sha validates_presence_of :sha
validates_presence_of :status validates_presence_of :status
...@@ -21,7 +23,7 @@ module Ci ...@@ -21,7 +23,7 @@ module Ci
def self.stages def self.stages
# We use pluck here due to problems with MySQL which doesn't allow LIMIT/OFFSET in queries # We use pluck here due to problems with MySQL which doesn't allow LIMIT/OFFSET in queries
CommitStatus.where(commit: pluck(:id)).stages CommitStatus.where(pipeline: pluck(:id)).stages
end end
def project_id def project_id
...@@ -47,7 +49,7 @@ module Ci ...@@ -47,7 +49,7 @@ module Ci
end end
def short_sha def short_sha
Ci::Commit.truncate_sha(sha) Ci::Pipeline.truncate_sha(sha)
end end
def commit_data def commit_data
......
...@@ -3,7 +3,7 @@ module Ci ...@@ -3,7 +3,7 @@ module Ci
extend Ci::Model extend Ci::Model
belongs_to :trigger, class_name: 'Ci::Trigger' belongs_to :trigger, class_name: 'Ci::Trigger'
belongs_to :commit, class_name: 'Ci::Commit' belongs_to :commit, class_name: 'Ci::Pipeline', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build' has_many :builds, class_name: 'Ci::Build'
serialize :variables serialize :variables
......
...@@ -214,13 +214,13 @@ class Commit ...@@ -214,13 +214,13 @@ class Commit
@raw.short_id(7) @raw.short_id(7)
end end
def ci_commits def pipelines
@ci_commits ||= project.ci_commits.where(sha: sha) @pipeline ||= project.pipelines.where(sha: sha)
end end
def status def status
return @status if defined?(@status) return @status if defined?(@status)
@status ||= ci_commits.status @status ||= pipelines.status
end end
def revert_branch_name def revert_branch_name
......
...@@ -4,10 +4,10 @@ class CommitStatus < ActiveRecord::Base ...@@ -4,10 +4,10 @@ class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds' self.table_name = 'ci_builds'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :commit, class_name: 'Ci::Commit', touch: true belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id, touch: true
belongs_to :user belongs_to :user
validates :commit, presence: true validates :pipeline, presence: true
validates_presence_of :name validates_presence_of :name
...@@ -44,18 +44,18 @@ class CommitStatus < ActiveRecord::Base ...@@ -44,18 +44,18 @@ class CommitStatus < ActiveRecord::Base
end end
after_transition [:pending, :running] => :success do |commit_status| after_transition [:pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status) MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
end end
after_transition any => :failed do |commit_status| after_transition any => :failed do |commit_status|
MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.commit.project, nil).execute(commit_status) MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status)
end end
end end
delegate :sha, :short_sha, to: :commit delegate :sha, :short_sha, to: :pipeline
def before_sha def before_sha
commit.before_sha || Gitlab::Git::BLANK_SHA pipeline.before_sha || Gitlab::Git::BLANK_SHA
end end
def self.stages def self.stages
......
...@@ -105,17 +105,24 @@ module Issuable ...@@ -105,17 +105,24 @@ module Issuable
where(t[:title].matches(pattern).or(t[:description].matches(pattern))) where(t[:title].matches(pattern).or(t[:description].matches(pattern)))
end end
def sort(method) def sort(method, excluded_labels: [])
case method.to_s case method.to_s
when 'milestone_due_asc' then order_milestone_due_asc when 'milestone_due_asc' then order_milestone_due_asc
when 'milestone_due_desc' then order_milestone_due_desc when 'milestone_due_desc' then order_milestone_due_desc
when 'downvotes_desc' then order_downvotes_desc when 'downvotes_desc' then order_downvotes_desc
when 'upvotes_desc' then order_upvotes_desc when 'upvotes_desc' then order_upvotes_desc
when 'priority' then order_labels_priority(excluded_labels: excluded_labels)
else else
order_by(method) order_by(method)
end end
end end
def order_labels_priority(excluded_labels: [])
select("#{table_name}.*, (#{highest_label_priority(excluded_labels).to_sql}) AS highest_priority").
group(arel_table[:id]).
reorder(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
end
def with_label(title, sort = nil) def with_label(title, sort = nil)
if title.is_a?(Array) && title.size > 1 if title.is_a?(Array) && title.size > 1
joins(:labels).where(labels: { title: title }).group(*grouping_columns(sort)).having("COUNT(DISTINCT labels.title) = #{title.size}") joins(:labels).where(labels: { title: title }).group(*grouping_columns(sort)).having("COUNT(DISTINCT labels.title) = #{title.size}")
...@@ -139,6 +146,20 @@ module Issuable ...@@ -139,6 +146,20 @@ module Issuable
grouping_columns grouping_columns
end end
private
def highest_label_priority(excluded_labels)
query = Label.select(Label.arel_table[:priority].minimum).
joins(:label_links).
where(label_links: { target_type: name }).
where("label_links.target_id = #{table_name}.id").
reorder(nil)
query.where.not(title: excluded_labels) if excluded_labels.present?
query
end
end end
def today? def today?
......
...@@ -75,7 +75,7 @@ class Issue < ActiveRecord::Base ...@@ -75,7 +75,7 @@ class Issue < ActiveRecord::Base
@link_reference_pattern ||= super("issues", /(?<issue>\d+)/) @link_reference_pattern ||= super("issues", /(?<issue>\d+)/)
end end
def self.sort(method) def self.sort(method, excluded_labels: [])
case method.to_s case method.to_s
when 'due_date_asc' then order_due_date_asc when 'due_date_asc' then order_due_date_asc
when 'due_date_desc' then order_due_date_desc when 'due_date_desc' then order_due_date_desc
......
...@@ -26,10 +26,20 @@ class Label < ActiveRecord::Base ...@@ -26,10 +26,20 @@ class Label < ActiveRecord::Base
format: { with: /\A[^&\?,]+\z/ }, format: { with: /\A[^&\?,]+\z/ },
uniqueness: { scope: :project_id } uniqueness: { scope: :project_id }
before_save :nullify_priority
default_scope { order(title: :asc) } default_scope { order(title: :asc) }
scope :templates, -> { where(template: true) } scope :templates, -> { where(template: true) }
def self.prioritized
where.not(priority: nil).reorder(:priority, :title)
end
def self.unprioritized
where(priority: nil)
end
alias_attribute :name, :title alias_attribute :name, :title
def self.reference_prefix def self.reference_prefix
...@@ -118,4 +128,8 @@ class Label < ActiveRecord::Base ...@@ -118,4 +128,8 @@ class Label < ActiveRecord::Base
id id
end end
end end
def nullify_priority
self.priority = nil if priority.blank?
end
end end
...@@ -313,13 +313,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -313,13 +313,6 @@ class MergeRequest < ActiveRecord::Base
) )
end end
# Returns the raw diff for this merge request
#
# see "git diff"
def to_diff
target_project.repository.diff_text(diff_base_commit.sha, source_sha)
end
# Returns the commit as a series of email patches. # Returns the commit as a series of email patches.
# #
# see "git format-patch" # see "git format-patch"
...@@ -579,8 +572,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -579,8 +572,8 @@ class MergeRequest < ActiveRecord::Base
diverged_commits_count > 0 diverged_commits_count > 0
end end
def ci_commit def pipeline
@ci_commit ||= source_project.ci_commit(last_commit.id, source_branch) if last_commit && source_project @pipeline ||= source_project.pipeline(last_commit.id, source_branch) if last_commit && source_project
end end
def diff_refs def diff_refs
......
class NotificationSetting < ActiveRecord::Base class NotificationSetting < ActiveRecord::Base
enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 } enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0 }
default_value_for :level, NotificationSetting.levels[:global] default_value_for :level, NotificationSetting.levels[:global]
......
...@@ -119,7 +119,7 @@ class Project < ActiveRecord::Base ...@@ -119,7 +119,7 @@ class Project < ActiveRecord::Base
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id
has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline', foreign_key: :gl_project_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id
has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
...@@ -930,12 +930,12 @@ class Project < ActiveRecord::Base ...@@ -930,12 +930,12 @@ class Project < ActiveRecord::Base
!namespace.share_with_group_lock !namespace.share_with_group_lock
end end
def ci_commit(sha, ref) def pipeline(sha, ref)
ci_commits.order(id: :desc).find_by(sha: sha, ref: ref) pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end end
def ensure_ci_commit(sha, ref) def ensure_pipeline(sha, ref)
ci_commit(sha, ref) || ci_commits.create(sha: sha, ref: ref) pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref)
end end
def enable_ci def enable_ci
......
module Ci module Ci
class CreateBuildsService class CreateBuildsService
def initialize(commit) def initialize(pipeline)
@commit = commit @pipeline = pipeline
end end
def execute(stage, user, status, trigger_request = nil) def execute(stage, user, status, trigger_request = nil)
builds_attrs = config_processor.builds_for_stage_and_ref(stage, @commit.ref, @commit.tag, trigger_request) builds_attrs = config_processor.builds_for_stage_and_ref(stage, @pipeline.ref, @pipeline.tag, trigger_request)
# check when to create next build # check when to create next build
builds_attrs = builds_attrs.select do |build_attrs| builds_attrs = builds_attrs.select do |build_attrs|
...@@ -21,7 +21,7 @@ module Ci ...@@ -21,7 +21,7 @@ module Ci
builds_attrs.map do |build_attrs| builds_attrs.map do |build_attrs|
# don't create the same build twice # don't create the same build twice
unless @commit.builds.find_by(ref: @commit.ref, tag: @commit.tag, unless @pipeline.builds.find_by(ref: @pipeline.ref, tag: @pipeline.tag,
trigger_request: trigger_request, name: build_attrs[:name]) trigger_request: trigger_request, name: build_attrs[:name])
build_attrs.slice!(:name, build_attrs.slice!(:name,
:commands, :commands,
...@@ -31,13 +31,13 @@ module Ci ...@@ -31,13 +31,13 @@ module Ci
:stage, :stage,
:stage_idx) :stage_idx)
build_attrs.merge!(ref: @commit.ref, build_attrs.merge!(ref: @pipeline.ref,
tag: @commit.tag, tag: @pipeline.tag,
trigger_request: trigger_request, trigger_request: trigger_request,
user: user, user: user,
project: @commit.project) project: @pipeline.project)
@commit.builds.create!(build_attrs) @pipeline.builds.create!(build_attrs)
end end
end end
end end
...@@ -45,7 +45,7 @@ module Ci ...@@ -45,7 +45,7 @@ module Ci
private private
def config_processor def config_processor
@config_processor ||= @commit.config_processor @config_processor ||= @pipeline.config_processor
end end
end end
end end
module Ci module Ci
class CreatePipelineService < BaseService class CreatePipelineService < BaseService
def execute def execute
pipeline = project.ci_commits.new(params) pipeline = project.pipelines.new(params)
unless ref_names.include?(params[:ref]) unless ref_names.include?(params[:ref])
pipeline.errors.add(:base, 'Reference not found') pipeline.errors.add(:base, 'Reference not found')
...@@ -19,7 +19,7 @@ module Ci ...@@ -19,7 +19,7 @@ module Ci
end end
begin begin
Ci::Commit.transaction do Ci::Pipeline.transaction do
pipeline.sha = commit.id pipeline.sha = commit.id
unless pipeline.config_processor unless pipeline.config_processor
......
...@@ -7,14 +7,14 @@ module Ci ...@@ -7,14 +7,14 @@ module Ci
# check if ref is tag # check if ref is tag
tag = project.repository.find_tag(ref).present? tag = project.repository.find_tag(ref).present?
ci_commit = project.ci_commits.create(sha: commit.sha, ref: ref, tag: tag) pipeline = project.pipelines.create(sha: commit.sha, ref: ref, tag: tag)
trigger_request = trigger.trigger_requests.create!( trigger_request = trigger.trigger_requests.create!(
variables: variables, variables: variables,
commit: ci_commit, commit: pipeline,
) )
if ci_commit.create_builds(nil, trigger_request) if pipeline.create_builds(nil, trigger_request)
trigger_request trigger_request
end end
end end
......
...@@ -3,9 +3,9 @@ module Ci ...@@ -3,9 +3,9 @@ module Ci
def execute(project, opts) def execute(project, opts)
sha = opts[:sha] || ref_sha(project, opts[:ref]) sha = opts[:sha] || ref_sha(project, opts[:ref])
ci_commits = project.ci_commits.where(sha: sha) pipelines = project.pipelines.where(sha: sha)
ci_commits = ci_commits.where(ref: opts[:ref]) if opts[:ref] pipelines = pipelines.where(ref: opts[:ref]) if opts[:ref]
image_name = image_for_status(ci_commits.status) image_name = image_for_status(pipelines.status)
image_path = Rails.root.join('public/ci', image_name) image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(path: image_path, name: image_name) OpenStruct.new(path: image_path, name: image_name)
......
...@@ -18,23 +18,23 @@ class CreateCommitBuildsService ...@@ -18,23 +18,23 @@ class CreateCommitBuildsService
return false return false
end end
commit = Ci::Commit.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag) pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
# Skip creating ci_commit when no gitlab-ci.yml is found # Skip creating pipeline when no gitlab-ci.yml is found
unless commit.ci_yaml_file unless pipeline.ci_yaml_file
return false return false
end end
# Create a new ci_commit # Create a new pipeline
commit.save! pipeline.save!
# Skip creating builds for commits that have [ci skip] # Skip creating builds for commits that have [ci skip]
unless commit.skip_ci? unless pipeline.skip_ci?
# Create builds for commit # Create builds for commit
commit.create_builds(user) pipeline.create_builds(user)
end end
commit.touch pipeline.touch
commit pipeline
end end
end end
...@@ -55,12 +55,12 @@ module MergeRequests ...@@ -55,12 +55,12 @@ module MergeRequests
def each_merge_request(commit_status) def each_merge_request(commit_status)
merge_request_from(commit_status).each do |merge_request| merge_request_from(commit_status).each do |merge_request|
ci_commit = merge_request.ci_commit pipeline = merge_request.pipeline
next unless ci_commit next unless pipeline
next unless ci_commit.sha == commit_status.sha next unless pipeline.sha == commit_status.sha
yield merge_request, ci_commit yield merge_request, pipeline
end end
end end
end end
......
...@@ -20,10 +20,10 @@ module MergeRequests ...@@ -20,10 +20,10 @@ module MergeRequests
# Triggers the automatic merge of merge_request once the build succeeds # Triggers the automatic merge of merge_request once the build succeeds
def trigger(commit_status) def trigger(commit_status)
each_merge_request(commit_status) do |merge_request, ci_commit| each_merge_request(commit_status) do |merge_request, pipeline|
next unless merge_request.merge_when_build_succeeds? next unless merge_request.merge_when_build_succeeds?
next unless merge_request.mergeable? next unless merge_request.mergeable?
next unless ci_commit.success? next unless pipeline.success?
MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params) MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params)
end end
......
...@@ -99,8 +99,8 @@ ...@@ -99,8 +99,8 @@
%td.build-link %td.build-link
- if project - if project
= link_to ci_status_path(build.commit) do = link_to ci_status_path(build.pipeline) do
%strong #{build.commit.short_sha} %strong #{build.pipeline.short_sha}
%td.timestamp %td.timestamp
- if build.finished_at - if build.finished_at
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
%i.fa.fa-github %i.fa.fa-github
Import projects from GitHub Import projects from GitHub
%p
%i.fa.fa-warning
To import GitHub pull requests, any pull request source branches that had been deleted are temporarily restored on GitHub. To prevent any connected CI services from being overloaded with dozens of irrelevant branches being created and deleted again, GitHub webhooks are temporarily disabled during the import process.
%p.light %p.light
Select projects you want to import. Select projects you want to import.
%hr %hr
......
.page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" } .page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" }
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class } .sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
= link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.header-logo .header-logo
%a#logo #logo
= brand_header_logo = brand_header_logo
= link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
- if defined?(sidebar) && sidebar - if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}" = render "layouts/nav/#{sidebar}"
...@@ -17,10 +15,8 @@ ...@@ -17,10 +15,8 @@
.collapse-nav .collapse-nav
= render partial: 'layouts/collapse_button' = render partial: 'layouts/collapse_button'
- if current_user - if current_user
= link_to current_user, class: 'sidebar-user', title: "Profile" do = link_to current_user, class: 'sidebar-user', title: "Profile", data: {user: current_user.username} do
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36' = image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s46'
.username
= current_user.username
- if defined?(nav) && nav - if defined?(nav) && nav
.layout-nav .layout-nav
.container-fluid .container-fluid
......
...@@ -2,54 +2,50 @@ ...@@ -2,54 +2,50 @@
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
= icon('bookmark fw') = icon('bookmark fw')
%span .nav-link-text
Projects Projects
= nav_link(controller: :todos) do = nav_link(controller: :todos) do
= link_to dashboard_todos_path, title: 'Todos' do = link_to dashboard_todos_path, title: 'Todos' do
= icon('bell fw') = icon('bell fw')
%span .nav-link-text
Todos Todos
%span.count.todos-pending-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do = nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
= icon('dashboard fw') = icon('dashboard fw')
%span .nav-link-text
Activity Activity
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to dashboard_groups_path, title: 'Groups' do = link_to dashboard_groups_path, title: 'Groups' do
= icon('group fw') = icon('group fw')
%span .nav-link-text
Groups Groups
= nav_link(controller: 'dashboard/milestones') do = nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, title: 'Milestones' do = link_to dashboard_milestones_path, title: 'Milestones' do
= icon('clock-o fw') = icon('clock-o fw')
%span .nav-link-text
Milestones Milestones
= nav_link(path: 'dashboard#issues') do = nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
= icon('exclamation-circle fw') = icon('exclamation-circle fw')
%span .nav-link-text
Issues Issues
%span.count= number_with_delimiter(current_user.assigned_open_issues_count)
= nav_link(path: 'dashboard#merge_requests') do = nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw') = icon('tasks fw')
%span .nav-link-text
Merge Requests Merge Requests
%span.count= number_with_delimiter(current_user.assigned_open_merge_request_count)
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to dashboard_snippets_path, title: 'Snippets' do = link_to dashboard_snippets_path, title: 'Snippets' do
= icon('clipboard fw') = icon('clipboard fw')
%span .nav-link-text
Snippets Snippets
= nav_link(controller: :help) do = nav_link(controller: :help) do
= link_to help_path, title: 'Help' do = link_to help_path, title: 'Help' do
= icon('question-circle fw') = icon('question-circle fw')
%span .nav-link-text
Help Help
= nav_link(html_options: {class: profile_tab_class}) do = nav_link(html_options: {class: profile_tab_class}) 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') = icon('user fw')
%span .nav-link-text
Profile Settings Profile Settings
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
= icon('gear fw') = icon('gear fw')
%span %span
Account Account
- if current_application_settings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do = nav_link(controller: 'oauth/applications') do
= link_to applications_profile_path, title: 'Applications' do = link_to applications_profile_path, title: 'Applications' do
= icon('cloud fw') = icon('cloud fw')
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
%p %p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.pipeline.git_author_name}
%p %p
Branch: #{@build.ref} Branch: #{@build.ref}
%p %p
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%p %p
Job: #{@build.name} Job: #{@build.name}
%p %p
Message: #{@build.commit.git_commit_message} Message: #{@build.pipeline.git_commit_message}
%p %p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build failed for <%= @project.name %> Build failed for <%= @project.name %>
Status: <%= @build.status %> Status: <%= @build.status %>
Commit: <%= @build.commit.short_sha %> Commit: <%= @build.pipeline.short_sha %>
Author: <%= @build.commit.git_author_name %> Author: <%= @build.pipeline.git_author_name %>
Branch: <%= @build.ref %> Branch: <%= @build.ref %>
Stage: <%= @build.stage %> Stage: <%= @build.stage %>
Job: <%= @build.name %> Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %> Message: <%= @build.pipeline.git_commit_message %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %> Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
%p %p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.pipeline.git_author_name}
%p %p
Branch: #{@build.ref} Branch: #{@build.ref}
%p %p
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%p %p
Job: #{@build.name} Job: #{@build.name}
%p %p
Message: #{@build.commit.git_commit_message} Message: #{@build.pipeline.git_commit_message}
%p %p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build successful for <%= @project.name %> Build successful for <%= @project.name %>
Status: <%= @build.status %> Status: <%= @build.status %>
Commit: <%= @build.commit.short_sha %> Commit: <%= @build.pipeline.short_sha %>
Author: <%= @build.commit.git_author_name %> Author: <%= @build.pipeline.git_author_name %>
Branch: <%= @build.ref %> Branch: <%= @build.ref %>
Stage: <%= @build.stage %> Stage: <%= @build.stage %>
Job: <%= @build.name %> Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %> Message: <%= @build.pipeline.git_commit_message %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %> Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
- @no_container = true
- page_title "Branches" - page_title "Branches"
= render "projects/commits/head" = render "projects/commits/head"
.row-content-block
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.pull-right .pull-right
- if can? current_user, :push_code, @project - if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do = link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
...@@ -25,7 +28,7 @@ ...@@ -25,7 +28,7 @@
= sort_title_oldest_updated = sort_title_oldest_updated
.oneline .oneline
Protected branches can be managed in project settings Protected branches can be managed in project settings
- unless @branches.empty? - unless @branches.empty?
%ul.content-list.all-branches %ul.content-list.all-branches
- @branches.each do |branch| - @branches.each do |branch|
= render "projects/branches/branch", branch: branch = render "projects/branches/branch", branch: branch
......
- @no_container = true
- page_title "Builds" - page_title "Builds"
= render "projects/pipelines/head" = render "projects/pipelines/head"
.top-area %div{ class: (container_class) }
.top-area
%ul.nav-links %ul.nav-links
%li{class: ('active' if @scope.nil?)} %li{class: ('active' if @scope.nil?)}
= link_to project_builds_path(@project) do = link_to project_builds_path(@project) do
...@@ -35,7 +37,7 @@ ...@@ -35,7 +37,7 @@
= icon('wrench') = icon('wrench')
%span CI Lint %span CI Lint
%ul.content-list %ul.content-list
- if @builds.blank? - if @builds.blank?
%li %li
.nothing-here-block No builds to show .nothing-here-block No builds to show
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
.build-page .build-page
.row-content-block.top-block .row-content-block.top-block
Build ##{@build.id} for commit Build ##{@build.id} for commit
%strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit) %strong.monospace= link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline)
from from
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
- merge_request = @build.merge_request - merge_request = @build.merge_request
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
= link_to "merge request #{merge_request.to_reference}", merge_request_path(merge_request) = link_to "merge request #{merge_request.to_reference}", merge_request_path(merge_request)
#up-build-trace #up-build-trace
- builds = @build.commit.builds.latest.to_a - builds = @build.pipeline.builds.latest.to_a
- if builds.size > 1 - if builds.size > 1
%ul.nav-links.no-top.no-bottom %ul.nav-links.no-top.no-bottom
- builds.each do |build| - builds.each do |build|
...@@ -178,16 +178,16 @@ ...@@ -178,16 +178,16 @@
Commit Commit
.pull-right .pull-right
%small %small
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" = link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline), class: "monospace"
%p %p
%span.attr-name Branch: %span.attr-name Branch:
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
%p %p
%span.attr-name Author: %span.attr-name Author:
#{@build.commit.git_author_name} #{@build.pipeline.git_author_name}
%p %p
%span.attr-name Message: %span.attr-name Message:
#{@build.commit.git_commit_message} #{@build.pipeline.git_commit_message}
- if @build.tags.any? - if @build.tags.any?
.build-widget .build-widget
...@@ -201,7 +201,7 @@ ...@@ -201,7 +201,7 @@
.build-widget .build-widget
%h4.title #{pluralize(@builds.count(:id), "other build")} for %h4.title #{pluralize(@builds.count(:id), "other build")} for
= succeed ":" do = succeed ":" do
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" = link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline), class: "monospace"
%table.table.builds %table.table.builds
- @builds.each_with_index do |build, i| - @builds.each_with_index do |build, i|
%tr.build %tr.build
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
= form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f| = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
= f.hidden_field :level = f.hidden_field :level
.dropdown .dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} %button.btn.btn-default.notifications-btn#notifications-button{ data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } }
= icon('bell') = icon('bell')
= notification_title(@notification_setting.level) = notification_title(@notification_setting.level)
= icon('caret-down') = icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown %ul.dropdown-menu.dropdown-menu-no-wrap.dropdown-menu-align-right.dropdown-menu-selectable.dropdown-menu-large{ role: "menu" }
- NotificationSetting.levels.each do |level| - NotificationSetting.levels.each do |level|
= notification_list_item(level.first, @notification_setting) = notification_list_item(level.first, @notification_setting)
- status = commit.status - status = pipeline.status
%tr.commit %tr.commit
%td.commit-link %td.commit-link
= link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: "ci-status ci-#{status}" do = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: "ci-status ci-#{status}" do
= ci_icon_for_status(status) = ci_icon_for_status(status)
%strong ##{commit.id} %strong ##{pipeline.id}
%td %td
%div.branch-commit %div.branch-commit
- if commit.ref - if pipeline.ref
= link_to commit.ref, namespace_project_commits_path(@project.namespace, @project, commit.ref), class: "monospace" = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace"
&middot; &middot;
= link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace" = link_to pipeline.short_sha, namespace_project_commit_path(@project.namespace, @project, pipeline.sha), class: "commit-id monospace"
&nbsp; &nbsp;
- if commit.tag? - if pipeline.tag?
%span.label.label-primary tag %span.label.label-primary tag
- elsif commit.latest? - elsif pipeline.latest?
%span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest %span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
- if commit.triggered? - if pipeline.triggered?
%span.label.label-primary triggered %span.label.label-primary triggered
- if commit.yaml_errors.present? - if pipeline.yaml_errors.present?
%span.label.label-danger.has-tooltip{ title: "#{commit.yaml_errors}" } yaml invalid %span.label.label-danger.has-tooltip{ title: "#{pipeline.yaml_errors}" } yaml invalid
- if commit.builds.any?(&:stuck?) - if pipeline.builds.any?(&:stuck?)
%span.label.label-warning stuck %span.label.label-warning stuck
%p.commit-title %p.commit-title
- if commit_data = commit.commit_data - if commit_data = pipeline.commit_data
= link_to_gfm truncate(commit_data.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message" = link_to_gfm truncate(commit_data.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
- else - else
Cant find HEAD commit for this branch Cant find HEAD commit for this branch
- stages_status = commit.statuses.stages_status - stages_status = pipeline.statuses.stages_status
- stages.each do |stage| - stages.each do |stage|
%td %td
- status = stages_status[stage] - status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}" - tooltip = "#{stage.titleize}: #{status || 'not found'}"
- if status - if status
= link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= ci_icon_for_status(status) = ci_icon_for_status(status)
- else - else
.light.has-tooltip{ title: tooltip } .light.has-tooltip{ title: tooltip }
\- \-
%td %td
- if commit.started_at && commit.finished_at - if pipeline.started_at && pipeline.finished_at
%p.duration %p.duration
#{duration_in_words(commit.finished_at, commit.started_at)} #{duration_in_words(pipeline.finished_at, pipeline.started_at)}
%td %td
.controls.hidden-xs.pull-right .controls.hidden-xs.pull-right
- artifacts = commit.builds.latest.select { |b| b.artifacts? } - artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
- if artifacts.present? - if artifacts.present?
.dropdown.inline.build-artifacts .dropdown.inline.build-artifacts
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
...@@ -63,9 +63,9 @@ ...@@ -63,9 +63,9 @@
%span #{build.name} %span #{build.name}
- if can?(current_user, :update_pipeline, @project) - if can?(current_user, :update_pipeline, @project)
- if commit.retryable? - if pipeline.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat") = icon("repeat")
- if commit.cancelable? - if pipeline.cancelable?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do = link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
= icon("remove") = icon("remove")
- @ci_commits.each do |ci_commit| - @pipelines.each do |pipeline|
= render "ci_commit", ci_commit: ci_commit, pipeline_details: true = render "pipeline", pipeline: pipeline, pipeline_details: true
...@@ -53,13 +53,13 @@ ...@@ -53,13 +53,13 @@
- if @commit.status - if @commit.status
.commit-info-row .commit-info-row
Builds for Builds for
= pluralize(@commit.ci_commits.count, 'pipeline') = pluralize(@commit.pipelines.count, 'pipeline')
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status-link ci-status-icon-#{@commit.status}" do = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status-link ci-status-icon-#{@commit.status}" do
= ci_icon_for_status(@commit.status) = ci_icon_for_status(@commit.status)
= ci_label_for_status(@commit.status) = ci_label_for_status(@commit.status)
- if @commit.ci_commits.duration - if @commit.pipelines.duration
in in
= time_interval_in_words @commit.ci_commits.duration = time_interval_in_words @commit.pipelines.duration
.commit-box.content-block .commit-box.content-block
%h3.commit-title %h3.commit-title
......
.row-content-block.build-content.middle-block .row-content-block.build-content.middle-block
.pull-right .pull-right
- if can?(current_user, :update_pipeline, ci_commit.project) - if can?(current_user, :update_pipeline, pipeline.project)
- if ci_commit.builds.latest.failed.any?(&:retryable?) - if pipeline.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: 'btn btn-grouped btn-primary', method: :post = link_to "Retry failed", retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-grouped btn-primary', method: :post
- if ci_commit.builds.running_or_pending.any? - if pipeline.builds.running_or_pending.any?
= link_to "Cancel running", cancel_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post = link_to "Cancel running", cancel_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
.oneline.clearfix .oneline.clearfix
- if defined?(pipeline_details) && pipeline_details - if defined?(pipeline_details) && pipeline_details
Pipeline Pipeline
= link_to "##{ci_commit.id}", namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: "monospace" = link_to "##{pipeline.id}", namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "monospace"
with with
= pluralize ci_commit.statuses.count(:id), "build" = pluralize pipeline.statuses.count(:id), "build"
- if ci_commit.ref - if pipeline.ref
for for
= link_to ci_commit.ref, namespace_project_commits_path(ci_commit.project.namespace, ci_commit.project, ci_commit.ref), class: "monospace" = link_to pipeline.ref, namespace_project_commits_path(pipeline.project.namespace, pipeline.project, pipeline.ref), class: "monospace"
- if defined?(link_to_commit) && link_to_commit - if defined?(link_to_commit) && link_to_commit
for commit for commit
= link_to ci_commit.short_sha, namespace_project_commit_path(ci_commit.project.namespace, ci_commit.project, ci_commit.sha), class: "monospace" = link_to pipeline.short_sha, namespace_project_commit_path(pipeline.project.namespace, pipeline.project, pipeline.sha), class: "monospace"
- if ci_commit.duration - if pipeline.duration
in in
= time_interval_in_words ci_commit.duration = time_interval_in_words pipeline.duration
- if ci_commit.yaml_errors.present? - if pipeline.yaml_errors.present?
.bs-callout.bs-callout-danger .bs-callout.bs-callout-danger
%h4 Found errors in your .gitlab-ci.yml: %h4 Found errors in your .gitlab-ci.yml:
%ul %ul
- ci_commit.yaml_errors.split(",").each do |error| - pipeline.yaml_errors.split(",").each do |error|
%li= error %li= error
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path} You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
- if ci_commit.project.builds_enabled? && !ci_commit.ci_yaml_file - if pipeline.project.builds_enabled? && !pipeline.ci_yaml_file
.bs-callout.bs-callout-warning .bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit \.gitlab-ci.yml not found in this commit
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
%th Tags %th Tags
%th Duration %th Duration
%th Finished at %th Finished at
- if ci_commit.project.build_coverage_enabled? - if pipeline.project.build_coverage_enabled?
%th Coverage %th Coverage
%th %th
- ci_commit.statuses.stages.each do |stage| - pipeline.statuses.stages.each do |stage|
= render 'projects/commit/ci_stage', stage: stage, statuses: ci_commit.statuses.where(stage: stage) = render 'projects/commit/ci_stage', stage: stage, statuses: pipeline.statuses.where(stage: stage)
%ul.nav-links .scrolling-tabs-container
%ul.nav-links.sub-nav.scrolling-tabs
%div{ class: (container_class) }
.fade-left
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project) do = link_to project_files_path(@project) do
Files Files
...@@ -22,3 +25,4 @@ ...@@ -22,3 +25,4 @@
= nav_link(controller: [:tags, :releases]) do = nav_link(controller: [:tags, :releases]) do
= link_to namespace_project_tags_path(@project.namespace, @project) do = link_to namespace_project_tags_path(@project.namespace, @project) do
Tags Tags
.fade-right
- @no_container = true
- page_title "Commits", @ref - page_title "Commits", @ref
= content_for :meta_tags do = content_for :meta_tags do
- if current_user - if current_user
...@@ -5,7 +7,8 @@ ...@@ -5,7 +7,8 @@
= render "head" = render "head"
.row-content-block.second-block %div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.tree-ref-holder .tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits' = render 'shared/ref_switcher', destination: 'commits'
...@@ -32,10 +35,10 @@ ...@@ -32,10 +35,10 @@
%ul.breadcrumb.repo-breadcrumb %ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs = commits_breadcrumbs
%div{id: dom_id(@project)} %div{id: dom_id(@project)}
#commits-list.content_list= render "commits", project: @project #commits-list.content_list= render "commits", project: @project
.clear .clear
= spinner = spinner
:javascript :javascript
CommitsList.init(#{@limit}); CommitsList.init(#{@limit});
- @no_container = true
- page_title "Compare" - page_title "Compare"
= render "projects/commits/head" = render "projects/commits/head"
.row-content-block %div{ class: (container_class) }
.row-content-block.second-block.content-component-block
Compare branches, tags or commit ranges. Compare branches, tags or commit ranges.
%br %br
Fill input field with commit id like Fill input field with commit id like
...@@ -12,5 +14,5 @@ ...@@ -12,5 +14,5 @@
%br %br
Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field. Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field.
.prepend-top-20 .prepend-top-20
= render "form" = render "form"
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
%li %li
Commits covered: Commits covered:
%strong %strong
= @project.ci_commits.count(:all) = @project.pipelines.count(:all)
- page_title "Webhooks" = render 'shared/web_hooks/form', hook: @hook, hooks: @hooks, url_components: [@project.namespace.becomes(Namespace), @project]
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
= page_title
%p
#{link_to "Webhooks", help_page_path("web_hooks", "web_hooks")} can be
used for binding events when something is happening within the project.
.col-lg-9.append-bottom-default
%h5.prepend-top-0
Add new webhook
= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project) do |f|
= form_errors(@hook)
.form-group
= f.label :url, "URL", class: "label-light"
= f.text_field :url, class: "form-control", placeholder: "http://example.com/trigger-ci.json"
.form-group
= f.label :token, "Secret Token", class: 'label-light'
= f.text_field :token, class: "form-control", placeholder: ''
%p.help-block
Use this token to validate received payloads
.form-group
= f.label :url, "Trigger", class: "label-light"
%div
= f.check_box :push_events, class: "pull-left"
.prepend-left-20
= f.label :push_events, class: "label-light append-bottom-0" do
Push events
%p.light
This url will be triggered by a push to the repository
%div
= f.check_box :tag_push_events, class: "pull-left"
.prepend-left-20
= f.label :tag_push_events, class: "label-light append-bottom-0" do
Tag push events
%p.light
This url will be triggered when a new tag is pushed to the repository
%div
= f.check_box :note_events, class: "pull-left"
.prepend-left-20
= f.label :note_events, class: "label-light append-bottom-0" do
Comments
%p.light
This url will be triggered when someone adds a comment
%div
= f.check_box :issues_events, class: "pull-left"
.prepend-left-20
= f.label :issues_events, class: "label-light append-bottom-0" do
Issues events
%p.light
This url will be triggered when an issue is created/updated/merged
%div
= f.check_box :merge_requests_events, class: "pull-left"
.prepend-left-20
= f.label :merge_requests_events, class: "label-light append-bottom-0" do
Merge Request events
%p.light
This url will be triggered when a merge request is created/updated/merged
%div
= f.check_box :build_events, class: "pull-left"
.prepend-left-20
= f.label :build_events, class: "label-light append-bottom-0" do
Build events
%p.light
This url will be triggered when the build status changes
%div
= f.check_box :wiki_page_events, class: 'pull-left'
.prepend-left-20
= f.label :wiki_page_events, class: 'label-light append-bottom-0' do
Wiki Page events
%p.light
This url will be triggered when a wiki page is created/updated
.form-group
= f.label :enable_ssl_verification, "SSL verification", class: "label-light"
%div
= f.check_box :enable_ssl_verification, class: "pull-left"
.prepend-left-20
= f.label :enable_ssl_verification, class: "label-light append-bottom-0" do
Enable SSL verification
= f.submit "Add Webhook", class: "btn btn-create"
%hr
%h5.prepend-top-default
Webhooks (#{@hooks.count})
- if @hooks.any?
%ul.well-list
- @hooks.each do |hook|
= render "project_hook", hook: hook
- else
%p.settings-message.text-center.append-bottom-0
No webhooks found, add one in the form above.
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
%h2.merge-requests-title %h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request') = pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list %ul.unstyled-list
- has_any_ci = @merge_requests.any?(&:ci_commit) - has_any_ci = @merge_requests.any?(&:pipeline)
- @merge_requests.each do |merge_request| - @merge_requests.each do |merge_request|
%li %li
%span.merge-request-ci-status %span.merge-request-ci-status
- if merge_request.ci_commit - if merge_request.pipeline
= render_pipeline_status(merge_request.ci_commit) = render_pipeline_status(merge_request.pipeline)
- elsif has_any_ci - elsif has_any_ci
= icon('blank fw') = icon('blank fw')
%span.merge-request-id %span.merge-request-id
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
- @related_branches.each do |branch| - @related_branches.each do |branch|
%li %li
- sha = @project.repository.find_branch(branch).target - sha = @project.repository.find_branch(branch).target
- ci_commit = @project.ci_commit(sha, branch) if sha - pipeline = @project.pipeline(sha, branch) if sha
- if ci_commit - if ci_copipelinemmit
%span.related-branch-ci-status %span.related-branch-ci-status
= render_pipeline_status(ci_commit) = render_pipeline_status(pipeline)
%span.related-branch-info %span.related-branch-info
%strong %strong
= link_to namespace_project_compare_path(@project.namespace, @project, from: @project.default_branch, to: branch), class: "label-branch" do = link_to namespace_project_compare_path(@project.namespace, @project, from: @project.default_branch, to: branch), class: "label-branch" do
......
%li{ id: dom_id(label), data: { id: label.id } } - label_css_id = dom_id(label)
%li{id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label = render "shared/label_row", label: label
.pull-info-right .pull-info-right
%span.append-right-20 %span.append-right-20
...@@ -10,18 +11,18 @@ ...@@ -10,18 +11,18 @@
= pluralize label.open_issues_count(current_user), 'open issue' = pluralize label.open_issues_count(current_user), 'open issue'
- if current_user - if current_user
.label-subscription{data: {url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label)}} .label-subscription{ data: { url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) } }
.subscription-status{data: {status: label_subscription_status(label)}} .subscription-status{ data: { status: label_subscription_status(label) } }
%button.js-subscribe-button.label-subscribe-button.btn.action-buttons{ type: "button", data: { toggle: "tooltip" } } %button.js-subscribe-button.label-subscribe-button.btn.action-buttons{ type: "button", data: { toggle: "tooltip" } }
%span= label_subscription_toggle_button_text(label) %span= label_subscription_toggle_button_text(label)
- if can? current_user, :admin_label, @project - if can?(current_user, :admin_label, @project)
= link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: {toggle: "tooltip"} do = link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: { toggle: 'tooltip' } do
%i.fa.fa-pencil-square-o %i.fa.fa-pencil-square-o
= link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?", toggle: "tooltip"} do = link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: { confirm: 'Remove this label? Are you sure?', toggle: 'tooltip' } do
%i.fa.fa-trash-o %i.fa.fa-trash-o
- if current_user - if current_user
:javascript :javascript
new Subscription('##{dom_id(label)} .label-subscription'); new Subscription('##{label_css_id} .label-subscription');
- page_title "Labels" - page_title "Labels"
- hide_class = ''
.top-area .top-area
.nav-text .nav-text
Labels can be applied to issues and merge requests. Labels can be applied to issues and merge requests.
.nav-controls .nav-controls
- if can? current_user, :admin_label, @project - if can?(current_user, :admin_label, @project)
= link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do = link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do
= icon('plus') = icon('plus')
New label New label
.labels .labels
- if can?(current_user, :admin_label, @project)
-# Only show it in the first page
- hide = @project.labels.empty? || (params[:page].present? && params[:page] != '1')
.prioritized-labels{ class: ('hide' if hide) }
%h5 Prioritized Labels
%ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_namespace_project_labels_path(@project.namespace, @project) }
- if @prioritized_labels.present?
= render @prioritized_labels
- else
%p.empty-message No prioritized labels yet
.other-labels
- if can?(current_user, :admin_label, @project)
%h5{ class: ('hide' if hide) } Other Labels
- if @labels.present? - if @labels.present?
%ul.content-list.manage-labels-list %ul.content-list.manage-labels-list.js-other-labels
= render @labels = render @labels
= paginate @labels, theme: 'gitlab' = paginate @labels, theme: 'gitlab'
- else - else
.nothing-here-block .nothing-here-block
- if can? current_user, :admin_label, @project - if can?(current_user, :admin_label, @project)
Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}. Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}.
- else - else
No labels created No labels created
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
= icon('ban') = icon('ban')
CLOSED CLOSED
- if merge_request.ci_commit - if merge_request.pipeline
%li %li
= render_pipeline_status(merge_request.ci_commit) = render_pipeline_status(merge_request.pipeline)
- if merge_request.open? && merge_request.broken? - if merge_request.open? && merge_request.broken?
%li %li
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
= link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do = link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits Commits
%span.badge= @commits.size %span.badge= @commits.size
- if @ci_commit - if @pipeline
%li.builds-tab.active %li.builds-tab.active
= link_to url_for(params), data: {target: 'div#builds', action: 'builds', toggle: 'tab'} do = link_to url_for(params), data: {target: 'div#builds', action: 'builds', toggle: 'tab'} do
Builds Builds
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
%p To preserve performance the line changes are not shown. %p To preserve performance the line changes are not shown.
- else - else
= render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs, show_whitespace_toggle: false = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs, show_whitespace_toggle: false
- if @ci_commit - if @pipeline
#builds.builds.tab-pane #builds.builds.tab-pane
= render "projects/merge_requests/show/builds" = render "projects/merge_requests/show/builds"
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits Commits
%span.badge= @commits.size %span.badge= @commits.size
- if @ci_commit - if @pipeline
%li.builds-tab %li.builds-tab
= link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
Builds Builds
......
= render "projects/commit/ci_commit", ci_commit: @ci_commit, link_to_commit: true = render "projects/commit/pipeline", pipeline: @pipeline, link_to_commit: true
- if @ci_commit - if @pipeline
.mr-widget-heading .mr-widget-heading
- %w[success skipped canceled failed running pending].each do |status| - %w[success skipped canceled failed running pending].each do |status|
.ci_widget{ class: "ci-#{status}", style: ("display:none" unless @ci_commit.status == status) } .ci_widget{ class: "ci-#{status}", style: ("display:none" unless @pipeline.status == status) }
= ci_icon_for_status(status) = ci_icon_for_status(status)
%span %span
CI build CI build
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
for for
- commit = @merge_request.last_commit - commit = @merge_request.last_commit
= succeed "." do = succeed "." do
= link_to @ci_commit.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @ci_commit.sha), class: "monospace" = link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace"
%span.ci-coverage %span.ci-coverage
= link_to "View details", builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "js-show-tab", data: {action: 'builds'} = link_to "View details", builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "js-show-tab", data: {action: 'builds'}
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
check_enable: #{@merge_request.unchecked? ? "true" : "false"}, check_enable: #{@merge_request.unchecked? ? "true" : "false"},
ci_status_url: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_status_url: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
gitlab_icon: "#{asset_path 'gitlab_logo.png'}", gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "#{@merge_request.ci_commit ? @merge_request.ci_commit.status : ''}", ci_status: "#{@merge_request.pipeline ? @merge_request.pipeline.status : ''}",
ci_message: { ci_message: {
normal: "Build {{status}} for \"{{title}}\"", normal: "Build {{status}} for \"{{title}}\"",
preparing: "{{status}} build for \"{{title}}\"" preparing: "{{status}} build for \"{{title}}\""
......
- status_class = @ci_commit ? " ci-#{@ci_commit.status}" : nil - status_class = @pipeline ? " ci-#{@pipeline.status}" : nil
= form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-quick-submit js-requires-input' } do |f| = form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-quick-submit js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token = hidden_field_tag :authenticity_token, form_authenticity_token
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.accept-merge-holder.clearfix.js-toggle-container .accept-merge-holder.clearfix.js-toggle-container
.clearfix .clearfix
.accept-action .accept-action
- if @ci_commit && @ci_commit.active? - if @pipeline && @pipeline.active?
%span.btn-group %span.btn-group
= button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do = button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do
Merge When Build Succeeds Merge When Build Succeeds
......
.row-content-block.append-bottom-default - @no_container = true
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.tree-ref-holder .tree-ref-holder
= render partial: 'shared/ref_switcher', locals: {destination: 'graph'} = render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
......
- page_title "Network", @ref - page_title "Network", @ref
= render "projects/commits/head" = render "projects/commits/head"
= render "head" = render "head"
.project-network %div{ class: (container_class) }
.project-network
.controls .controls
= form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f| = form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha' = text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha'
......
%ul.nav-links %ul.nav-links.sub-nav
%div{ class: (container_class) }
- if project_nav_tab? :pipelines - if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do = nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span %span
Pipelines Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count) %span.badge.count.ci_counter= number_with_delimiter(@project.pipelines.running_or_pending.count)
- if project_nav_tab? :builds - if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do = nav_link(controller: %w(builds)) do
......
- @no_container = true
- page_title "Pipelines" - page_title "Pipelines"
= render "projects/pipelines/head" = render "projects/pipelines/head"
.top-area %div{ class: (container_class) }
.top-area
%ul.nav-links %ul.nav-links
%li{class: ('active' if @scope.nil?)} %li{class: ('active' if @scope.nil?)}
= link_to project_pipelines_path(@project) do = link_to project_pipelines_path(@project) do
...@@ -36,7 +38,7 @@ ...@@ -36,7 +38,7 @@
= icon('wrench') = icon('wrench')
%span CI Lint %span CI Lint
%ul.content-list.pipelines %ul.content-list.pipelines
- stages = @pipelines.stages - stages = @pipelines.stages
- if @pipelines.blank? - if @pipelines.blank?
%li %li
......
...@@ -5,4 +5,4 @@ ...@@ -5,4 +5,4 @@
= render "projects/pipelines/info" = render "projects/pipelines/info"
%div.block-connector %div.block-connector
= render "projects/commit/ci_commit", ci_commit: @pipeline = render "projects/commit/pipeline", pipeline: @pipeline
- @no_container = true
- page_title "Tags" - page_title "Tags"
= render "projects/commits/head" = render "projects/commits/head"
.row-content-block %div{ class: (container_class) }
.row-content-block.second-block.content-component-block
- if can? current_user, :push_code, @project - if can? current_user, :push_code, @project
.pull-right .pull-right
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do = link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
...@@ -10,7 +12,7 @@ ...@@ -10,7 +12,7 @@
.oneline .oneline
Tags give the ability to mark specific points in history as being important Tags give the ability to mark specific points in history as being important
.tags .tags
- unless @tags.empty? - unless @tags.empty?
%ul.content-list %ul.content-list
- @tags.each do |tag| - @tags.each do |tag|
......
- @no_container = true
- page_title @path.presence || "Files", @ref - page_title @path.presence || "Files", @ref
= content_for :meta_tags do = content_for :meta_tags do
- if current_user - if current_user
...@@ -5,12 +7,13 @@ ...@@ -5,12 +7,13 @@
= render 'projects/last_push' = render 'projects/last_push'
= render "projects/commits/head" = render "projects/commits/head"
.tree-controls %div{ class: (container_class) }
.tree-controls
= render 'projects/find_file_link' = render 'projects/find_file_link'
- if can? current_user, :download_code, @project - if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true
#tree-holder.tree-holder.clearfix #tree-holder.tree-holder.clearfix
.nav-block .nav-block
= render 'projects/tree/tree_header', tree: @tree = render 'projects/tree/tree_header', tree: @tree
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
= render 'nav' = render 'nav'
.top-area .top-area
.nav-text .nav-text.wiki-page
%strong %strong
- if @page.persisted? - if @page.persisted?
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page) = link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
......
- if @issues.any? - if @issues.reorder(nil).any?
- @issues.group_by(&:project).each do |group| - @issues.group_by(&:project).each do |group|
.panel.panel-default.panel-small .panel.panel-default.panel-small
- project = group[0] - project = group[0]
......
%span.label-row %span.label-row
- if can?(current_user, :admin_label, @project)
.js-toggle-priority.toggle-priority{ data: { url: remove_priority_namespace_project_label_path(@project.namespace, @project, label),
dom_id: dom_id(label) } }
%button.add-priority.btn.has-tooltip{ title: 'Prioritize', :'data-placement' => 'top' }
= icon('star-o')
%button.remove-priority.btn.has-tooltip{ title: 'Remove priority', :'data-placement' => 'top' }
= icon('star')
%span.label-name %span.label-name
= link_to_label(label, tooltip: false) = link_to_label(label, tooltip: false)
%span.prepend-left-10 %span.prepend-left-10
......
- labels.each do |label| - labels.each do |label|
%span.label-row %span.label-row.btn-group{ role: "group", aria: { label: escape_once(label.name) }, style: "color: #{text_color_for_bg(label.color)}" }
= link_to_label(label, tooltip: false) = link_to namespace_project_label_path(@project.namespace, @project, label),
class: "btn btn-transparent has-tooltip",
style: "background-color: #{label.color};",
title: escape_once(label.description),
data: { container: "body" } do
= escape_once label.name
%button.btn.btn-transparent.label-remove.js-label-filter-remove{ type: "button", style: "background-color: #{label.color};", data: { label: label.title } }
= icon("times")
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
%b.caret %b.caret
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li %li
= link_to page_filter_path(sort: sort_value_priority) do
= sort_title_priority
= link_to page_filter_path(sort: sort_value_recently_created) do = link_to page_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created = sort_title_recently_created
= link_to page_filter_path(sort: sort_value_oldest_created) do = link_to page_filter_path(sort: sort_value_oldest_created) do
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment