Commit 7863319b authored by Raffael Schmid's avatar Raffael Schmid

Merge branch 'master' into dont-depend-on-appid-and-appsecret

* master: (238 commits)
  Version 6.5.1
  Fix selectbox when submit MR from fork to origin
  Fix HELP layout
  No need for code tag here.
  Spelling mistake and add links.
  Warn against RVM.
  Remove GitHub mention because we also have a GitLab issue tracker now.
  Replace 6.0-to-6.4.md with 6.0-to-6.5.md
  Add public assets to gitignore
  Version 6.5.0
  Use 6-5 branch in installation docs
  Remove deprecated twitter handle.
  Further explain userPrincipalName settings
  Update from 6.4 to 6.5 guide
  Explain how to use AD userPrincipalName for logins
  More entries to CHANGELOG. Version to rc1
  Rephrase LDAP check script output
  add O'Reilly sponsorship in CHANGELOG
  Fix select2 css for drop above style
  Rename "Website url" labels to "Website"
  ...
parents 568d1c27 68590fdd
......@@ -34,3 +34,4 @@ doc/code/*
.secret
*.log
public/uploads.*
public/assets/
v 6.5.1
- Fix branch selectbox when create merge request from fork
v 6.5.0
- Dropdown menus on issue#show page for assignee and milestone (Jason Blanchard)
- Add color custimization and previewing to broadcast messages
- Fixed notes anchors
- Load new comments in issues dynamically
- Added sort options to Public page
- Added new filters(assigned/authored/all) to Dashboard#issues, Dashboard#merge_request pages
- New filters (assigned/authored/all) for Dashboard#issues/merge_requests (sponsored by Say Media)
- Add project visibility icons to dashboard
- Enable secure cookies if https used
- Protect users/confirmation with rack_attack
- Default HTTP headers to protect against MIME-sniffing, force https if enabled
- Bootstrap 3 with responsive UI
- New repository download formats: tar.bz2, zip, tar (Jason Hollingsworth)
- Restyled accept widgets for MR
- SCSS refactored
- Use jquery timeago plugin
- Fix 500 error for rdoc files
- Ability to customize merge commit message (sponsored by Say Media)
- Search autocomplete via ajax
- Add website url to user profile
- Files API supports base64 encoded content (sponsored by O'Reilly Media)
- Added support for Go's repository retrieval (Bruno Albuquerque)
v6.4.3
- Don't use unicorn worker killer if PhusionPassenger is defined
......
This diff is collapsed.
......@@ -14,7 +14,6 @@ gem "protected_attributes"
gem 'rails-observers'
gem 'actionpack-page_caching'
gem 'actionpack-action_caching'
gem 'activerecord-deprecated_finders'
# Supported DBs
gem "mysql2", group: :mysql
......@@ -52,6 +51,9 @@ gem "grape", "~> 0.6.1"
gem "grape-entity", "~> 0.3.0"
gem 'rack-cors', require: 'rack/cors'
# Email validation
gem "email_validator", "~> 1.4.0", :require => 'email_validator/strict'
# Format dates and times
# based on human-friendly examples
gem "stamp"
......@@ -60,7 +62,7 @@ gem "stamp"
gem 'enumerize'
# Pagination
gem "kaminari", "~> 0.14.1"
gem "kaminari", "~> 0.15.1"
# HAML
gem "haml-rails"
......@@ -120,7 +122,7 @@ gem "redis-rails"
gem 'tinder', '~> 1.9.2'
# HipChat integration
gem "hipchat", "~> 0.9.0"
gem "hipchat", "~> 0.14.0"
# Flowdock integration
gem "gitlab-flowdock-git-hook", "~> 0.4.2"
......@@ -144,17 +146,16 @@ gem "therubyracer"
gem 'turbolinks'
gem 'jquery-turbolinks'
gem 'chosen-rails', "1.0.1"
gem 'select2-rails'
gem 'jquery-atwho-rails', "~> 0.3.3"
gem "jquery-rails", "2.1.3"
gem "jquery-ui-rails", "2.0.2"
gem "modernizr", "2.6.2"
gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 2.3'
gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 3.2'
gem "gemoji", "~> 1.3.0"
gem "gon", git: "https://github.com/gitlabhq/gon.git", ref: '58ca8e17273051cb370182cabd3602d1da6783ab'
gem "gon", '~> 5.0.0'
group :development do
gem "annotate", "~> 2.6.0.beta2"
......
GIT
remote: https://github.com/gitlabhq/gon.git
revision: 58ca8e17273051cb370182cabd3602d1da6783ab
ref: 58ca8e17273051cb370182cabd3602d1da6783ab
specs:
gon (4.1.1)
actionpack (>= 2.3.0)
json
GIT
remote: https://github.com/gitlabhq/markup.git
revision: 61ade389c1e1c159359338f570d18464a44ddbc4
......@@ -64,7 +55,7 @@ GEM
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bootstrap-sass (2.3.2.2)
bootstrap-sass (3.0.3.0)
sass (~> 3.2)
builder (3.1.4)
capybara (2.1.0)
......@@ -80,12 +71,6 @@ GEM
celluloid (0.15.2)
timers (~> 1.1.0)
charlock_holmes (0.6.9.4)
chosen-rails (1.0.1)
coffee-rails (>= 3.2)
compass-rails (>= 1.0)
railties (>= 3.0)
sass-rails (>= 3.2)
chunky_png (1.2.9)
cliver (0.2.2)
code_analyzer (0.4.3)
sexp_processor
......@@ -101,12 +86,6 @@ GEM
coffee-script-source (1.6.3)
colored (1.2)
colorize (0.5.8)
compass (0.12.2)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
compass-rails (1.1.1)
compass (>= 0.12.2)
connection_pool (1.2.0)
coveralls (0.7.0)
multi_json (~> 1.3)
......@@ -135,6 +114,8 @@ GEM
email_spec (1.5.0)
launchy (~> 2.1)
mail (~> 2.2)
email_validator (1.4.0)
activemodel
enumerize (0.7.0)
activesupport (>= 3.2)
equalizer (0.0.8)
......@@ -170,7 +151,6 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.4)
fssm (0.2.10)
gemoji (1.3.1)
gherkin-ruby (0.3.1)
racc
......@@ -212,6 +192,9 @@ GEM
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.1.1)
gon (5.0.1)
actionpack (>= 2.3.0)
json
grape (0.6.1)
activesupport
builder
......@@ -247,7 +230,7 @@ GEM
railties (~> 4.0.0)
hashie (2.0.5)
hike (1.2.3)
hipchat (0.9.0)
hipchat (0.14.0)
httparty
httparty
http_parser.rb (0.5.3)
......@@ -276,7 +259,7 @@ GEM
json (1.8.1)
jwt (0.1.8)
multi_json (>= 1.5)
kaminari (0.14.1)
kaminari (0.15.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kgio (2.8.1)
......@@ -298,7 +281,7 @@ GEM
minitest (4.7.5)
modernizr (2.6.2)
sprockets (~> 2.0)
multi_json (1.8.2)
multi_json (1.8.4)
multi_xml (0.5.5)
multipart-post (1.2.0)
mysql2 (0.3.11)
......@@ -568,17 +551,15 @@ PLATFORMS
DEPENDENCIES
actionpack-action_caching
actionpack-page_caching
activerecord-deprecated_finders
acts-as-taggable-on
annotate (~> 2.6.0.beta2)
asciidoctor
awesome_print
better_errors
binding_of_caller
bootstrap-sass (~> 2.3)
bootstrap-sass (~> 3.0)
capybara
carrierwave
chosen-rails (= 1.0.1)
coffee-rails
colored
coveralls
......@@ -587,6 +568,7 @@ DEPENDENCIES
devise (= 3.0.4)
devise-async (= 0.8.0)
email_spec
email_validator (~> 1.4.0)
enumerize
factory_girl_rails
ffaker
......@@ -603,21 +585,21 @@ DEPENDENCIES
gitlab_git (~> 4.0.0)
gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3)
gon!
gon (~> 5.0.0)
grape (~> 0.6.1)
grape-entity (~> 0.3.0)
growl
guard-rspec
guard-spinach
haml-rails
hipchat (~> 0.9.0)
hipchat (~> 0.14.0)
httparty
jasmine (= 2.0.0.rc5)
jquery-atwho-rails (~> 0.3.3)
jquery-rails (= 2.1.3)
jquery-turbolinks
jquery-ui-rails (= 2.0.2)
kaminari (~> 0.14.1)
kaminari (~> 0.15.1)
launchy
letter_opener
minitest (~> 4.7.0)
......
This diff is collapsed.
## GitLab: self hosted Git management software
![logo](https://raw.github.com/gitlabhq/gitlabhq/master/public/gitlab_logo.png)
![logo](https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/gitlab_logo.png)
![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif)
......@@ -34,7 +34,7 @@
* [GitLab Enterprise Edition](https://www.gitlab.com/features/) offers additional features that are useful for larger organizations (100+ users).
* [GitLab CI](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab.
* [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab.
### Requirements
......@@ -62,7 +62,7 @@
#### Unofficial installation methods
* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) repository with unofficial guides for using GitLab with different software (operating systems, webservers, etc.) than the official version.
* [GitLab recipes](https://gitlab.com/gitlab-org/gitlab-recipes/) repository with unofficial guides for using GitLab with different software (operating systems, webservers, etc.) than the official version.
* [Installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) public wiki with unofficial guides to install GitLab on different operating systems.
......@@ -145,13 +145,13 @@ or start each component separately
* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
* [Contributing guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) describes how to submit merge requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
* [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
* [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
* [#gitlab IRC channel](http://www.freenode.net/) on Freenode to get in touch with other GitLab users and get help, it's managed by James Newton, Drew Blessing and Sam Gleske
* [#gitlab IRC channel](http://www.freenode.net/) on Freenode to get in touch with other GitLab users and get help, it's managed by James Newton (newton), Drew Blessing (dblessing), and Sam Gleske (sag47).
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
......
......@@ -19,7 +19,6 @@
//= require jquery.turbolinks
//= require bootstrap
//= require modernizr
//= require chosen-jquery
//= require select2
//= require raphael
//= require g.raphael-min
......
......@@ -3,7 +3,7 @@ $ ->
container = $(@).closest(".js-toggler-container")
container.toggleClass("on")
$("body").on "click", ".js-toggle-visibility-link", (e) ->
$(@).find('i').
toggleClass('icon-chevron-down').
......@@ -11,7 +11,7 @@ $ ->
container = $(".js-toggle-visibility-container")
container.toggleClass("hide")
e.preventDefault()
$("body").on "click", ".js-toggle-button", (e) ->
$(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
e.preventDefault()
......@@ -194,11 +194,14 @@ class BranchGraph
fill: @colors[commit.space]
stroke: "none"
)
r.rect(@offsetX + @unitSpace * @mspace + 10, y - 10, 20, 20).attr(
fill: "url(#{commit.author.icon})"
avatar_box_x = @offsetX + @unitSpace * @mspace + 10
avatar_box_y = y - 10
r.rect(avatar_box_x, avatar_box_y, 20, 20).attr(
stroke: @colors[commit.space]
"stroke-width": 2
)
r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20)
r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr(
"text-anchor": "start"
font: "14px Monaco, monospace"
......
......@@ -47,5 +47,9 @@ class Dispatcher
initSearch: ->
autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts')
new SearchAutocomplete(autocomplete_json)
opts = $('.search-autocomplete-opts')
path = opts.data('autocomplete-path')
project_id = opts.data('autocomplete-project-id')
project_ref = opts.data('autocomplete-project-ref')
new SearchAutocomplete(path, project_id, project_ref)
......@@ -29,12 +29,10 @@
$('#filter_issue_search').val($('#issue_search').val())
initSelects: ->
$("#update_status").chosen()
$("#update_assignee_id").chosen()
$("#update_milestone_id").chosen()
$("#label_name").chosen()
$("#assignee_id").chosen()
$("#milestone_id").chosen()
$("select#update_status").select2(width: 'resolve', dropdownAutoWidth: true)
$("select#update_assignee_id").select2(width: 'resolve', dropdownAutoWidth: true)
$("select#update_milestone_id").select2(width: 'resolve', dropdownAutoWidth: true)
$("select#label_name").select2(width: 'resolve', dropdownAutoWidth: true)
$("#milestone_id, #assignee_id, #label_name").on "change", ->
$(this).closest("form").submit()
......
......@@ -67,8 +67,8 @@ $ ->
$('.appear-data').fadeIn()
e.preventDefault()
# Initialize chosen selects
$('select.chosen').chosen()
# Initialize select2 selects
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
# Initialize tooltips
$('.has_tooltip').tooltip()
......@@ -81,6 +81,7 @@ $ ->
$(@).parents('form').submit()
$("abbr.timeago").timeago()
$('.js-timeago').timeago()
# Flash
if (flash = $(".flash-container")).length > 0
......@@ -125,12 +126,6 @@ $ ->
$(@).remove()
(($) ->
_chosen = $.fn.chosen
$.fn.extend chosen: (options) ->
default_options = search_contains: "true"
$.extend default_options, options
_chosen.apply @, [default_options]
# Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: ->
$(@).attr('disabled', 'disabled').addClass('disabled')
......
......@@ -2,8 +2,8 @@
# * Filter merge requests
#
@merge_requestsPage = ->
$('#assignee_id').chosen()
$('#milestone_id').chosen()
$('#assignee_id').select2()
$('#milestone_id').select2()
$('#milestone_id, #assignee_id').on 'change', ->
$(this).closest('form').submit()
......@@ -24,6 +24,8 @@ class MergeRequest
modal = $('#modal_merge_info').modal(show: false)
disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
# Local jQuery finder
$: (selector) ->
this.$el.find(selector)
......
......@@ -37,6 +37,9 @@ class Notes
# attachment button
$(document).on "click", ".js-choose-note-attachment-button", @chooseNoteAttachment
# update the file name when an attachment is selected
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
# reply to diff/discussion notes
$(document).on "click", ".js-discussion-reply-button", @replyToDiscussionNote
......@@ -429,4 +432,16 @@ class Notes
updateVotes: ->
(new NotesVotes).updateVotes()
###
Called after an attachment file has been selected.
Updates the file name for the selected attachment.
###
updateFormAttachment: ->
form = $(this).closest("form")
# get only the basename
filename = $(this).val().replace(/^.*[\\\/]/, "")
form.find(".js-attachment-filename").text filename
@Notes = Notes
......@@ -35,7 +35,7 @@ $ ->
$('a, button', scope).removeClass 'active'
$(@).addClass 'active'
$('#project_clone', scope).val $(@).data 'clone'
$(".clone").text("").append 'git remote add origin ' + $(@).data 'clone'
$(".clone").text("").append $(@).data 'clone'
# Ref switcher
$('.project-refs-select').on 'change', ->
......
class SearchAutocomplete
constructor: (json) ->
constructor: (search_autocomplete_path, project_id, project_ref) ->
project_id = '' unless project_id
project_ref = '' unless project_ref
query = "?project_id=" + project_id + "&project_ref=" + project_ref
$("#search").autocomplete
source: json
source: search_autocomplete_path + query
minLength: 1
select: (event, ui) ->
location.href = ui.item.url
......
......@@ -46,11 +46,7 @@ class window.ContributorsGraph
class window.ContributorsMasterGraph extends ContributorsGraph
constructor: (@data) ->
if $(window).width() > 1214
@width = 1100
else
@width = 870
@width = $('.container').width() - 70
@height = 200
@x = null
@y = null
......@@ -88,7 +84,6 @@ class window.ContributorsMasterGraph extends ContributorsGraph
x(d.date)
).y0(@height).y1((d) ->
xa = d.commits = d.commits ? d.additions ? d.deletions
console.log(xa)
y(xa)
).interpolate("basis")
create_brush: ->
......@@ -124,11 +119,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
class window.ContributorsAuthorGraph extends ContributorsGraph
constructor: (@data) ->
if $(window).width() > 1214
@width = 490
else
@width = 380
@width = $('.container').width()/2 - 100
@height = 200
@x = null
@y = null
......
......@@ -4,19 +4,44 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require jquery.ui.gitlab
*= require jquery.atwho
*= require chosen
*= require select2
*= require_self
*/
@import "main/variables.scss";
@import "main/mixins.scss";
@import "main/fonts.scss";
@import "main/layout.scss";
/**
* Customized Twitter bootstrap
*/
@import 'gl_bootstrap';
/**
* GitLab bootstrap:
* Font icons
*
*/
@import "gitlab_bootstrap.scss";
@import "font-awesome";
@import "common.scss";
@import "selects.scss";
/**
* Generic css (forms, nav etc):
*/
@import "generic/avatar.scss";
@import "generic/common.scss";
@import "generic/typography.scss";
@import "generic/buttons.scss";
@import "generic/blocks.scss";
@import "generic/ui_box.scss";
@import "generic/issue_box.scss";
@import "generic/files.scss";
@import "generic/lists.scss";
@import "generic/forms.scss";
@import "generic/selects.scss";
/**
* Page specific styles (issues, projects etc):
*/
@import "sections/header.scss";
@import "sections/nav.scss";
@import "sections/commits.scss";
......@@ -39,6 +64,9 @@
@import "sections/dashboard.scss";
@import "sections/stat_graph.scss";
/**
* Code ighlight
*/
@import "highlight/white.scss";
@import "highlight/dark.scss";
@import "highlight/solarized_dark.scss";
......@@ -57,4 +85,3 @@
* Styles for JS behaviors.
*/
@import "behaviors.scss";
......@@ -143,16 +143,27 @@
line-height: 16px;
margin: 2px;
}
}
.btn-block {
width: 100%;
margin: 0;
margin-bottom: 15px;
&.btn {
padding: 6px 0;
}
}
.btn,
.btn-group {
&.grouped {
margin-right: 7px;
float: left;
}
&.btn-block {
width: 100%;
margin: 0;
padding: 6px 0;
margin-bottom: 15px;
&:last-child {
margin-right: 0px;
}
}
}
.btn-group-small > .btn { @extend .btn.btn-small; }
.btn-group-tiny > .btn { @extend .btn.btn-tiny; }
html {
overflow-y: scroll;
/** COLORS **/
.cgray { color: gray }
.clgray { color: #BBB }
.cred { color: #D12F19 }
.cgreen { color: #4a2 }
.cblue { color: #29A }
.cblack { color: #111 }
.cdark { color: #444 }
.camber { color: #ffc000 }
.cwhite { color: #fff!important }
.bgred { background: #F2DEDE!important }
/** COMMON CLASSES **/
.left { float:left }
.prepend-top-10 { margin-top:10px }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
.prepend-left-20 { margin-left:20px }
.append-right-10 { margin-right:10px }
.append-right-20 { margin-right:20px }
.append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px }
.inline { display: inline-block }
.padded { padding:20px }
.ipadded { padding:20px!important }
.lborder { border-left:1px solid #eee }
.underlined_link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
.light { color: #888 }
.tiny { font-weight: normal }
.vtop { vertical-align: top !important; }
/** ALERT MESSAGES **/
.alert.alert-disabled {
background: #EEE;
color: #777;
border-color: #DDD;
}
/** HELPERS **/
.nothing_here_message {
text-align: center;
padding: 20px;
color: #666;
font-weight: normal;
font-size: 16px;
line-height: 36px;
}
/** LAYOUT **/
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin-bottom: 20px;
.slead {
color: #666;
font-size: 14px;
margin-bottom: 12px;
font-weight: normal;
line-height: 24px;
}
.container {
padding-top: 0;
z-index: 5;
.tab-content {
overflow: visible;
}
.container .content {
margin: 0 0;
@media (max-width: 1200px) {
.only-wide {
display: none;
}
}
.author_link {
color: $link_color;
pre.well-pre {
border: 1px solid #EEE;
background: #f9f9f9;
border-radius: 0;
color: #555;
}
.help li { color:$style_color; }
.input-append .btn.active, .input-prepend .btn.active {
background: #CCC;
border-color: #BBB;
text-shadow: 0 1px 1px #fff;
font-weight: bold;
@include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
}
.back-link {
/** Big Labels **/
.state-label {
font-size: 14px;
padding: 6px 25px;
text-align: center;
@include border-radius(4px);
text-shadow: none;
margin-left: 10px;
&.state-label-green {
background: #4A4;
color: #FFF;
}
&.state-label-red {
background: #DA4E49;
color: #FFF;
}
}
table a code {
position: relative;
top: -2px;
margin-right: 3px;
.dropdown-menu > li > a {
text-shadow: none;
}
.loading {
margin: 20px auto;
background: url(ajax_loader.gif) no-repeat center center;
width: 40px;
height: 40px;
&.loading-gray {
background: url(ajax_loader_gray.gif) no-repeat center center;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: #29b;
}
.breadcrumb > li + li:before {
content: "/";
padding: 0;
color: #666;
}
.str-truncated {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
max-width: 82%;
}
/** FLASH message **/
......@@ -71,6 +155,31 @@ table a code {
padding: 10px;
}
}
.author_link {
color: $link_color;
}
.help li { color:$style_color; }
.back-link {
font-size: 14px;
}
table a code {
position: relative;
top: -2px;
margin-right: 3px;
}
.loading {
margin: 20px auto;
background: url(ajax_loader.gif) no-repeat center center;
width: 40px;
height: 40px;
&.loading-gray {
background: url(ajax_loader_gray.gif) no-repeat center center;
}
}
span.update-author {
display: block;
......@@ -92,19 +201,6 @@ span.update-author {
display: inline;
}
ul.breadcrumb {
background: white;
border: none;
li {
display: inline;
text-shadow: 0 1px 0 white
}
a {
font-size: 16px;
}
}
.line_holder {
&:hover {
td {
......@@ -119,18 +215,6 @@ p.time {
margin: 30px 3px 3px 2px;
}
.search-holder {
label, input {
height: 30px;
padding: 0;
font-size: 14px;
}
label {
line-height: 30px;
color: #666;
}
}
.highlight {
text-shadow: none;
}
......@@ -209,7 +293,7 @@ li.note {
}
.git_error_tips {
@extend .span6;
@extend .col-md-6;
text-align: left;
margin-top: 40px;
pre {
......@@ -236,6 +320,7 @@ li.note {
background: #C67;
margin: 0;
color: #FFF;
margin-top: -1px;
text-align: center;
a {
......@@ -344,12 +429,6 @@ table {
min-height: 100px;
}
.navbar-gitlab .navbar-inner .nav > li .btn-sign-in {
@extend .btn-new;
padding: 5px 15px;
text-shadow: none;
}
.broadcast-message {
padding: 10px;
text-align: center;
......@@ -395,3 +474,14 @@ table {
font-weight: bolder;
}
}
.btn-sign-in {
margin-top: 7px;
text-shadow: none;
}
.side-filters {
fieldset {
margin-bottom: 15px;
}
}
......@@ -20,7 +20,6 @@
text-align: left;
color: $style_color;
padding: 9px 10px;
height: 18px;
.options {
float: right;
......@@ -46,7 +45,7 @@
text-align: center;
img {
padding: 100px;
max-width: 300px;
max-width: 50%;
}
}
......
form {
@extend .form-horizontal;
label {
@extend .control-label;
&.radio-label {
text-align: left;
width: 100%;
margin-left: 0;
input[type="radio"] {
margin-top: 1px !important;
}
}
&.list-label {
float: none;
padding: 0 !important;
margin: 0;
text-align: left;
}
}
&.form-tiny {
margin: 0;
}
}
input.input-xpadding,
.add-on.input-xpadding {
padding: 6px 10px;
}
.control-group {
.control-label {
padding-top: 6px;
}
.controls {
input, textarea {
padding: 6px 10px;
}
input[type="radio"], input[type="checkbox"] {
margin-top: 6px;
}
.add-on {
padding: 6px;
}
}
}
input[type='search'].search-text-input {
background-image: url("icon-search.png");
background-repeat: no-repeat;
background-position: 10px;
padding-left: 25px;
@include border-radius(4px);
border: 1px solid #ccc;
}
input[type='text'].danger {
......@@ -68,7 +13,6 @@ input[type='text'].danger {
fieldset legend {
font-size: 16px;
margin-bottom: 10px;
}
.datetime-controls {
......@@ -76,3 +20,34 @@ fieldset legend {
width: 100px;
}
}
.form-actions {
padding: 17px 20px 18px;
margin-top: 18px;
margin-bottom: 18px;
background-color: whitesmoke;
border-top: 1px solid #e5e5e5;
padding-left: 17%;
}
label {
&.control-label {
@extend .col-sm-2;
}
&.inline-label {
margin: 0;
}
}
.inline-input-group {
width: 250px;
}
.input-mx-250 {
max-width: 250px;
}
.input-mn-300 {
min-width: 300px;
}
......@@ -4,7 +4,9 @@
*/
.well-list {
margin: 0;
padding: 0;
list-style: none;
li {
padding: 10px;
min-height: 20px;
......
/** Select2 selectbox style override **/
.select2-container, .select2-container.select2-drop-above {
.select2-choice {
background: #FFF;
border-color: #BBB;
.select2-arrow {
background: #FFF;
}
}
}
.select2-drop-active {
border: 1px solid #BBB;
margin-top: 4px;
.select2-search input {
background: #fafafa;
border-color: #DDD;
}
.select2-results {
max-height: 350px;
.select2-highlighted {
background: $bg_style_color;
}
}
}
select {
&.select2 {
width: 100px;
}
&.select2-sm {
width: 100px;
}
}
@media (min-width: $screen-sm-min) {
select {
&.select2 {
width: 150px;
}
&.select2-sm {
width: 120px;
}
}
}
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) {
select {
&.select2 {
width: 170px;
}
&.select2-sm {
width: 140px;
}
}
}
/* Large devices (large desktops, 1200px and up) */
@media (min-width: $screen-lg-min) {
select {
&.select2 {
width: 200px;
}
&.select2-sm {
width: 150px;
}
}
}
/** Branch/tag selector **/
.project-refs-form .select2-container {
margin-right: 10px;
}
......@@ -2,11 +2,6 @@
* Headers
*
*/
h1, h2, h3, h4, h5, h6 {
font-weight: 500;
line-height: 1.1;
}
h1.page-title {
@include page-title;
font-size: 28px;
......@@ -99,6 +94,7 @@ a:focus {
background: #f5f5f5;
}
ul {
padding: 0;
margin: 0 0 9px 25px !important;
}
}
......
......@@ -43,6 +43,7 @@
ul {
margin: 0;
padding: 0;
}
.title {
......@@ -157,7 +158,8 @@
.title {
background: #D65;
color: #fff;
text-shadow: 0 1px 1px #900;
text-shadow: none;
font-weight: 500;
}
}
......
/** Override bootstrap variables **/
$baseFontSize: 13px !default;
$baseLineHeight: 18px !default;
/**
* BOOTSTRAP
*/
@import "bootstrap/variables";
@import "bootstrap/mixins";
@import "bootstrap/reset";
@import "bootstrap/scaffolding";
@import "bootstrap/grid";
@import "bootstrap/layouts";
@import "bootstrap/type";
@import "bootstrap/code";
@import "bootstrap/forms";
@import "bootstrap/tables";
@import "bootstrap/sprites";
@import "bootstrap/dropdowns";
@import "bootstrap/wells";
@import "bootstrap/component-animations";
@import "bootstrap/close";
@import "bootstrap/button-groups";
@import "bootstrap/alerts";
@import "bootstrap/navs";
@import "bootstrap/navbar";
@import "bootstrap/breadcrumbs";
@import "bootstrap/pagination";
@import "bootstrap/pager";
@import "bootstrap/modals";
@import "bootstrap/tooltip";
@import "bootstrap/popovers";
@import "bootstrap/thumbnails";
@import "bootstrap/media";
@import "bootstrap/labels-badges";
@import "bootstrap/progress-bars";
@import "bootstrap/accordion";
@import "bootstrap/carousel";
@import "bootstrap/hero-unit";
@import "bootstrap/utilities";
@import "bootstrap/responsive-utilities";
@import "bootstrap/responsive-1200px-min";
/**
* Font icons
*
*/
@import "font-awesome";
/**
* GitLab bootstrap.
* Overrides some styles of twitter bootstrap.
* Also give some common classes for GitLab app
*/
@import "gitlab_bootstrap/variables.scss";
@import "gitlab_bootstrap/fonts.scss";
@import "gitlab_bootstrap/mixins.scss";
@import "gitlab_bootstrap/avatar.scss";
@import "gitlab_bootstrap/nav.scss";
@import "gitlab_bootstrap/common.scss";
@import "gitlab_bootstrap/typography.scss";
@import "gitlab_bootstrap/buttons.scss";
@import "gitlab_bootstrap/blocks.scss";
@import "gitlab_bootstrap/ui_box.scss";
@import "gitlab_bootstrap/issue_box.scss";
@import "gitlab_bootstrap/files.scss";
@import "gitlab_bootstrap/lists.scss";
@import "gitlab_bootstrap/forms.scss";
/** COLORS **/
.cgray { color: gray }
.clgray { color: #BBB }
.cred { color: #D12F19 }
.cgreen { color: #4a2 }
.cblue { color: #29A }
.cblack { color: #111 }
.cdark { color: #444 }
.camber { color: #ffc000 }
.cwhite { color: #fff!important }
.bgred { background: #F2DEDE!important }
/** COMMON CLASSES **/
.left { float:left }
.prepend-top-10 { margin-top:10px }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
.prepend-left-20 { margin-left:20px }
.append-right-10 { margin-right:10px }
.append-right-20 { margin-right:20px }
.append-bottom-10 { margin-bottom:10px }
.append-bottom-20 { margin-bottom:20px }
.inline { display: inline-block }
.padded { padding:20px }
.ipadded { padding:20px!important }
.lborder { border-left:1px solid #eee }
.underlined_link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
.light { color: #888 }
.tiny { font-weight: normal }
.vtop { vertical-align: top !important; }
/** ALERT MESSAGES **/
.alert.alert-disabled {
background: #EEE;
color: #777;
border-color: #DDD;
}
/** HELPERS **/
.nothing_here_message {
text-align: center;
padding: 20px;
color: #666;
font-weight: normal;
font-size: 16px;
line-height: 36px;
}
.slead {
color: #666;
font-size: 14px;
margin-bottom: 12px;
font-weight: normal;
line-height: 24px;
}
.tab-content {
overflow: visible;
}
@media (max-width: 1200px) {
.only-wide {
display: none;
}
}
.pagination ul > li > a, .pagination ul > li >span {
@include linear-gradient(#f1f1f1, #e1e1e1);
color: #333;
text-shadow: 0 1px 1px #FFF;
}
pre.well-pre {
border: 1px solid #EEE;
background: #f9f9f9;
border-radius: 0;
color: #555;
}
.input-append .btn.active, .input-prepend .btn.active {
background: #CCC;
border-color: #BBB;
text-shadow: 0 1px 1px #fff;
font-weight: bold;
@include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
}
.label {
padding: 2px 4px;
font-size: 12px;
font-style: normal;
font-weight: normal;
&.label-gray {
background-color: #eee;
color: #999;
text-shadow: none;
}
}
/** Big Labels **/
.state-label {
font-size: 14px;
padding: 6px 25px;
text-align: center;
@include border-radius(4px);
text-shadow: none;
margin-left: 10px;
&.state-label-green {
background: #4A4;
color: #FFF;
}
&.state-label-red {
background: #DA4E49;
color: #FFF;
}
}
.dropdown-menu > li > a {
text-shadow: none;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: #29b;
}
/**
* nav-pills
*
*/
.nav-pills {
.active a {
background: $primary_color;
}
> li > a {
@include border-radius(0);
}
&.nav-stacked {
> li > a {
border-left: 4px solid #EEE;
padding: 12px;
color: #777;
}
> .active > a {
border-color: $primary_color;
background: none;
color: #333;
font-weight: bolder;
}
&.nav-stacked-menu {
li > a {
padding: 16px;
}
}
}
&.nav-pills-small {
> li > a {
padding: 8px 12px;
font-size: 12px;
}
}
}
.nav-pills > .active > a > i[class^="icon-"] { background: inherit; }
/**
* nav-tabs
*
*/
.nav-tabs > li > a, .nav-pills > li > a { color: $style_color; }
.nav.nav-tabs {
li {
> a {
padding: 8px 20px;
margin-right: 7px;
line-height: 20px;
border-color: #EEE;
color: #888;
border-bottom: 1px solid #ddd;
.badge {
background-color: #eee;
color: #888;
text-shadow: 0 1px 1px #fff;
}
i[class^="icon-"] {
line-height: 14px;
}
}
&.active {
> a {
border-color: #CCC;
border-bottom: 1px solid #fff;
color: #333;
font-weight: bold;
}
}
}
&.nav-small-tabs > li > a { padding: 6px 9px; }
}
/**
* fix to keep tooltips position in top navigation bar
*
*/
.navbar .nav > li {
position: relative;
white-space: nowrap;
}
/*
* Twitter bootstrap with GitLab customizations/additions
*
* Some unused bootstrap compontents like panels are not included.
* Other components like tabs are modified to GitLab style.
*
*/
$font-size-base: 13px !default;
$nav-pills-active-link-hover-bg: $bg_style_color;
$pagination-active-bg: $bg_style_color;
// Core variables and mixins
@import "bootstrap/variables";
@import "bootstrap/mixins";
// Reset
@import "bootstrap/normalize";
@import "bootstrap/print";
// Core CSS
@import "bootstrap/scaffolding";
@import "bootstrap/type";
@import "bootstrap/code";
@import "bootstrap/grid";
@import "bootstrap/tables";
@import "bootstrap/forms";
// Components
@import "bootstrap/component-animations";
@import "bootstrap/dropdowns";
@import "bootstrap/button-groups";
@import "bootstrap/input-groups";
@import "bootstrap/navs";
@import "bootstrap/navbar";
@import "bootstrap/breadcrumbs";
@import "bootstrap/pagination";
@import "bootstrap/pager";
@import "bootstrap/labels";
@import "bootstrap/badges";
@import "bootstrap/jumbotron";
@import "bootstrap/thumbnails";
@import "bootstrap/alerts";
@import "bootstrap/progress-bars";
@import "bootstrap/list-group";
@import "bootstrap/wells";
@import "bootstrap/close";
// Components w/ JavaScript
@import "bootstrap/modals";
@import "bootstrap/tooltip";
@import "bootstrap/popovers";
@import "bootstrap/carousel";
// Utility classes
.clearfix {
@include clearfix();
}
.center-block {
@include center-block();
}
.pull-right {
float: right !important;
}
.pull-left {
float: left !important;
}
.hide {
display: none;
}
.show {
display: block !important;
}
.invisible {
visibility: hidden;
}
.text-hide {
@include text-hide();
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.affix {
position: fixed;
}
@import "bootstrap/responsive-utilities";
// Labels
.label {
padding: 2px 4px;
font-size: 12px;
font-style: normal;
font-weight: normal;
display: inline-block;
&.label-gray {
background-color: #eee;
color: #999;
text-shadow: none;
}
&.label-inverse {
background-color: #333333;
}
}
// Nav tabs
.nav.nav-tabs {
li {
> a {
padding: 8px 20px;
margin-right: 7px;
line-height: 20px;
border-color: #EEE;
color: #888;
border-bottom: 1px solid #ddd;
.badge {
background-color: #eee;
color: #888;
text-shadow: 0 1px 1px #fff;
}
i[class^="icon-"] {
line-height: 14px;
}
}
&.active {
> a {
border-color: #CCC;
border-bottom: 1px solid #fff;
color: #333;
font-weight: bold;
}
}
}
&.nav-small-tabs > li > a {
padding: 6px 9px;
}
}
.nav-tabs > li > a,
.nav-pills > li > a {
color: #666;
}
.nav-small > li > a {
padding: 3px 5px;
font-size: 12px;
}
/*
* Callouts from Bootstrap3 docs
*
* Not quite alerts, but custom and helpful notes for folks reading the docs.
* Requires a base and modifier class.
*/
/* Common styles for all types */
.bs-callout {
margin: 20px 0;
padding: 20px;
border-left: 3px solid #eee;
color: #666;
background: #f9f9f9;
}
.bs-callout h4 {
margin-top: 0;
margin-bottom: 5px;
}
.bs-callout p:last-child {
margin-bottom: 0;
}
/* Variations */
.bs-callout-danger {
background-color: #fdf7f7;
border-color: #eed3d7;
color: #b94a48;
}
.bs-callout-warning {
background-color: #faf8f0;
border-color: #faebcc;
color: #8a6d3b;
}
.bs-callout-info {
background-color: #f4f8fa;
border-color: #bce8f1;
color: #34789a;
}
.bs-callout-success {
background-color: #dff0d8;
border-color: #5cA64d;
color: #3c763d;
}
// Breadcrumb
ul.breadcrumb {
background: white;
border: none;
li {
display: inline;
text-shadow: 0 1px 0 white
}
a {
font-size: 16px;
}
}
/**
* fix to keep tooltips position in top navigation bar
*
*/
.navbar .nav > li {
position: relative;
white-space: nowrap;
}
html {
overflow-y: scroll;
}
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin-bottom: 20px;
}
.container {
padding-top: 0;
z-index: 5;
}
.container .content {
margin: 0 0;
}
......@@ -79,11 +79,15 @@
color: $style_color;
text-shadow: 0 1px 1px #FFF;
font-size: 16px;
line-height: 40px;
line-height: 44px;
font-weight: normal;
}
@mixin md-typography {
img {
max-width: 100%;
}
*:first-child {
margin-top: 0;
}
......
......@@ -4,6 +4,7 @@
$primary_color: #2FA0BB;
$link_color: #3A89A3;
$style_color: #474D57;
$bg_style_color: #2299BB;
$hover: #D9EDF7;
/**
......
......@@ -80,7 +80,7 @@
border-right: 1px solid #ccc;
text-align: right;
min-width: 35px;
max-width: 35px;
max-width: 50px;
width: 35px;
@include user-select(none);
a {
......@@ -399,8 +399,8 @@
.commits-compare-switch{
background: url("switch_icon.png") no-repeat center center;
width: 22px;
height: 22px;
width: 32px;
height: 32px;
text-indent: -9999px;
float: left;
margin-right: 9px;
......@@ -481,6 +481,10 @@ li.commit {
font-family: $monospace_font;
}
.str-truncated {
max-width: 70%;
}
.commit-row-message {
color: #333;
font-weight: 500;
......
.dashboard {
@extend .row;
.activities {
}
.side {
@extend .pull-right;
.ui-box {
margin: 0px;
box-shadow: none;
......@@ -20,7 +14,7 @@
.search-text-input {
float:left;
@extend .span2;
@extend .col-md-2;
}
.btn {
margin-left: 5px;
......@@ -32,14 +26,15 @@
.dash-filter {
margin: 7px 0;
padding: 4px 6px;
width: 202px;
width: 220px;
float: left;
height: inherit;
}
}
@media (max-width: 1200px) {
.dashboard .dash-filter {
width: 132px;
width: 150px;
}
}
......@@ -107,7 +102,6 @@
padding: 8px 12px;
border-radius: 50px;
background: #f5f5f5;
width: 16px;
text-align: center;
i {
......
......@@ -34,15 +34,4 @@
margin: 5px 8px 0 8px;
}
}
.commit_message-group {
margin-top: 20px;
label {
font-size: 16px;
line-height: 20px;
}
textarea {
@extend .span8;
}
}
}
......@@ -75,6 +75,7 @@
margin-top: 4px;
margin-left: 0px;
max-width: 200px;
float: none;
}
p:last-child {
......@@ -147,7 +148,7 @@
float: left;
padding: 9px 6px;
font-size: 18px;
width: 26px;
width: 40px;
@include border-radius(3px);
}
......
......@@ -4,17 +4,24 @@
*/
header {
&.navbar-gitlab {
margin-bottom: 0;
min-height: 40px;
.navbar-inner {
height: 40px;
padding: 3px;
background: #F1F1F1;
border-bottom: 1px solid #DDD;
filter: none;
.nav > li > a {
color: $style_color;
text-shadow: 0 1px 0 #fff;
font-size: 14px;
padding: 10px;
line-height: 32px;
padding: 6px 10px;
&:hover {
background: none;
}
}
/** NAV block with links and profile **/
......@@ -35,9 +42,6 @@ header {
.app_logo {
float: left;
margin-right: 9px;
position: relative;
top: -3px;
padding-top: 3px;
a {
float: left;
......@@ -49,7 +53,7 @@ header {
background: url('logo-black.png') no-repeat center center;
background-size: 32px;
float: left;
height: 40px;
height: 46px;
width: 40px;
@include header-font;
text-indent: -9999px;
......@@ -75,7 +79,7 @@ header {
.profile-pic {
position: relative;
top: -4px;
top: -1px;
img {
width: 26px;
height: 26px;
......@@ -91,21 +95,25 @@ header {
.search {
margin-right: 10px;
margin-left: 10px;
margin-top: 8px;
form {
margin: 0;
padding: 0;
}
.search-input {
@extend .span3;
background-image: url("icon-search.png");
background-repeat: no-repeat;
background-position: 10px;
height: inherit;
padding: 4px 6px;
padding-left: 25px;
font-size: 13px;
@include border-radius(3px);
border: 1px solid #c6c6c6;
box-shadow: none;
@include transition(all 0.15s ease-in 0s);
&:focus {
@extend .span4;
}
}
}
......@@ -181,12 +189,26 @@ header {
.separator {
float: left;
height: 46px;
width: 1px;
width: 2px;
background: white;
border-left: 1px solid #DDD;
margin-top: -3px;
margin-left: 10px;
margin-right: 10px;
}
}
.search .search-input {
width: 300px;
&:focus {
width: 400px;
}
}
@media (max-width: 1200px) {
.search .search-input {
width: 200px;
&:focus {
width: 300px;
}
}
}
......@@ -77,8 +77,8 @@ input.check_all_issues {
@media (min-width: 800px) { .issues_filters select { width: 160px; } }
@media (min-width: 1200px) { .issues_filters select { width: 220px; } }
@media (min-width: 800px) { .issues_bulk_update .chosen-container { min-width: 120px; } }
@media (min-width: 1200px) { .issues_bulk_update .chosen-container { min-width: 160px; } }
@media (min-width: 800px) { .issues_bulk_update .select2-container { min-width: 120px; } }
@media (min-width: 1200px) { .issues_bulk_update .select2-container { min-width: 160px; } }
.issues-holder {
.issues_filters {
......@@ -105,7 +105,7 @@ input.check_all_issues {
}
.issues_bulk_update {
.chosen-container {
.select2-container {
text-shadow: none;
}
}
......@@ -120,11 +120,6 @@ input.check_all_issues {
}
}
.edit-issue.inline-update select {
width: 100%;
max-width: 200px;
}
.issue-show-labels .label {
padding: 6px 10px;
}
......
/* Login Page */
body.login-page{
.container > .content {
padding-top: 20px;
.login-page {
h1 {
font-size: 3em;
font-weight: 200;
}
}
.login-box{
width: 304px;
position: relative;
@include border-radius(5px);
margin: auto;
padding: 20px;
background: white;
}
.login-box .login-logo{
margin: 10px 0 30px 0;
display: block;
}
.login-box input.text{background-color: #f1f1f1; font-size: 16px; @include border-radius(0); padding: 14px 10px; width: 280px}
.login-box input.text.top{
@include border-radius(5px 5px 0 0);
margin-bottom: 0px;
}
.login-box input.text.bottom{
@include border-radius(0 0 5px 5px);
border-top: 0;
margin-bottom: 20px;
}
.login-box input.text.middle{
border-top: 0;
margin-bottom:0px;
}
.login-box{
width: 304px;
position: relative;
@include border-radius(5px);
margin: auto;
padding: 20px;
background: white;
}
.login-box a.forgot{float: right; padding-top: 6px}
.login-logo{
margin: 10px 0 30px 0;
display: block;
}
.remember_me {
text-align: left;
.form-control {
background-color: #f1f1f1;
font-size: 16px;
padding: 14px 10px;
width: 280px;
height: auto;
&.top {
@include border-radius(5px 5px 0 0);
margin-bottom: 0px;
}
&.bottom {
@include border-radius(0 0 5px 5px);
border-top: 0;
margin-bottom: 20px;
}
&.middle {
border-top: 0;
margin-bottom:0px;
@include border-radius(0);
}
}
input {
margin: 2px;
.login-box a.forgot {
float: right;
padding-top: 6px
}
}
.devise-errors {
h2 {
font-size: 14px;
color: #a00;
.devise-errors {
h2 {
font-size: 14px;
color: #a00;
}
}
}
......@@ -4,10 +4,6 @@
*
*/
.automerge_widget {
&.can_be_merged {
background: #DFF0D8;
}
form {
margin-bottom: 0;
.clearfix {
......@@ -15,32 +11,12 @@
}
}
.accept_group {
float: left;
border: 1px solid #ADA;
padding: 2px;
@include border-radius(5px);
background: #CEB;
.accept_merge_request {
font-size: 13px;
float: left;
}
.remove_branch_holder {
margin-left: 20px;
margin-right: 10px;
float: left;
}
.accept-group {
label {
color: #444;
text-align: left
margin: 5px;
margin-left: 20px;
}
}
.how_to_merge_link {
@extend .primary;
}
}
.merge-request .nav-tabs{
......@@ -53,11 +29,6 @@
}
}
.merge-in-progress {
@extend .padded;
@extend .append-bottom-10;
}
.mr_source_commit,
.mr_target_commit {
.commit {
......@@ -111,12 +82,8 @@
.merge-request-angle {
text-align: center;
margin: 0 auto;
background: #eee;
border-radius: 100px;
width: 60px;
line-height: 60px;
color: #777;
text-shadow: 0 1px 2px #FFF;
font-size: 2em;
line-height: 1.1;
}
.merge-request-form-info {
......@@ -128,8 +95,7 @@
font-weight: normal !important;
}
.chosen-container .chosen-single {
padding: 2px 0 2px 10px;
.select2-container .select2-single {
span {
font-weight: bold;
color: #555;
......
......@@ -6,6 +6,7 @@
border-bottom: 1px solid #E1E1E1;
ul {
padding: 0;
margin: auto;
height: 40px;
overflow: hidden;
......
......@@ -2,7 +2,7 @@
* Notes
*/
@-webkit-keyframes target-note {
@-webkit-keyframes targe3-note {
from { background:#fffff0; }
50% { background:#ffffd3; }
to { background:#fffff0; }
......@@ -119,9 +119,9 @@ ul.notes {
}
.file .notes_holder {
font-family: $sansFontFamily;
font-size: 13px;
line-height: 18px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
td {
border: 1px solid #ddd;
......@@ -138,7 +138,7 @@ ul.notes {
border-left: 1px solid #ddd !important;
}
&.notes_content {
background-color: $white;
background-color: #fff;
border-width: 1px 0;
padding-top: 0;
......@@ -303,7 +303,7 @@ ul.notes {
}
.note-image-attach {
@extend .span4;
@extend .col-md-4;
@extend .thumbnail;
margin-left: 45px;
}
......
.update-notifications {
margin-bottom: 0;
label {
margin-bottom: 0;
.radio-inline {
margin-right: 9%;
}
}
......@@ -17,7 +16,7 @@
legend {
border: none;
margin: 0;
margin-bottom: 10px;
}
}
}
......@@ -47,3 +46,62 @@
margin: 10px 0;
}
}
.user-show-username {
font-weight: 200;
color: #666;
}
/*
* Appearance settings
*
*/
.themes_opts {
label {
margin-right: 20px;
text-align: center;
.prev {
@extend .thumbnail;
height: 30px;
width: 175px;
margin-bottom: 10px;
&.classic {
background: #31363e;
}
&.default {
background: #f1f1f1;
}
&.modern {
background: #345;
}
&.gray {
background: #373737;
}
&.violet {
background: #547;
}
}
}
}
.code_highlight_opts {
margin-top: 10px;
label {
margin-right: 20px;
text-align: center;
.prev {
@extend .thumbnail;
height: 151px;
width: 220px;
margin-bottom: 10px;
}
}
}
......@@ -16,7 +16,7 @@
.project-home-panel {
border-bottom: 1px solid #DDD;
padding-bottom: 25px;
padding-bottom: 15px;
margin-bottom: 30px;
&.empty-project {
......@@ -41,24 +41,29 @@
.project-home-desc {
float: left;
color: #777;
margin-bottom: 10px;
}
.project-home-links {
float: right;
a {
margin-left: 10px;
font-weight: 500;
}
}
}
.visibility-level-label {
font-size: 14px;
font-size: 17px;
background: #f1f1f1;
padding: 8px 10px;
border-radius: 4px;
margin-left: 10px;
color: #888;
position: absolute;
margin-left: -55px;
text-shadow: 0 1px 1px #FFF;
width: 40px;
text-align: center;
padding: 6px;
i {
color: inherit;
......@@ -67,76 +72,53 @@
}
.git-clone-holder {
float: right;
border: 1px solid #E1E1E1;
@include border-radius(4px);
.project-home-dropdown + & {
margin-right: 45px;
}
input[type="text"],
.btn {
border: none;
@include border-radius(0px);
border-left: 1px solid #E1E1E1;
.btn,
.form-control {
border: 1px solid #E1E1E1;
box-shadow: none;
padding: 6px 9px;
}
.btn {
float: left;
background: none;
color: #29b;
&:first-child {
@include border-radius-left(4px);
border-left: 0px;
}
&.active {
color: #333;
font-weight: bold;
}
}
input[type="text"] {
.form-control {
cursor: auto;
@extend .monospace;
background: #FAFAFA;
width: 100%;
}
}
.project-visibility-level-holder {
.controls {
padding-bottom: 9px;
}
.radio {
margin-bottom: 10px;
.controls {
input {
float: left;
i {
margin: 0 3px;
font-size: 20px;
}
.descr {
display: block;
margin-left: 1.5em;
&.restricted {
color: #888;
}
label {
float: none;
padding: 0;
margin: 0;
text-align: left;
}
}
.info {
display: block;
margin-top: 5px;
}
strong {
.option-title {
font-weight: bold;
display: inline-block;
width: 4em;
}
}
i {
color: inherit;
.option-descr {
margin-left: 24px;
color: #666;
}
}
}
......@@ -218,11 +200,26 @@ ul.nav.nav-projects-tabs {
.project-side {
.btn-block {
background-image: none;
background-color: #F1f1f1;
border-color: #EEE;
&:hover {
background-color: #eee;
border-color: #DDD;
.btn,
&.btn,
&.btn-group ul.dropdown-menu {
background-color: #F1f1f1;
border-color: #EEE;
&:hover {
background-color: #eee;
border-color: #DDD;
}
}
&.btn-group-justified {
.btn {
width: 100%;
}
.dropdown-toggle {
width: 26px;
}
}
ul {
width: 100%;
}
}
.project-fork-icon {
......@@ -233,46 +230,10 @@ ul.nav.nav-projects-tabs {
}
}
.transfer-project .chosen-container {
.transfer-project .select2-container {
min-width: 200px;
}
/** Branch/tag selector **/
.project-refs-form {
margin: 0;
span {
background:none !important;
position:static !important;
width:auto !important;
height:auto !important;
}
}
.project-refs-select {
width: 120px;
}
.project-refs-form .chosen-container {
position: relative;
top: 0;
left: 0;
margin-right: 10px;
.chosen-single span {
font-weight: bold;
color: #555;
}
&.chosen-container-active {
.chosen-drop {
min-width: 400px;
}
.chosen-results {
max-height: 400px;
}
}
}
.deploy-project-label {
margin: 1px;
}
.snippet.file-holder {
.file-title {
.snippet-file-name {
padding: 4px 10px;
position: relative;
top: -4px;
left: -4px;
}
}
}
.my-snippets li:first-child {
h4 { margin-top: 0; }
padding-top: 0;
......
.themes_opts {
padding-left: 20px;
label {
width: 175px;
margin-right: 40px;
.prev {
@extend .thumbnail;
height: 30px;
width: 175px;
margin-bottom: 10px;
&.classic {
background: #31363e;
}
&.default {
background: #f1f1f1;
}
&.modern {
background: #345;
}
&.gray {
background: #373737;
}
&.violet {
background: #547;
}
}
}
}
.code_highlight_opts {
padding-left: 20px;
label {
width: 220px;
margin-right: 40px;
.prev {
@extend .thumbnail;
height: 151px;
width: 220px;
margin-bottom: 10px;
}
}
}
......@@ -24,10 +24,10 @@
th {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid #CCC;
border-bottom: 1px solid #CCC !important;
}
td {
border-color: #F1F1F1;
border-color: #F1F1F1 !important;
}
&:hover {
td {
......@@ -49,6 +49,7 @@
.tree-item {
.tree-item-file-name {
max-width: 320px;
vertical-align: middle;
a {
&:hover {
......@@ -61,6 +62,14 @@
top:-1px;
}
}
.tree_commit {
max-width: 320px;
}
.tree_time_ago {
min-width: 135px;
}
}
.tree_author {
......@@ -111,7 +120,7 @@
.tree-ref-holder {
float: left;
margin-top: 5px;
margin-top: 8px;
}
.readme-holder {
......
......@@ -36,3 +36,8 @@
display: inline-block;
margin: 0 8px;
}
.votes-holder {
float: right;
width: 250px;
}
.wall-page {
.wall-note-form {
@extend .span12;
@extend .col-md-12;
margin: 0;
height: 140px;
......
/** Chosen.js selectbox style override **/
.chosen-container {
min-width: 100px;
.chosen-single {
background: #EEE !important;
border: 1px solid #DDD !important;
@include box-shadow(none !important);
@include border-radius(4px !important);
}
.chosen-results li.highlighted {
background: #29b;
}
.chosen-drop {
margin-top: 10px;
border: 1px solid #DDD !important;
@include border-radius(4px !important);
}
.chosen-search input {
border: 1px solid #CCC !important;
@include box-shadow(none !important);
}
}
/** Select2 styling **/
.select2-container .select2-choice {
@include bg-light-gray-gradient;
}
.select2-container .select2-choice div {
border: none;
background: none;
}
.select2-drop {
padding-top: 8px;
}
.select2-no-results, .select2-searching {
padding: 7px;
color: #666;
}
.chosen-container .chosen-single div b {
background-position-y: 0px !important;
}
.chosen-container .chosen-drop .chosen-search input {
background-position-y: -24px !important;
}
.chosen-compact {
max-width: 170px !important;
}
class CommitLoadContext < BaseContext
def execute
result = {
commit: nil,
suppress_diff: false,
line_notes: [],
notes_count: 0,
note: nil,
status: :ok
}
commit = project.repository.commit(params[:id])
if commit
line_notes = project.notes.for_commit_id(commit.id).inline
result[:commit] = commit
result[:note] = project.build_commit_note(commit)
result[:line_notes] = line_notes
result[:notes_count] = project.notes.for_commit_id(commit.id).count
result[:branches] = project.repository.branch_names_contains(commit.id)
begin
result[:suppress_diff] = true if commit.diff_suppress? && !params[:force_show_diff]
result[:force_suppress_diff] = commit.diff_force_suppress?
rescue Grit::Git::GitTimeout
result[:suppress_diff] = true
result[:status] = :huge_commit
end
end
result
end
end
module Issues
class ListContext < BaseContext
attr_accessor :issues
def execute
@issues = @project.issues
@issues = case params[:state]
when 'all' then @issues
when 'closed' then @issues.closed
else @issues.opened
end
@issues = case params[:scope]
when 'assigned-to-me' then @issues.assigned_to(current_user)
when 'created-by-me' then @issues.authored(current_user)
else @issues
end
@issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
@issues = @issues.includes(:author, :project)
# Filter by specific assignee_id (or lack thereof)?
if params[:assignee_id].present?
@issues = @issues.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
end
# Filter by specific milestone_id (or lack thereof)?
if params[:milestone_id].present?
@issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
end
# Sort by :sort param
@issues = sort(@issues, params[:sort])
@issues
end
private
def sort(issues, condition)
case condition
when 'newest' then issues.except(:order).order('created_at DESC')
when 'oldest' then issues.except(:order).order('created_at ASC')
when 'recently_updated' then issues.except(:order).order('updated_at DESC')
when 'last_updated' then issues.except(:order).order('updated_at ASC')
when 'milestone_due_soon' then issues.except(:order).joins(:milestone).order("milestones.due_date ASC")
when 'milestone_due_later' then issues.except(:order).joins(:milestone).order("milestones.due_date DESC")
else issues
end
end
end
end
# Build collection of Merge Requests
# based on filtering passed via params for @project
class MergeRequestsLoadContext < BaseContext
def execute
merge_requests = @project.merge_requests
merge_requests = case params[:state]
when 'all' then merge_requests
when 'closed' then merge_requests.closed
else merge_requests.opened
end
merge_requests = case params[:scope]
when 'assigned-to-me' then merge_requests.assigned_to(current_user)
when 'created-by-me' then merge_requests.authored(current_user)
else merge_requests
end
merge_requests = merge_requests.page(params[:page]).per(20)
merge_requests = merge_requests.includes(:author, :source_project, :target_project).order("created_at desc")
# Filter by specific assignee_id (or lack thereof)?
if params[:assignee_id].present?
merge_requests = merge_requests.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
end
# Filter by specific milestone_id (or lack thereof)?
if params[:milestone_id].present?
merge_requests = merge_requests.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
end
merge_requests
end
end
class SearchContext
attr_accessor :project_ids, :current_user, :params
def initialize(project_ids, user, params)
@project_ids, @current_user, @params = project_ids, user, params.dup
end
def execute
query = params[:search]
query = Shellwords.shellescape(query) if query.present?
return result unless query.present?
visibility_levels = @current_user ? [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] : [ Gitlab::VisibilityLevel::PUBLIC ]
result[:projects] = Project.where("projects.id in (?) OR projects.visibility_level in (?)", project_ids, visibility_levels).search(query).limit(20)
# Search inside single project
single_project_search(Project.where(id: project_ids), query)
result
end
def single_project_search(projects, query)
project = projects.first if projects.length == 1
if params[:search_code].present?
result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo?
else
result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20)
result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20)
result[:wiki_pages] = []
end
end
def result
@result ||= {
projects: [],
merge_requests: [],
issues: [],
wiki_pages: [],
blobs: []
}
end
end
class TestHookContext < BaseContext
def execute
hook = project.hooks.find(params[:id])
data = GitPushService.new.sample_data(project, current_user)
hook.execute(data)
end
end
......@@ -52,6 +52,6 @@ class Admin::GroupsController < Admin::ApplicationController
private
def group
@group = Group.find_by_path(params[:id])
@group = Group.find_by(path: params[:id])
end
end
......@@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController
def index
owner_id = params[:owner_id]
user = User.find_by_id(owner_id)
user = User.find_by(id: owner_id)
@projects = user ? user.owned_projects : Project.all
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
......@@ -19,7 +19,7 @@ class Admin::ProjectsController < Admin::ApplicationController
end
def transfer
result = ::Projects::TransferContext.new(@project, current_user, project: params).execute(:admin)
result = ::Projects::TransferService.new(@project, current_user, project: params).execute(:admin)
if result
redirect_to [:admin, @project]
......
......@@ -100,6 +100,6 @@ class Admin::UsersController < Admin::ApplicationController
protected
def user
@user ||= User.find_by_username!(params[:id])
@user ||= User.find_by!(username: params[:id])
end
end
......@@ -161,6 +161,8 @@ class ApplicationController < ActionController::Base
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
headers['X-UA-Compatible'] = 'IE=edge'
headers['X-Content-Type-Options'] = 'nosniff'
headers['Strict-Transport-Security'] = 'max-age=31536000' if Gitlab.config.gitlab.https
end
def add_gon_variables
......@@ -205,7 +207,7 @@ class ApplicationController < ActionController::Base
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :name, :password, :password_confirmation) }
end
end
......@@ -3,6 +3,8 @@ class DashboardController < ApplicationController
before_filter :load_projects, except: [:projects]
before_filter :event_filter, only: :show
before_filter :default_filter, only: [:issues, :merge_requests]
def show
# Fetch only 30 projects.
......@@ -39,7 +41,7 @@ class DashboardController < ApplicationController
current_user.authorized_projects
end
@projects = @projects.where(namespace_id: Group.find_by_name(params[:group])) if params[:group].present?
@projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present?
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.includes(:namespace)
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
......@@ -51,12 +53,12 @@ class DashboardController < ApplicationController
end
def merge_requests
@merge_requests = FilterContext.new(MergeRequest, current_user, params).execute
@merge_requests = FilteringService.new.execute(MergeRequest, current_user, params)
@merge_requests = @merge_requests.recent.page(params[:page]).per(20)
end
def issues
@issues = FilterContext.new(Issue, current_user, params).execute
@issues = FilteringService.new.execute(Issue, current_user, params)
@issues = @issues.recent.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project)
......@@ -71,4 +73,9 @@ class DashboardController < ApplicationController
def load_projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
def default_filter
params[:scope] = 'assigned-to-me' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
end
end
......@@ -10,6 +10,8 @@ class GroupsController < ApplicationController
# Load group projects
before_filter :projects, except: [:new, :create]
before_filter :default_filter, only: [:issues, :merge_requests]
layout :determine_layout
before_filter :set_title, only: [:new, :create]
......@@ -43,18 +45,14 @@ class GroupsController < ApplicationController
end
end
# Get authored or assigned open merge requests
def merge_requests
@merge_requests = FilterContext.new(MergeRequest, current_user, params).execute
@merge_requests = @merge_requests.of_group(@group)
@merge_requests = @merge_requests.recent.page(params[:page]).per(20)
@merge_requests = FilteringService.new.execute(MergeRequest, current_user, params)
@merge_requests = @merge_requests.page(params[:page]).per(20)
end
# Get only assigned issues
def issues
@issues = FilterContext.new(Issue, current_user, params).execute
@issues = @issues.of_group(@group)
@issues = @issues.recent.page(params[:page]).per(20)
@issues = FilteringService.new.execute(Issue, current_user, params)
@issues = @issues.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project)
respond_to do |format|
......@@ -89,7 +87,7 @@ class GroupsController < ApplicationController
protected
def group
@group ||= Group.find_by_path(params[:id])
@group ||= Group.find_by(path: params[:id])
end
def projects
......@@ -130,4 +128,10 @@ class GroupsController < ApplicationController
'group'
end
end
def default_filter
params[:scope] = 'assigned-to-me' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
params[:group_id] = @group.id
end
end
......@@ -19,6 +19,6 @@ class Profiles::GroupsController < ApplicationController
private
def group
@group ||= Group.find_by_path(params[:id])
@group ||= Group.find_by(path: params[:id])
end
end
......@@ -13,7 +13,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def destroy
result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute
result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
......
......@@ -6,34 +6,35 @@ class Projects::CommitController < Projects::ApplicationController
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
before_filter :commit
def show
result = CommitLoadContext.new(project, current_user, params).execute
return git_not_found! unless @commit
@commit = result[:commit]
@line_notes = project.notes.for_commit_id(commit.id).inline
@branches = project.repository.branch_names_contains(commit.id)
if @commit.nil?
git_not_found!
return
begin
@suppress_diff = true if commit.diff_suppress? && !params[:force_show_diff]
@force_suppress_diff = commit.diff_force_suppress?
rescue Grit::Git::GitTimeout
@suppress_diff = true
@status = :huge_commit
end
@suppress_diff = result[:suppress_diff]
@force_suppress_diff = result[:force_suppress_diff]
@note = result[:note]
@line_notes = result[:line_notes]
@branches = result[:branches]
@notes_count = result[:notes_count]
@note = project.build_commit_note(commit)
@notes_count = project.notes.for_commit_id(commit.id).count
@notes = project.notes.for_commit_id(@commit.id).not_inline.fresh
@noteable = @commit
@comments_allowed = @reply_allowed = true
@comments_target = { noteable_type: 'Commit',
commit_id: @commit.id }
@comments_target = {
noteable_type: 'Commit',
commit_id: @commit.id
}
respond_to do |format|
format.html do
if result[:status] == :huge_commit
if @status == :huge_commit
render "huge_commit" and return
end
end
......@@ -42,4 +43,8 @@ class Projects::CommitController < Projects::ApplicationController
format.patch { render text: @commit.to_patch }
end
end
def commit
@commit ||= project.repository.commit(params[:id])
end
end
......@@ -7,7 +7,7 @@ class Projects::EditTreeController < Projects::BaseTreeController
end
def update
result = Files::UpdateContext.new(@project, current_user, params, @ref, @path).execute
result = Files::UpdateService.new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
......
......@@ -24,15 +24,20 @@ class Projects::HooksController < Projects::ApplicationController
end
def test
TestHookContext.new(project, current_user, params).execute
TestHookService.new.execute(hook, current_user)
redirect_to :back
end
def destroy
@hook = @project.hooks.find(params[:id])
@hook.destroy
hook.destroy
redirect_to project_hooks_path(@project)
end
private
def hook
@hook ||= @project.hooks.find(params[:id])
end
end
......@@ -89,7 +89,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def bulk_update
result = Issues::BulkUpdateContext.new(project, current_user, params).execute
result = Issues::BulkUpdateService.new(project, current_user, params).execute
redirect_to :back, notice: "#{result[:count]} issues updated"
end
......@@ -97,7 +97,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue
@issue ||= begin
@project.issues.find_by_iid!(params[:id])
@project.issues.find_by!(iid: params[:id])
rescue ActiveRecord::RecordNotFound
redirect_old
end
......@@ -116,7 +116,9 @@ class Projects::IssuesController < Projects::ApplicationController
end
def issues_filtered
@issues = Issues::ListContext.new(project, current_user, params).execute
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@issues = FilteringService.new.execute(Issue, current_user, params.merge(project_id: @project.id))
end
# Since iids are implemented only in 6.1
......@@ -125,7 +127,7 @@ class Projects::IssuesController < Projects::ApplicationController
# To prevent 404 errors we provide a redirect to correct iids until 7.0 release
#
def redirect_old
issue = @project.issues.find_by_id(params[:id])
issue = @project.issues.find_by(id: params[:id])
if issue
redirect_to project_issue_path(@project, issue)
......
......@@ -17,7 +17,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
@merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
params[:sort] ||= 'newest'
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@merge_requests = FilteringService.new.execute(MergeRequest, current_user, params.merge(project_id: @project.id))
@merge_requests = @merge_requests.page(params[:page]).per(20)
@sort = params[:sort].humanize
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
......@@ -123,7 +130,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if @merge_request.opened? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch]
@merge_request.automerge!(current_user)
@merge_request.automerge!(current_user, params[:merge_commit_message])
@status = true
else
@status = false
......@@ -145,6 +152,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@target_project = selected_target_project
@target_branches = @target_project.repository.branch_names
@target_branches
respond_to do |format|
format.js
end
end
def ci_status
......@@ -161,7 +172,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_request
@merge_request ||= @project.merge_requests.find_by_iid!(params[:id])
@merge_request ||= @project.merge_requests.find_by!(iid: params[:id])
end
def closes_issues
......
......@@ -76,7 +76,7 @@ class Projects::MilestonesController < Projects::ApplicationController
protected
def milestone
@milestone ||= @project.milestones.find_by_iid!(params[:id])
@milestone ||= @project.milestones.find_by!(iid: params[:id])
end
def authorize_admin_milestone!
......
......@@ -6,7 +6,7 @@ class Projects::NewTreeController < Projects::BaseTreeController
def update
file_path = File.join(@path, File.basename(params[:file_name]))
result = Files::CreateContext.new(@project, current_user, params, @ref, file_path).execute
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
......
......@@ -5,7 +5,7 @@ class Projects::NotesController < Projects::ApplicationController
before_filter :authorize_admin_note!, only: [:update, :destroy]
def index
@notes = Notes::LoadContext.new(project, current_user, params).execute
@notes = Notes::LoadService.new(project, current_user, params).execute
notes_json = { notes: [] }
......@@ -20,7 +20,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def create
@note = Notes::CreateContext.new(project, current_user, params).execute
@note = Notes::CreateService.new(project, current_user, params).execute
respond_to do |format|
format.json { render_note_json(@note) }
......
......@@ -16,7 +16,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
storage_path = Rails.root.join("tmp", "repositories")
file_path = @repository.archive_repo(params[:ref], storage_path)
file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase)
if file_path
# Send file to user
......
......@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def update
@user_project_relation = project.users_projects.find_by_user_id(member)
@user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.update_attributes(params[:team_member])
unless @user_project_relation.valid?
......@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def destroy
@user_project_relation = project.users_projects.find_by_user_id(member)
@user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.destroy
respond_to do |format|
......@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def leave
project.users_projects.find_by_user_id(current_user).destroy
project.users_projects.find_by(user_id: current_user).destroy
respond_to do |format|
format.html { redirect_to :back }
......@@ -65,6 +65,6 @@ class Projects::TeamMembersController < Projects::ApplicationController
protected
def member
@member ||= User.find_by_username(params[:id])
@member ||= User.find_by(username: params[:id])
end
end
......@@ -20,7 +20,7 @@ class ProjectsController < ApplicationController
end
def create
@project = ::Projects::CreateContext.new(current_user, params[:project]).execute
@project = ::Projects::CreateService.new(current_user, params[:project]).execute
respond_to do |format|
flash[:notice] = 'Project was successfully created.' if @project.saved?
......@@ -36,7 +36,7 @@ class ProjectsController < ApplicationController
end
def update
status = ::Projects::UpdateContext.new(@project, current_user, params).execute
status = ::Projects::UpdateService.new(@project, current_user, params).execute
respond_to do |format|
if status
......@@ -51,7 +51,7 @@ class ProjectsController < ApplicationController
end
def transfer
::Projects::TransferContext.new(project, current_user, params).execute
::Projects::TransferService.new(project, current_user, params).execute
end
def show
......@@ -89,7 +89,7 @@ class ProjectsController < ApplicationController
end
def fork
@forked_project = ::Projects::ForkContext.new(project, current_user).execute
@forked_project = ::Projects::ForkService.new(project, current_user).execute
respond_to do |format|
format.html do
......
class SearchController < ApplicationController
def show
project_id = params[:project_id]
group_id = params[:group_id]
include SearchHelper
project_ids = current_user.authorized_projects.map(&:id)
def show
@project = Project.find_by(id: params[:project_id]) if params[:project_id].present?
@group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
if group_id.present?
@group = Group.find(group_id)
group_project_ids = @group.projects.map(&:id)
project_ids.select! { |id| group_project_ids.include?(id)}
elsif project_id.present?
@project = Project.find(params[:project_id])
project_ids.select! { |id| id == project_id.to_i}
if @project
return access_denied! unless can?(current_user, :download_code, @project)
@search_results = Search::ProjectService.new(@project, current_user, params).execute
else
@search_results = Search::GlobalService.new(current_user, params).execute
end
end
result = SearchContext.new(project_ids, current_user, params).execute
def autocomplete
term = params[:term]
@project = Project.find(params[:project_id]) if params[:project_id].present?
@ref = params[:project_ref] if params[:project_ref].present?
@projects = result[:projects]
@merge_requests = result[:merge_requests]
@issues = result[:issues]
@wiki_pages = result[:wiki_pages]
@blobs = Kaminari.paginate_array(result[:blobs]).page(params[:page]).per(20)
@total_results = @projects.count + @merge_requests.count + @issues.count + @wiki_pages.count + @blobs.total_count
render json: search_autocomplete_opts(term).to_json
end
end
......@@ -18,7 +18,7 @@ class SnippetsController < ApplicationController
end
def user_index
@user = User.find_by_username(params[:username])
@user = User.find_by(username: params[:username])
@snippets = @user.snippets.fresh.non_expired
if @user == current_user
......
......@@ -2,8 +2,8 @@ class UsersController < ApplicationController
layout 'navless'
def show
@user = User.find_by_username!(params[:username])
@projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id))
@user = User.find_by!(username: params[:username])
@projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace)
@events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
@title = @user.name
......
......@@ -30,7 +30,7 @@ class UsersGroupsController < ApplicationController
protected
def group
@group ||= Group.find_by_path(params[:group_id])
@group ||= Group.find_by(path: params[:group_id])
end
def authorize_admin_group!
......
......@@ -50,7 +50,7 @@ module ApplicationHelper
end
def avatar_icon(user_email = '', size = nil)
user = User.find_by_email(user_email)
user = User.find_by(email: user_email)
if user && user.avatar.present?
user.avatar.url
else
......@@ -72,7 +72,7 @@ module ApplicationHelper
def last_commit(project)
if project.repo_exists?
time_ago_with_tooltip(project.repository.commit.committed_date) + " ago"
time_ago_with_tooltip(project.repository.commit.committed_date)
else
"Never"
end
......@@ -210,11 +210,15 @@ module ApplicationHelper
def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago')
capture_haml do
haml_tag :time, time_ago_in_words(date),
class: html_class, datetime: date, title: date.stamp("Aug 21, 2011 9:23pm"),
haml_tag :time, date.to_s,
class: html_class, datetime: date.getutc.iso8601, title: date.stamp("Aug 21, 2011 9:23pm"),
data: { toggle: 'tooltip', placement: placement }
haml_tag :script, "$('." + html_class + "').tooltip()"
haml_tag :script, "$('." + html_class + "').timeago().tooltip()"
end.html_safe
end
def render_markup(file_name, file_content)
GitHub::Markup.render(file_name, file_content).html_safe
end
end
module DashboardHelper
def filter_path(entity, options={})
exist_opts = {
status: params[:status],
state: params[:state],
scope: params[:scope],
project_id: params[:project_id],
}
......
......@@ -16,11 +16,11 @@ module LabelsHelper
when *klass.warning_labels
'label-warning'
when *klass.neutral_labels
'label-inverse'
'label-primary'
when *klass.positive_labels
'label-success'
when *klass.important_labels
'label-important'
'label-danger'
else
'label-info'
end
......
......@@ -23,11 +23,11 @@ module NotesHelper
def note_timestamp(note)
# Shows the created at time and the updated at time if different
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')} ago"
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}"
if note.updated_at != note.created_at
ts << capture_haml do
haml_tag :small do
haml_concat " (Edited #{time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')} ago)"
haml_concat " (Edited #{time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')})"
end
end
end
......
......@@ -153,7 +153,7 @@ module ProjectsHelper
"#{@project.path}\/#{@path} at #{@ref} - " + title
elsif current_controller?(:issues)
if current_action?(:show)
"Issue ##{@issue.iid} - " + title
"Issue ##{@issue.iid} - #{@issue.title} - " + title
else
"Issues - " + title
end
......@@ -180,8 +180,9 @@ module ProjectsHelper
title
end
def default_url_to_repo
current_user ? @project.url_to_repo : @project.http_url_to_repo
def default_url_to_repo(project = nil)
project = project || @project
current_user ? project.url_to_repo : project.http_url_to_repo
end
def default_clone_protocol
......@@ -190,7 +191,7 @@ module ProjectsHelper
def project_last_activity(project)
if project.last_activity_at
time_ago_with_tooltip(project.last_activity_at, 'bottom', 'last_activity_time_ago') + " ago"
time_ago_with_tooltip(project.last_activity_at, 'bottom', 'last_activity_time_ago')
else
"Never"
end
......
module SearchHelper
def search_autocomplete_source
def search_autocomplete_opts(term)
return unless current_user
resources_results = [
groups_autocomplete(term),
projects_autocomplete(term),
public_projects_autocomplete(term),
].flatten
generic_results = project_autocomplete + default_autocomplete + help_autocomplete
generic_results.select! { |result| result[:label] =~ Regexp.new(term, "i") }
[
groups_autocomplete,
projects_autocomplete,
public_projects_autocomplete,
default_autocomplete,
project_autocomplete,
help_autocomplete
resources_results,
generic_results
].flatten.uniq do |item|
item[:label]
end.to_json
end
end
private
......@@ -43,7 +49,7 @@ module SearchHelper
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
prefix = simple_sanitize(@project.name_with_namespace)
prefix = search_result_sanitize(@project.name_with_namespace)
ref = @ref || @project.repository.root_ref
[
......@@ -65,23 +71,36 @@ module SearchHelper
end
# Autocomplete results for the current user's groups
def groups_autocomplete
current_user.authorized_groups.map do |group|
{ label: "group: #{simple_sanitize(group.name)}", url: group_path(group) }
def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group)
}
end
end
# Autocomplete results for the current user's projects
def projects_autocomplete
current_user.authorized_projects.non_archived.map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
def projects_autocomplete(term, limit = 5)
current_user.authorized_projects.search_by_title(term).non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
url: project_path(p)
}
end
end
# Autocomplete results for the current user's projects
def public_projects_autocomplete
Project.public_or_internal_only(current_user).non_archived.map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
def public_projects_autocomplete(term, limit = 5)
Project.public_or_internal_only(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
url: project_path(p)
}
end
end
def search_result_sanitize(str)
Sanitize.clean(str)
end
end
......@@ -8,7 +8,7 @@ module Emails
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
@issue = Issue.find(issue_id)
@previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project
mail(to: recipient(recipient_id), subject: subject("Changed issue ##{@issue.iid}", @issue.title))
end
......
......@@ -8,7 +8,7 @@ module Emails
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
@merge_request = MergeRequest.find(merge_request_id)
@previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
mail(to: recipient(recipient_id), subject: subject("Changed merge request ##{@merge_request.iid}", @merge_request.title))
end
......
......@@ -45,6 +45,18 @@ module Issuable
def search(query)
where("title like :query", query: "%#{query}%")
end
def sort(method)
case method.to_s
when 'newest' then reorder('created_at DESC')
when 'oldest' then reorder('created_at ASC')
when 'recently_updated' then reorder('updated_at DESC')
when 'last_updated' then reorder('updated_at ASC')
when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
else reorder('created_at DESC')
end
end
end
def today?
......
......@@ -214,8 +214,8 @@ class MergeRequest < ActiveRecord::Base
self.merge
end
def automerge!(current_user)
if Gitlab::Satellite::MergeAction.new(current_user, self).merge! && self.unmerged_commits.empty?
def automerge!(current_user, commit_message = nil)
if Gitlab::Satellite::MergeAction.new(current_user, self).merge!(commit_message) && self.unmerged_commits.empty?
self.merge!(current_user.id)
true
end
......@@ -319,6 +319,15 @@ class MergeRequest < ActiveRecord::Base
update_all(updated_at: Time.now)
end
def merge_commit_message
message = "Merge branch '#{source_branch}' into '#{target_branch}'"
message << "\n\n"
message << title.to_s
message << "\n\n"
message << description.to_s
message
end
private
def dump_commits(commits)
......
......@@ -82,6 +82,18 @@ class Note < ActiveRecord::Base
}, without_protection: true)
end
def create_assignee_change_note(noteable, project, author, assignee)
body = assignee.nil? ? '_Assignee removed_' : "_Reassigned to @#{assignee.username}_"
create({
noteable: noteable,
project: project,
author: author,
note: body,
system: true
}, without_protection: true)
end
def discussions_from_notes(notes)
discussion_ids = []
discussions = []
......@@ -111,8 +123,8 @@ class Note < ActiveRecord::Base
def commit_author
@commit_author ||=
project.users.find_by_email(noteable.author_email) ||
project.users.find_by_name(noteable.author_name)
project.users.find_by(email: noteable.author_email) ||
project.users.find_by(name: noteable.author_name)
rescue
nil
end
......
......@@ -138,13 +138,17 @@ class Project < ActiveRecord::Base
joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
end
def search_by_title query
where("projects.archived = ?", false).where("LOWER(projects.name) LIKE :query", query: "%#{query.downcase}%")
end
def find_with_namespace(id)
if id.include?("/")
id = id.split("/")
namespace = Namespace.find_by_path(id.first)
namespace = Namespace.find_by(path: id.first)
return nil unless namespace
where(namespace_id: namespace.id).find_by_path(id.second)
where(namespace_id: namespace.id).find_by(path: id.second)
else
where(path: id, namespace_id: nil).last
end
......@@ -201,6 +205,10 @@ class Project < ActiveRecord::Base
[Gitlab.config.gitlab.url, path_with_namespace].join("/")
end
def web_url_without_protocol
web_url.split("://")[1]
end
def build_commit_note(commit)
notes.new(commit_id: commit.id, noteable_type: "Commit")
end
......@@ -270,9 +278,7 @@ class Project < ActiveRecord::Base
end
def send_move_instructions
team.members.each do |user|
Notify.delay.project_was_moved_email(self.id, user.id)
end
NotificationService.new.project_was_moved(self)
end
def owner
......@@ -290,7 +296,7 @@ class Project < ActiveRecord::Base
# Get Team Member record by user id
def team_member_by_id(user_id)
users_projects.find_by_user_id(user_id)
users_projects.find_by(user_id: user_id)
end
def name_with_namespace
......
......@@ -22,22 +22,22 @@ class ProjectTeam
end
def find(user_id)
user = project.users.find_by_id(user_id)
user = project.users.find_by(id: user_id)
if group
user ||= group.users.find_by_id(user_id)
user ||= group.users.find_by(id: user_id)
end
user
end
def find_tm(user_id)
tm = project.users_projects.find_by_user_id(user_id)
tm = project.users_projects.find_by(user_id: user_id)
# If user is not in project members
# we should check for group membership
if group && !tm
tm = group.users_groups.find_by_user_id(user_id)
tm = group.users_groups.find_by(user_id: user_id)
end
tm
......
......@@ -41,7 +41,8 @@
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
# hide_no_ssh_key :boolean default(FALSE), not null
# hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null
#
require 'carrierwave/orm/activerecord'
......@@ -52,7 +53,7 @@ class User < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
as: [:default, :admin]
......@@ -103,7 +104,7 @@ class User < ActiveRecord::Base
# Validations
#
validates :name, presence: true
validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }, uniqueness: true
validates :email, presence: true, email: {strict_mode: true}, uniqueness: true
validates :bio, length: { maximum: 255 }, allow_blank: true
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
......@@ -238,7 +239,7 @@ class User < ActiveRecord::Base
def namespace_uniq
namespace_name = self.username
if Namespace.find_by_path(namespace_name)
if Namespace.find_by(path: namespace_name)
self.errors.add :username, "already exist"
end
end
......@@ -382,7 +383,7 @@ class User < ActiveRecord::Base
end
def created_by
User.find_by_id(created_by_id) if created_by_id
User.find_by(id: created_by_id) if created_by_id
end
def sanitize_attrs
......@@ -424,4 +425,14 @@ class User < ActiveRecord::Base
order('id DESC').limit(1000).
update_all(updated_at: Time.now)
end
def full_website_url
return "http://#{website_url}" if website_url !~ /^https?:\/\//
website_url
end
def short_website_url
website_url.gsub(/https?:\/\//, '')
end
end
......@@ -28,7 +28,7 @@ class WebHook < ActiveRecord::Base
def execute(data)
parsed_url = URI.parse(url)
if parsed_url.userinfo.blank?
WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" })
WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }, verify: false)
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = {
......@@ -38,6 +38,7 @@ class WebHook < ActiveRecord::Base
WebHook.post(post_url,
body: data.to_json,
headers: {"Content-Type" => "application/json"},
verify: false,
basic_auth: auth)
end
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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