Commit ae0d8222 authored by Timothy Andrew's avatar Timothy Andrew

Merge remote-tracking branch 'origin/master' into 2979-personal-access-tokens

parents ffe111c1 07b46517

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

...@@ -4,46 +4,46 @@ ...@@ -4,46 +4,46 @@
.bundle .bundle
.chef .chef
.directory .directory
.envrc /.envrc
.gitlab_shell_secret /.gitlab_shell_secret
.idea .idea
.rbenv-version /.rbenv-version
.rbx/ .rbx/
.ruby-gemset /.ruby-gemset
.ruby-version /.ruby-version
.rvmrc /.rvmrc
.sass-cache/ .sass-cache/
.secret /.secret
.vagrant /.vagrant
.byebug_history /.byebug_history
Vagrantfile /Vagrantfile
backups/* /backups/*
config/aws.yml /config/aws.yml
config/database.yml /config/database.yml
config/gitlab.yml /config/gitlab.yml
config/gitlab_ci.yml /config/gitlab_ci.yml
config/initializers/rack_attack.rb /config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb /config/initializers/smtp_settings.rb
config/initializers/relative_url.rb /config/initializers/relative_url.rb
config/resque.yml /config/resque.yml
config/unicorn.rb /config/unicorn.rb
config/secrets.yml /config/secrets.yml
config/sidekiq.yml /config/sidekiq.yml
coverage/* /coverage/*
db/*.sqlite3 /db/*.sqlite3
db/*.sqlite3-journal /db/*.sqlite3-journal
db/data.yml /db/data.yml
doc/code/* /doc/code/*
dump.rdb /dump.rdb
log/*.log* /log/*.log*
nohup.out /nohup.out
public/assets/ /public/assets/
public/uploads.* /public/uploads.*
public/uploads/ /public/uploads/
shared/artifacts/ /shared/artifacts/
rails_best_practices_output.html /rails_best_practices_output.html
/tags /tags
tmp/ /tmp/*
vendor/bundle/* /vendor/bundle/*
builds/* /builds/*
shared/* /shared/*
This diff is collapsed.
This diff is collapsed.
...@@ -311,13 +311,11 @@ request is as follows: ...@@ -311,13 +311,11 @@ request is as follows:
1. Create a feature branch 1. Create a feature branch
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code 1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG) 1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you are changing the README, some documentation or other things which 1. If you are writing documentation, make sure to read the [documentation styleguide][doc-styleguide]
have no effect on the tests, add `[ci skip]` somewhere in the commit message
and make sure to read the [documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by 1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash] [squashing them][git-squash]
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
1. Submit a merge request (MR) to the master branch 1. Submit a merge request (MR) to the `master` branch
1. The MR title should describe the change you want to make 1. The MR title should describe the change you want to make
1. The MR description should give a motive for your change and the method you 1. The MR description should give a motive for your change and the method you
used to achieve it, see the [merge request description format] used to achieve it, see the [merge request description format]
......
...@@ -18,9 +18,8 @@ gem "mysql2", '~> 0.3.16', group: :mysql ...@@ -18,9 +18,8 @@ gem "mysql2", '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries # Authentication libraries
gem 'devise', '~> 3.5.4' gem 'devise', '~> 4.0'
gem 'doorkeeper', '~> 3.1' gem 'doorkeeper', '~> 3.1'
gem 'devise-async', '~> 0.9.0'
gem 'omniauth', '~> 1.3.1' gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
...@@ -36,15 +35,16 @@ gem 'omniauth-shibboleth', '~> 1.2.0' ...@@ -36,15 +35,16 @@ gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0' gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd', '~> 2.2.0' gem 'omniauth_crowd', '~> 2.2.0'
gem 'rack-oauth2', '~> 1.2.1' gem 'rack-oauth2', '~> 1.2.1'
gem 'jwt'
# Spam and anti-bot protection # Spam and anti-bot protection
gem 'recaptcha', require: 'recaptcha/rails' gem 'recaptcha', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0' gem 'akismet', '~> 2.0'
# Two-factor authentication # Two-factor authentication
gem 'devise-two-factor', '~> 2.0.0' gem 'devise-two-factor', '~> 3.0.0'
gem 'rqrcode-rails3', '~> 0.1.7' gem 'rqrcode-rails3', '~> 0.1.7'
gem 'attr_encrypted', '~> 1.3.4' gem 'attr_encrypted', '~> 3.0.0'
# Browser detection # Browser detection
gem "browser", '~> 1.0.0' gem "browser", '~> 1.0.0'
...@@ -72,7 +72,7 @@ gem 'grape-entity', '~> 0.4.2' ...@@ -72,7 +72,7 @@ gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Pagination # Pagination
gem "kaminari", "~> 0.16.3" gem "kaminari", "~> 0.17.0"
# HAML # HAML
gem "haml-rails", '~> 0.9.0' gem "haml-rails", '~> 0.9.0'
...@@ -83,8 +83,14 @@ gem "carrierwave", '~> 0.10.0' ...@@ -83,8 +83,14 @@ gem "carrierwave", '~> 0.10.0'
# Drag and Drop UI # Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1' gem 'dropzonejs-rails', '~> 0.7.1'
# for backups
gem 'fog-aws', '~> 0.9'
gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3'
gem 'fog-openstack', '~> 0.1'
# for aws storage # for aws storage
gem "fog", "~> 1.36.0"
gem "unf", '~> 0.1.4' gem "unf", '~> 0.1.4'
# Authorization # Authorization
...@@ -120,7 +126,7 @@ group :unicorn do ...@@ -120,7 +126,7 @@ group :unicorn do
end end
# State machine # State machine
gem "state_machines-activerecord", '~> 0.3.0' gem "state_machines-activerecord", '~> 0.4.0'
# Run events after state machine commits # Run events after state machine commits
gem 'after_commit_queue' gem 'after_commit_queue'
...@@ -177,9 +183,6 @@ gem 'ruby-fogbugz', '~> 0.2.1' ...@@ -177,9 +183,6 @@ gem 'ruby-fogbugz', '~> 0.2.1'
# d3 # d3
gem 'd3_rails', '~> 3.5.0' gem 'd3_rails', '~> 3.5.0'
#cal-heatmap
gem 'cal-heatmap-rails', '~> 3.6.0'
# underscore-rails # underscore-rails
gem "underscore-rails", "~> 1.8.0" gem "underscore-rails", "~> 1.8.0"
...@@ -218,13 +221,13 @@ gem 'gitlab_emoji', '~> 0.3.0' ...@@ -218,13 +221,13 @@ gem 'gitlab_emoji', '~> 0.3.0'
gem 'gon', '~> 6.0.1' gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2' gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0' gem 'jquery-rails', '~> 4.1.0'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 5.0.0' gem 'jquery-ui-rails', '~> 5.0.0'
gem 'raphael-rails', '~> 2.1.2' gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.3.0' gem 'request_store', '~> 1.3.0'
gem 'select2-rails', '~> 3.5.9' gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1' gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1' gem 'net-ssh', '~> 3.0.1'
gem 'base32', '~> 0.3.0'
# Sentry integration # Sentry integration
gem 'sentry-raven', '~> 0.15' gem 'sentry-raven', '~> 0.15'
...@@ -292,7 +295,8 @@ group :development, :test do ...@@ -292,7 +295,8 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.38.0', require: false gem 'rubocop', '~> 0.40.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.11.0', require: false gem 'simplecov', '~> 0.11.0', require: false
...@@ -324,8 +328,7 @@ gem "mail_room", "~> 0.7" ...@@ -324,8 +328,7 @@ gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8' gem 'email_reply_parser', '~> 0.5.8'
## CI ## CI
gem 'activerecord-deprecated_finders', '~> 1.0.3' gem 'activerecord-session_store', '~> 1.0.0'
gem 'activerecord-session_store', '~> 0.1.0'
gem "nested_form", '~> 0.3.2' gem "nested_form", '~> 0.3.2'
# OAuth # OAuth
...@@ -333,3 +336,6 @@ gem 'oauth2', '~> 1.0.0' ...@@ -333,3 +336,6 @@ gem 'oauth2', '~> 1.0.0'
# Soft deletion # Soft deletion
gem "paranoia", "~> 2.0" gem "paranoia", "~> 2.0"
# Health check
gem 'health_check', '~> 1.5.1'
This diff is collapsed.
# GitLab # GitLab
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
## Canonical source ## Canonical source
......
8.8.0-pre 8.9.0-pre
@Api = @Api =
groups_path: "/api/:version/groups.json" groupsPath: "/api/:version/groups.json"
group_path: "/api/:version/groups/:id.json" groupPath: "/api/:version/groups/:id.json"
namespaces_path: "/api/:version/namespaces.json" namespacesPath: "/api/:version/namespaces.json"
group_projects_path: "/api/:version/groups/:id/projects.json" groupProjectsPath: "/api/:version/groups/:id/projects.json"
projects_path: "/api/:version/projects.json" projectsPath: "/api/:version/projects.json"
labels_path: "/api/:version/projects/:id/labels" labelsPath: "/api/:version/projects/:id/labels"
license_path: "/api/:version/licenses/:key" licensePath: "/api/:version/licenses/:key"
gitignorePath: "/api/:version/gitignores/:key"
group: (group_id, callback) -> group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path) url = Api.buildUrl(Api.groupPath)
url = url.replace(':id', group_id) url = url.replace(':id', group_id)
$.ajax( $.ajax(
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
# Return groups list. Filtered by query # Return groups list. Filtered by query
# Only active groups retrieved # Only active groups retrieved
groups: (query, skip_ldap, callback) -> groups: (query, skip_ldap, callback) ->
url = Api.buildUrl(Api.groups_path) url = Api.buildUrl(Api.groupsPath)
$.ajax( $.ajax(
url: url url: url
...@@ -36,7 +37,7 @@ ...@@ -36,7 +37,7 @@
# Return namespaces list. Filtered by query # Return namespaces list. Filtered by query
namespaces: (query, callback) -> namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path) url = Api.buildUrl(Api.namespacesPath)
$.ajax( $.ajax(
url: url url: url
...@@ -50,7 +51,7 @@ ...@@ -50,7 +51,7 @@
# Return projects list. Filtered by query # Return projects list. Filtered by query
projects: (query, order, callback) -> projects: (query, order, callback) ->
url = Api.buildUrl(Api.projects_path) url = Api.buildUrl(Api.projectsPath)
$.ajax( $.ajax(
url: url url: url
...@@ -64,7 +65,7 @@ ...@@ -64,7 +65,7 @@
callback(projects) callback(projects)
newLabel: (project_id, data, callback) -> newLabel: (project_id, data, callback) ->
url = Api.buildUrl(Api.labels_path) url = Api.buildUrl(Api.labelsPath)
url = url.replace(':id', project_id) url = url.replace(':id', project_id)
data.private_token = gon.api_token data.private_token = gon.api_token
...@@ -80,7 +81,7 @@ ...@@ -80,7 +81,7 @@
# Return group projects list. Filtered by query # Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) -> groupProjects: (group_id, query, callback) ->
url = Api.buildUrl(Api.group_projects_path) url = Api.buildUrl(Api.groupProjectsPath)
url = url.replace(':id', group_id) url = url.replace(':id', group_id)
$.ajax( $.ajax(
...@@ -95,7 +96,7 @@ ...@@ -95,7 +96,7 @@
# Return text for a specific license # Return text for a specific license
licenseText: (key, data, callback) -> licenseText: (key, data, callback) ->
url = Api.buildUrl(Api.license_path).replace(':key', key) url = Api.buildUrl(Api.licensePath).replace(':key', key)
$.ajax( $.ajax(
url: url url: url
...@@ -103,6 +104,12 @@ ...@@ -103,6 +104,12 @@
).done (license) -> ).done (license) ->
callback(license) callback(license)
gitignoreText: (key, callback) ->
url = Api.buildUrl(Api.gitignorePath).replace(':key', key)
$.get url, (gitignore) ->
callback(gitignore)
buildUrl: (url) -> buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root? url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version) return url.replace(':version', gon.api_version)
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#= require jquery.atwho #= require jquery.atwho
#= require jquery.scrollTo #= require jquery.scrollTo
#= require jquery.turbolinks #= require jquery.turbolinks
#= require d3
#= require cal-heatmap
#= require turbolinks #= require turbolinks
#= require autosave #= require autosave
#= require bootstrap/affix #= require bootstrap/affix
...@@ -52,7 +50,13 @@ ...@@ -52,7 +50,13 @@
#= require shortcuts_network #= require shortcuts_network
#= require jquery.nicescroll #= require jquery.nicescroll
#= require date.format #= require date.format
#= require_tree . #= require_directory ./behaviors
#= require_directory ./blob
#= require_directory ./ci
#= require_directory ./commit
#= require_directory ./extensions
#= require_directory ./lib
#= require_directory .
#= require fuzzaldrin-plus #= require fuzzaldrin-plus
#= require cropper #= require cropper
...@@ -246,38 +250,6 @@ $ -> ...@@ -246,38 +250,6 @@ $ ->
if $navIcon.hasClass('fa-angle-left') if $navIcon.hasClass('fa-angle-left')
$navIconToggle.trigger('click') $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 = -> fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint oldBootstrapBreakpoint = bootstrapBreakpoint
bootstrapBreakpoint = bp.getBreakpointSize() bootstrapBreakpoint = bp.getBreakpointSize()
......
class @BlobGitignoreSelector
constructor: (opts) ->
{
@dropdown
@editor
@$wrapper = @dropdown.closest('.gitignore-selector')
@$filenameInput = $('#file_name')
@data = @dropdown.data('filenames')
} = opts
@dropdown.glDropdown(
data: @data,
filterable: true,
selectable: true,
search:
fields: ['name']
clicked: @onClick
text: (gitignore) ->
gitignore.name
)
@toggleGitignoreSelector()
@bindEvents()
bindEvents: ->
@$filenameInput
.on 'keyup blur', (e) =>
@toggleGitignoreSelector()
toggleGitignoreSelector: ->
filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
@$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
onClick: (item, el, e) =>
e.preventDefault()
@requestIgnoreFile(item.name)
requestIgnoreFile: (name) ->
Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
requestIgnoreFileSuccess: (gitignore) ->
@editor.setValue(gitignore.content, 1)
@editor.focus()
class @BlobGitignoreSelectors
constructor: (opts) ->
{
@$dropdowns = $('.js-gitignore-selector')
@editor
} = opts
@$dropdowns.each (i, dropdown) =>
$dropdown = $(dropdown)
new BlobGitignoreSelector(
dropdown: $dropdown,
editor: @editor
)
...@@ -13,6 +13,7 @@ class @EditBlob ...@@ -13,6 +13,7 @@ class @EditBlob
@initModePanesAndLinks() @initModePanesAndLinks()
new BlobLicenseSelector(@editor) new BlobLicenseSelector(@editor)
new BlobGitignoreSelectors(editor: @editor)
initModePanesAndLinks: -> initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane") @$editModePanes = $(".js-edit-mode-pane")
......
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
class CiBuild class CiBuild
@interval: null @interval: null
@state: null
constructor: (build_url, build_status) -> constructor: (build_url, build_status, build_state) ->
clearInterval(CiBuild.interval) clearInterval(CiBuild.interval)
@state = build_state
@initScrollButtonAffix() @initScrollButtonAffix()
if build_status == "running" || build_status == "pending" if build_status == "running" || build_status == "pending"
...@@ -25,15 +28,22 @@ class CiBuild ...@@ -25,15 +28,22 @@ class CiBuild
# #
CiBuild.interval = setInterval => CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is build_url if window.location.href.split("#").first() is build_url
last_state = @state
$.ajax $.ajax
url: build_url url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
dataType: "json" dataType: "json"
success: (build) => success: (log) =>
if build.status == "running" return unless last_state is @state
$('#build-trace code').html build.trace_html
if log.state and log.status is "running"
@state = log.state
if log.append
$('.fa-refresh').before log.html
else
$('#build-trace code').html log.html
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>' $('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
@checkAutoscroll() @checkAutoscroll()
else if build.status != build_status else if log.status isnt build_status
Turbolinks.visit build_url Turbolinks.visit build_url
, 4000 , 4000
......
...@@ -16,7 +16,6 @@ class Dispatcher ...@@ -16,7 +16,6 @@ class Dispatcher
shortcut_handler = null shortcut_handler = null
switch page switch page
when 'projects:issues:index' when 'projects:issues:index'
Issues.init()
Issuable.init() Issuable.init()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:issues:show' when 'projects:issues:show'
...@@ -119,7 +118,7 @@ class Dispatcher ...@@ -119,7 +118,7 @@ class Dispatcher
new UsersSelect() new UsersSelect()
when 'projects' when 'projects'
new NamespaceSelect() new NamespaceSelect()
when 'dashboard' when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation() shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles' when 'profiles'
new Profile() new Profile()
......
...@@ -11,6 +11,7 @@ class @DueDateSelect ...@@ -11,6 +11,7 @@ class @DueDateSelect
$block = $dropdown.closest('.block') $block = $dropdown.closest('.block')
$selectbox = $dropdown.closest('.selectbox') $selectbox = $dropdown.closest('.selectbox')
$value = $block.find('.value') $value = $block.find('.value')
$valueContent = $block.find('.value-content')
$sidebarValue = $('.js-due-date-sidebar-value', $block) $sidebarValue = $('.js-due-date-sidebar-value', $block)
fieldName = $dropdown.data('field-name') fieldName = $dropdown.data('field-name')
...@@ -23,11 +24,15 @@ class @DueDateSelect ...@@ -23,11 +24,15 @@ class @DueDateSelect
$value.removeAttr('style') $value.removeAttr('style')
) )
addDueDate = -> addDueDate = (isDropdown) ->
# Create the post date # Create the post date
value = $("input[name='#{fieldName}']").val() value = $("input[name='#{fieldName}']").val()
if value isnt ''
date = new Date value.replace(new RegExp('-', 'g'), ',') date = new Date value.replace(new RegExp('-', 'g'), ',')
mediumDate = $.datepicker.formatDate 'M d, yy', date mediumDate = $.datepicker.formatDate 'M d, yy', date
else
mediumDate = 'None'
data = {} data = {}
data[abilityName] = {} data[abilityName] = {}
...@@ -39,23 +44,35 @@ class @DueDateSelect ...@@ -39,23 +44,35 @@ class @DueDateSelect
data: data data: data
beforeSend: -> beforeSend: ->
$loading.fadeIn() $loading.fadeIn()
if isDropdown
$dropdown.trigger('loading.gl.dropdown') $dropdown.trigger('loading.gl.dropdown')
$selectbox.hide() $selectbox.hide()
$value.removeAttr('style') $value.removeAttr('style')
$value.html(mediumDate) $valueContent.html(mediumDate)
$sidebarValue.html(mediumDate) $sidebarValue.html(mediumDate)
if value isnt ''
$('.js-remove-due-date-holder').removeClass 'hidden'
else
$('.js-remove-due-date-holder').addClass 'hidden'
).done (data) -> ).done (data) ->
if isDropdown
$dropdown.trigger('loaded.gl.dropdown') $dropdown.trigger('loaded.gl.dropdown')
$dropdown.dropdown('toggle') $dropdown.dropdown('toggle')
$loading.fadeOut() $loading.fadeOut()
$block.on 'click', '.js-remove-due-date', (e) ->
e.preventDefault()
$("input[name='#{fieldName}']").val ''
addDueDate(false)
$datePicker.datepicker( $datePicker.datepicker(
dateFormat: 'yy-mm-dd', dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='#{fieldName}']").val() defaultDate: $("input[name='#{fieldName}']").val()
altField: "input[name='#{fieldName}']" altField: "input[name='#{fieldName}']"
onSelect: -> onSelect: ->
addDueDate() addDueDate(true)
) )
$(document) $(document)
......
...@@ -18,6 +18,10 @@ GitLab.GfmAutoComplete = ...@@ -18,6 +18,10 @@ GitLab.GfmAutoComplete =
Issues: Issues:
template: '<li><small>${id}</small> ${title}</li>' template: '<li><small>${id}</small> ${title}</li>'
# Milestones
Milestones:
template: '<li>${title}</li>'
# Add GFM auto-completion to all input fields, that accept GFM input. # Add GFM auto-completion to all input fields, that accept GFM input.
setup: (wrap) -> setup: (wrap) ->
@input = $('.js-gfm-input') @input = $('.js-gfm-input')
...@@ -81,6 +85,19 @@ GitLab.GfmAutoComplete = ...@@ -81,6 +85,19 @@ GitLab.GfmAutoComplete =
title: sanitize(i.title) title: sanitize(i.title)
search: "#{i.iid} #{i.title}" search: "#{i.iid} #{i.title}"
@input.atwho
at: '%'
alias: 'milestones'
searchKey: 'search'
displayTpl: @Milestones.template
insertTpl: '${atwho-at}"${title}"'
callbacks:
beforeSave: (milestones) ->
$.map milestones, (m) ->
id: m.iid
title: sanitize(m.title)
search: "#{m.title}"
@input.atwho @input.atwho
at: '!' at: '!'
alias: 'mergerequests' alias: 'mergerequests'
...@@ -105,6 +122,8 @@ GitLab.GfmAutoComplete = ...@@ -105,6 +122,8 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', '@', data.members @input.atwho 'load', '@', data.members
# load issues # load issues
@input.atwho 'load', 'issues', data.issues @input.atwho 'load', 'issues', data.issues
# load milestones
@input.atwho 'load', 'milestones', data.milestones
# load merge requests # load merge requests
@input.atwho 'load', 'mergerequests', data.mergerequests @input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis # load emojis
......
...@@ -60,9 +60,36 @@ class GitLabDropdownFilter ...@@ -60,9 +60,36 @@ class GitLabDropdownFilter
results = data results = data
if search_text isnt '' if search_text isnt ''
# When data is an array of objects therefore [object Array] e.g.
# [
# { prop: 'foo' },
# { prop: 'baz' }
# ]
if _.isArray(data)
results = fuzzaldrinPlus.filter(data, search_text, results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys key: @options.keys
) )
else
# If data is grouped therefore an [object Object]. e.g.
# {
# groupName1: [
# { prop: 'foo' },
# { prop: 'baz' }
# ],
# groupName2: [
# { prop: 'abc' },
# { prop: 'def' }
# ]
# }
if gl.utils.isObject data
results = {}
for key, group of data
tmp = fuzzaldrinPlus.filter(group, search_text,
key: @options.keys
)
if tmp.length
results[key] = tmp.map (item) -> item
@options.callback results @options.callback results
else else
...@@ -141,8 +168,9 @@ class GitLabDropdown ...@@ -141,8 +168,9 @@ class GitLabDropdown
searchFields = if @options.search then @options.search.fields else []; searchFields = if @options.search then @options.search.fields else [];
if @options.data if @options.data
# If data is an array # If we provided data
if _.isArray @options.data # data could be an array of objects or a group of arrays
if _.isObject(@options.data) and not _.isFunction(@options.data)
@fullData = @options.data @fullData = @options.data
@parseData @options.data @parseData @options.data
else else
...@@ -230,19 +258,33 @@ class GitLabDropdown ...@@ -230,19 +258,33 @@ class GitLabDropdown
parseData: (data) -> parseData: (data) ->
@renderedData = data @renderedData = data
# Render each row
html = $.map data, (obj) =>
return @renderItem(obj)
if @options.filterable and data.length is 0 if @options.filterable and data.length is 0
# render no matching results # render no matching results
html = [@noResults()] html = [@noResults()]
else
# Handle array groups
if gl.utils.isObject data
html = []
for name, groupData of data
# Add header for each group
html.push(@renderItem(header: name, name))
@renderData(groupData, name)
.map (item) ->
html.push item
else
# Render each row
html = @renderData(data)
# Render the full menu # Render the full menu
full_html = @renderMenu(html.join("")) full_html = @renderMenu(html.join(""))
@appendMenu(full_html) @appendMenu(full_html)
renderData: (data, group = false) ->
data.map (obj, index) =>
return @renderItem(obj, group, index)
shouldPropagate: (e) => shouldPropagate: (e) =>
if @options.multiSelect if @options.multiSelect
$target = $(e.target) $target = $(e.target)
...@@ -299,11 +341,10 @@ class GitLabDropdown ...@@ -299,11 +341,10 @@ class GitLabDropdown
selector = '.dropdown-content' selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content" selector = ".dropdown-page-one .dropdown-content"
$(selector, @dropdown).html html $(selector, @dropdown).html html
# Render the row # Render the row
renderItem: (data) -> renderItem: (data, group = false, index = false) ->
html = "" html = ""
# Divider # Divider
...@@ -346,8 +387,13 @@ class GitLabDropdown ...@@ -346,8 +387,13 @@ class GitLabDropdown
if @highlight if @highlight
text = @highlightTextMatches(text, @filterInput.val()) text = @highlightTextMatches(text, @filterInput.val())
if group
groupAttrs = "data-group='#{group}' data-index='#{index}'"
else
groupAttrs = ''
html = "<li> html = "<li>
<a href='#{url}' class='#{cssClass}'> <a href='#{url}' #{groupAttrs} class='#{cssClass}'>
#{text} #{text}
</a> </a>
</li>" </li>"
...@@ -377,9 +423,15 @@ class GitLabDropdown ...@@ -377,9 +423,15 @@ class GitLabDropdown
rowClicked: (el) -> rowClicked: (el) ->
fieldName = @options.fieldName fieldName = @options.fieldName
selectedIndex = el.parent().index()
if @renderedData if @renderedData
groupName = el.data('group')
if groupName
selectedIndex = el.data('index')
selectedObject = @renderedData[groupName][selectedIndex]
else
selectedIndex = el.closest('li').index()
selectedObject = @renderedData[selectedIndex] selectedObject = @renderedData[selectedIndex]
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
if el.hasClass(ACTIVE_CLASS) if el.hasClass(ACTIVE_CLASS)
...@@ -460,7 +512,7 @@ class GitLabDropdown ...@@ -460,7 +512,7 @@ class GitLabDropdown
return false return false
if currentKeyCode is 13 if currentKeyCode is 13
@selectRowAtIndex currentIndex @selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: -> removeArrayKeyEvent: ->
$('body').off 'keydown' $('body').off 'keydown'
......
# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require_tree .
#= require d3 #= require d3
#= require stat_graph_contributors_util
class @ContributorsStatGraph class @ContributorsStatGraph
init: (log) -> init: (log) ->
......
#= require d3 #= require d3
#= require jquery
#= require underscore
class @ContributorsGraph class @ContributorsGraph
MARGIN: MARGIN:
......
issuable_created = false
@Issuable = @Issuable =
init: -> init: ->
unless issuable_created
issuable_created = true
Issuable.initTemplates() Issuable.initTemplates()
Issuable.initSearch() Issuable.initSearch()
Issuable.initChecks()
initTemplates: -> initTemplates: ->
Issuable.labelRow = _.template( Issuable.labelRow = _.template(
...@@ -19,7 +23,16 @@ ...@@ -19,7 +23,16 @@
.on 'keyup', -> .on 'keyup', ->
clearTimeout(@timer) clearTimeout(@timer)
@timer = setTimeout( -> @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) , 500)
toggleLabelFilters: -> toggleLabelFilters: ->
...@@ -59,15 +72,22 @@ ...@@ -59,15 +72,22 @@
dataType: "json" dataType: "json"
reload: -> reload: ->
if Issues.created if Issuable.created
Issues.initChecks() Issuable.initChecks()
$('#filter_issue_search').val($('#issue_search').val()) $('#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: -> updateStateFilters: ->
stateFilters = $('.issues-state-filters') stateFilters = $('.issues-state-filters, .dropdown-menu-sort')
newParams = {} 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 for paramKey in paramKeys
newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or '' newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
...@@ -82,3 +102,17 @@ ...@@ -82,3 +102,17 @@
else else
newUrl = gl.utils.mergeUrlParams(newParams, initialUrl) newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
$(this).attr 'href', newUrl $(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,16 @@ class @IssuableForm ...@@ -19,6 +19,16 @@ class @IssuableForm
@form.on "click", ".btn-cancel", @resetAutosave @form.on "click", ".btn-cancel", @resetAutosave
@initWip() @initWip()
@initMoveDropdown()
$issuableDueDate = $('#issuable-due-date')
if $issuableDueDate.length
$('.datepicker').datepicker(
dateFormat: 'yy-mm-dd',
onSelect: (dateText, inst) ->
$issuableDueDate.val dateText
).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
initAutosave: -> initAutosave: ->
new Autosave @titleField, [ new Autosave @titleField, [
...@@ -80,3 +90,19 @@ class @IssuableForm ...@@ -80,3 +90,19 @@ class @IssuableForm
addWip: -> addWip: ->
@titleField.val "WIP: #{@titleField.val()}" @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)
((w) ->
w.gl ?= {}
w.gl.utils ?= {}
w.gl.utils.isObject = (obj) ->
obj? and (obj.constructor is Object)
) window
...@@ -26,10 +26,19 @@ ...@@ -26,10 +26,19 @@
newUrl = decodeURIComponent(url) newUrl = decodeURIComponent(url)
for paramName, paramValue of params for paramName, paramValue of params
pattern = new RegExp "\\b(#{paramName}=).*?(&|$)" 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" newUrl = newUrl.replace pattern, "$1#{paramValue}$2"
else else
newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}" 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 newUrl
# removes parameter query string from url. returns the modified url # removes parameter query string from url. returns the modified url
......
...@@ -75,6 +75,9 @@ class @MergeRequestTabs ...@@ -75,6 +75,9 @@ class @MergeRequestTabs
@loadDiff($target.attr('href')) @loadDiff($target.attr('href'))
if bp? and bp.getBreakpointSize() isnt 'lg' if bp? and bp.getBreakpointSize() isnt 'lg'
@shrinkView() @shrinkView()
navBarHeight = $('.navbar-gitlab').outerHeight()
$.scrollTo(".merge-request-details .merge-request-tabs", offset: -navBarHeight)
else if action == 'builds' else if action == 'builds'
@loadBuilds($target.attr('href')) @loadBuilds($target.attr('href'))
@expandView() @expandView()
......
...@@ -10,6 +10,7 @@ class @MergeRequestWidget ...@@ -10,6 +10,7 @@ class @MergeRequestWidget
$('#modal_merge_info').modal(show: false) $('#modal_merge_info').modal(show: false)
@firstCICheck = true @firstCICheck = true
@readyForCICheck = false @readyForCICheck = false
@cancel = false
clearInterval @fetchBuildStatusInterval clearInterval @fetchBuildStatusInterval
@clearEventListeners() @clearEventListeners()
...@@ -21,10 +22,16 @@ class @MergeRequestWidget ...@@ -21,10 +22,16 @@ class @MergeRequestWidget
clearEventListeners: -> clearEventListeners: ->
$(document).off 'page:change.merge_request' $(document).off 'page:change.merge_request'
cancelPolling: ->
@cancel = true
addEventListeners: -> addEventListeners: ->
allowedPages = ['show', 'commits', 'builds', 'changes']
$(document).on 'page:change.merge_request', => $(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 clearInterval @fetchBuildStatusInterval
@cancelPolling()
@clearEventListeners() @clearEventListeners()
mergeInProgress: (deleteSourceBranch = false)-> mergeInProgress: (deleteSourceBranch = false)->
...@@ -67,6 +74,7 @@ class @MergeRequestWidget ...@@ -67,6 +74,7 @@ class @MergeRequestWidget
$('.ci-widget-fetching').show() $('.ci-widget-fetching').show()
$.getJSON @opts.ci_status_url, (data) => $.getJSON @opts.ci_status_url, (data) =>
return if @cancel
@readyForCICheck = true @readyForCICheck = true
if data.status is '' if data.status is ''
...@@ -106,6 +114,7 @@ class @MergeRequestWidget ...@@ -106,6 +114,7 @@ class @MergeRequestWidget
@firstCICheck = false @firstCICheck = false
showCIStatus: (state) -> showCIStatus: (state) ->
return if not state?
$('.ci_widget').hide() $('.ci_widget').hide()
allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"] allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
if state in allowed_states if state in allowed_states
...@@ -113,7 +122,7 @@ class @MergeRequestWidget ...@@ -113,7 +122,7 @@ class @MergeRequestWidget
switch state switch state
when "failed", "canceled", "not_found" when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger') @setMergeButtonClass('btn-danger')
when "running", "pending" when "running"
@setMergeButtonClass('btn-warning') @setMergeButtonClass('btn-warning')
when "success" when "success"
@setMergeButtonClass('btn-create') @setMergeButtonClass('btn-create')
...@@ -126,6 +135,6 @@ class @MergeRequestWidget ...@@ -126,6 +135,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text) $('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) -> setMergeButtonClass: (css_class) ->
$('.accept_merge_request') $('.js-merge-button,.accept-action .dropdown-toggle')
.removeClass('btn-danger btn-warning btn-create') .removeClass('btn-danger btn-warning btn-create')
.addClass(css_class) .addClass(css_class)
...@@ -114,9 +114,9 @@ class @Notes ...@@ -114,9 +114,9 @@ class @Notes
@refresh() @refresh()
, @pollingInterval , @pollingInterval
refresh: -> refresh: =>
return if @refreshing is true return if @refreshing is true
refreshing = true @refreshing = true
if not document.hidden and document.URL.indexOf(@noteable_url) is 0 if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent() @getContent()
...@@ -134,7 +134,7 @@ class @Notes ...@@ -134,7 +134,7 @@ class @Notes
@renderDiscussionNote(note) @renderDiscussionNote(note)
else else
@renderNote(note) @renderNote(note)
always: => .always () =>
@refreshing = false @refreshing = false
### ###
...@@ -285,6 +285,7 @@ class @Notes ...@@ -285,6 +285,7 @@ class @Notes
form.addClass "js-main-target-form" form.addClass "js-main-target-form"
form.find("#note_line_code").remove() form.find("#note_line_code").remove()
form.find("#note_type").remove()
### ###
General note form setup. General note form setup.
...@@ -328,7 +329,7 @@ class @Notes ...@@ -328,7 +329,7 @@ class @Notes
@renderDiscussionNote(note) @renderDiscussionNote(note)
# cleanup after successfully creating a diff/discussion 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 Called in response to the edit note form being submitted
...@@ -472,6 +473,7 @@ class @Notes ...@@ -472,6 +473,7 @@ class @Notes
setupDiscussionNoteForm: (dataHolder, form) => setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target # setup note target
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}" form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
form.find("#note_type").val dataHolder.data("noteType")
form.find("#line_type").val dataHolder.data("lineType") form.find("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId") form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode") form.find("#note_line_code").val dataHolder.data("lineCode")
......
...@@ -10,6 +10,40 @@ class @Sidebar ...@@ -10,6 +10,40 @@ class @Sidebar
$('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading) $('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading)
$('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded) $('.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) -> sidebarDropdownLoading: (e) ->
$sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon') $sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon')
img = $sidebarCollapsedIcon.find('img') img = $sidebarCollapsedIcon.find('img')
...@@ -76,7 +110,7 @@ class @Sidebar ...@@ -76,7 +110,7 @@ class @Sidebar
@triggerOpenSidebar() if not @isOpen() @triggerOpenSidebar() if not @isOpen()
if action is 'hide' if action is 'hide'
@triggerOpenSidebar() is @isOpen() @triggerOpenSidebar() if @isOpen()
isOpen: -> isOpen: ->
@sidebar.is('.right-sidebar-expanded') @sidebar.is('.right-sidebar-expanded')
......
...@@ -20,8 +20,7 @@ class @SearchAutocomplete ...@@ -20,8 +20,7 @@ class @SearchAutocomplete
@dropdown = @wrap.find('.dropdown') @dropdown = @wrap.find('.dropdown')
@dropdownContent = @dropdown.find('.dropdown-content') @dropdownContent = @dropdown.find('.dropdown-content')
@locationBadgeEl = @getElement('.search-location-badge') @locationBadgeEl = @getElement('.location-badge')
@locationText = @getElement('.location-text')
@scopeInputEl = @getElement('#scope') @scopeInputEl = @getElement('#scope')
@searchInput = @getElement('.search-input') @searchInput = @getElement('.search-input')
@projectInputEl = @getElement('#search_project_id') @projectInputEl = @getElement('#search_project_id')
...@@ -133,7 +132,7 @@ class @SearchAutocomplete ...@@ -133,7 +132,7 @@ class @SearchAutocomplete
scope: @scopeInputEl.val() scope: @scopeInputEl.val()
# Location badge # Location badge
_location: @locationText.text() _location: @locationBadgeEl.text()
} }
bindEvents: -> bindEvents: ->
...@@ -143,12 +142,14 @@ class @SearchAutocomplete ...@@ -143,12 +142,14 @@ class @SearchAutocomplete
@searchInput.on 'click', @onSearchInputClick @searchInput.on 'click', @onSearchInputClick
@searchInput.on 'focus', @onSearchInputFocus @searchInput.on 'focus', @onSearchInputFocus
@clearInput.on 'click', @onClearInputClick @clearInput.on 'click', @onClearInputClick
@locationBadgeEl.on 'click', =>
@searchInput.focus()
onDocumentClick: (e) => onDocumentClick: (e) =>
# If clicking outside the search box # If clicking outside the search box
# And search input is not focused # And search input is not focused
# And we are not clicking inside a suggestion # And we are not clicking inside a suggestion
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).parents('ul').length if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).closest('.search-form').length
@onSearchInputBlur() @onSearchInputBlur()
enableAutocomplete: -> enableAutocomplete: ->
...@@ -221,10 +222,8 @@ class @SearchAutocomplete ...@@ -221,10 +222,8 @@ class @SearchAutocomplete
category = if item.category? then "#{item.category}: " else '' category = if item.category? then "#{item.category}: " else ''
value = if item.value? then item.value else '' value = if item.value? then item.value else ''
html = "<span class='location-badge'> badgeText = "#{category}#{value}"
<i class='location-text'>#{category}#{value}</i> @locationBadgeEl.text(badgeText).show()
</span>"
@locationBadgeEl.html(html)
@wrap.addClass('has-location-badge') @wrap.addClass('has-location-badge')
restoreOriginalState: -> restoreOriginalState: ->
...@@ -233,9 +232,8 @@ class @SearchAutocomplete ...@@ -233,9 +232,8 @@ class @SearchAutocomplete
for input in inputs for input in inputs
@getElement("##{input}").val(@originalState[input]) @getElement("##{input}").val(@originalState[input])
if @originalState._location is '' if @originalState._location is ''
@locationBadgeEl.empty() @locationBadgeEl.hide()
else else
@addLocationBadge( @addLocationBadge(
value: @originalState._location value: @originalState._location
...@@ -244,7 +242,7 @@ class @SearchAutocomplete ...@@ -244,7 +242,7 @@ class @SearchAutocomplete
@dropdown.removeClass 'open' @dropdown.removeClass 'open'
badgePresent: -> badgePresent: ->
@locationBadgeEl.children().length @locationBadgeEl.length
resetSearchState: -> resetSearchState: ->
inputs = Object.keys @originalState inputs = Object.keys @originalState
...@@ -257,7 +255,7 @@ class @SearchAutocomplete ...@@ -257,7 +255,7 @@ class @SearchAutocomplete
@getElement("##{input}").val('') @getElement("##{input}").val('')
removeLocationBadge: -> removeLocationBadge: ->
@locationBadgeEl.empty() @locationBadgeEl.hide()
# Reset state # Reset state
@resetSearchState() @resetSearchState()
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
class @ShortcutsDashboardNavigation extends Shortcuts class @ShortcutsDashboardNavigation extends Shortcuts
constructor: -> constructor: ->
super() super()
Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-activity')) Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-activity'))
Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-issues')) Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-issues'))
Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-merge_requests')) Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-merge_requests'))
Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-projects')) Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-projects'))
@findAndFollowLink: (selector) -> @findAndFollowLink: (selector) ->
link = $(selector).attr('href') link = $(selector).attr('href')
......
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
# Personal projects # Personal projects
# </a> # </a>
# </li> # </li>
# <li class="snippets-tab">
# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
# </a>
# </li>
# </ul> # </ul>
# #
# <div class="tab-content"> # <div class="tab-content">
...@@ -41,6 +45,9 @@ ...@@ -41,6 +45,9 @@
# <div class="tab-pane" id="projects"> # <div class="tab-pane" id="projects">
# Projects content # Projects content
# </div> # </div>
# <div class="tab-pane" id="snippets">
# Snippets content
# </div>
# </div> # </div>
# #
# <div class="loading-status"> # <div class="loading-status">
...@@ -100,7 +107,7 @@ class @UserTabs ...@@ -100,7 +107,7 @@ class @UserTabs
if action is 'activity' if action is 'activity'
@loadActivities(source) @loadActivities(source)
if action in ['groups', 'contributed', 'projects'] if action in ['groups', 'contributed', 'projects', 'snippets']
@loadTab(source, action) @loadTab(source, action)
loadTab: (source, action) -> loadTab: (source, action) ->
......
# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require d3
#= require_tree .
class @Calendar
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
...@@ -93,7 +93,9 @@ class @UsersSelect ...@@ -93,7 +93,9 @@ class @UsersSelect
$dropdown.glDropdown( $dropdown.glDropdown(
data: (term, callback) => data: (term, callback) =>
@users term, (users) => isAuthorFilter = $('.js-author-search')
@users term, term is '' and isAuthorFilter, (users) =>
if term.length is 0 if term.length is 0
showDivider = 0 showDivider = 0
...@@ -138,7 +140,7 @@ class @UsersSelect ...@@ -138,7 +140,7 @@ class @UsersSelect
toggleLabel: (selected) -> toggleLabel: (selected) ->
if selected && 'id' of selected if selected && 'id' of selected
selected.name if selected.text then selected.text else selected.name
else else
defaultLabel defaultLabel
...@@ -219,7 +221,7 @@ class @UsersSelect ...@@ -219,7 +221,7 @@ class @UsersSelect
multiple: $(select).hasClass('multiselect') multiple: $(select).hasClass('multiselect')
minimumInputLength: 0 minimumInputLength: 0
query: (query) => query: (query) =>
@users query.term, (users) => @users query.term, @projectId?, (users) =>
data = { results: users } data = { results: users }
if query.term.length == 0 if query.term.length == 0
...@@ -302,7 +304,7 @@ class @UsersSelect ...@@ -302,7 +304,7 @@ class @UsersSelect
# Return users list. Filtered by query # Return users list. Filtered by query
# Only active users retrieved # Only active users retrieved
users: (query, callback) => users: (query, fromProject, callback) =>
url = @buildUrl(@usersPath) url = @buildUrl(@usersPath)
$.ajax( $.ajax(
...@@ -311,7 +313,7 @@ class @UsersSelect ...@@ -311,7 +313,7 @@ class @UsersSelect
search: query search: query
per_page: 20 per_page: 20
active: true active: true
project_id: @projectId project_id: @projectId if fromProject
group_id: @groupId group_id: @groupId
current_user: @showCurrentUser current_user: @showCurrentUser
author_id: @authorId author_id: @authorId
......
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
*= require select2 *= require select2
*= require_self *= require_self
*= require dropzone/basic *= require dropzone/basic
*= require cal-heatmap
*= require cropper.css *= require cropper.css
*= require animate
*/ */
/* /*
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
@import 'framework/tw_bootstrap'; @import 'framework/tw_bootstrap';
@import "framework/layout"; @import "framework/layout";
@import "framework/animations.scss";
@import "framework/avatar.scss"; @import "framework/avatar.scss";
@import "framework/blocks.scss"; @import "framework/blocks.scss";
@import "framework/buttons.scss"; @import "framework/buttons.scss";
......
// This file is based off animate.css 3.5.1, available here:
// https://github.com/daneden/animate.css/blob/3.5.1/animate.css
//
// animate.css - http://daneden.me/animate
// Version - 3.5.1
// Licensed under the MIT license - http://opensource.org/licenses/MIT
//
// Copyright (c) 2016 Daniel Eden
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animated.infinite {
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.hinge {
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
.animated.flipOutX,
.animated.flipOutY,
.animated.bounceIn,
.animated.bounceOut {
-webkit-animation-duration: .75s;
animation-duration: .75s;
}
@-webkit-keyframes pulse {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
-webkit-transform: scale3d(1.05, 1.05, 1.05);
transform: scale3d(1.05, 1.05, 1.05);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@keyframes pulse {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
-webkit-transform: scale3d(1.05, 1.05, 1.05);
transform: scale3d(1.05, 1.05, 1.05);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
.pulse {
-webkit-animation-name: pulse;
animation-name: pulse;
}
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
&.s32 { font-size: 20px; line-height: 32px; } &.s32 { font-size: 20px; line-height: 32px; }
&.s40 { font-size: 16px; line-height: 40px; } &.s40 { font-size: 16px; line-height: 40px; }
&.s60 { font-size: 32px; line-height: 60px; } &.s60 { font-size: 32px; line-height: 60px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 90px; } &.s90 { font-size: 36px; line-height: 90px; }
&.s110 { font-size: 40px; line-height: 112px; font-weight: 300; } &.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 140px; } &.s140 { font-size: 72px; line-height: 140px; }
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
background-color: $background-color; background-color: $background-color;
padding: $gl-padding; padding: $gl-padding;
margin-bottom: 0; margin-bottom: 0;
border-top: 1px solid $border-color; border-top: 1px solid $white-dark;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $white-dark;
color: $gl-gray; color: $gl-gray;
&.oneline-block { &.oneline-block {
...@@ -110,9 +110,9 @@ ...@@ -110,9 +110,9 @@
.cover-title { .cover-title {
color: $gl-header-color; color: $gl-header-color;
margin: 0; margin: 0;
font-size: 23px; font-size: 24px;
font-weight: normal; font-weight: normal;
margin: 16px 0 5px; margin-bottom: 5px;
color: #4c4e54; color: #4c4e54;
font-size: 23px; font-size: 23px;
line-height: 1.1; line-height: 1.1;
...@@ -137,7 +137,6 @@ ...@@ -137,7 +137,6 @@
} }
.cover-desc { .cover-desc {
padding: 0 $gl-padding 3px;
color: $gl-text-color; color: $gl-text-color;
&.username:last-child { &.username:last-child {
...@@ -205,7 +204,7 @@ ...@@ -205,7 +204,7 @@
.content-block { .content-block {
padding: $gl-padding 0; padding: $gl-padding 0;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $white-dark;
&.oneline-block { &.oneline-block {
line-height: 36px; line-height: 36px;
......
...@@ -16,6 +16,19 @@ ...@@ -16,6 +16,19 @@
@include btn-default; @include btn-default;
} }
@mixin btn-outline($background, $text, $border, $hover-background, $hover-text, $hover-border) {
background-color: $background;
color: $text;
border-color: $border;
&:hover,
&:focus {
background-color: $hover-background;
color: $hover-text;
border-color: $hover-border;;
}
}
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) { @mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
background-color: $light; background-color: $light;
border-color: $border-light; border-color: $border-light;
...@@ -106,11 +119,14 @@ ...@@ -106,11 +119,14 @@
@include btn-blue; @include btn-blue;
} }
&.btn-close,
&.btn-warning { &.btn-warning {
@include btn-orange; @include btn-orange;
} }
&.btn-close {
@include btn-outline($white-light, $orange-normal, $orange-normal, $orange-light, $white-light, $orange-light);
}
&.btn-danger, &.btn-danger,
&.btn-remove, &.btn-remove,
&.btn-red { &.btn-red {
......
.calender-block { .calender-block {
padding-left: 0;
padding-right: 0;
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) { @media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
overflow-x: scroll; overflow-x: scroll;
} }
} }
.user-calendar-activities { .user-calendar-activities {
.calendar_onclick_hr {
padding: 0;
margin: 10px 0;
}
.str-truncated { .str-truncated {
max-width: 70%; max-width: 70%;
} }
.text-expander { .user-calendar-activities-loading {
background: #eee; font-size: 24px;
color: #555;
padding: 0 5px;
cursor: pointer;
margin-left: 4px;
&:hover {
background-color: #ddd;
}
} }
} }
/** .user-calendar {
* This overwrites the default values of the cal-heatmap gem text-align: center;
*/
.calendar {
.qi {
fill: #fff;
}
.q1 {
fill: #ededed !important;
}
.q2 {
fill: #acd5f2 !important;
}
.q3 {
fill: #7fa8d1 !important;
}
.q4 {
fill: #49729b !important;
}
.q5 { .calendar {
fill: #254e77 !important; display: inline-block;
} }
}
.future { .user-contrib-cell {
visibility: hidden; &:hover {
cursor: pointer;
stroke: #000;
} }
}
.domain-background { .user-contrib-text {
fill: none; font-size: 12px;
shape-rendering: crispedges; fill: #959494;
} }
.ch-tooltip { .calendar-hint {
padding: 3px; margin-top: -23px;
font-weight: 550; float: right;
} font-size: 12px;
} }
...@@ -289,7 +289,7 @@ table { ...@@ -289,7 +289,7 @@ table {
text-shadow: none; text-shadow: none;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
margin-top: 11px; margin-top: 8px;
} }
} }
......
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
color: $dropdown-header-color; color: $dropdown-header-color;
font-size: 13px; font-size: 13px;
line-height: 22px; line-height: 22px;
padding: 0 10px 10px; padding: 0 10px;
} }
.separator + .dropdown-header { .separator + .dropdown-header {
...@@ -162,6 +162,10 @@ ...@@ -162,6 +162,10 @@
} }
} }
.dropdown-menu-full-width {
width: 100%;
}
.dropdown-menu-paging { .dropdown-menu-paging {
.dropdown-page-two, .dropdown-page-two,
.dropdown-menu-back { .dropdown-menu-back {
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
.file-holder { .file-holder {
border: 1px solid $border-color; border: 1px solid $border-color;
&.file-holder-no-border {
border: 0;
}
&.readme-holder { &.readme-holder {
margin: $gl-padding-top 0; margin: $gl-padding-top 0;
} }
...@@ -23,8 +27,17 @@ ...@@ -23,8 +27,17 @@
word-wrap: break-word; word-wrap: break-word;
border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0;
&.file-title-clear {
padding-left: 0;
padding-right: 0;
background-color: transparent;
.file-actions {
right: 0;
}
}
.file-actions { .file-actions {
float: right;
position: absolute; position: absolute;
top: 5px; top: 5px;
right: 15px; right: 15px;
...@@ -36,22 +49,6 @@ ...@@ -36,22 +49,6 @@
} }
} }
.filename {
&.old {
display: inline-block;
span.idiff {
background-color: #f8cbcb;
}
}
&.new {
display: inline-block;
span.idiff {
background-color: #a6f3a6;
}
}
}
a:not(.btn) { a:not(.btn) {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
......
...@@ -28,10 +28,6 @@ input[type='text'].danger { ...@@ -28,10 +28,6 @@ input[type='text'].danger {
} }
label { label {
&.control-label {
@extend .col-sm-2;
}
&.inline-label { &.inline-label {
margin: 0; margin: 0;
} }
...@@ -41,6 +37,10 @@ label { ...@@ -41,6 +37,10 @@ label {
} }
} }
.control-label {
@extend .col-sm-2;
}
.inline-input-group { .inline-input-group {
width: 250px; width: 250px;
} }
......
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) { @mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
.page-with-sidebar { .page-with-sidebar {
.header-logo { .header-logo {
background-color: $color; background: $color-darker;
border-color: $color;
a { a {
color: $color-light; color: $color-light;
...@@ -21,7 +20,7 @@ ...@@ -21,7 +20,7 @@
} }
&:hover { &:hover {
background-color: $color-darker; background-color: $color-dark;
a { a {
color: #fff; color: #fff;
...@@ -91,8 +90,8 @@ ...@@ -91,8 +90,8 @@
} }
$theme-blue: #2980b9; $theme-blue: #2980b9;
$theme-charcoal: #333c47; $theme-charcoal: #3d454d;
$theme-graphite: #888; $theme-graphite: #666;
$theme-gray: #373737; $theme-gray: #373737;
$theme-green: #019875; $theme-green: #019875;
$theme-violet: #548; $theme-violet: #548;
...@@ -103,11 +102,11 @@ body { ...@@ -103,11 +102,11 @@ body {
} }
&.ui_charcoal { &.ui_charcoal {
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d); @include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41);
} }
&.ui_graphite { &.ui_graphite {
@include gitlab-theme(#ccc, $theme-graphite, #777, #666); @include gitlab-theme(#ccc, #777, $theme-graphite, #555);
} }
&.ui_gray { &.ui_gray {
......
...@@ -6,12 +6,12 @@ header { ...@@ -6,12 +6,12 @@ header {
transition-duration: .3s; transition-duration: .3s;
&.navbar-empty { &.navbar-empty {
height: 58px; height: $header-height;
background: #fff; background: #fff;
border-bottom: 1px solid $btn-gray-hover; border-bottom: 1px solid $btn-gray-hover;
.center-logo { .center-logo {
margin: 11px 0; margin: 8px 0;
text-align: center; text-align: center;
#tanuki-logo, img { #tanuki-logo, img {
......
...@@ -48,10 +48,6 @@ ...@@ -48,10 +48,6 @@
display: block; display: block;
} }
.project-home-desc {
font-size: 21px;
}
.project-repo-buttons, .project-repo-buttons,
.git-clone-holder { .git-clone-holder {
display: none; display: none;
......
@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 { .nav-links {
padding: 0; padding: 0;
margin: 0; margin: 0;
...@@ -119,7 +150,7 @@ ...@@ -119,7 +150,7 @@
} }
input { input {
height: 34px; height: 35px;
display: inline-block; display: inline-block;
position: relative; position: relative;
top: 2px; top: 2px;
...@@ -196,7 +227,7 @@ ...@@ -196,7 +227,7 @@
position: fixed; position: fixed;
top: $header-height; top: $header-height;
width: 100%; width: 100%;
z-index: 1; z-index: 11;
background: $background-color; background: $background-color;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
transition-duration: .3s; transition-duration: .3s;
...@@ -209,6 +240,10 @@ ...@@ -209,6 +240,10 @@
float: right; float: right;
padding: 7px 0 0; padding: 7px 0 0;
@media (max-width: $screen-xs-max) {
display: none;
}
i { i {
color: $layout-link-gray; color: $layout-link-gray;
} }
...@@ -225,14 +260,31 @@ ...@@ -225,14 +260,31 @@
.dropdown { .dropdown {
margin-left: 7px; margin-left: 7px;
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
li.active {
font-weight: bold;
}
} }
} }
.nav-links { .nav-links {
@include scrolling-links();
border-bottom: none; border-bottom: none;
height: 51px; height: 51px;
white-space: nowrap;
overflow-x: auto; .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 { li {
...@@ -256,8 +308,62 @@ ...@@ -256,8 +308,62 @@
} }
} }
.nav-control {
.fade-right {
@media (min-width: $screen-xs-max) {
right: 67px;
}
@media (max-width: $screen-xs-min) {
right: 0;
}
}
}
}
.nav-block {
position: relative;
.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 { .page-with-layout-nav {
margin-top: 50px; 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;
}
}
} }
...@@ -312,7 +312,7 @@ ...@@ -312,7 +312,7 @@
} }
.nav-sidebar li a { .nav-sidebar li a {
width: 230px; width: $sidebar_width;
&.back-link { &.back-link {
i { i {
...@@ -324,7 +324,7 @@ ...@@ -324,7 +324,7 @@
.layout-nav { .layout-nav {
@media (max-width: $screen-xs-min) { @media (max-width: $screen-xs-min) {
padding-right: 0;; padding-right: 0;
} }
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) { @media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
......
...@@ -269,3 +269,11 @@ h1, h2, h3, h4 { ...@@ -269,3 +269,11 @@ h1, h2, h3, h4 {
text-align: right; text-align: right;
} }
} }
.idiff.deletion {
background: $line-removed-dark;
}
.idiff.addition {
background: $line-added-dark;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Layout * Layout
*/ */
$sidebar_collapsed_width: 62px; $sidebar_collapsed_width: 62px;
$sidebar_width: 230px; $sidebar_width: 220px;
$gutter_collapsed_width: 62px; $gutter_collapsed_width: 62px;
$gutter_width: 290px; $gutter_width: 290px;
$gutter_inner_width: 258px; $gutter_inner_width: 258px;
...@@ -12,7 +12,7 @@ $gutter_inner_width: 258px; ...@@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
*/ */
$border-color: #e5e5e5; $border-color: #e5e5e5;
$focus-border-color: #3aabf0; $focus-border-color: #3aabf0;
$table-border-color: #ececec; $table-border-color: #f0f0f0;
$background-color: #fafafa; $background-color: #fafafa;
/* /*
...@@ -63,7 +63,8 @@ $gl-padding-top: 10px; ...@@ -63,7 +63,8 @@ $gl-padding-top: 10px;
/* /*
* Misc * Misc
*/ */
$row-hover: #f4f8fe; $row-hover: #f7faff;
$row-hover-border: #b2d7ff;
$progress-color: #c0392b; $progress-color: #c0392b;
$avatar_radius: 50%; $avatar_radius: 50%;
$header-height: 50px; $header-height: 50px;
...@@ -104,7 +105,7 @@ $blue-medium-light: #3498cb; ...@@ -104,7 +105,7 @@ $blue-medium-light: #3498cb;
$blue-medium: #2f8ebf; $blue-medium: #2f8ebf;
$blue-medium-dark: #2d86b4; $blue-medium-dark: #2d86b4;
$orange-light: rgba(252, 109, 38, 0.80); $orange-light: #fc8a51;
$orange-normal: #e75e40; $orange-normal: #e75e40;
$orange-dark: #ce5237; $orange-dark: #ce5237;
...@@ -119,8 +120,8 @@ $border-white-light: #f1f2f4; ...@@ -119,8 +120,8 @@ $border-white-light: #f1f2f4;
$border-white-normal: #d6dae2; $border-white-normal: #d6dae2;
$border-white-dark: #c6cacf; $border-white-dark: #c6cacf;
$border-gray-light: rgba(0, 0, 0, 0.06); $border-gray-light: #dcdcdc;
$border-gray-normal: rgba(0, 0, 0, 0.10);; $border-gray-normal: rgba(0, 0, 0, 0.10);
$border-gray-dark: #c6cacf; $border-gray-dark: #c6cacf;
$border-green-light: #2faa60; $border-green-light: #2faa60;
...@@ -178,6 +179,7 @@ $table-border-gray: #f0f0f0; ...@@ -178,6 +179,7 @@ $table-border-gray: #f0f0f0;
$line-target-blue: #eaf3fc; $line-target-blue: #eaf3fc;
$line-select-yellow: #fcf8e7; $line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd; $line-select-yellow-dark: #f0e2bd;
/* /*
* Fonts * Fonts
*/ */
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
} }
} }
.zen-cotrol { .zen-control {
padding: 0; padding: 0;
color: #555; color: #555;
background: none; background: none;
......
// 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;
}
}
@import "framework/variables";
table.code {
width: 100%;
font-family: monospace;
border: none;
border-collapse: separate;
margin: 0;
padding: 0;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
td {
line-height: $code_line_height;
font-family: monospace;
font-size: $code_font_size;
}
td.diff-line-num {
margin: 0;
padding: 0;
border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0 5px;
border-right: 1px solid $border-color;
text-align: right;
min-width: 35px;
max-width: 50px;
width: 35px;
}
td.line_content {
display: block;
margin: 0;
padding: 0 0.5em;
border: none;
white-space: pre;
}
}
@import "highlight/white";
...@@ -26,8 +26,28 @@ ...@@ -26,8 +26,28 @@
.commit-info-row { .commit-info-row {
margin-bottom: 10px; 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 { .avatar {
@extend .avatar-inline; @extend .avatar-inline;
margin-left: 0;
@media (min-width: $screen-sm-min) {
margin-left: 4px;
}
} }
.commit-committer-link, .commit-committer-link,
.commit-author-link { .commit-author-link {
...@@ -35,10 +55,6 @@ ...@@ -35,10 +55,6 @@
font-weight: bold; font-weight: bold;
} }
.time_ago {
margin-left: 8px;
}
.fa-clipboard { .fa-clipboard {
color: $dropdown-title-btn-color; color: $dropdown-title-btn-color;
} }
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
margin-top: 6px; margin-top: 6px;
p { p {
overflow-x: auto;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.file-title { .file-title {
@extend .monospace; @extend .monospace;
line-height: 42px; line-height: 35px;
padding-top: 7px; padding-top: 7px;
padding-bottom: 7px; padding-bottom: 7px;
...@@ -59,7 +59,22 @@ ...@@ -59,7 +59,22 @@
} }
.encoding-selector, .encoding-selector,
.license-selector { .license-selector,
.gitignore-selector {
display: inline-block; display: inline-block;
vertical-align: top;
font-family: $regular_font;
}
.gitignore-selector {
.dropdown {
line-height: 21px;
}
.dropdown-menu-toggle {
vertical-align: top;
width: 220px;
}
} }
} }
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
.right-sidebar { .right-sidebar {
position: fixed; position: fixed;
top: 58px; top: $header-height;
bottom: 0; bottom: 0;
right: 0; right: 0;
z-index: 10; z-index: 10;
...@@ -150,6 +150,10 @@ ...@@ -150,6 +150,10 @@
font-weight: 600; font-weight: 600;
} }
.light {
font-weight: normal;
}
.sidebar-collapsed-icon { .sidebar-collapsed-icon {
display: none; display: none;
} }
......
...@@ -40,11 +40,6 @@ ...@@ -40,11 +40,6 @@
} }
} }
.issue-search-form {
margin: 0;
height: 24px;
}
form.edit-issue { form.edit-issue {
margin: 0; margin: 0;
} }
...@@ -96,8 +91,3 @@ form.edit-issue { ...@@ -96,8 +91,3 @@ form.edit-issue {
.issue-form .select2-container { .issue-form .select2-container {
width: 250px !important; width: 250px !important;
} }
.issue-closed-by-widget {
color: $gl-text-color;
margin-left: 52px;
}
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
margin: 0; margin: 0;
margin-left: 20px; margin-left: 20px;
padding: 5px; padding: 5px;
padding-top: 12px; padding-top: 8px;
line-height: 20px; line-height: 20px;
&.right { &.right {
...@@ -110,6 +110,29 @@ ...@@ -110,6 +110,29 @@
p:last-child { p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@media (max-width: $screen-sm-max) {
h4 {
font-size: 15px;
}
p {
font-size: 13px;
}
.btn,
.btn-group,
.accept-action {
width: 100%;
margin-bottom: 4px;
}
.accept-control {
width: 100%;
text-align: center;
margin: 0;
}
}
} }
.mr-widget-footer { .mr-widget-footer {
...@@ -280,11 +303,5 @@ ...@@ -280,11 +303,5 @@
background-color: $white-light; background-color: $white-light;
color: $gl-placeholder-color; color: $gl-placeholder-color;
} }
th,
td {
padding: 16px;
}
} }
} }
...@@ -226,8 +226,7 @@ ul.notes { ...@@ -226,8 +226,7 @@ ul.notes {
} }
} }
.note-action-button, .note-action-button {
.discussion-action-button {
display: inline-block; display: inline-block;
margin-left: 10px; margin-left: 10px;
line-height: 24px; line-height: 24px;
......
.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 @@ ...@@ -66,12 +66,6 @@
} }
} }
.calendar-hint {
margin-top: -12px;
float: right;
font-size: 12px;
}
.profile-link-holder { .profile-link-holder {
display: inline; display: inline;
...@@ -134,14 +128,6 @@ ...@@ -134,14 +128,6 @@
} }
} }
.change-username-title {
color: $gl-warning;
}
.remove-account-title {
color: $gl-danger;
}
.provider-btn-group { .provider-btn-group {
display: inline-block; display: inline-block;
margin-right: 10px; margin-right: 10px;
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
} }
.no-ssh-key-message, .project-limit-message { .no-ssh-key-message, .project-limit-message {
background-color: #f28d35; background-color: #f28d35;
margin-bottom: 16px; margin-bottom: 0;
} }
.new_project, .new_project,
.edit_project { .edit-project {
fieldset.features { fieldset.features {
.control-label { .control-label {
font-weight: normal; font-weight: normal;
...@@ -26,8 +26,13 @@ ...@@ -26,8 +26,13 @@
} }
.project-home-panel { .project-home-panel {
padding-bottom: 40px; background: $white-light;
border-bottom: 1px solid $border-color; text-align: left;
padding: 24px 0;
.container-fluid {
position: relative;
}
.cover-controls { .cover-controls {
.project-settings-dropdown { .project-settings-dropdown {
...@@ -43,21 +48,55 @@ ...@@ -43,21 +48,55 @@
} }
} }
.project-identicon-holder { .cover-title {
margin-bottom: 16px; margin-bottom: 0;
}
.project-image-container {
@include make-sm-column(1);
max-width: 86px;
min-width: 86px;
padding-right: 0;
margin: 11px 0;
.avatar, .identicon { @media (max-width: $screen-md-max) {
margin: 0 auto; padding-left: 0;
float: none; margin: 0 0 10px;
max-width: none;
min-width: none;
.avatar.s70 {
margin: auto;
}
}
}
.project-info {
@include make-sm-column(10);
h1 {
font-size: 24px;
font-weight: normal;
margin: 0;
}
.project-home-desc {
p {
margin: 0;
}
}
} }
.identicon { .identicon {
float: left;
@include border-radius(50%); @include border-radius(50%);
} }
.avatar {
float: none;
} }
.notifications-btn { .notifications-btn {
margin-top: -28px;
.fa-bell { .fa-bell {
margin-right: 6px; margin-right: 6px;
...@@ -69,28 +108,45 @@ ...@@ -69,28 +108,45 @@
} }
.project-repo-buttons { .project-repo-buttons {
margin-top: 20px; font-size: 0;
margin-bottom: 0;
.count-buttons { .btn {
display: block; @include btn-gray;
margin-bottom: 20px; padding: 3px 10px;
text-transform: none;
background-color: $background-color;
.fa {
color: $layout-link-gray;
} }
.clone-row { .fa-caret-down {
.split-repo-buttons, margin-left: 3px;
.project-clone-holder { }
display: inline-block;
} }
.split-repo-buttons { .btn-group:not(:first-child):not(:last-child) > .btn {
margin: 0 12px; border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
} }
form {
margin-left: 10px;
} }
.btn { .count-buttons {
@include btn-gray; display: inline-block;
text-transform: none; vertical-align: top;
margin-top: 16px;
}
.project-clone-holder {
display: inline-block;
margin-top: 16px;
input {
height: 29px;
}
} }
.count-with-arrow { .count-with-arrow {
...@@ -140,14 +196,18 @@ ...@@ -140,14 +196,18 @@
line-height: 13px; line-height: 13px;
padding: $gl-vert-padding $gl-padding; padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px; letter-spacing: .4px;
padding: 10px 14px; padding: 7px 14px;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
touch-action: manipulation; touch-action: manipulation;
cursor: pointer; cursor: pointer;
background-image: none; background-image: none;
white-space: nowrap; white-space: nowrap;
margin: 0 11px 0 4px; margin: 0 10px 0 4px;
a {
color: inherit;
}
&:hover { &:hover {
background: #fff; background: #fff;
...@@ -155,13 +215,37 @@ ...@@ -155,13 +215,37 @@
} }
} }
} }
.project-right-buttons {
position: absolute;
right: 16px;
bottom: 0;
.btn {
padding: 3px 10px;
background-color: $background-color;
}
@media (max-width: 1304px) {
top: 0;
}
}
@media (max-width: $screen-md-max) {
text-align: center;
.project-info,
.project-image-container {
width: 100%;
}
}
} }
.split-one { .split-one {
display: inline-table; display: inline-table;
margin-right: 12px; margin-right: 12px;
a { > a {
margin: -1px; margin: -1px;
} }
} }
...@@ -285,11 +369,11 @@ a.deploy-project-label { ...@@ -285,11 +369,11 @@ a.deploy-project-label {
} }
.project-stats { .project-stats {
text-align: center;
margin-top: $gl-padding; margin-top: $gl-padding;
margin-bottom: 0; margin-bottom: 0;
padding-top: 10px; padding: 16px 0;
padding-bottom: 4px; background-color: $white-light;
font-size: 0;
ul.nav { ul.nav {
display: inline-block; display: inline-block;
...@@ -300,12 +384,11 @@ a.deploy-project-label { ...@@ -300,12 +384,11 @@ a.deploy-project-label {
} }
.nav > li > a { .nav > li > a {
@include btn-default;
@include btn-gray;
background-color: transparent; background-color: transparent;
border: 1px solid #f7f8fa; margin-right: 12px;
margin-left: 12px; padding: 0 10px;
font-size: 15px;
color: $notes-light-color;
} }
li { li {
...@@ -325,6 +408,10 @@ a.deploy-project-label { ...@@ -325,6 +408,10 @@ a.deploy-project-label {
background-color: #f0f2f5; background-color: #f0f2f5;
} }
} }
&.row-content-block.second-block {
margin-top: 0;
}
} }
pre.light-well { pre.light-well {
...@@ -442,9 +529,14 @@ pre.light-well { ...@@ -442,9 +529,14 @@ pre.light-well {
border-top: 0; border-top: 0;
.edit-project-readme { .edit-project-readme {
z-index: 100; z-index: 2;
position: relative; position: relative;
} }
.wiki h1 {
border-bottom: none;
padding: 0;
}
} }
.git-clone-holder { .git-clone-holder {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
} }
.search-input { .search-input {
padding-right: 20px;
border: none; border: none;
font-size: 14px; font-size: 14px;
outline: none; outline: none;
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
display: inline-block; display: inline-block;
background-color: $location-badge-bg; background-color: $location-badge-bg;
vertical-align: top; vertical-align: top;
cursor: default;
} }
.search-input-container { .search-input-container {
...@@ -55,7 +57,7 @@ ...@@ -55,7 +57,7 @@
position: relative; position: relative;
} }
.search-location-badge, .search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported // Fallback if flexbox is not supported
display: inline-block; display: inline-block;
} }
......
...@@ -12,3 +12,11 @@ ...@@ -12,3 +12,11 @@
border: 1px solid $warning-message-border; border: 1px solid $warning-message-border;
border-radius: $border-radius-base; border-radius: $border-radius-base;
} }
.warning-title {
color: $gl-warning;
}
.danger-title {
color: $gl-danger;
}
...@@ -16,19 +16,6 @@ ...@@ -16,19 +16,6 @@
} }
} }
.snippet-box {
@include border-radius(2px);
display: block;
float: left;
padding: 0 $gl-padding;
font-weight: normal;
margin-right: 10px;
font-size: $gl-font-size;
border: 1px solid;
line-height: 32px;
}
.markdown-snippet-copy { .markdown-snippet-copy {
position: fixed; position: fixed;
top: -10px; top: -10px;
...@@ -36,3 +23,34 @@ ...@@ -36,3 +23,34 @@
max-height: 0; max-height: 0;
max-width: 0; max-width: 0;
} }
.file-holder.snippet-file-content {
padding-bottom: $gl-padding;
border-bottom: 1px solid $border-color;
.file-title {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
}
.file-actions {
top: 12px;
}
.file-content {
border-left: 1px solid $border-color;
border-right: 1px solid $border-color;
border-bottom: 1px solid $border-color;
}
}
.snippet-title {
font-size: 24px;
font-weight: normal;
}
.snippet-actions {
@media (min-width: $screen-sm-min) {
float: right;
}
}
...@@ -29,6 +29,17 @@ ...@@ -29,6 +29,17 @@
.todo-item { .todo-item {
.todo-title { .todo-title {
@include str-truncated(calc(100% - 174px)); @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 { .todo-body {
...@@ -76,12 +87,11 @@ ...@@ -76,12 +87,11 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.todo-item { .todo-item {
padding-left: $gl-padding;
.todo-title { .todo-title {
white-space: normal; white-space: normal;
overflow: visible; overflow: visible;
max-width: 100%; max-width: 100%;
margin-bottom: 10px;
} }
.avatar { .avatar {
......
...@@ -15,16 +15,23 @@ ...@@ -15,16 +15,23 @@
margin-bottom: 0; margin-bottom: 0;
tr { tr {
> td, > th { border-bottom: 1px solid $table-border-gray;
border-top: 1px solid $table-border-gray;
td, th {
line-height: 23px; line-height: 23px;
} }
&:hover { &:hover {
cursor: pointer;
td { td {
background: $row-hover; background-color: $row-hover;
border-top: 1px solid $row-hover-border;
border-bottom: 1px solid $row-hover-border;
} }
cursor: pointer;
} }
&.selected { &.selected {
td { td {
background: $gray-dark; background: $gray-dark;
......
...@@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController ...@@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
abuse_report.remove_user(deleted_by: current_user) if params[:remove_user] abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
abuse_report.destroy abuse_report.destroy
render nothing: true head :ok
end end
end end
...@@ -19,6 +19,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -19,6 +19,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
redirect_to admin_runners_path redirect_to admin_runners_path
end end
def reset_health_check_token
@application_setting.reset_health_check_access_token!
flash[:notice] = 'New health check access token has been generated!'
redirect_to :back
end
def clear_repository_check_states def clear_repository_check_states
RepositoryCheck::ClearWorker.perform_async RepositoryCheck::ClearWorker.perform_async
...@@ -53,6 +59,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -53,6 +59,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end end
end end
enabled_oauth_sign_in_sources = params[:application_setting].delete(:enabled_oauth_sign_in_sources)
params[:application_setting][:disabled_oauth_sign_in_sources] =
AuthHelper.button_based_providers.map(&:to_s) -
Array(enabled_oauth_sign_in_sources)
params.require(:application_setting).permit( params.require(:application_setting).permit(
:default_projects_limit, :default_projects_limit,
:default_branch_protection, :default_branch_protection,
...@@ -94,8 +106,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -94,8 +106,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:email_author_in_body, :email_author_in_body,
:repository_checks_enabled, :repository_checks_enabled,
:metrics_packet_size, :metrics_packet_size,
:send_user_confirmation_email,
:container_registry_token_expire_delay,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [] import_sources: [],
disabled_oauth_sign_in_sources: []
) )
end end
end end
...@@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController ...@@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
respond_to do |format| respond_to do |format|
format.html { redirect_back_or_default(default: { action: 'index' }) } format.html { redirect_back_or_default(default: { action: 'index' }) }
format.js { render nothing: true } format.js { head :ok }
end end
end end
......
class Admin::HealthCheckController < Admin::ApplicationController
def show
@errors = HealthCheck::Utils.process_checks('standard')
end
end
...@@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController ...@@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.js { render nothing: true } format.js { head :ok }
end end
end end
......
...@@ -9,24 +9,19 @@ class Admin::RunnersController < Admin::ApplicationController ...@@ -9,24 +9,19 @@ class Admin::RunnersController < Admin::ApplicationController
end end
def show def show
@builds = @runner.builds.order('id DESC').first(30) assign_builds_and_projects
@projects =
if params[:search].present?
::Project.search(params[:search])
else
Project.all
end
@projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
end end
def update def update
@runner.update_attributes(runner_params) if @runner.update_attributes(runner_params)
respond_to do |format| respond_to do |format|
format.js format.js
format.html { redirect_to admin_runner_path(@runner) } format.html { redirect_to admin_runner_path(@runner) }
end end
else
assign_builds_and_projects
render 'show'
end
end end
def destroy def destroy
...@@ -58,6 +53,18 @@ class Admin::RunnersController < Admin::ApplicationController ...@@ -58,6 +53,18 @@ class Admin::RunnersController < Admin::ApplicationController
end end
def runner_params def runner_params
params.require(:runner).permit(:token, :description, :tag_list, :active) params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
def assign_builds_and_projects
@builds = runner.builds.order('id DESC').first(30)
@projects =
if params[:search].present?
::Project.search(params[:search])
else
Project.all
end
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
end end
end end
...@@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController ...@@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed." redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
else else
spam_log.destroy spam_log.destroy
render nothing: true head :ok
end end
end end
end end
...@@ -119,6 +119,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -119,6 +119,7 @@ class Admin::UsersController < Admin::ApplicationController
user_params_with_pass.merge!( user_params_with_pass.merge!(
password: params[:user][:password], password: params[:user][:password],
password_confirmation: params[:user][:password_confirmation], password_confirmation: params[:user][:password_confirmation],
password_expires_at: Time.now
) )
end end
...@@ -153,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -153,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController
respond_to do |format| respond_to do |format|
format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") } format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
format.js { render nothing: true } format.js { head :ok }
end end
end end
......
...@@ -222,7 +222,7 @@ class ApplicationController < ActionController::Base ...@@ -222,7 +222,7 @@ class ApplicationController < ActionController::Base
end end
def configure_permitted_parameters def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me, :otp_attempt) } devise_parameter_sanitizer.permit(:sign_in, keys: [:username, :email, :password, :login, :remember_me, :otp_attempt])
end end
def hexdigest(string) def hexdigest(string)
...@@ -253,7 +253,7 @@ class ApplicationController < ActionController::Base ...@@ -253,7 +253,7 @@ class ApplicationController < ActionController::Base
# internal repos where you are not a member. Enable this filter # internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you # or improve current implementation to filter only issues you
# created or assigned or mentioned # created or assigned or mentioned
#@filter_params[:authorized_only] = true # @filter_params[:authorized_only] = true
end end
@filter_params @filter_params
......
...@@ -31,6 +31,24 @@ class AutocompleteController < ApplicationController ...@@ -31,6 +31,24 @@ class AutocompleteController < ApplicationController
render json: @user, only: [:name, :username, :id], methods: [:avatar_url] render json: @user, only: [:name, :username, :id], methods: [:avatar_url]
end 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 private
def find_users def find_users
......
...@@ -6,7 +6,7 @@ module ToggleSubscriptionAction ...@@ -6,7 +6,7 @@ module ToggleSubscriptionAction
subscribable_resource.toggle_subscription(current_user) subscribable_resource.toggle_subscription(current_user)
render nothing: true head :ok
end end
private private
......
...@@ -28,7 +28,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -28,7 +28,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end end
def starred def starred
@projects = current_user.starred_projects.sorted_by_activity @projects = current_user.viewable_starred_projects.sorted_by_activity
@projects = filter_projects(@projects) @projects = filter_projects(@projects)
@projects = @projects.includes(:namespace, :forked_from_project, :tags) @projects = @projects.includes(:namespace, :forked_from_project, :tags)
@projects = @projects.sort(@sort = params[:sort]) @projects = @projects.sort(@sort = params[:sort])
......
...@@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController ...@@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format| respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: todo_notice } format.html { redirect_to dashboard_todos_path, notice: todo_notice }
format.js { render nothing: true } format.js { head :ok }
format.json do format.json do
render json: { count: @todos.size, done_count: current_user.todos.done.count } render json: { count: @todos.size, done_count: current_user.todos.done.count }
end end
...@@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController ...@@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format| respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' } format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
format.js { render nothing: true } format.js { head :ok }
format.json do format.json do
find_todos find_todos
render json: { count: @todos.size, done_count: current_user.todos.done.count } render json: { count: @todos.size, done_count: current_user.todos.done.count }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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