Commit cbd7801b authored by ZJ van de Weg's avatar ZJ van de Weg Committed by Z.J. van de Weg

Merge branch 'master' into awardables

parents f99b38c9 2485bd7b
......@@ -4,46 +4,46 @@
.bundle
.chef
.directory
.envrc
.gitlab_shell_secret
/.envrc
/.gitlab_shell_secret
.idea
.rbenv-version
/.rbenv-version
.rbx/
.ruby-gemset
.ruby-version
.rvmrc
/.ruby-gemset
/.ruby-version
/.rvmrc
.sass-cache/
.secret
.vagrant
.byebug_history
Vagrantfile
backups/*
config/aws.yml
config/database.yml
config/gitlab.yml
config/gitlab_ci.yml
config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb
config/initializers/relative_url.rb
config/resque.yml
config/unicorn.rb
config/secrets.yml
config/sidekiq.yml
coverage/*
db/*.sqlite3
db/*.sqlite3-journal
db/data.yml
doc/code/*
dump.rdb
log/*.log*
nohup.out
public/assets/
public/uploads.*
public/uploads/
shared/artifacts/
rails_best_practices_output.html
/.secret
/.vagrant
/.byebug_history
/Vagrantfile
/backups/*
/config/aws.yml
/config/database.yml
/config/gitlab.yml
/config/gitlab_ci.yml
/config/initializers/rack_attack.rb
/config/initializers/smtp_settings.rb
/config/initializers/relative_url.rb
/config/resque.yml
/config/unicorn.rb
/config/secrets.yml
/config/sidekiq.yml
/coverage/*
/db/*.sqlite3
/db/*.sqlite3-journal
/db/data.yml
/doc/code/*
/dump.rdb
/log/*.log*
/nohup.out
/public/assets/
/public/uploads.*
/public/uploads/
/shared/artifacts/
/rails_best_practices_output.html
/tags
tmp/
vendor/bundle/*
builds/*
shared/*
/tmp/*
/vendor/bundle/*
/builds/*
/shared/*
......@@ -59,7 +59,7 @@ Style/AndOr:
# Use `Array#join` instead of `Array#*`.
Style/ArrayJoin:
Enabled: false
Enabled: true
# Use only ascii symbols in comments.
Style/AsciiComments:
......@@ -71,7 +71,7 @@ Style/AsciiIdentifiers:
# Checks for uses of Module#attr.
Style/Attr:
Enabled: false
Enabled: true
# Avoid the use of BEGIN blocks.
Style/BeginBlock:
......@@ -83,7 +83,7 @@ Style/BarePercentLiterals:
# Do not use block comments.
Style/BlockComments:
Enabled: false
Enabled: true
# Put end statement of multiline block on its own line.
Style/BlockEndNewline:
......@@ -124,7 +124,7 @@ Style/ClassCheck:
# Use self when defining module/class methods.
Style/ClassMethods:
Enabled: false
Enabled: true
# Avoid the use of class variables.
Style/ClassVars:
......@@ -218,7 +218,7 @@ Style/EmptyLiteral:
# Avoid the use of END blocks.
Style/EndBlock:
Enabled: false
Enabled: true
# Use Unix-style line endings.
Style/EndOfLine:
......@@ -226,7 +226,7 @@ Style/EndOfLine:
# Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd:
Enabled: false
Enabled: true
# Do not use unnecessary spacing.
Style/ExtraSpacing:
......@@ -234,11 +234,16 @@ Style/ExtraSpacing:
# Use snake_case for source file names.
Style/FileName:
Enabled: false
Enabled: true
# Checks for a line break before the first parameter in a multi-line method
# parameter definition.
Style/FirstMethodParameterLineBreak:
Enabled: true
# Checks for flip flops.
Style/FlipFlop:
Enabled: false
Enabled: true
# Checks use of for or each in multiline loops.
Style/For:
......@@ -250,7 +255,7 @@ Style/FormatString:
# Do not introduce global variables.
Style/GlobalVars:
Enabled: false
Enabled: true
# Check for conditionals that can be replaced with guard clauses.
Style/GuardClause:
......@@ -271,7 +276,7 @@ Style/IfUnlessModifier:
# Do not use if x; .... Use the ternary operator instead.
Style/IfWithSemicolon:
Enabled: false
Enabled: true
# Checks that conditional statements do not have an identical line at the
# end of each branch, which can validly be moved out of the conditional.
......@@ -309,7 +314,7 @@ Style/Lambda:
# Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall:
Enabled: false
Enabled: true
# Comments should start with a space.
Style/LeadingCommentSpace:
......@@ -329,7 +334,7 @@ Style/MethodDefParentheses:
# Use the configured style when naming methods.
Style/MethodName:
Enabled: false
Enabled: true
# Checks for usage of `extend self` in modules.
Style/ModuleFunction:
......@@ -370,6 +375,11 @@ Style/MultilineMethodCallBraceLayout:
Style/MultilineMethodCallIndentation:
Enabled: false
# Checks that the closing brace in a method definition is symmetrical with
# respect to the opening brace and the method parameters.
Style/MultilineMethodDefinitionBraceLayout:
Enabled: false
# Checks indentation of binary operations that span more than one line.
Style/MultilineOperationIndentation:
Enabled: false
......@@ -392,7 +402,7 @@ Style/NegatedWhile:
# Avoid using nested modifiers.
Style/NestedModifier:
Enabled: false
Enabled: true
# Parenthesize method calls which are nested inside the argument list of
# another parenthesized method call.
......@@ -429,7 +439,7 @@ Style/OneLineConditional:
# When defining binary operators, name the argument other.
Style/OpMethod:
Enabled: false
Enabled: true
# Check for simple usages of parallel assignment. It will only warn when
# the number of variables matches on both sides of the assignment.
......@@ -509,7 +519,8 @@ Style/Semicolon:
# Checks for proper usage of fail and raise.
Style/SignalException:
Enabled: false
EnforcedStyle: only_raise
Enabled: true
# Enforces the names of some block params.
Style/SingleLineBlockParams:
......@@ -534,11 +545,11 @@ Style/SpaceAfterMethodName:
# Tracks redundant space after the ! operator.
Style/SpaceAfterNot:
Enabled: false
Enabled: true
# Use spaces after semicolons.
Style/SpaceAfterSemicolon:
Enabled: false
Enabled: true
# Checks that the equals signs in parameter default assignments have or don't
# have surrounding space depending on configuration.
......@@ -572,7 +583,7 @@ Style/SpaceBeforeFirstArg:
# No spaces before semicolons.
Style/SpaceBeforeSemicolon:
Enabled: false
Enabled: true
# Checks that block braces have or don't have surrounding space.
# For blocks taking parameters, checks that the left brace has or doesn't
......@@ -594,11 +605,12 @@ Style/SpaceInsideParens:
# No spaces inside range literals.
Style/SpaceInsideRangeLiteral:
Enabled: false
Enabled: true
# Checks for padding/surrounding spaces inside string interpolation.
Style/SpaceInsideStringInterpolation:
Enabled: false
EnforcedStyle: no_space
Enabled: true
# Avoid Perl-style global variables.
Style/SpecialGlobalVars:
......@@ -606,7 +618,8 @@ Style/SpecialGlobalVars:
# Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses:
Enabled: false
EnforcedStyle: require_parentheses
Enabled: true
# Checks if uses of quotes match the configured preference.
Style/StringLiterals:
......@@ -619,7 +632,9 @@ Style/StringLiteralsInInterpolation:
# Checks if configured preferred methods are used over non-preferred.
Style/StringMethods:
Enabled: false
PreferredMethods:
intern: to_sym
Enabled: true
# Use %i or %I for arrays of symbols.
Style/SymbolArray:
......@@ -677,15 +692,16 @@ Style/UnneededPercentQ:
# Don't interpolate global, instance and class variables directly in strings.
Style/VariableInterpolation:
Enabled: false
Enabled: true
# Use the configured style when naming variables.
Style/VariableName:
Enabled: false
EnforcedStyle: snake_case
Enabled: true
# Use when x then ... for one-line cases.
Style/WhenThen:
Enabled: false
Enabled: true
# Checks for redundant do after while or until.
Style/WhileUntilDo:
......@@ -693,7 +709,7 @@ Style/WhileUntilDo:
# Favor modifier while/until usage when you have a single-line body.
Style/WhileUntilModifier:
Enabled: false
Enabled: true
# Use %w or %W for arrays of words.
Style/WordArray:
......@@ -1130,7 +1146,7 @@ RSpec/MultipleDescribes:
# Enforces the usage of the same method on all negative message expectations.
RSpec/NotToNot:
EnforcedStyle: not_to
Enabled: false
Enabled: true
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
......
Please view this file on the master branch, on stable branches it's out of date.
v 8.9.0 (unreleased)
- Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API
- Redesign navigation for project pages
- Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails
- Use gitlab-shell v3.0.0
- Add DB index on users.state
- Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
- Changed the Slack build message to use the singular duration if necessary (Aran Koning)
v 8.8.2 (unreleased)
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
- Fix Error 500 in CI charts by gracefully handling commits with no durations
- Fix concurrent request when updating build log in browser
- Fix issues filter when ordering by milestone
- Todos will display target state if issuable target is 'Closed' or 'Merged'
- Remove 'main language' feature
- Projects pending deletion will render a 404 page
- Measure queue duration between gitlab-workhorse and Rails
v 8.8.3
- Fix gitlab importer failing to import new projects due to missing credentials
- Fix import URL migration not rescuing with the correct Error
v 8.8.2
- Added remove due date button. !4209
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources. !4242
- Fix Error 500 in CI charts by gracefully handling commits with no durations. !4245
- Fix table UI on CI builds page. !4249
- Fix backups if registry is disabled. !4263
- Fixed issue with merge button color. !4211
- Fixed issue with enter key selecting wrong option in dropdown. !4210
- When creating a .gitignore file a dropdown with templates will be provided. !4075
- Fix concurrent request when updating build log in browser. !4183
v 8.8.1
- Add documentation for the "Health Check" feature
- Allow anonymous users to access a public project's pipelines
- Allow anonymous users to access a public project's pipelines !4233
- Fix MySQL compatibility in zero downtime migrations helpers
- Fix the CI login to Container Registry (the gitlab-ci-token user)
......@@ -29,6 +50,7 @@ v 8.8.0
- Added inline diff styling for `change_title` system notes. (Adam Butler)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Improve design of Pipeline View
- Fix scope used when accessing container registry
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
- Improve multiple branch push performance by memoizing permission checking
......@@ -90,10 +112,14 @@ v 8.8.0
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
- When creating a .gitignore file a dropdown with templates will be provided
v 8.7.7
- Fix import by `Any Git URL` broken if the URL contains a space
v 8.7.6
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
- Fix import from GitLab.com to a private instance failure. !4181
- Fix external imports not finding the import data. !4106
- Fix notification delay when changing status of an issue
v 8.7.5
- Fix relative links in wiki pages. !4050
......
......@@ -121,7 +121,7 @@ group :unicorn do
end
# State machine
gem "state_machines-activerecord", '~> 0.3.0'
gem "state_machines-activerecord", '~> 0.4.0'
# Run events after state machine commits
gem 'after_commit_queue'
......@@ -178,9 +178,6 @@ gem 'ruby-fogbugz', '~> 0.2.1'
# d3
gem 'd3_rails', '~> 3.5.0'
#cal-heatmap
gem 'cal-heatmap-rails', '~> 3.6.0'
# underscore-rails
gem "underscore-rails", "~> 1.8.0"
......
......@@ -102,7 +102,6 @@ GEM
bundler (~> 1.2)
thor (~> 0.18)
byebug (8.2.1)
cal-heatmap-rails (3.6.0)
capybara (2.6.2)
addressable
mime-types (>= 1.16)
......@@ -790,11 +789,11 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
state_machines (0.4.0)
state_machines-activemodel (0.3.0)
activemodel (~> 4.1)
state_machines-activemodel (0.4.0)
activemodel (>= 4.1, < 5.1)
state_machines (>= 0.4.0)
state_machines-activerecord (0.3.0)
activerecord (~> 4.1)
state_machines-activerecord (0.4.0)
activerecord (>= 4.1, < 5.1)
state_machines-activemodel (>= 0.3.0)
stringex (2.5.2)
systemu (2.6.5)
......@@ -908,7 +907,6 @@ DEPENDENCIES
bullet
bundler-audit
byebug
cal-heatmap-rails (~> 3.6.0)
capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0)
......@@ -1043,7 +1041,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.1.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.6.0)
state_machines-activerecord (~> 0.3.0)
state_machines-activerecord (~> 0.4.0)
task_list (~> 1.0.2)
teaspoon (~> 1.1.0)
teaspoon-jasmine (~> 2.2.0)
......
......@@ -19,7 +19,6 @@
#= require jquery.scrollTo
#= require jquery.turbolinks
#= require d3
#= require cal-heatmap
#= require turbolinks
#= require autosave
#= require bootstrap/affix
......@@ -246,38 +245,6 @@ $ ->
if $navIcon.hasClass('fa-angle-left')
$navIconToggle.trigger('click')
$(document)
.off 'click', '.js-sidebar-toggle'
.on 'click', '.js-sidebar-toggle', (e, triggered) ->
e.preventDefault()
$this = $(this)
$thisIcon = $this.find 'i'
$allGutterToggleIcons = $('.js-sidebar-toggle i')
if $thisIcon.hasClass('fa-angle-double-right')
$allGutterToggleIcons
.removeClass('fa-angle-double-right')
.addClass('fa-angle-double-left')
$('aside.right-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
$('.page-with-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
else
$allGutterToggleIcons
.removeClass('fa-angle-double-left')
.addClass('fa-angle-double-right')
$('aside.right-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
$('.page-with-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
if not triggered
$.cookie("collapsed_gutter",
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint
bootstrapBreakpoint = bp.getBreakpointSize()
......
class @Calendar
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
cal = new CalHeatMap()
cal.init
itemName: ["contribution"]
data: timestamps
start: new Date(starting_year, starting_month)
domainLabelFormat: "%b"
id: "cal-heatmap"
domain: "month"
subDomain: "day"
range: 12
tooltip: true
label:
position: "top"
legend: [
0
10
20
30
]
legendCellPadding: 3
cellSize: $('.user-calendar').width() / 73
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
url: calendar_activities_path
data:
date: formated_date
cache: false
dataType: "html"
success: (data) ->
$(".user-calendar-activities").html data
constructor: (timestamps, @calendar_activities_path) ->
@currentSelectedDate = ''
@daySpace = 1
@daySize = 15
@daySizeWithSpace = @daySize + (@daySpace * 2)
@monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
@months = []
@highestValue = 0
# Get the highest value from the timestampes
_.each timestamps, (count) =>
if count > @highestValue
@highestValue = count
# Loop through the timestamps to create a group of objects
# The group of objects will be grouped based on the day of the week they are
@timestampsTmp = []
i = 0
group = 0
_.each timestamps, (count, date) =>
newDate = new Date parseInt(date) * 1000
day = newDate.getDay()
# Create a new group array if this is the first day of the week
# or if is first object
if (day is 0 and i isnt 0) or i is 0
@timestampsTmp.push []
group++
innerArray = @timestampsTmp[group-1]
# Push to the inner array the values that will be used to render map
innerArray.push
count: count
date: newDate
day: day
i++
# Init color functions
@color = @initColor()
@colorKey = @initColorKey()
# Init the svg element
@renderSvg(group)
@renderDays()
@renderMonths()
@renderDayTitles()
@renderKey()
@initTooltips()
renderSvg: (group) ->
@svg = d3.select '.js-contrib-calendar'
.append 'svg'
.attr 'width', (group + 1) * @daySizeWithSpace
.attr 'height', 167
.attr 'class', 'contrib-calendar'
renderDays: ->
@svg.selectAll 'g'
.data @timestampsTmp
.enter()
.append 'g'
.attr 'transform', (group, i) =>
_.each group, (stamp, a) =>
if a is 0 and stamp.day is 0
month = stamp.date.getMonth()
x = (@daySizeWithSpace * i + 1) + @daySizeWithSpace
lastMonth = _.last(@months)
if lastMonth?
lastMonthX = lastMonth.x
if !lastMonth?
@months.push
month: month
x: x
else if month isnt lastMonth.month and x - @daySizeWithSpace isnt lastMonthX
@months.push
month: month
x: x
"translate(#{(@daySizeWithSpace * i + 1) + @daySizeWithSpace}, 18)"
.selectAll 'rect'
.data (stamp) ->
stamp
.enter()
.append 'rect'
.attr 'x', '0'
.attr 'y', (stamp, i) =>
(@daySizeWithSpace * stamp.day)
.attr 'width', @daySize
.attr 'height', @daySize
.attr 'title', (stamp) =>
contribText = 'No contributions'
if stamp.count > 0
contribText = "#{stamp.count} contribution#{if stamp.count > 1 then 's' else ''}"
date = dateFormat(stamp.date, 'mmm d, yyyy')
"#{contribText}<br />#{date}"
.attr 'class', 'user-contrib-cell js-tooltip'
.attr 'fill', (stamp) =>
if stamp.count isnt 0
@color(stamp.count)
else
'#ededed'
.attr 'data-container', 'body'
.on 'click', @clickDay
renderDayTitles: ->
days = [{
text: 'M'
y: 29 + (@daySizeWithSpace * 1)
}, {
text: 'W'
y: 29 + (@daySizeWithSpace * 3)
}, {
text: 'F'
y: 29 + (@daySizeWithSpace * 5)
}]
@svg.append 'g'
.selectAll 'text'
.data days
.enter()
.append 'text'
.attr 'text-anchor', 'middle'
.attr 'x', 8
.attr 'y', (day) ->
day.y
.text (day) ->
day.text
.attr 'class', 'user-contrib-text'
renderMonths: ->
@svg.append 'g'
.selectAll 'text'
.data @months
.enter()
.append 'text'
.attr 'x', (date) ->
date.x
.attr 'y', 10
.attr 'class', 'user-contrib-text'
.text (date) =>
@monthNames[date.month]
renderKey: ->
keyColors = ['#ededed', @colorKey(0), @colorKey(1), @colorKey(2), @colorKey(3)]
@svg.append 'g'
.attr 'transform', "translate(18, #{@daySizeWithSpace * 8 + 16})"
.selectAll 'rect'
.data keyColors
.enter()
.append 'rect'
.attr 'width', @daySize
.attr 'height', @daySize
.attr 'x', (color, i) =>
@daySizeWithSpace * i
.attr 'y', 0
.attr 'fill', (color) ->
color
initColor: ->
d3.scale
.linear()
.range(['#acd5f2', '#254e77'])
.domain([0, @highestValue])
initColorKey: ->
d3.scale
.linear()
.range(['#acd5f2', '#254e77'])
.domain([0, 3])
clickDay: (stamp) =>
if @currentSelectedDate isnt stamp.date
@currentSelectedDate = stamp.date
formatted_date = @currentSelectedDate.getFullYear() + "-" + (@currentSelectedDate.getMonth()+1) + "-" + @currentSelectedDate.getDate()
$.ajax
url: @calendar_activities_path
data:
date: formatted_date
cache: false
dataType: 'html'
beforeSend: ->
$('.user-calendar-activities').html '<div class="text-center"><i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i></div>'
success: (data) ->
$('.user-calendar-activities').html data
else
$('.user-calendar-activities').html ''
initTooltips: ->
$('.js-contrib-calendar .js-tooltip').tooltip
html: true
......@@ -16,7 +16,6 @@ class Dispatcher
shortcut_handler = null
switch page
when 'projects:issues:index'
Issues.init()
Issuable.init()
shortcut_handler = new ShortcutsNavigation()
when 'projects:issues:show'
......
issuable_created = false
@Issuable =
init: ->
Issuable.initTemplates()
Issuable.initSearch()
unless issuable_created
issuable_created = true
Issuable.initTemplates()
Issuable.initSearch()
Issuable.initChecks()
initTemplates: ->
Issuable.labelRow = _.template(
......@@ -19,7 +23,16 @@
.on 'keyup', ->
clearTimeout(@timer)
@timer = setTimeout( ->
Issuable.filterResults $('#issue_search_form')
$search = $('#issue_search')
$form = $('.js-filter-form')
$input = $("input[name='#{$search.attr('name')}']", $form)
if $input.length is 0
$form.append "<input type='hidden' name='#{$search.attr('name')}' value='#{_.escape($search.val())}'/>"
else
$input.val $search.val()
Issuable.filterResults $form
, 500)
toggleLabelFilters: ->
......@@ -59,15 +72,22 @@
dataType: "json"
reload: ->
if Issues.created
Issues.initChecks()
if Issuable.created
Issuable.initChecks()
$('#filter_issue_search').val($('#issue_search').val())
initChecks: ->
$('.check_all_issues').on 'click', ->
$('.selected_issue').prop('checked', @checked)
Issuable.checkChanged()
$('.selected_issue').on 'change', Issuable.checkChanged
updateStateFilters: ->
stateFilters = $('.issues-state-filters')
stateFilters = $('.issues-state-filters, .dropdown-menu-sort')
newParams = {}
paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search']
paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search', 'issue_search']
for paramKey in paramKeys
newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
......@@ -82,3 +102,17 @@
else
newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
$(this).attr 'href', newUrl
checkChanged: ->
checked_issues = $('.selected_issue:checked')
if checked_issues.length > 0
ids = $.map checked_issues, (value) ->
$(value).data('id')
$('#update_issues_ids').val ids
$('.issues-other-filters').hide()
$('.issues_bulk_update').show()
else
$('#update_issues_ids').val []
$('.issues_bulk_update').hide()
$('.issues-other-filters').show()
......@@ -19,6 +19,7 @@ class @IssuableForm
@form.on "click", ".btn-cancel", @resetAutosave
@initWip()
@initMoveDropdown()
$issuableDueDate = $('#issuable-due-date')
......@@ -89,3 +90,19 @@ class @IssuableForm
addWip: ->
@titleField.val "WIP: #{@titleField.val()}"
initMoveDropdown: ->
$moveDropdown = $('.js-move-dropdown')
if $moveDropdown.length
$('.js-move-dropdown').select2
ajax:
url: $moveDropdown.data('projects-url')
results: (data) ->
return {
results: data
}
formatResult: (project) ->
project.name_with_namespace
formatSelection: (project) ->
project.name_with_namespace
@Issues =
init: ->
Issues.created = true
Issues.initChecks()
$("body").on "ajax:success", ".close_issue, .reopen_issue", ->
t = $(this)
totalIssues = undefined
reopen = t.hasClass("reopen_issue")
$(".issue_counter").each ->
issue = $(this)
totalIssues = parseInt($(this).html(), 10)
if reopen and issue.closest(".main_menu").length
$(this).html totalIssues + 1
else
$(this).html totalIssues - 1
initChecks: ->
$(".check_all_issues").click ->
$(".selected_issue").prop("checked", @checked)
Issues.checkChanged()
$(".selected_issue").bind "change", Issues.checkChanged
checkChanged: ->
checked_issues = $(".selected_issue:checked")
if checked_issues.length > 0
ids = []
$.each checked_issues, (index, value) ->
ids.push $(value).attr("data-id")
$("#update_issues_ids").val ids
$(".issues-other-filters").hide()
$(".issues_bulk_update").show()
else
$("#update_issues_ids").val []
$(".issues_bulk_update").hide()
$(".issues-other-filters").show()
class @LayoutNav
$ ->
$('.fade-left').addClass('end-scroll')
$('.scrolling-tabs').on 'scroll', (event) ->
$this = $(this)
$el = $(event.target)
currentPosition = $this.scrollLeft()
size = bp.getBreakpointSize()
controlBtnWidth = $('.controls').width()
maxPosition = $this.get(0).scrollWidth - $this.parent().width()
maxPosition += controlBtnWidth if size isnt 'xs' and $('.nav-control').length
$el.find('.fade-left').toggleClass('end-scroll', currentPosition is 0)
$el.find('.fade-right').toggleClass('end-scroll', currentPosition is maxPosition)
......@@ -26,10 +26,19 @@
newUrl = decodeURIComponent(url)
for paramName, paramValue of params
pattern = new RegExp "\\b(#{paramName}=).*?(&|$)"
if url.search(pattern) >= 0
if not paramValue?
newUrl = newUrl.replace pattern, ''
else if url.search(pattern) isnt -1
newUrl = newUrl.replace pattern, "$1#{paramValue}$2"
else
newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}"
# Remove a trailing ampersand
lastChar = newUrl[newUrl.length - 1]
if lastChar is '&'
newUrl = newUrl.slice 0, -1
newUrl
# removes parameter query string from url. returns the modified url
......
......@@ -10,6 +10,7 @@ class @MergeRequestWidget
$('#modal_merge_info').modal(show: false)
@firstCICheck = true
@readyForCICheck = false
@cancel = false
clearInterval @fetchBuildStatusInterval
@clearEventListeners()
......@@ -21,10 +22,16 @@ class @MergeRequestWidget
clearEventListeners: ->
$(document).off 'page:change.merge_request'
cancelPolling: ->
@cancel = true
addEventListeners: ->
allowedPages = ['show', 'commits', 'builds', 'changes']
$(document).on 'page:change.merge_request', =>
if $('body').data('page') isnt 'projects:merge_requests:show'
page = $('body').data('page').split(':').last()
if allowedPages.indexOf(page) < 0
clearInterval @fetchBuildStatusInterval
@cancelPolling()
@clearEventListeners()
mergeInProgress: (deleteSourceBranch = false)->
......@@ -67,6 +74,7 @@ class @MergeRequestWidget
$('.ci-widget-fetching').show()
$.getJSON @opts.ci_status_url, (data) =>
return if @cancel
@readyForCICheck = true
if data.status is ''
......@@ -106,6 +114,7 @@ class @MergeRequestWidget
@firstCICheck = false
showCIStatus: (state) ->
return if not state?
$('.ci_widget').hide()
allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
if state in allowed_states
......@@ -126,6 +135,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
$('.js-merge-button')
$('.js-merge-button,.accept-action .dropdown-toggle')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
......@@ -114,9 +114,9 @@ class @Notes
@refresh()
, @pollingInterval
refresh: ->
refresh: =>
return if @refreshing is true
refreshing = true
@refreshing = true
if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent()
......@@ -134,8 +134,8 @@ class @Notes
@renderDiscussionNote(note)
else
@renderNote(note)
always: =>
@refreshing = false
.always () =>
@refreshing = false
###
Increase @pollingInterval up to 120 seconds on every function call,
......@@ -329,7 +329,7 @@ class @Notes
@renderDiscussionNote(note)
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm($("#new-discussion-note-form-#{note.discussion_id}"))
@removeDiscussionNoteForm($(xhr.target))
###
Called in response to the edit note form being submitted
......
......@@ -10,6 +10,40 @@ class @Sidebar
$('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading)
$('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded)
$(document)
.off 'click', '.js-sidebar-toggle'
.on 'click', '.js-sidebar-toggle', (e, triggered) ->
e.preventDefault()
$this = $(this)
$thisIcon = $this.find 'i'
$allGutterToggleIcons = $('.js-sidebar-toggle i')
if $thisIcon.hasClass('fa-angle-double-right')
$allGutterToggleIcons
.removeClass('fa-angle-double-right')
.addClass('fa-angle-double-left')
$('aside.right-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
$('.page-with-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
else
$allGutterToggleIcons
.removeClass('fa-angle-double-left')
.addClass('fa-angle-double-right')
$('aside.right-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
$('.page-with-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
if not triggered
$.cookie("collapsed_gutter",
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
sidebarDropdownLoading: (e) ->
$sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon')
img = $sidebarCollapsedIcon.find('img')
......@@ -76,7 +110,7 @@ class @Sidebar
@triggerOpenSidebar() if not @isOpen()
if action is 'hide'
@triggerOpenSidebar() is @isOpen()
@triggerOpenSidebar() if @isOpen()
isOpen: ->
@sidebar.is('.right-sidebar-expanded')
......
......@@ -93,7 +93,9 @@ class @UsersSelect
$dropdown.glDropdown(
data: (term, callback) =>
@users term, (users) =>
isAuthorFilter = $('.js-author-search')
@users term, term is '' and isAuthorFilter, (users) =>
if term.length is 0
showDivider = 0
......@@ -138,7 +140,7 @@ class @UsersSelect
toggleLabel: (selected) ->
if selected && 'id' of selected
selected.name
if selected.text then selected.text else selected.name
else
defaultLabel
......@@ -219,7 +221,7 @@ class @UsersSelect
multiple: $(select).hasClass('multiselect')
minimumInputLength: 0
query: (query) =>
@users query.term, (users) =>
@users query.term, @projectId?, (users) =>
data = { results: users }
if query.term.length == 0
......@@ -302,7 +304,7 @@ class @UsersSelect
# Return users list. Filtered by query
# Only active users retrieved
users: (query, callback) =>
users: (query, fromProject, callback) =>
url = @buildUrl(@usersPath)
$.ajax(
......@@ -311,7 +313,7 @@ class @UsersSelect
search: query
per_page: 20
active: true
project_id: @projectId
project_id: @projectId if fromProject
group_id: @groupId
current_user: @showCurrentUser
author_id: @authorId
......
......@@ -8,7 +8,6 @@
*= require select2
*= require_self
*= require dropzone/basic
*= require cal-heatmap
*= require cropper.css
*/
......
.calender-block {
padding-left: 0;
padding-right: 0;
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
overflow-x: scroll;
}
}
.user-calendar-activities {
.calendar_onclick_hr {
padding: 0;
margin: 10px 0;
}
.str-truncated {
max-width: 70%;
}
.text-expander {
background: #eee;
color: #555;
padding: 0 5px;
cursor: pointer;
margin-left: 4px;
&:hover {
background-color: #ddd;
}
.user-calendar-activities-loading {
font-size: 24px;
}
}
/**
* This overwrites the default values of the cal-heatmap gem
*/
.calendar {
.qi {
fill: #fff;
}
.q1 {
fill: #ededed !important;
}
.user-calendar {
text-align: center;
.q2 {
fill: #acd5f2 !important;
}
.q3 {
fill: #7fa8d1 !important;
}
.q4 {
fill: #49729b !important;
}
.q5 {
fill: #254e77 !important;
.calendar {
display: inline-block;
}
}
.future {
visibility: hidden;
.user-contrib-cell {
&:hover {
cursor: pointer;
stroke: #000;
}
}
.domain-background {
fill: none;
shape-rendering: crispedges;
}
.user-contrib-text {
font-size: 12px;
fill: #959494;
}
.ch-tooltip {
padding: 3px;
font-weight: 550;
}
.calendar-hint {
margin-top: -23px;
float: right;
font-size: 12px;
}
......@@ -154,7 +154,7 @@
color: $dropdown-header-color;
font-size: 13px;
line-height: 22px;
padding: 0 10px 10px;
padding: 0 10px;
}
.separator + .dropdown-header {
......
@mixin fade($gradient-direction, $rgba, $gradient-color) {
visibility: visible;
opacity: 1;
position: absolute;
bottom: 12px;
width: 43px;
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: -webkit-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: -o-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: -moz-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
background: linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
&.end-scroll {
visibility: hidden;
opacity: 0;
transition-duration: .3s;
}
}
@mixin scrolling-links() {
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
}
.nav-links {
padding: 0;
margin: 0;
......@@ -119,7 +150,7 @@
}
input {
height: 34px;
height: 35px;
display: inline-block;
position: relative;
top: 2px;
......@@ -196,7 +227,7 @@
position: fixed;
top: $header-height;
width: 100%;
z-index: 3;
z-index: 11;
background: $background-color;
border-bottom: 1px solid $border-color;
transition-duration: .3s;
......@@ -209,13 +240,8 @@
float: right;
padding: 7px 0 0;
@media (max-width: $screen-xs-min) {
float: none;
padding: 0 9px;
.dropdown-new {
width: 100%;
}
@media (max-width: $screen-xs-max) {
display: none;
}
i {
......@@ -246,14 +272,18 @@
}
.nav-links {
@include scrolling-links();
border-bottom: none;
height: 51px;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
.fade-right {
@include fade(left, rgba(250, 250, 250, 0.4), $background-color);
right: 0;
}
.fade-left {
@include fade(right, rgba(250, 250, 250, 0.4), $background-color);
left: 0;
}
li {
......@@ -278,18 +308,62 @@
}
}
.nav-control {
.fade-right {
@media (min-width: $screen-xs-max) {
right: 67px;
}
@media (max-width: $screen-xs-min) {
right: 0;
}
}
}
}
.page-with-layout-nav {
margin-top: 50px;
.nav-block {
position: relative;
&.controls-dropdown-visible {
@media (max-width: $screen-xs-min) {
margin-top: 96px;
.nav-links {
@include scrolling-links();
.fade-right {
@include fade(left, rgba(255, 255, 255, 0.4), $white-light);
right: 0;
}
.fade-left {
@include fade(right, rgba(255, 255, 255, 0.4), $white-light);
left: 0;
}
&.event-filter {
.fade-right {
visibility: hidden;
@media (max-width: $screen-xs-max) {
visibility: visible;
}
}
}
}
}
.page-with-layout-nav {
margin-top: $header-height + 2;
.right-sidebar {
top: ($header-height * 2) + 2;
}
}
.activities {
.nav-block {
border-bottom: 1px solid $border-color;
.nav-links {
border-bottom: none;
}
}
}
......@@ -324,7 +324,7 @@
.layout-nav {
@media (max-width: $screen-xs-min) {
padding-right: 0;;
padding-right: 0;
}
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
......
// NOTE: This stylesheet is for the exclusive use of the `devise_mailer` layout
// used for Devise email templates, and _should not_ be included in any
// application stylesheets.
//
// Styles defined here are embedded directly into the resulting email HTML via
// the `premailer` gem.
$body-background-color: #363636;
$message-background-color: #fafafa;
$header-color: #6b4fbb;
$body-color: #444;
$cta-color: #e14329;
$footer-link-color: #7e7e7e;
$font-family: Helvetica, Arial, sans-serif;
body {
background-color: $body-background-color;
font-family: $font-family;
margin: 0;
padding: 0;
}
table {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
border: 0;
border-collapse: separate;
&#wrapper {
background-color: $body-background-color;
width: 100%;
}
&#header {
margin: 0 auto;
text-align: left;
width: 600px;
}
&#body {
background-color: $message-background-color;
border: 1px solid #000;
border-radius: 4px;
margin: 0 auto;
width: 600px;
}
&#footer {
color: $footer-link-color;
font-size: 14px;
text-align: center;
width: 100%;
}
td {
&#body-container {
padding: 20px 40px;
}
}
}
.center {
text-align: center;
}
#logo {
border: none;
outline: none;
min-height: 88px;
width: 134px;
}
#content {
h2 {
color: $header-color;
font-size: 30px;
font-weight: 400;
line-height: 34px;
margin-top: 0;
}
p {
color: $body-color;
font-size: 17px;
line-height: 24px;
margin-bottom: 0;
}
}
#cta {
border: 1px solid $cta-color;
border-radius: 3px;
display: inline-block;
margin: 20px 0;
padding: 12px 24px;
a {
background-color: $message-background-color;
color: $cta-color;
display: inline-block;
text-decoration: none;
}
}
#tanuki {
padding: 40px 0 0;
img {
border: none;
outline: none;
width: 37px;
min-height: 36px;
}
}
#tagline {
font-size: 22px;
font-weight: 100;
padding: 4px 0 40px;
}
#social {
padding: 0 10px 20px;
width: 600px;
word-spacing: 20px;
a {
color: $footer-link-color;
text-decoration: none;
}
}
......@@ -26,8 +26,28 @@
.commit-info-row {
margin-bottom: 10px;
&.commit-info-row-header {
line-height: 34px;
@media (min-width: $screen-sm-min) {
margin-bottom: 0;
}
.commit-options-dropdown-caret {
@media (max-width: $screen-sm) {
margin-left: 0;
}
}
}
.avatar {
@extend .avatar-inline;
margin-left: 0;
@media (min-width: $screen-sm-min) {
margin-left: 4px;
}
}
.commit-committer-link,
.commit-author-link {
......@@ -35,10 +55,6 @@
font-weight: bold;
}
.time_ago {
margin-left: 8px;
}
.fa-clipboard {
color: $dropdown-title-btn-color;
}
......
......@@ -40,11 +40,6 @@
}
}
.issue-search-form {
margin: 0;
height: 24px;
}
form.edit-issue {
margin: 0;
}
......@@ -96,8 +91,3 @@ form.edit-issue {
.issue-form .select2-container {
width: 250px !important;
}
.issue-closed-by-widget {
color: $gl-text-color;
margin-left: 52px;
}
......@@ -280,11 +280,5 @@
background-color: $white-light;
color: $gl-placeholder-color;
}
th,
td {
padding: 16px;
}
}
}
.pipeline-stage {
overflow: hidden;
text-overflow: ellipsis;
.pipelines {
.stage {
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.duration, .finished_at {
margin: 4px 0;
}
.commit-title {
margin: 0;
}
.controls {
white-space: nowrap;
}
.btn {
margin: 4px;
}
}
......@@ -66,12 +66,6 @@
}
}
.calendar-hint {
margin-top: -12px;
float: right;
font-size: 12px;
}
.profile-link-holder {
display: inline;
......
......@@ -29,6 +29,17 @@
.todo-item {
.todo-title {
@include str-truncated(calc(100% - 174px));
overflow: visible;
}
.status-box {
margin: 0;
float: none;
display: inline-block;
font-weight: normal;
padding: 0 5px;
line-height: inherit;
font-size: 14px;
}
.todo-body {
......@@ -76,12 +87,11 @@
@media (max-width: $screen-xs-max) {
.todo-item {
padding-left: $gl-padding;
.todo-title {
white-space: normal;
overflow: visible;
max-width: 100%;
margin-bottom: 10px;
}
.avatar {
......
......@@ -31,6 +31,24 @@ class AutocompleteController < ApplicationController
render json: @user, only: [:name, :username, :id], methods: [:avatar_url]
end
def projects
project = Project.find_by_id(params[:project_id])
projects = current_user.authorized_projects
projects = projects.select do |project|
current_user.can?(:admin_issue, project)
end
no_project = {
id: 0,
name_with_namespace: 'No project',
}
projects.unshift(no_project)
projects.delete(project)
render json: projects.to_json(only: [:id, :name_with_namespace], methods: :name_with_namespace)
end
private
def find_users
......
......@@ -26,7 +26,7 @@ class Projects::ApplicationController < ApplicationController
project_path = "#{namespace}/#{id}"
@project = Project.find_with_namespace(project_path)
if @project && can?(current_user, :read_project, @project)
if can?(current_user, :read_project, @project) && !@project.pending_delete?
if @project.path_with_namespace != project_path
redirect_to request.original_url.gsub(project_path, @project.path_with_namespace)
end
......
......@@ -230,6 +230,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if ci_commit
status = ci_commit.status
coverage = ci_commit.try(:coverage)
status ||= "preparing"
else
ci_service = @merge_request.source_project.ci_service
status = ci_service.commit_status(merge_request.last_commit.sha, merge_request.source_branch) if ci_service
......@@ -239,8 +241,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
status = "preparing" if status.nil?
response = {
title: merge_request.title,
sha: merge_request.last_commit_short_sha,
......
......@@ -74,8 +74,6 @@ class UsersController < ApplicationController
def calendar
calendar = contributions_calendar
@timestamps = calendar.timestamps
@starting_year = calendar.starting_year
@starting_month = calendar.starting_month
render 'calendar', layout: false
end
......
......@@ -18,7 +18,7 @@ class GroupProjectsFinder < UnionFinder
projects = []
if current_user
if @group.users.include?(current_user)
if @group.users.include?(current_user) || current_user.admin?
projects << @group.projects unless only_shared
projects << @group.shared_projects unless only_owned
else
......
......@@ -250,12 +250,12 @@ class IssuableFinder
def by_milestone(items)
if milestones?
if filter_by_no_milestone?
items = items.where(milestone_id: [-1, nil])
items = items.left_joins_milestones.where(milestone_id: [-1, nil])
elsif filter_by_upcoming_milestone?
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
items = items.joins(:milestone).where(milestone_id: upcoming_ids)
items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
else
items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
items = items.with_milestone(params[:milestone_title])
if projects
items = items.where(milestones: { project_id: projects })
......
......@@ -262,6 +262,8 @@ module ApplicationHelper
assignee_id: params[:assignee_id],
author_id: params[:author_id],
sort: params[:sort],
issue_search: params[:issue_search],
label_name: params[:label_name]
}
options = exist_opts.merge(options)
......@@ -272,16 +274,11 @@ module ApplicationHelper
end
end
path = request.path
path << "?#{options.to_param}"
if add_label
if params[:label_name].present? and params[:label_name].respond_to?('any?')
params[:label_name].each do |label|
path << "&label_name[]=#{label}"
end
end
end
path
params = options.compact
params.delete(:label_name) unless add_label
"#{request.path}?#{params.to_param}"
end
def outdated_browser?
......
......@@ -123,13 +123,14 @@ module CommitsHelper
)
end
def revert_commit_link(commit, continue_to_path, btn_class: nil)
def revert_commit_link(commit, continue_to_path, btn_class: nil, has_tooltip: true)
return unless current_user
tooltip = "Revert this #{commit.change_type_title} in a new merge request"
tooltip = "Revert this #{commit.change_type_title} in a new merge request" if has_tooltip
if can_collaborate_with_project?
link_to 'Revert', '#modal-revert-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: tooltip, class: "btn btn-default btn-grouped btn-#{btn_class} has-tooltip"
btn_class = "btn btn-grouped btn-close btn-#{btn_class}" unless btn_class.nil?
link_to 'Revert', '#modal-revert-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}"
elsif can?(current_user, :fork_project, @project)
continue_params = {
to: continue_to_path,
......@@ -140,17 +141,20 @@ module CommitsHelper
namespace_key: current_user.namespace.id,
continue: continue_params)
link_to 'Revert', fork_path, class: 'btn btn-grouped btn-close', method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: tooltip
btn_class = "btn btn-grouped btn-close" unless btn_class.nil?
link_to 'Revert', fork_path, class: btn_class, method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip)
end
end
def cherry_pick_commit_link(commit, continue_to_path, btn_class: nil)
def cherry_pick_commit_link(commit, continue_to_path, btn_class: nil, has_tooltip: true)
return unless current_user
tooltip = "Cherry-pick this #{commit.change_type_title} in a new merge request"
if can_collaborate_with_project?
link_to 'Cherry-pick', '#modal-cherry-pick-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: tooltip, class: "btn btn-default btn-grouped btn-#{btn_class} has-tooltip"
btn_class = "btn btn-default btn-grouped btn-#{btn_class}" unless btn_class.nil?
link_to 'Cherry-pick', '#modal-cherry-pick-commit', 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}"
elsif can?(current_user, :fork_project, @project)
continue_params = {
to: continue_to_path,
......@@ -161,7 +165,8 @@ module CommitsHelper
namespace_key: current_user.namespace.id,
continue: continue_params)
link_to 'Cherry-pick', fork_path, class: 'btn btn-grouped btn-close', method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: tooltip
btn_class = "btn btn-grouped btn-close" unless btn_class.nil?
link_to 'Cherry-pick', fork_path, class: "#{btn_class}", method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip)
end
end
......
......@@ -159,28 +159,6 @@ module EventsHelper
"--broken encoding"
end
def event_to_atom(xml, event)
if event.visible_to_user?(current_user)
xml.entry do
event_link = event_feed_url(event)
event_title = event_feed_title(event)
event_summary = event_feed_summary(event)
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link href: event_link
xml.title truncate(event_title, length: 80)
xml.updated event.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
xml.author do |author|
xml.name event.author_name
xml.email event.author_email
end
xml.summary(type: "xhtml") { |x| x << event_summary unless event_summary.nil? }
end
end
end
def event_row_class(event)
if event.body?
"event-block"
......
......@@ -50,14 +50,10 @@ module IssuablesHelper
end
def user_dropdown_label(user_id, default_label)
return default_label if user_id.nil?
return "Unassigned" if user_id == "0"
if @project
member = @project.team.find_member(user_id)
user = member.user if member
else
user = User.find_by(id: user_id)
end
user = User.find_by(id: user_id)
if user
user.name
......@@ -76,7 +72,7 @@ module IssuablesHelper
def issuable_meta(issuable, project, text)
output = content_tag :strong, "#{text} #{issuable.to_reference}", class: "identifier"
output << " opened #{time_ago_with_tooltip(issuable.created_at)} by".html_safe
output << " opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
output << content_tag(:strong) do
author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs")
author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg")
......
......@@ -105,23 +105,6 @@ module IssuesHelper
return 'hidden' if issue.closed? == closed
end
def issue_to_atom(xml, issue)
xml.entry do
xml.id namespace_project_issue_url(issue.project.namespace,
issue.project, issue)
xml.link href: namespace_project_issue_url(issue.project.namespace,
issue.project, issue)
xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author|
xml.name issue.author_name
xml.email issue.author_email
end
xml.summary issue.title
end
end
def merge_requests_sentence(merge_requests)
# Sorting based on the `!123` or `group/project!123` reference will sort
# local merge requests first.
......
......@@ -48,7 +48,7 @@ module NavHelper
"page-with-layout-nav" if defined?(nav) && nav
end
def layout_dropdown_class
"controls-dropdown-visible" if current_user
def nav_control_class
"nav-control" if current_user
end
end
......@@ -37,6 +37,16 @@ module TodosHelper
end
end
def todo_target_state_pill(todo)
return unless show_todo_state?(todo)
content_tag(:span, nil, class: 'target-status') do
content_tag(:span, nil, class: "status-box status-box-#{todo.target.state.dasherize}") do
todo.target.state.capitalize
end
end
end
def todos_filter_params
{
state: params[:state],
......@@ -95,4 +105,10 @@ module TodosHelper
options_from_collection_for_select(types, 'name', 'title', params[:type])
end
private
def show_todo_state?(todo)
(todo.target.is_a?(MergeRequest) || todo.target.is_a?(Issue)) && ['closed', 'merged'].include?(todo.target.state)
end
end
class DeviseMailer < Devise::Mailer
default from: "#{Gitlab.config.gitlab.email_display_name} <#{Gitlab.config.gitlab.email_from}>"
default reply_to: Gitlab.config.gitlab.email_reply_to
layout 'devise_mailer'
end
......@@ -32,18 +32,21 @@ module Issuable
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) }
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
scope :opened, -> { with_state(:opened, :reopened) }
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) }
scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :left_joins_milestones, -> { joins("LEFT OUTER JOIN milestones ON #{table_name}.milestone_id = milestones.id") }
scope :order_milestone_due_desc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date DESC') }
scope :order_milestone_due_asc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
scope :outer_join_milestone, -> { joins("LEFT OUTER JOIN milestones ON milestones.id = #{table_name}.milestone_id") }
delegate :name,
:email,
......
......@@ -28,10 +28,17 @@ class Note < ActiveRecord::Base
# Attachments are deprecated and are handled by Markdown uploader
validates :attachment, file_size: { maximum: :max_attachment_size }
validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' }
validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' }
validates :noteable_type, presence: true
validates :noteable_id, presence: true, unless: :for_commit?
validates :commit_id, presence: true, if: :for_commit?
validates :author, presence: true
validate unless: :for_commit? do |note|
unless note.noteable.try(:project) == note.project
errors.add(:invalid_project, 'Note and noteable project mismatch')
end
end
mount_uploader :attachment, AttachmentUploader
# Scopes
......
......@@ -431,7 +431,13 @@ class Project < ActiveRecord::Base
def check_limit
unless creator.can_create_project? or namespace.kind == 'group'
self.errors.add(:limit_reached, "Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
projects_limit = creator.projects_limit
if projects_limit == 0
self.errors.add(:limit_reached, "Personal project creation is not allowed. Please contact your administrator with questions")
else
self.errors.add(:limit_reached, "Your project limit is #{projects_limit} projects! Please contact your administrator to increase it")
end
end
rescue
self.errors.add(:base, "Can't check your ability to create project")
......
......@@ -972,12 +972,6 @@ class Repository
end
end
def main_language
return unless head_exists?
Linguist::Repository.new(rugged, rugged.head.target_id).language
end
def avatar
return nil unless exists?
......
......@@ -53,10 +53,6 @@ class GitPushService < BaseService
# could cause the last commit of a merge request to change.
update_merge_requests
# Checks if the main language has changed in the project and if so
# it updates it accordingly
update_main_language
perform_housekeeping
end
......@@ -64,19 +60,6 @@ class GitPushService < BaseService
@project.repository.copy_gitattributes(params[:ref])
end
def update_main_language
# Performance can be bad so for now only check main_language once
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937
return if @project.main_language.present?
return unless is_default_branch?
return unless push_to_new_branch? || push_to_existing_branch?
current_language = @project.repository.main_language
@project.update_attributes(main_language: current_language)
true
end
protected
def update_merge_requests
......
......@@ -12,8 +12,6 @@ module Notes
return noteable.create_award_emoji(note.award_emoji_name, current_user)
end
return unless valid_project?(note)
if note.save
# Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params)
......@@ -22,14 +20,5 @@ module Notes
note
end
private
def valid_project?(note)
return false unless project
return true if note.for_commit?
note.noteable.try(:project) == project
end
end
end
......@@ -3,7 +3,7 @@ module Projects
def execute
new_params = {
forked_from_project_id: @project.id,
visibility_level: @project.visibility_level,
visibility_level: allowed_visibility_level,
description: @project.description,
name: @project.name,
path: @project.path,
......@@ -19,5 +19,17 @@ module Projects
new_project = CreateService.new(current_user, new_params).execute
new_project
end
private
def allowed_visibility_level
project_level = @project.visibility_level
if Gitlab::VisibilityLevel.non_restricted_level?(project_level)
project_level
else
Gitlab::VisibilityLevel.highest_allowed_level
end
end
end
end
......@@ -47,4 +47,3 @@
= render "admin/builds/build", build: build
= paginate @builds, theme: 'gitlab'
......@@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id issues_dashboard_url
xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
issue_to_atom(xml, issue)
end
xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
end
......@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id dashboard_projects_url
xml.updated @events[0].updated_at.xmlschema if @events[0]
@events.each do |event|
event_to_atom(xml, event)
end
xml << render(partial: 'events/event', collection: @events) if @events.any?
end
......@@ -3,6 +3,8 @@
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title.title
- unless todo.build_failed?
= todo_target_state_pill(todo)
%span.author-name
- if todo.author
= link_to_author(todo)
......
<p>Welcome <%= @resource.name %>!</p>
<% if @resource.unconfirmed_email.present? %>
<p>You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:</p>
<% else %>
<p>You can confirm your account through the link below:</p>
<% end %>
<p><%= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token) %></p>
.center
- if @resource.unconfirmed_email.present?
#content
%h2= @resource.unconfirmed_email
%p Click the link below to confirm your email address.
#cta
= link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
- else
#content
- if Gitlab.com?
%h2 Thanks for signing up to GitLab!
- else
%h2 Welcome, #{@resource.name}!
%p To get started, click the link below to confirm your account.
#cta
= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
Welcome, <%= @resource.name %>!
<% if @resource.unconfirmed_email.present? %>
You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:
<% else %>
You can confirm your account through the link below:
<% end %>
<%= confirmation_url(@resource, confirmation_token: @token) %>
%h3.page-title Authorize required
%h3.page-title Authorization required
%main{:role => "main"}
%p.h4
Authorize
......
return unless event.visible_to_user?(current_user)
xml.entry do
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link href: event_feed_url(event)
xml.title truncate(event_feed_title(event), length: 80)
xml.updated event.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
xml.author do
xml.name event.author_name
xml.email event.author_email
end
xml.summary(type: "xhtml") do |summary|
event_summary = event_feed_summary(event)
summary << event_summary unless event_summary.nil?
end
end
......@@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id issues_group_url
xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
issue_to_atom(xml, issue)
end
xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
end
......@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id group_url(@group)
xml.updated @events[0].updated_at.xmlschema if @events[0]
@events.each do |event|
event_to_atom(xml, event)
end
xml << render(@events) if @events.any?
end
......@@ -47,7 +47,7 @@
%td.import-target
= repo["path_with_namespace"]
%td.import-actions.job-status
= button_tag class: "btn js-add-to-import" do
= button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
......
xml.entry do
xml.id namespace_project_issue_url(issue.project.namespace, issue.project, issue)
xml.link href: namespace_project_issue_url(issue.project.namespace, issue.project, issue)
xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author|
xml.name issue.author_name
xml.email issue.author_email
end
xml.summary issue.title
end
......@@ -25,7 +25,7 @@
.layout-nav
.container-fluid
= render "layouts/nav/#{nav}"
.content-wrapper{ class: "#{layout_nav_class} #{layout_dropdown_class}" }
.content-wrapper{ class: "#{layout_nav_class}" }
= render "layouts/broadcast"
= render "layouts/flash"
= yield :flash_message
......
!!! 5
%html
%head
%meta(content='text/html; charset=UTF-8' http-equiv='Content-Type')
= stylesheet_link_tag 'mailers/devise'
%body
%table#wrapper
%tr
%td
%table#header
%td{valign: "top"}
= image_tag('mailers/gitlab_header_logo.png', id: 'logo', alt: 'GitLab Wordmark')
%table#body
%tr
%td#body-container
= yield
- if Gitlab.com?
%table#footer
%tr
%td#tanuki
= image_tag('mailers/gitlab_tanuki_2x.png', alt: 'GitLab Logo')
%tr
%td#tagline
Everyone can contribute
%tr
%td#social
= link_to 'Blog', 'https://about.gitlab.com/blog/'
= link_to 'Twitter', 'https://twitter.com/gitlab'
= link_to 'Facebook', 'https://www.facebook.com/gitlab/'
= link_to 'YouTube', 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg'
= link_to 'LinkedIn', 'https://www.linkedin.com/company/gitlab-com'
= render 'layouts/nav/group_settings'
%div{ class: nav_control_class }
= render 'layouts/nav/group_settings'
%ul.nav-links
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: 'Home' do
= icon('group fw')
%span
Group
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
= icon('dashboard fw')
%span
Activity
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group), title: 'Issues' do
= icon('exclamation-circle fw')
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(issues.count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
= icon('tasks fw')
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
%span
Members
%ul.nav-links.scrolling-tabs
.fade-left
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: 'Home' do
= icon('group fw')
%span
Group
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
= icon('dashboard fw')
%span
Activity
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group), title: 'Issues' do
= icon('exclamation-circle fw')
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(issues.count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
= icon('tasks fw')
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
%span
Members
.fade-right
%ul.nav-links
%ul.nav-links.scrolling-tabs
.fade-left
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile Settings' do
= icon('user fw')
......@@ -47,3 +48,4 @@
= icon('history fw')
%span
Audit Log
.fade-right
......@@ -19,113 +19,117 @@
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
Leave Project
%ul.nav-links
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
= icon('bookmark fw')
%span
Project
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
= icon('dashboard fw')
%span
Activity
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
= icon('files-o fw')
%div{ class: nav_control_class }
%ul.nav-links.scrolling-tabs
.fade-left
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
= icon('bookmark fw')
%span
Files
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
= icon('history fw')
Project
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
= icon('dashboard fw')
%span
Commits
Activity
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
= icon('files-o fw')
%span
Files
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
= icon('ship fw')
%span
Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
= icon('history fw')
%span
Commits
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
= icon('cubes fw')
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
= icon('ship fw')
%span
Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
- if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
= icon('hdd-o fw')
%span
Container Registry
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
= icon('cubes fw')
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
= icon('area-chart fw')
%span
Graphs
- if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
= icon('hdd-o fw')
%span
Container Registry
- if project_nav_tab? :milestones
= nav_link(controller: :milestones) do
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
= icon('area-chart fw')
%span
Graphs
- if project_nav_tab? :issues
= nav_link(controller: :issues) do
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
= icon('exclamation-circle fw')
%span
Issues
- if @project.default_issues_tracker?
%span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- if project_nav_tab? :milestones
= nav_link(controller: :milestones) do
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
= icon('clock-o fw')
%span
Milestones
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
%span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :issues
= nav_link(controller: :issues) do
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
= icon('exclamation-circle fw')
%span
Issues
- if @project.default_issues_tracker?
%span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
= icon('tags fw')
%span
Labels
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
%span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
= icon('book fw')
%span
Wiki
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
= icon('tags fw')
%span
Labels
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
= icon('clipboard fw')
%span
Snippets
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
= icon('book fw')
%span
Wiki
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
= icon('clipboard fw')
%span
Snippets
-# Global shortcut to network page for compatibility
- if project_nav_tab? :network
%li.hidden
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
Network
-# Global shortcut to network page for compatibility
- if project_nav_tab? :network
-# Shortcut to create a new issue
%li.hidden
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
Network
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
Create a new issue
-# Shortcut to create a new issue
%li.hidden
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
Create a new issue
.fade-right
......@@ -5,7 +5,7 @@
%h4.prepend-top-0
Application theme
%p
This setting allows you to customize the appearance of the site, ex. sidebar.
This setting allows you to customize the appearance of the site, e.g. the sidebar.
.col-lg-9.application-theme
- Gitlab::Themes.each do |theme|
= label_tag do
......
- page_title "Activity"
- header_title project_title(@project, "Activity", activity_project_path(@project))
= render 'projects/last_push'
......
- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Builds'
= render 'projects/builds/header_title'
.top-block.row-content-block.clearfix
.pull-right
......
- page_title 'Badges'
- badges_path = namespace_project_badges_path(@project.namespace, @project)
- header_title project_title(@project, 'Badges', badges_path)
.prepend-top-10
.panel.panel-default
......
- page_title "Blame", @blob.path, @ref
- header_title project_title(@project, "Files", project_files_path(@project))
%h3.page-title Blame view
......
- header_title project_title(@project, "Files", project_files_path(@project))
- page_title "Edit", @blob.path, @ref
= render "header_title"
.file-editor
%ul.nav-links.no-bottom.js-edit-mode
......
- page_title "New File", @path.presence, @ref
= render "header_title"
%h3.page-title
New File
......
- page_title @blob.path, @ref
= render "header_title"
= render 'projects/last_push'
......
- page_title "Branches"
= render "projects/commits/header_title"
= render "projects/commits/head"
.row-content-block
.pull-right
......
- page_title "New Branch"
= render "projects/commits/header_title"
- if @error
.alert.alert-danger
......
- header_title project_title(@project, "Builds", project_builds_path(@project))
- page_title "Builds"
= render "header_title"
.top-area
%ul.nav-links
......@@ -35,9 +34,6 @@
= icon('wrench')
%span CI Lint
.row-content-block
#{(@scope || 'all').capitalize} builds from this project
%ul.content-list
- if @builds.blank?
%li
......
- page_title "#{@build.name} (##{@build.id})", "Builds"
= render "header_title"
- trace_with_state = @build.trace_with_state
.build-page
......
......@@ -57,14 +57,10 @@
%td.duration
- if build.duration
= icon("clock-o")
&nbsp;
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
= icon("calendar")
&nbsp;
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
......
......@@ -12,10 +12,10 @@
&middot;
= link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace"
&nbsp;
- if commit.latest?
%span.label.label-success latest
- if commit.tag?
%span.label.label-primary tag
- elsif commit.latest?
%span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
- if commit.triggered?
%span.label.label-primary triggered
- if commit.yaml_errors.present?
......@@ -23,33 +23,29 @@
- if commit.builds.any?(&:stuck?)
%span.label.label-warning stuck
%p
%span
- if commit_data = commit.commit_data
= link_to_gfm commit_data.title, namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
- else
Cant find HEAD commit for this branch
%p.commit-title
- if commit_data = commit.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"
- else
Cant find HEAD commit for this branch
- stages_status = commit.statuses.stages_status
- stages.each do |stage|
%td
- if status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status}"
%span.has-tooltip{ title: "#{tooltip}", class: "ci-status-icon-#{status}" }
- status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
- 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
= ci_icon_for_status(status)
- else
.light.has-tooltip{ title: tooltip }
\-
%td
- if commit.started_at && commit.finished_at
%p
= icon("clock-o")
&nbsp;
%p.duration
#{duration_in_words(commit.finished_at, commit.started_at)}
- if commit.finished_at
%p
= icon("calendar")
&nbsp;
#{time_ago_with_tooltip(commit.finished_at)}
%td
.controls.hidden-xs.pull-right
......@@ -67,11 +63,9 @@
%span #{build.name}
- if can?(current_user, :update_pipeline, @project)
&nbsp;
- if commit.retryable? && commit.builds.failed.any?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat")
&nbsp;
- if commit.active?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
= icon("remove")
%tr
%th{colspan: 10}
%strong
%a{name: stage}
- status = statuses.latest.status
%span{class: "ci-status-link ci-status-icon-#{status}"}
= ci_icon_for_status(status)
......
.pull-right.commit-action-buttons
%div
.commit-info-row.commit-info-row-header
%span.hidden-xs Authored by
%strong
= commit_author_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.authored_date)}
.pull-right.commit-action-buttons
- if defined?(@notes_count) && @notes_count > 0
%span.btn.disabled.btn-grouped
%i.fa.fa-comment
%span.btn.disabled.btn-grouped.hidden-xs
= icon('comment')
= @notes_count
.pull-left.btn-group
%a.btn.btn-grouped.dropdown-toggle{ data: {toggle: :dropdown} }
%i.fa.fa-download
Download as
%span.caret
%ul.dropdown-menu
= link_to namespace_project_tree_path(@project.namespace, @project, @commit), class: "btn btn-grouped hidden-xs hidden-sm" do
Browse Files
.dropdown.inline
%a.btn.btn-default.dropdown-toggle{ data: { toggle: "dropdown" } }
%span.hidden-xs Options
%span.caret.commit-options-dropdown-caret
%ul.dropdown-menu.dropdown-menu-align-right
%li.visible-xs-block.visible-sm-block
= link_to namespace_project_tree_path(@project.namespace, @project, @commit) do
Browse Files
- unless @commit.has_been_reverted?(current_user)
%li.clearfix
= revert_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id), has_tooltip: false)
%li.clearfix
= cherry_pick_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id), has_tooltip: false)
%li.divider
%li.dropdown-header
Download
- unless @commit.parents.length > 1
%li= link_to "Email Patches", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch)
%li= link_to "Plain Diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff)
= link_to namespace_project_tree_path(@project.namespace, @project, @commit), class: "btn btn-grouped" do
= icon('files-o')
Browse Files
- unless @commit.has_been_reverted?(current_user)
= revert_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id))
= cherry_pick_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id))
%div
%p
.commit-info-row
%span.light Authored by
%strong
= commit_author_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.authored_date)}
- if @commit.different_committer?
.commit-info-row
......@@ -36,8 +39,9 @@
#{time_ago_with_tooltip(@commit.committed_date)}
.commit-info-row
%span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
%span.hidden-xs.hidden-sm Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace hidden-xs hidden-sm"
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace visible-xs-inline visible-sm-inline"
= clipboard_button(clipboard_text: @commit.id)
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
......
- page_title "Builds", "#{@commit.title} (#{@commit.short_id})", "Commits"
= render "projects/commits/header_title"
.prepend-top-default
= render "commit_box"
= render "ci_menu"
= render "ci_menu"
= render "builds"
- page_title "#{@commit.title} (#{@commit.short_id})", "Commits"
- page_description @commit.description
= render "projects/commits/header_title"
.prepend-top-default
= render "commit_box"
- if @commit.status
......
xml.entry do
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.title truncate(commit.title, length: 80)
xml.updated commit.committed_date.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
xml.author do |author|
xml.name commit.author_name
xml.email commit.author_email
end
xml.summary markdown(commit.description, pipeline: :single_line)
end
- header_title project_title(@project, "Commits", project_commits_path(@project))
......@@ -6,18 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
xml.updated @commits.first.committed_date.xmlschema if @commits.any?
@commits.each do |commit|
xml.entry do
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.title truncate(commit.title, length: 80)
xml.updated commit.committed_date.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
xml.author do |author|
xml.name commit.author_name
xml.email commit.author_email
end
xml.summary markdown(commit.description, pipeline: :single_line)
end
end
xml << render(@commits) if @commits.any?
end
- page_title "Commits", @ref
= render "header_title"
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits")
......
- page_title "Compare"
= render "projects/commits/header_title"
= render "projects/commits/head"
.row-content-block
......
- page_title "#{params[:from]}...#{params[:to]}"
= render "projects/commits/header_title"
= render "projects/commits/head"
......
- header_title project_title(@project, "Container Registry", project_container_registry_path(@project))
- page_title "Container Registry"
= render "header_title"
%hr
......@@ -37,4 +36,4 @@
%th
- @tags.each do |tag|
= render 'tag', tag: tag
\ No newline at end of file
= render 'tag', tag: tag
- page_title "Find File", @ref
- header_title project_title(@project, "Files", project_files_path(@project))
.file-finder-holder.tree-holder.clearfix
.nav-block
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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