Merge remote-tracking branch 'gitlabhq/master' into git_commit_fix

Conflicts:
	doc/install/installation.md
This commit is contained in:
David Barri 2012-11-11 21:27:55 +11:00
commit 93f0a8c9b3
369 changed files with 102667 additions and 1369 deletions

View file

@ -4,7 +4,7 @@ env:
before_install: before_install:
- sudo apt-get install libicu-dev -y - sudo apt-get install libicu-dev -y
- sudo apt-get install libqt4-dev libqtwebkit-dev -y - sudo apt-get install libqt4-dev libqtwebkit-dev -y
- gem install charlock_holmes -v="0.6.8" - gem install charlock_holmes -v="0.6.9"
branches: branches:
only: only:
- 'master' - 'master'

View file

@ -28,7 +28,7 @@ v 3.0.0
- Reject ssh keys that break gitolite - Reject ssh keys that break gitolite
- [API] list one project hook - [API] list one project hook
- [API] edit project hook - [API] edit project hook
- [API] add project snippets list - [API] list project snippets
- [API] allow to authorize using private token in HTTP header - [API] allow to authorize using private token in HTTP header
- [API] add user creation - [API] add user creation

View file

@ -1,4 +1,4 @@
## Contribute to GitLab ## Contribute to GitLab
If you want to contribute to GitLab, follow this process: If you want to contribute to GitLab, follow this process:
@ -7,24 +7,20 @@ If you want to contribute to GitLab, follow this process:
3. Code 3. Code
4. Create a pull request 4. Create a pull request
We will only accept pull requests if: We will only accept pull requests if:
* Your code has proper tests and all tests pass * Your code has proper tests and all tests pass
* Your code can be merged w/o problems * Your code can be merged w/o problems
* It won't break existing functionality * It won't break existing functionality
* It's quality code * It's quality code
* We like it :) * We like it :)
## [You may need a developer VM](https://github.com/gitlabhq/developer-vm) For examples of feedback on pull requests please look at the [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed).
## Installation
Install the Gitlab development in a virtual machine with the [Gitlab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm). Installing it in a virtual machine makes it much easier to set up all the dependencies for integration testing.
## Running tests ## Running tests
To run the specs for GitLab, you need to run seeds for test db. For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
cd gitlabhq
rake db:seed_fu RAILS_ENV=test
Then you can run the test suite with rake:
rake gitlab:test

31
Gemfile
View file

@ -11,9 +11,9 @@ end
gem "rails", "3.2.8" gem "rails", "3.2.8"
# Supported DBs # Supported DBs
gem "sqlite3", :group => :sqlite gem "sqlite3", group: :sqlite
gem "mysql2", :group => :mysql gem "mysql2", group: :mysql
gem "pg", :group => :postgres gem "pg", group: :postgres
# Auth # Auth
gem "devise", "~> 2.1.0" gem "devise", "~> 2.1.0"
@ -23,10 +23,11 @@ gem 'omniauth-twitter'
gem 'omniauth-github' gem 'omniauth-github'
# GITLAB patched libs # GITLAB patched libs
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837'
gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e" gem "omniauth-ldap", git: "https://github.com/gitlabhq/omniauth-ldap.git", ref: 'f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e'
gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" gem 'yaml_db', git: "https://github.com/gitlabhq/yaml_db.git", ref: '98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd'
gem 'grack', :git => "https://github.com/gitlabhq/grack.git" gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '212fd40bea61f3c6a167223768e7295dc32bbc10'
# Gitolite client (for work with gitolite-admin repo) # Gitolite client (for work with gitolite-admin repo)
gem "gitolite", '1.1.0' gem "gitolite", '1.1.0'
@ -35,7 +36,7 @@ gem "gitolite", '1.1.0'
gem "pygments.rb", "0.3.1" gem "pygments.rb", "0.3.1"
# Language detection # Language detection
gem "github-linguist", "~> 2.3.4" , :require => "linguist" gem "github-linguist", "~> 2.3.4" , require: "linguist"
# API # API
gem "grape", "~> 0.2.1" gem "grape", "~> 0.2.1"
@ -83,9 +84,6 @@ gem 'resque_mailer'
# HTTP requests # HTTP requests
gem "httparty" gem "httparty"
# Handle encodings
gem "charlock_holmes"
# Colored output to console # Colored output to console
gem "colored" gem "colored"
@ -114,8 +112,9 @@ group :assets do
end end
group :development do group :development do
gem "annotate", git: "https://github.com/ctran/annotate_models.git"
gem "letter_opener" gem "letter_opener"
gem "annotate", :git => "https://github.com/ctran/annotate_models.git" gem 'quiet_assets', '1.0.1'
gem 'rack-mini-profiler' gem 'rack-mini-profiler'
end end
@ -137,13 +136,13 @@ group :development, :test do
gem 'guard-spinach' gem 'guard-spinach'
# Notification # Notification
gem 'rb-fsevent', :require => darwin_only('rb-fsevent') gem 'rb-fsevent', require: darwin_only('rb-fsevent')
gem 'growl', :require => darwin_only('growl') gem 'growl', require: darwin_only('growl')
gem 'rb-inotify', :require => linux_only('rb-inotify') gem 'rb-inotify', require: linux_only('rb-inotify')
end end
group :test do group :test do
gem "simplecov", :require => false gem "simplecov", require: false
gem "shoulda-matchers" gem "shoulda-matchers"
gem 'email_spec' gem 'email_spec'
gem 'resque_spec' gem 'resque_spec'

View file

@ -7,6 +7,7 @@ GIT
GIT GIT
remote: https://github.com/gitlabhq/grack.git remote: https://github.com/gitlabhq/grack.git
revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8 revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
specs: specs:
grack (1.0.0) grack (1.0.0)
rack (~> 1.4.1) rack (~> 1.4.1)
@ -21,6 +22,14 @@ GIT
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
GIT
remote: https://github.com/gitlabhq/grit_ext.git
revision: 212fd40bea61f3c6a167223768e7295dc32bbc10
ref: 212fd40bea61f3c6a167223768e7295dc32bbc10
specs:
grit_ext (0.6.0)
charlock_holmes (~> 0.6.9)
GIT GIT
remote: https://github.com/gitlabhq/omniauth-ldap.git remote: https://github.com/gitlabhq/omniauth-ldap.git
revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
@ -35,6 +44,7 @@ GIT
GIT GIT
remote: https://github.com/gitlabhq/yaml_db.git remote: https://github.com/gitlabhq/yaml_db.git
revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
ref: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
specs: specs:
yaml_db (0.2.2) yaml_db (0.2.2)
@ -90,7 +100,7 @@ GEM
carrierwave (0.6.2) carrierwave (0.6.2)
activemodel (>= 3.2.0) activemodel (>= 3.2.0)
activesupport (>= 3.2.0) activesupport (>= 3.2.0)
charlock_holmes (0.6.8) charlock_holmes (0.6.9)
childprocess (0.3.2) childprocess (0.3.2)
ffi (~> 1.0.6) ffi (~> 1.0.6)
chosen-rails (0.9.8.3) chosen-rails (0.9.8.3)
@ -260,6 +270,8 @@ GEM
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0) yajl-ruby (~> 1.1.0)
pyu-ruby-sasl (0.0.3.3) pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.1)
railties (~> 3.1)
rack (1.4.1) rack (1.4.1)
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
@ -411,7 +423,6 @@ DEPENDENCIES
capybara capybara
capybara-webkit capybara-webkit
carrierwave carrierwave
charlock_holmes
chosen-rails chosen-rails
coffee-rails (= 3.2.2) coffee-rails (= 3.2.2)
colored colored
@ -432,6 +443,7 @@ DEPENDENCIES
grack! grack!
grape (~> 0.2.1) grape (~> 0.2.1)
grit! grit!
grit_ext!
growl growl
guard-rspec guard-rspec
guard-spinach guard-spinach
@ -454,6 +466,7 @@ DEPENDENCIES
pg pg
pry pry
pygments.rb (= 0.3.1) pygments.rb (= 0.3.1)
quiet_assets (= 1.0.1)
rack-mini-profiler rack-mini-profiler
rails (= 3.2.8) rails (= 3.2.8)
rails-dev-tweaks rails-dev-tweaks

View file

@ -1,2 +0,0 @@
web: bundle exec rails s -p $PORT -e production
worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=*

19
ROADMAP.md Normal file
View file

@ -0,0 +1,19 @@
## GitLab Roadmap
### Common
* Help page for service tasks like repos import, backup etc
* Hide last push widget after following link
* Add comment events
* Dashboard/Project activity events filter
### Issues
* labels autocomplete via jquery autocomplete
* Import/Export issues
* Form: Assign to me link right to the selectbox
### Merge Request
* CI build status
* Save code fragments with MR comments

View file

@ -1 +1 @@
3.0.3 3.1.0pre

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -17,6 +17,8 @@
//= require modernizr //= require modernizr
//= require chosen-jquery //= require chosen-jquery
//= require raphael //= require raphael
//= require g.raphael-min
//= require g.bar-min
//= require branch-graph //= require branch-graph
//= require ace-src-noconflict/ace //= require ace-src-noconflict/ace
//= require_tree . //= require_tree .

View file

@ -1,57 +1,47 @@
# Creates the variables for setting up GFM auto-completion
###
Creates the variables for setting up GFM auto-completion
###
# Emoji # Emoji
window.autocompleteEmojiData = []; data = []
window.autocompleteEmojiTemplate = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"; template = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"
window.autocompleteEmoji = {data, template}
# Team Members # Team Members
window.autocompleteMembersUrl = ""; url = '';
window.autocompleteMembersParams = params = {private_token: '', page: 1}
private_token: "" window.autocompleteMembers = {data, url, params}
page: 1
window.autocompleteMembersData = [];
# Add GFM auto-completion to all input fields, that accept GFM input.
###
Add GFM auto-completion to all input fields, that accept GFM input.
###
window.setupGfmAutoComplete = -> window.setupGfmAutoComplete = ->
### $input = $('.js-gfm-input')
Emoji
###
$('.gfm-input').atWho ':',
data: autocompleteEmojiData,
tpl: autocompleteEmojiTemplate
### # Emoji
Team Members $input.atWho ':',
### data: autocompleteEmoji.data,
$('.gfm-input').atWho '@', (query, callback) -> tpl: autocompleteEmoji.template
# Team Members
$input.atWho '@', (query, callback) ->
(getMoreMembers = -> (getMoreMembers = ->
$.getJSON(autocompleteMembersUrl, autocompleteMembersParams) $.getJSON(autocompleteMembers.url, autocompleteMembers.params).success (members) ->
.success (members) -> # pick the data we need
# pick the data we need newMembersData = $.map members, (m) -> m.name
newMembersData = $.map members, (m) -> m.name
# add the new page of data to the rest # add the new page of data to the rest
$.merge autocompleteMembersData, newMembersData $.merge autocompleteMembers.data, newMembersData
# show the pop-up with a copy of the current data # show the pop-up with a copy of the current data
callback autocompleteMembersData[..] callback autocompleteMembers.data[..]
# are we past the last page? # are we past the last page?
if newMembersData.length == 0 if newMembersData.length is 0
# set static data and stop callbacks # set static data and stop callbacks
$('.gfm-input').atWho '@', $input.atWho '@',
data: autocompleteMembersData data: autocompleteMembers.data
callback: null callback: null
else else
# get next page # get next page
getMoreMembers() getMoreMembers()
# so the next request gets the next page # so the next request gets the next page
autocompleteMembersParams.page += 1; autocompleteMembers.params.page += 1
).call(); ).call()

View file

@ -1,10 +0,0 @@
initGraphNav = ->
$('.graph svg').css 'position', 'relative'
$('body').bind 'keyup', (e) ->
if e.keyCode is 37 # left
$('.graph svg').animate left: '+=400'
else if e.keyCode is 39 # right
$('.graph svg').animate left: '-=400'
window.initGraphNav = initGraphNav

View file

@ -1,6 +1,5 @@
function switchToNewIssue(form){ function switchToNewIssue(){
$(".issues_content").hide("fade", { direction: "left" }, 150, function(){ $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
$(".issues_content").after(form);
$('select#issue_assignee_id').chosen(); $('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#new_issue_dialog").show("fade", { direction: "right" }, 150); $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
@ -10,9 +9,8 @@ function switchToNewIssue(form){
}); });
} }
function switchToEditIssue(form){ function switchToEditIssue(){
$(".issues_content").hide("fade", { direction: "left" }, 150, function(){ $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
$(".issues_content").after(form);
$('select#issue_assignee_id').chosen(); $('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150); $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
@ -33,8 +31,8 @@ function switchFromEditIssue(){
function backToIssues(){ function backToIssues(){
$("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){ $("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){
$(".issues_content").show("fade", { direction: "left" }, 150, function() { $(".issues_content").show("fade", { direction: "left" }, 150, function() {
$("#edit_issue_dialog").remove(); $("#edit_issue_dialog").html("");
$("#new_issue_dialog").remove(); $("#new_issue_dialog").html("");
$('.add_new').show(); $('.add_new').show();
}); });
}); });

View file

@ -1,5 +0,0 @@
Loader =
html: (width) ->
$('<img>').attr src: '/assets/ajax-loader.gif', width: width
window.Loader = Loader

View file

@ -7,29 +7,32 @@ window.slugify = (text) ->
window.ajaxGet = (url) -> window.ajaxGet = (url) ->
$.ajax({type: "GET", url: url, dataType: "script"}) $.ajax({type: "GET", url: url, dataType: "script"})
# Disable button if text field is empty # Disable button if text field is empty
window.disableButtonIfEmptyField = (field_selector, button_selector) -> window.disableButtonIfEmptyField = (field_selector, button_selector) ->
field = $(field_selector) field = $(field_selector)
closest_submit = field.closest("form").find(button_selector) closest_submit = field.closest("form").find(button_selector)
closest_submit.disable() if field.val() is "" closest_submit.disable() if field.val() is ""
field.on "keyup", -> field.on "input", ->
if $(this).val() is "" if $(@).val() is ""
closest_submit.disable() closest_submit.disable()
else else
closest_submit.enable() closest_submit.enable()
$ -> $ ->
# Click a .one_click_select field, select the contents # Click a .one_click_select field, select the contents
$(".one_click_select").live 'click', -> $(this).select() $(".one_click_select").on 'click', -> $(@).select()
# Initialize chosen selects # Initialize chosen selects
$('select.chosen').chosen() $('select.chosen').chosen()
# Initialize tooltips
$('.has_tooltip').tooltip()
# Disable form buttons while a form is submitting # Disable form buttons while a form is submitting
$('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
buttons = $('[type="submit"]', this) buttons = $('[type="submit"]', @)
switch e.type switch e.type
when 'ajax:beforeSend', 'submit' when 'ajax:beforeSend', 'submit'
@ -38,7 +41,7 @@ $ ->
buttons.enable() buttons.enable()
# Show/Hide the profile menu when hovering the account box # Show/Hide the profile menu when hovering the account box
$('.account-box').hover -> $(this).toggleClass('hover') $('.account-box').hover -> $(@).toggleClass('hover')
# Focus search field by pressing 's' key # Focus search field by pressing 's' key
$(document).keypress (e) -> $(document).keypress (e) ->
@ -52,22 +55,22 @@ $ ->
# Commit show suppressed diff # Commit show suppressed diff
$(".supp_diff_link").bind "click", -> $(".supp_diff_link").bind "click", ->
$(this).next('table').show() $(@).next('table').show()
$(this).remove() $(@).remove()
# Note markdown preview # Note markdown preview
$(document).on 'click', '#preview-link', (e) -> $(document).on 'click', '#preview-link', (e) ->
$('#preview-note').text('Loading...') $('#preview-note').text 'Loading...'
previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview' previewLinkText = if $(@).text() is 'Preview' then 'Edit' else 'Preview'
$(this).text(previewLinkText) $(@).text previewLinkText
note = $('#note_note').val() note = $('#note_note').val()
if note.trim().length == 0 if note.trim().length is 0
$('#preview-note').text("Nothing to preview.") $('#preview-note').text 'Nothing to preview.'
else else
$.post $(this).attr('href'), {note: note}, (data) -> $.post $(@).attr('href'), {note: note}, (data) ->
$('#preview-note').html(data) $('#preview-note').html(data)
$('#preview-note, #note_note').toggle() $('#preview-note, #note_note').toggle()
@ -79,14 +82,14 @@ $ ->
$.fn.extend chosen: (options) -> $.fn.extend chosen: (options) ->
default_options = search_contains: "true" default_options = search_contains: "true"
$.extend default_options, options $.extend default_options, options
_chosen.apply this, [default_options] _chosen.apply @, [default_options]
# Disable an element and add the 'disabled' Bootstrap class # Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: -> $.fn.extend disable: ->
$(this).attr('disabled', 'disabled').addClass('disabled') $(@).attr('disabled', 'disabled').addClass('disabled')
# Enable an element and remove the 'disabled' Bootstrap class # Enable an element and remove the 'disabled' Bootstrap class
$.fn.extend enable: -> $.fn.extend enable: ->
$(this).removeAttr('disabled').removeClass('disabled') $(@).removeAttr('disabled').removeClass('disabled')
)(jQuery) )(jQuery)

View file

@ -115,4 +115,15 @@ var MergeRequest = {
$(".merge_in_progress").hide(); $(".merge_in_progress").hide();
$(".automerge_widget.already_cannot_be_merged").show(); $(".automerge_widget.already_cannot_be_merged").show();
} }
};
/*
* Filter merge requests
*/
function merge_requestsPage() {
$("#assignee_id").chosen();
$("#milestone_id").chosen();
$("#milestone_id, #assignee_id").on("change", function(){
$(this).closest("form").submit();
});
} }

View file

@ -5,3 +5,10 @@ $ ->
$('.milestone-issue-filter li').toggleClass('active') $('.milestone-issue-filter li').toggleClass('active')
$('.milestone-issue-filter tr[data-closed]').toggleClass('hide') $('.milestone-issue-filter tr[data-closed]').toggleClass('hide')
false false
$('.milestone-merge-requests-filter tr[data-closed]').addClass('hide')
$('.milestone-merge-requests-filter ul.nav li a').click ->
$('.milestone-merge-requests-filter li').toggleClass('active')
$('.milestone-merge-requests-filter tr[data-closed]').toggleClass('hide')
false

View file

@ -22,3 +22,10 @@ $ ->
# Ref switcher # Ref switcher
$('.project-refs-select').on 'change', -> $('.project-refs-select').on 'change', ->
$(@).parents('form').submit() $(@).parents('form').submit()
class @GraphNav
@init: ->
$('.graph svg').css 'position', 'relative'
$('body').bind 'keyup', (e) ->
$('.graph svg').animate(left: '+=400') if e.keyCode is 37 # left
$('.graph svg').animate(left: '-=400') if e.keyCode is 39 # right

View file

@ -1,6 +0,0 @@
$ ->
$('#snippets-table .snippet').live 'click', (e) ->
if e.target.nodeName isnt 'A' and e.target.nodeName isnt 'INPUT'
location.href = $(@).attr 'url'
e.stopPropagation()
false

View file

@ -17,23 +17,21 @@ $ ->
"ajax:beforeSend": -> $('.tree_progress').addClass("loading") "ajax:beforeSend": -> $('.tree_progress').addClass("loading")
"ajax:complete": -> $('.tree_progress').removeClass("loading") "ajax:complete": -> $('.tree_progress').removeClass("loading")
# Maintain forward/back history while browsing the file tree # Maintain forward/back history while browsing the file tree
((window) ->
History = window.History
$ = window.jQuery
document = window.document
((window) -> # Check to see if History.js is enabled for our Browser
History = window.History unless History.enabled
$ = window.jQuery return false
document = window.document
# Check to see if History.js is enabled for our Browser $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
unless History.enabled History.pushState(null, null, $(@).attr('href'))
return false return false
$ -> History.Adapter.bind window, 'statechange', ->
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) -> state = History.getState()
History.pushState(null, null, $(@).attr('href')) window.ajaxGet(state.url)
return false )(window)
History.Adapter.bind window, 'statechange', ->
state = History.getState()
window.ajaxGet(state.url)
)(window)

View file

@ -670,3 +670,16 @@ pre {
padding:0; padding:0;
} }
} }
.milestone .progress {
margin-bottom: 0;
margin-top:4px;
}
.float-link {
float:left;
margin-right:15px;
.s16 {
margin-right:5px;
}
}

View file

@ -26,8 +26,10 @@
.underlined { border-bottom: 1px solid #CCC; } .underlined { border-bottom: 1px solid #CCC; }
.no-borders { border:none; } .no-borders { border:none; }
.vlink { color: $link_color !important; } .vlink { color: $link_color !important; }
.underlined_link { text-decoration: underline; }
.borders { border: 1px solid #ccc; @include shade; } .borders { border: 1px solid #ccc; @include shade; }
.hint { font-style: italic; color: #999; } .hint { font-style: italic; color: #999; }
.light { color: #888 }
/** PILLS & TABS**/ /** PILLS & TABS**/
.nav-pills a:hover { background-color:#888; } .nav-pills a:hover { background-color:#888; }
@ -66,10 +68,10 @@
.alert-message.error { @extend .alert-error; } .alert-message.error { @extend .alert-error; }
/** AVATARS **/ /** AVATARS **/
img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; } img.avatar { float:left; margin-right:12px; width:40px; border:1px solid #ddd; padding:1px; }
img.avatar.s16 { width:16px; height:16px; } img.avatar.s16 { width:16px; height:16px; margin-right:6px; }
img.avatar.s24 { width:24px; height:24px; } img.avatar.s24 { width:24px; height:24px; margin-right:8px; }
img.avatar.s32 { width:32px; height:32px; } img.avatar.s32 { width:32px; height:32px; margin-right:10px; }
img.lil_av { padding-left: 4px; padding-right:3px; } img.lil_av { padding-left: 4px; padding-right:3px; }
/** HELPERS **/ /** HELPERS **/

View file

@ -157,10 +157,15 @@
font-size:12px !important; font-size:12px !important;
} }
table.highlighttable .linenodiv pre { table.highlighttable .linenodiv {
text-align: right; a {
padding-right: 4px; color: #666;
color:#666; }
pre {
text-align: right;
padding-right: 4px;
color:#666;
}
} }
} }
} }

View file

@ -21,7 +21,7 @@ ul {
.author { color: #999; } .author { color: #999; }
p { p {
padding-top:5px; padding-top: 1px;
margin:0; margin:0;
color:#222; color:#222;
img { img {
@ -31,3 +31,11 @@ ul {
} }
} }
} }
ol, ul {
&.styled {
li {
padding:2px;
}
}
}

View file

@ -34,6 +34,11 @@ table {
border-color:#f1f1f1; border-color:#f1f1f1;
line-height:28px; line-height:28px;
.s16 {
margin-top: 5px;
margin-right: 5px;
}
&:first-child { &:first-child {
border-left:1px solid #bbb; border-left:1px solid #bbb;
} }

View file

@ -3,10 +3,11 @@
@import 'font-awesome'; @import 'font-awesome';
/** GitLab colors **/ /** GitLab colors **/
$link_color:#3A89A3; $link_color: #3A89A3;
$blue_link: #2fa0bb; $blue_link: #2FA0BB;
$style_color: #474d57; $style_color: #474D57;
$hover: #D9EDF7; $hover: #D9EDF7;
$hover_border: #ADF;
/** GitLab Fonts **/ /** GitLab Fonts **/
@font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); } @font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); }
@ -19,9 +20,9 @@ $hover: #D9EDF7;
} }
@mixin solid_shade { @mixin solid_shade {
-moz-box-shadow: 0 0 0 3px #eee; -moz-box-shadow: 0 0 0 3px #f1f1f1;
-webkit-box-shadow: 0 0 0 3px #eee; -webkit-box-shadow: 0 0 0 3px #f1f1f1;
box-shadow: 0 0 0 3px #eee; box-shadow: 0 0 0 3px #f1f1f1;
} }
@mixin border-radius($radius) { @mixin border-radius($radius) {
@ -64,6 +65,14 @@ $hover: #D9EDF7;
background-image: -o-linear-gradient($from, $to); background-image: -o-linear-gradient($from, $to);
} }
@mixin bg-light-gray-gradient {
background:#f1f1f1;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1));
background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
}
@mixin bg-gray-gradient { @mixin bg-gray-gradient {
background:#eee; background:#eee;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));

View file

@ -19,41 +19,14 @@
margin-right: 10px; margin-right: 10px;
.chzn-drop { .chzn-drop {
margin:7px 0;
min-width: 400px; min-width: 400px;
border: 2px solid $blue_link;
@include border-radius(4px);
.chzn-results { .chzn-results {
max-height:300px; max-height:300px;
.group-result {
color: $blue_link;
}
.active-result {
&.highlighted {
background: $blue_link;
}
}
} }
.chzn-search input { .chzn-search input {
min-width:365px; min-width:365px;
} }
} }
.chzn-single {
@include bg-gray-gradient;
div {
background:transparent;
border-left:none;
}
span {
font-weight: normal;
}
}
} }
/** Fix for Search Dropdown Border **/ /** Fix for Search Dropdown Border **/
@ -65,4 +38,55 @@
box-shadow: none; box-shadow: none;
} }
} }
.chzn-drop {
margin:7px 0;
min-width: 200px;
border: 1px solid #bbb;
border-radius:0;
.chzn-results {
margin-top: 5px;
max-height:300px;
.group-result {
color: $style_color;
border-bottom: 1px solid #EEE;
padding: 8px;
}
.active-result {
border-radius: 0;
&.highlighted {
background: $hover;
color: $style_color;
}
&.result-selected {
background: #EEE;
border-left: 4px solid #CCC;
}
}
}
.chzn-search {
@include bg-gray-gradient;
input {
min-width:165px;
border-color: #CCC;
}
}
}
.chzn-single {
@include bg-light-gray-gradient;
div {
background:transparent;
border-left:none;
}
span {
font-weight: normal;
}
}
} }

View file

@ -47,12 +47,15 @@
padding-left: 32px; padding-left: 32px;
} }
.author, .author a,
.committer { .committer a {
font-size:14px; font-size:14px;
line-height:22px; line-height:22px;
text-shadow:0 1px 1px #fff; text-shadow:0 1px 1px #fff;
color:#777; color:#777;
&:hover {
color: #999;
}
} }
.avatar { .avatar {
@ -227,6 +230,9 @@
.commit-author-name { .commit-author-name {
color: #777; color: #777;
&:hover {
color: #999;
}
} }
} }

View file

@ -43,6 +43,7 @@
.event-body { .event-body {
p { p {
color:#555; color:#555;
padding-top: 5px;
} }
.event-info { .event-info {
color:#666; color:#666;
@ -115,3 +116,29 @@
margin: -3px; margin: -3px;
} }
} }
/**
* Event filter
*
*/
.event_filter {
position: absolute;
width: 40px;
margin-left: -50px;
.filter_icon {
float: left;
border-left: 3px solid #4bc;
padding: 7px;
background: #f9f9f9;
margin-bottom: 10px;
img {
width:20px;
}
&.inactive {
border-left: 3px solid #EEE;
opacity: 0.5;
}
}
}

View file

@ -44,7 +44,7 @@
img.avatar { img.avatar {
width:32px; width:32px;
margin-top:4px; margin-top:1px;
} }
} }
} }

View file

@ -71,7 +71,7 @@ li.merge_request {
padding:7px 10px; padding:7px 10px;
img.avatar { img.avatar {
width: 32px; width: 32px;
margin-top: 4px; margin-top: 1px;
} }
p { p {
padding: 0px; padding: 0px;
@ -121,3 +121,20 @@ li.merge_request {
.mr_direction_tip { .mr_direction_tip {
margin-top:40px margin-top:40px
} }
.merge_requests_form_box {
@extend .main_box;
.merge_requests_middle_box {
@extend .middle_box_content;
height:30px;
.merge_requests_assignee {
@extend .span6;
float:left;
}
.merge_requests_milestone {
@extend .span4;
float:left;
}
}
}

View file

@ -57,10 +57,7 @@
padding-right: 8px; padding-right: 8px;
img.avatar { img.avatar {
border: 0 none; margin-top: 0;
float: none;
margin-right: 0;
padding: 0;
width: 16px; width: 16px;
} }
} }
@ -75,6 +72,15 @@
} }
} }
} }
.blame {
img.avatar {
border: 0 none;
float: none;
margin: 0;
padding: 0;
}
}
} }
.tree-btn-group { .tree-btn-group {

View file

@ -37,9 +37,6 @@
background-image: -o-linear-gradient(#595D63 6.6%, #202227); background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0; background-position:0 0;
color:#fff; color:#fff;
i {
@extend .icon-white;
}
} }
border: 1px solid #31363E; border: 1px solid #31363E;

View file

@ -70,9 +70,6 @@
color:#ccc; color:#ccc;
&:hover { &:hover {
color:#fff; color:#fff;
i {
@extend .icon-white;
}
} }
border: none; border: none;
box-shadow:none; box-shadow:none;

View file

@ -21,7 +21,7 @@ class CommitLoadContext < BaseContext
result[:notes_count] = line_notes.count + project.commit_notes(commit).count result[:notes_count] = line_notes.count + project.commit_notes(commit).count
begin begin
result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff] result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff]
rescue Grit::Git::GitTimeout rescue Grit::Git::GitTimeout
result[:suppress_diff] = true result[:suppress_diff] = true
result[:status] = :huge_commit result[:status] = :huge_commit

View file

@ -1,3 +1,5 @@
# Build collection of Merge Requests
# based on filtering passed via params for @project
class MergeRequestsLoadContext < BaseContext class MergeRequestsLoadContext < BaseContext
def execute def execute
type = params[:f] type = params[:f]
@ -9,8 +11,21 @@ class MergeRequestsLoadContext < BaseContext
when 'closed' then merge_requests.closed when 'closed' then merge_requests.closed
when 'assigned-to-me' then merge_requests.opened.assigned(current_user) when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
else merge_requests.opened else merge_requests.opened
end.page(params[:page]).per(20) end
merge_requests.includes(:author, :project).order("closed, created_at desc") merge_requests = merge_requests.page(params[:page]).per(20)
merge_requests = merge_requests.includes(:author, :project).order("closed, 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
end end

View file

@ -13,6 +13,7 @@ class SearchContext
result[:projects] = Project.where(id: project_ids).search(query).limit(10) result[:projects] = Project.where(id: project_ids).search(query).limit(10)
result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10) result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10)
result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
result[:wiki_pages] = Wiki.where(project_id: project_ids).search(query).limit(10)
result result
end end
@ -20,7 +21,8 @@ class SearchContext
@result ||= { @result ||= {
projects: [], projects: [],
merge_requests: [], merge_requests: [],
issues: [] issues: [],
wiki_pages: []
} }
end end
end end

View file

@ -9,19 +9,28 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can? helper_method :abilities, :can?
rescue_from Gitlab::Gitolite::AccessDenied do |exception| rescue_from Gitlab::Gitolite::AccessDenied do |exception|
log_exception(exception)
render "errors/gitolite", layout: "errors", status: 500 render "errors/gitolite", layout: "errors", status: 500
end end
rescue_from Encoding::CompatibilityError do |exception| rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
render "errors/encoding", layout: "errors", status: 500 render "errors/encoding", layout: "errors", status: 500
end end
rescue_from ActiveRecord::RecordNotFound do |exception| rescue_from ActiveRecord::RecordNotFound do |exception|
log_exception(exception)
render "errors/not_found", layout: "errors", status: 404 render "errors/not_found", layout: "errors", status: 404
end end
protected protected
def log_exception(exception)
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" }
logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
end
def reject_blocked! def reject_blocked!
if current_user && current_user.blocked if current_user && current_user.blocked
sign_out current_user sign_out current_user

View file

@ -1,7 +1,6 @@
# Controller for viewing a file's blame # Controller for viewing a file's blame
class BlobController < ProjectResourceController class BlobController < ProjectResourceController
include ExtractsPath include ExtractsPath
include Gitlab::Encode
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
@ -12,16 +11,9 @@ class BlobController < ProjectResourceController
def show def show
if @tree.is_blob? if @tree.is_blob?
if @tree.text?
encoding = detect_encoding(@tree.data)
mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"
else
mime_type = @tree.mime_type
end
send_data( send_data(
@tree.data, @tree.data,
type: mime_type, type: @tree.mime_type,
disposition: 'inline', disposition: 'inline',
filename: @tree.name filename: @tree.name
) )

View file

@ -1,12 +1,17 @@
class DashboardController < ApplicationController class DashboardController < ApplicationController
respond_to :html respond_to :html
before_filter :event_filter, only: :index
def index def index
@groups = Group.where(id: current_user.projects.pluck(:group_id)) @groups = Group.where(id: current_user.projects.pluck(:group_id))
@projects = current_user.projects_with_events @projects = current_user.projects_with_events
@projects = @projects.page(params[:page]).per(30) @projects = @projects.page(params[:page]).per(30)
@events = Event.in_projects(current_user.project_ids).limit(20).offset(params[:offset] || 0) @events = Event.in_projects(current_user.project_ids)
@events = @event_filter.apply_filter(@events)
@events = @events.limit(20).offset(params[:offset] || 0)
@last_push = current_user.recent_push @last_push = current_user.recent_push
respond_to do |format| respond_to do |format|
@ -34,4 +39,8 @@ class DashboardController < ApplicationController
format.atom { render layout: false } format.atom { render layout: false }
end end
end end
def event_filter
@event_filter ||= EventFilter.new(params[:event_filter])
end
end end

View file

@ -31,7 +31,8 @@ class MilestonesController < ProjectResourceController
def show def show
@issues = @milestone.issues @issues = @milestone.issues
@users = @milestone.participants @users = UserDecorator.decorate(@milestone.participants)
@merge_requests = @milestone.merge_requests
respond_to do |format| respond_to do |format|
format.html format.html

View file

@ -22,7 +22,7 @@ class ProfileController < ApplicationController
flash[:notice] = "Password was successfully updated. Please login with it" flash[:notice] = "Password was successfully updated. Please login with it"
redirect_to new_user_session_path redirect_to new_user_session_path
else else
render action: "password" render 'account'
end end
end end

View file

@ -1,4 +1,4 @@
require Rails.root.join('lib', 'gitlab', 'graph_commit') require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder')
class ProjectsController < ProjectResourceController class ProjectsController < ProjectResourceController
skip_before_filter :project, only: [:new, :create] skip_before_filter :project, only: [:new, :create]
@ -79,7 +79,9 @@ class ProjectsController < ProjectResourceController
end end
def graph def graph
@days_json, @commits_json = Gitlab::GraphCommit.to_graph(project) graph = Gitlab::Graph::JsonBuilder.new(project)
@days_json, @commits_json = graph.days_json, graph.commits_json
end end
def destroy def destroy

View file

@ -1,5 +1,4 @@
class RefsController < ProjectResourceController class RefsController < ProjectResourceController
include Gitlab::Encode
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!

View file

@ -16,9 +16,14 @@ class RepositoriesController < ProjectResourceController
@tags = @project.tags @tags = @project.tags
end end
def stats
@stats = Gitlab::GitStats.new(@project.repo, @project.root_ref)
@graph = @stats.graph
end
def archive def archive
unless can?(current_user, :download_code, @project) unless can?(current_user, :download_code, @project)
render_404 and return render_404 and return
end end

View file

@ -5,5 +5,6 @@ class SearchController < ApplicationController
@projects = result[:projects] @projects = result[:projects]
@merge_requests = result[:merge_requests] @merge_requests = result[:merge_requests]
@issues = result[:issues] @issues = result[:issues]
@wiki_pages = result[:wiki_pages]
end end
end end

View file

@ -26,15 +26,14 @@ class TreeController < ProjectResourceController
end end
def update def update
file_editor = Gitlab::FileEditor.new(current_user, @project, @ref) edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
update_status = file_editor.update( updated_successfully = edit_file_action.commit!(
@path,
params[:content], params[:content],
params[:commit_message], params[:commit_message],
params[:last_commit] params[:last_commit]
) )
if update_status if updated_successfully
redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited" redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited"
else else
flash[:notice] = "Your changes could not be commited, because the file has been changed" flash[:notice] = "Your changes could not be commited, because the file has been changed"

View file

@ -47,21 +47,15 @@ class CommitDecorator < ApplicationDecorator
# Otherwise it will link to the author email as specified in the commit. # Otherwise it will link to the author email as specified in the commit.
# #
# options: # options:
# avatar: true will prepend avatar image # avatar: true will prepend the avatar image
def author_link(options) # size: size of the avatar image in px
text = if options[:avatar] def author_link(options = {})
avatar = h.image_tag h.gravatar_icon(author_email), class: "avatar", width: 16 person_link(options.merge source: :author)
"#{avatar} #{author_name}" end
else
author_name
end
team_member = @project.try(:team_member_by_name_or_email, author_name, author_email)
if team_member.nil? # Just like #author_link but for the committer.
h.mail_to author_email, text.html_safe, class: "commit-author-link" def committer_link(options = {})
else person_link(options.merge source: :committer)
h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-author-link"
end
end end
protected protected
@ -69,4 +63,30 @@ class CommitDecorator < ApplicationDecorator
def no_commit_message def no_commit_message
"--no commit message" "--no commit message"
end end
# Private: Returns a link to a person. If the person has a matching user and
# is a member of the current @project it will link to the team member page.
# Otherwise it will link to the person email as specified in the commit.
#
# options:
# source: one of :author or :committer
# avatar: true will prepend the avatar image
# size: size of the avatar image in px
def person_link(options = {})
source_name = send "#{options[:source]}_name".to_sym
source_email = send "#{options[:source]}_email".to_sym
text = if options[:avatar]
avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size]
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
else
source_name
end
team_member = @project.try(:team_member_by_name_or_email, source_name, source_email)
if team_member.nil?
h.mail_to source_email, text.html_safe, class: "commit-#{options[:source]}-link"
else
h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-#{options[:source]}-link"
end
end
end end

View file

@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator
#parts = parts[0...-1] if is_blob? #parts = parts[0...-1] if is_blob?
yield(h.link_to("..", "#", remote: true)) if parts.count > max_links yield(h.link_to("..", "#")) if parts.count > max_links
parts.each do |part| parts.each do |part|
part_path = File.join(part_path, part) unless part_path.empty? part_path = File.join(part_path, part) unless part_path.empty?
part_path = part if part_path.empty? part_path = part if part_path.empty?
next unless parts.last(2).include?(part) if parts.count > max_links next unless parts.last(2).include?(part) if parts.count > max_links
yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: true)) yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path))))
end end
end end
end end

View file

@ -0,0 +1,11 @@
class UserDecorator < ApplicationDecorator
decorates :user
def avatar_image size = 16
h.image_tag h.gravatar_icon(self.email, size), class: "avatar #{"s#{size}"}", width: size
end
def tm_of(project)
project.team_member_by_id(self.id)
end
end

View file

@ -36,7 +36,7 @@ module ApplicationHelper
else else
gravatar_prefix = request.ssl? ? "https://secure" : "http://www" gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
user_email.strip! user_email.strip!
"#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=mm"
end end
end end

View file

@ -65,4 +65,9 @@ module CommitsHelper
end end
end end
def commit_to_html commit
if commit.model
escape_javascript(render 'commits/commit', commit: commit)
end
end
end end

View file

@ -33,4 +33,22 @@ module EventsHelper
image_tag event_image_path image_tag event_image_path
end end
end end
def event_filter_link key, tooltip
key = key.to_s
filter = @event_filter.options key
inactive = if @event_filter.active? key
nil
else
'inactive'
end
content_tag :div, class: "filter_icon #{inactive}" do
link_to dashboard_path(event_filter: filter), class: 'has_tooltip', 'data-original-title' => tooltip do
image_tag "event_filter_#{key}.png"
end
end
end
end end

View file

@ -10,5 +10,9 @@ module ProjectsHelper
def link_to_project project def link_to_project project
link_to project.name, project link_to project.name, project
end end
def tm_path team_member
project_team_member_path(@project, team_member)
end
end end

View file

@ -67,4 +67,29 @@ module TreeHelper
can?(current_user, :push_code, @project) can?(current_user, :push_code, @project)
end end
end end
# Breadcrumb links for a Project and, if applicable, a tree path
def breadcrumbs
return unless @project && @ref
# Add the root project link and the arrow icon
crumbs = content_tag(:li) do
content_tag(:span, nil, class: 'arrow') +
link_to(@project.name, project_commits_path(@project, @ref))
end
if @path
parts = @path.split('/')
parts.each_with_index do |part, i|
crumbs += content_tag(:span, '/', class: 'divider')
crumbs += content_tag(:li) do
# The text is just the individual part, but the link needs all the parts before it
link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
end
end
end
crumbs.html_safe
end
end end

View file

@ -1,9 +1,13 @@
class Commit class Commit
include ActiveModel::Conversion include ActiveModel::Conversion
include Gitlab::Encode
include StaticModel include StaticModel
extend ActiveModel::Naming extend ActiveModel::Naming
# Safe amount of files with diffs in one commit to render
# Used to prevent 500 error on huge commits by suppressing diff
#
DIFF_SAFE_SIZE = 100
attr_accessor :commit, :head, :refs attr_accessor :commit, :head, :refs
delegate :message, :authored_date, :committed_date, :parents, :sha, delegate :message, :authored_date, :committed_date, :parents, :sha,
@ -107,7 +111,7 @@ class Commit
end end
def safe_message def safe_message
@safe_message ||= utf8 message @safe_message ||= message
end end
def created_at def created_at
@ -119,7 +123,7 @@ class Commit
end end
def author_name def author_name
utf8 author.name author.name
end end
# Was this commit committed by a different person than the original author? # Was this commit committed by a different person than the original author?
@ -128,7 +132,7 @@ class Commit
end end
def committer_name def committer_name
utf8 committer.name committer.name
end end
def committer_email def committer_email

View file

@ -7,8 +7,6 @@ class Issue < ActiveRecord::Base
acts_as_taggable_on :labels acts_as_taggable_on :labels
belongs_to :milestone
validates :description, length: { within: 0..2000 } validates :description, length: { within: 0..2000 }
def self.open_for(user) def self.open_for(user)

View file

@ -1,10 +1,11 @@
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
require Rails.root.join("app/roles/static_model")
class MergeRequest < ActiveRecord::Base class MergeRequest < ActiveRecord::Base
include IssueCommonality include IssueCommonality
include Votes include Votes
attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id,
:author_id_of_changes :author_id_of_changes
attr_accessor :should_remove_source_branch attr_accessor :should_remove_source_branch
@ -26,6 +27,10 @@ class MergeRequest < ActiveRecord::Base
where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
end end
def self.find_all_by_milestone(milestone)
where("milestone_id = :milestone_id", milestone_id: milestone)
end
def human_state def human_state
states = { states = {
CAN_BE_MERGED => "can_be_merged", CAN_BE_MERGED => "can_be_merged",
@ -60,7 +65,7 @@ class MergeRequest < ActiveRecord::Base
end end
def check_if_can_be_merged def check_if_can_be_merged
self.state = if Gitlab::Merge.new(self, self.author).can_be_merged? self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
CAN_BE_MERGED CAN_BE_MERGED
else else
CANNOT_BE_MERGED CANNOT_BE_MERGED
@ -167,7 +172,7 @@ class MergeRequest < ActiveRecord::Base
end end
def automerge!(current_user) def automerge!(current_user)
if Gitlab::Merge.new(self, current_user).merge! && self.unmerged_commits.empty? if Gitlab::Satellite::MergeAction.new(current_user, self).merge! && self.unmerged_commits.empty?
self.merge!(current_user.id) self.merge!(current_user.id)
true true
end end
@ -212,5 +217,6 @@ end
# st_diffs :text(4294967295 # st_diffs :text(4294967295
# merged :boolean default(FALSE), not null # merged :boolean default(FALSE), not null
# state :integer default(1), not null # state :integer default(1), not null
# milestone_id :integer
# #

View file

@ -3,6 +3,7 @@ class Milestone < ActiveRecord::Base
belongs_to :project belongs_to :project
has_many :issues has_many :issues
has_many :merge_requests
validates :title, presence: true validates :title, presence: true
validates :project, presence: true validates :project, presence: true
@ -15,8 +16,20 @@ class Milestone < ActiveRecord::Base
User.where(id: issues.pluck(:assignee_id)) User.where(id: issues.pluck(:assignee_id))
end end
def open_items_count
self.issues.opened.count + self.merge_requests.opened.count
end
def closed_items_count
self.issues.closed.count + self.merge_requests.closed.count
end
def total_items_count
self.issues.count + self.merge_requests.count
end
def percent_complete def percent_complete
((self.issues.closed.count * 100) / self.issues.count).abs ((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError rescue ZeroDivisionError
100 100
end end

View file

@ -23,13 +23,13 @@ class Note < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader mount_uploader :attachment, AttachmentUploader
# Scopes # Scopes
scope :common, where(noteable_id: nil) scope :common, ->{ where(noteable_id: nil) }
scope :today, where("created_at >= :date", date: Date.today) scope :today, ->{ where("created_at >= :date", date: Date.today) }
scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) }
scope :since, ->(day) { where("created_at >= :date", date: (day)) } scope :since, ->(day) { where("created_at >= :date", date: (day)) }
scope :fresh, order("created_at ASC, id ASC") scope :fresh, ->{ order("created_at ASC, id ASC") }
scope :inc_author_project, includes(:project, :author) scope :inc_author_project, ->{ includes(:project, :author) }
scope :inc_author, includes(:author) scope :inc_author, ->{ includes(:author) }
def self.create_status_change_note(noteable, author, status) def self.create_status_change_note(noteable, author, status)
create({ create({

View file

@ -104,8 +104,10 @@ class Project < ActiveRecord::Base
end end
def repo_name def repo_name
if path == "gitolite-admin" denied_paths = %w(gitolite-admin groups projects dashboard)
errors.add(:path, " like 'gitolite-admin' is not allowed")
if denied_paths.include?(path)
errors.add(:path, "like #{path} is not allowed")
end end
end end

View file

@ -8,7 +8,7 @@ class Tree
def initialize(raw_tree, project, ref = nil, path = nil) def initialize(raw_tree, project, ref = nil, path = nil)
@project, @ref, @path = project, ref, path @project, @ref, @path = project, ref, path
@tree = if path.present? @tree = if path.present?
raw_tree / path.dup.force_encoding('ascii-8bit') raw_tree / path
else else
raw_tree raw_tree
end end

View file

@ -15,6 +15,12 @@ class Wiki < ActiveRecord::Base
slug slug
end end
class << self
def search(query)
where("title like :query OR content like :query", query: "%#{query}%")
end
end
protected protected
def self.regenerate_from wiki def self.regenerate_from wiki

View file

@ -6,6 +6,7 @@ module IssueCommonality
belongs_to :project belongs_to :project
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :assignee, class_name: "User" belongs_to :assignee, class_name: "User"
belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy has_many :notes, as: :noteable, dependent: :destroy
validates :project, presence: true validates :project, presence: true

View file

@ -41,7 +41,7 @@ module Repository
end end
def satellite def satellite
@satellite ||= Gitlab::Satellite.new(self) @satellite ||= Gitlab::Satellite::Satellite.new(self)
end end
def has_post_receive_file? def has_post_receive_file?

View file

@ -43,7 +43,7 @@
%b %b
Owner: Owner:
%td %td
= @admin_project.owner.name = @admin_project.owner_name || '(deleted)'
%tr %tr
%td %td
%b %b

View file

@ -1,4 +1,4 @@
%h3.page_title Resque %h3.page_title Resque
%br %br
.ui-box .ui-box
%iframe{src: resque_url, width: '100%', height: 600, style: "border: none"} %iframe{src: resque_path, width: '100%', height: 600, style: "border: none"}

View file

@ -4,7 +4,4 @@
= nav_link(controller: :refs) do = nav_link(controller: :refs) do
= link_to 'Source', project_tree_path(@project, @ref) = link_to 'Source', project_tree_path(@project, @ref)
%li.right %li.right
.input-prepend.project_clone_holder = render "shared/clone_panel"
%button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
%button{class: "btn small", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.web_protocol.upcase
= text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"

View file

@ -15,7 +15,7 @@
.file_title .file_title
%i.icon-file %i.icon-file
%span.file_name %span.file_name
= @tree.name.force_encoding('utf-8') = @tree.name
%small= number_to_human_size @tree.size %small= number_to_human_size @tree.size
%span.options= render "tree/blob_actions" %span.options= render "tree/blob_actions"
.file_content.blame .file_content.blame
@ -24,9 +24,7 @@
- commit = Commit.new(commit) - commit = Commit.new(commit)
- commit = CommitDecorator.decorate(commit) - commit = CommitDecorator.decorate(commit)
%tr %tr
%td.author %td.author= commit.author_link avatar: true, size: 16
= image_tag gravatar_icon(commit.author_email, 16)
= commit.author_name
%td.blame_commit %td.blame_commit
&nbsp; &nbsp;
%code= link_to commit.short_id, project_commit_path(@project, commit) %code= link_to commit.short_id, project_commit_path(@project, commit)
@ -34,4 +32,4 @@
%td.lines %td.lines
= preserve do = preserve do
%pre %pre
= Gitlab::Encode.utf8 lines.join("\n") = lines.join("\n")

View file

@ -4,9 +4,8 @@
%strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
%p %p
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
%strong.commit-author-name= commit.author_name = commit.author_link avatar: true, size: 24
%span.dash &ndash; &nbsp;
= image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
= link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title" = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
%span.committed_ago %span.committed_ago

View file

@ -18,16 +18,15 @@
.commit-info .commit-info
.row .row
.span5 .span5
= image_tag gravatar_icon(@commit.author_email, 40), class: "avatar"
.author .author
%strong= @commit.author_name %strong= @commit.author_link avatar: true, size: 40
authored authored
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.authored_date)} ago #{time_ago_in_words(@commit.authored_date)} ago
- if @commit.different_committer? - if @commit.different_committer?
.committer .committer
&rarr; &rarr;
%strong= @commit.committer_name %strong= @commit.committer_link
committed committed
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.committed_date)} ago #{time_ago_in_words(@commit.committed_date)} ago

View file

@ -1,11 +1,11 @@
- if @suppress_diff - if @suppress_diff
.alert-message.block-message .alert-message.block-message
%p %p
%strong Warning! Large commit with more then 200 files changed. %strong Warning! Large commit with more then #{Commit::DIFF_SAFE_SIZE} files changed.
%p To prevent performance issue we rejected diff information. %p To prevent performance issue we rejected diff information.
%p %p
But if you still want to see diff But if you still want to see diff
= link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "dark" = link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "underlined_link"
%p.cgray %p.cgray
Showing #{pluralize(diffs.count, "changed file")} Showing #{pluralize(diffs.count, "changed file")}
@ -35,10 +35,10 @@
- if file.text? - if file.text?
= render "commits/text_file", diff: diff, index: i = render "commits/text_file", diff: diff, index: i
- elsif file.image? - elsif file.image?
- if diff.renamed_file || diff.new_file || diff.deleted_file - if diff.renamed_file || diff.new_file || diff.deleted_file
.diff_file_content_image .diff_file_content_image
%img{class: image_diff_class(diff), src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} %img{class: image_diff_class(diff), src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else - else
- old_file = (@commit.prev_commit.tree / diff.old_path) - old_file = (@commit.prev_commit.tree / diff.old_path)
.diff_file_content_image.img_compared .diff_file_content_image.img_compared
%img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} %img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"}

View file

@ -16,6 +16,11 @@
Tags Tags
%span.badge= @project.tags.length %span.badge= @project.tags.length
= nav_link(controller: :repositories, action: :stats) do
= link_to stats_project_repository_path(@project) do
Stats
- if current_controller?(:commits) && current_user.private_token - if current_controller?(:commits) && current_user.private_token
%li.right %li.right
%span.rss-icon %span.rss-icon

View file

@ -2,14 +2,7 @@
- if @path.present? - if @path.present?
%ul.breadcrumb %ul.breadcrumb
%li = breadcrumbs
%span.arrow
= link_to project_commits_path(@project) do
= @project.name
%span.divider
\/
%li
%a{href: "#"}= @path.split("/").join(" / ")
%div{id: dom_id(@project)} %div{id: dom_id(@project)}
#commits_list= render "commits" #commits_list= render "commits"

View file

@ -3,10 +3,17 @@
.activities.span8 .activities.span8
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
= render 'shared/no_ssh' = render 'shared/no_ssh'
.event_filter
= event_filter_link EventFilter.push, 'Push events'
= event_filter_link EventFilter.merged, 'Merge events'
= event_filter_link EventFilter.comments, 'Comments'
= event_filter_link EventFilter.team, 'Team'
- if @events.any? - if @events.any?
.content_list= render @events .content_list= render @events
- else - else
%h4.nothing_here_message Projects activity will be displayed here %p.nothing_here_message Projects activity will be displayed here
.loading.hide .loading.hide
.side .side
- if @groups.present? - if @groups.present?

View file

@ -14,8 +14,9 @@
= f.submit "Sign in", :class => "primary btn wide" = f.submit "Sign in", :class => "primary btn wide"
.right .right
= render :partial => "devise/shared/links" = render :partial => "devise/shared/links"
- if devise_mapping.omniauthable? .clearfix
%hr/ - if devise_mapping.omniauthable? && resource_class.omniauth_providers.present?
- resource_class.omniauth_providers.each do |provider| %div
%span - resource_class.omniauth_providers.each do |provider|
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) %span
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)

View file

@ -5,9 +5,10 @@
%hr %hr
%p.slead %p.slead
Your GitLab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. Your GitLab instance can perform HTTP POST requests on the following events: create_project, delete_project, create_user, delete_user, change_team_member.
%br %br
System Hooks can be used for logging or change information in LDAP server. %br
System Hooks can be used, e.g. for logging or changing information in a LDAP server.
%br %br
%h5 Hooks request example: %h5 Hooks request example:
= render "admin/hooks/data_ex" = render "admin/hooks/data_ex"

View file

@ -12,7 +12,7 @@
= f.label :title do = f.label :title do
%strong= "Subject *" %strong= "Subject *"
.input .input
= f.text_field :title, maxlength: 255, class: "xxlarge gfm-input", autofocus: true = f.text_field :title, maxlength: 255, class: "xxlarge js-gfm-input", autofocus: true
.issue_middle_block .issue_middle_block
.issue_assignee .issue_assignee
= f.label :assignee_id do = f.label :assignee_id do
@ -37,7 +37,7 @@
.clearfix .clearfix
= f.label :description, "Details" = f.label :description, "Details"
.input .input
= f.text_area :description, maxlength: 2000, class: "xxlarge gfm-input", rows: 14 = f.text_area :description, maxlength: 2000, class: "xxlarge js-gfm-input", rows: 14
%p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.

View file

@ -1,5 +1,4 @@
:plain :plain
var edit_issue_dialog = $("<div id='edit_issue_dialog'></div>"); $("#edit_issue_dialog").html("#{escape_javascript(render('form'))}");
edit_issue_dialog.html("#{escape_javascript(render('form'))}"); switchToEditIssue();
switchToEditIssue(edit_issue_dialog);

View file

@ -58,6 +58,8 @@
%ul#issues-table.unstyled.issues_table %ul#issues-table.unstyled.issues_table
= render "issues" = render "issues"
#new_issue_dialog
#edit_issue_dialog
:javascript :javascript
$(function(){ $(function(){

View file

@ -1,4 +1,3 @@
:plain :plain
var new_issue_dialog = $("<div id='new_issue_dialog'></div>"); $("#new_issue_dialog").html("#{escape_javascript(render('form'))}");
new_issue_dialog.html("#{escape_javascript(render('form'))}"); switchToNewIssue();
switchToNewIssue(new_issue_dialog);

View file

@ -8,9 +8,7 @@
GITLAB GITLAB
%span.separator %span.separator
%h1.project_name= title %h1.project_name= title
.search = render "layouts/search"
= form_tag search_path, method: :get do |f|
= text_field_tag "search", nil, placeholder: "Search", class: "search-input"
.fbtn .fbtn
- if current_user.is_admin? - if current_user.is_admin?
= link_to admin_root_path, class: "btn small", title: "Admin area" do = link_to admin_root_path, class: "btn small", title: "Admin area" do
@ -29,11 +27,3 @@
= link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete
= render "layouts/init_auto_complete" = render "layouts/init_auto_complete"
:javascript
$(function(){
$("#search").autocomplete({
source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url }
});
});

View file

@ -1,11 +1,11 @@
:javascript :javascript
$(function() { $(function() {
autocompleteMembersUrl = "#{ "/api/v2/projects/#{@project.code}/members" if @project }"; autocompleteMembers.url = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
autocompleteMembersParams.private_token = "#{current_user.authentication_token}"; autocompleteMembers.params.private_token = "#{current_user.private_token}";
autocompleteEmojiData = #{raw emoji_autocomplete_source}; autocompleteEmoji.data = #{raw emoji_autocomplete_source};
// convert the list so that the items have the right format for completion // convert the list so that the items have the right format for completion
autocompleteEmojiData = $.map(autocompleteEmojiData, function(value) { autocompleteEmoji.data = $.map(autocompleteEmoji.data, function(value) {
return { return {
name: value, name: value,
insert: value+':', insert: value+':',

View file

@ -0,0 +1,11 @@
.search
= form_tag search_path, method: :get do |f|
= text_field_tag "search", nil, placeholder: "Search", class: "search-input"
:javascript
$(function(){
$("#search").autocomplete({
source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url }
});
});

View file

@ -28,16 +28,22 @@
%h4.cdark 2. Fill info %h4.cdark 2. Fill info
.clearfix .clearfix
.main_box .merge_requests_form_box
.top_box_content .top_box_content
= f.label :title do = f.label :title do
%strong= "Title *" %strong= "Title *"
.input= f.text_field :title, class: "input-xxlarge pad gfm-input", maxlength: 255, rows: 5 .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5
.middle_box_content .merge_requests_middle_box
= f.label :assignee_id do .merge_requests_assignee
%i.icon-user = f.label :assignee_id do
Assign to %i.icon-user
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
.merge_requests_milestone
= f.label :milestone_id do
%i.icon-time
Milestone
.input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
.control-group .control-group

View file

@ -10,6 +10,10 @@
%span.btn.small.disabled.grouped %span.btn.small.disabled.grouped
%i.icon-comment %i.icon-comment
= merge_request.mr_and_commit_notes.count = merge_request.mr_and_commit_notes.count
- if merge_request.milestone_id?
%span.btn.small.disabled.grouped
%i.icon-time
= merge_request.milestone.title
%span.btn.small.disabled.grouped %span.btn.small.disabled.grouped
= merge_request.source_branch = merge_request.source_branch
&rarr; &rarr;

View file

@ -1,2 +1,2 @@
:plain :plain
$(".mr_source_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}"); $(".mr_source_commit").html("#{commit_to_html(@commit)}");

View file

@ -1,3 +1,2 @@
:plain :plain
$(".mr_target_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}"); $(".mr_target_commit").html("#{commit_to_html(@commit)}");

View file

@ -9,19 +9,26 @@
.ui-box .ui-box
.title .title
%ul.nav.nav-pills .left
%li{class: ("active" if (params[:f] == 'open' || !params[:f]))} %ul.nav.nav-pills
= link_to project_merge_requests_path(@project, f: 'open') do %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
Open = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do
%li{class: ("active" if params[:f] == "closed")} Open
= link_to project_merge_requests_path(@project, f: "closed") do %li{class: ("active" if params[:f] == "closed")}
Closed = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do
%li{class: ("active" if params[:f] == 'assigned-to-me')} Closed
= link_to project_merge_requests_path(@project, f: 'assigned-to-me') do %li{class: ("active" if params[:f] == 'assigned-to-me')}
To Me = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do
%li{class: ("active" if params[:f] == 'all')} To Me
= link_to project_merge_requests_path(@project, f: 'all') do %li{class: ("active" if params[:f] == 'all')}
All = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do
All
.right
= form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :right do
= select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")
= select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone")
= hidden_field_tag :f, params[:f]
.clearfix
%ul.unstyled %ul.unstyled
= render @merge_requests = render @merge_requests
@ -35,3 +42,7 @@
.span4.right .span4.right
%span.cgray.right #{@merge_requests.total_count} merge requests for this filter %span.cgray.right #{@merge_requests.total_count} merge requests for this filter
:javascript
$(function() {
merge_requestsPage();
})

View file

@ -14,9 +14,13 @@
%strong.author= link_to_merge_request_author(@merge_request) %strong.author= link_to_merge_request_author(@merge_request)
- if @merge_request.assignee - if @merge_request.assignee
%cite.cgray and currently assigned to %cite.cgray , currently assigned to
= image_tag gravatar_icon(@merge_request.assignee_email), width: 16, class: "lil_av" = image_tag gravatar_icon(@merge_request.assignee_email), width: 16, class: "lil_av"
%strong.author= link_to_merge_request_assignee(@merge_request) %strong.author= link_to_merge_request_assignee(@merge_request)
- if @merge_request.milestone
- milestone = @merge_request.milestone
%cite.cgray and attached to milestone
%strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
- if @merge_request.closed - if @merge_request.closed

View file

@ -1,18 +1,22 @@
%li{class: "milestone", id: dom_id(milestone) } %li{class: "milestone", id: dom_id(milestone) }
.right .right
- if milestone.issues.any?
%span.btn.small.disabled.grouped= pluralize milestone.issues.count, 'issues'
- if milestone.issues.count > 0
= link_to 'Browse Issues', project_issues_path(milestone.project, milestone_id: milestone.id), class: "btn small grouped"
- if can? current_user, :admin_milestone, milestone.project - if can? current_user, :admin_milestone, milestone.project
= link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" do
%i.icon-edit
Edit
%h4 %h4
= link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone), class: "row_title" = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
%small %small
= milestone.expires_at = milestone.expires_at
%br .row
.progress.progress-success.span3 .span4
.bar{style: "width: #{milestone.percent_complete}%;"} .progress.progress-info
.bar{style: "width: #{milestone.percent_complete}%;"}
.span6
&nbsp; = link_to project_issues_path(milestone.project, milestone_id: milestone.id) do
= pluralize milestone.issues.count, 'Issue'
&nbsp;
= link_to project_merge_requests_path(milestone.project, milestone_id: milestone.id) do
= pluralize milestone.merge_requests.count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete

View file

@ -31,10 +31,10 @@
%h5 %h5
Progress: Progress:
%small %small
#{@milestone.issues.closed.count} closed #{@milestone.closed_items_count} closed
&ndash; &ndash;
#{@milestone.issues.opened.count} open #{@milestone.open_items_count} open
.progress.progress-success .progress.progress-info
.bar{style: "width: #{@milestone.percent_complete}%;"} .bar{style: "width: #{@milestone.percent_complete}%;"}
@ -58,15 +58,28 @@
%span.badge.badge-info ##{issue.id} %span.badge.badge-info ##{issue.id}
&ndash; &ndash;
= link_to_gfm truncate(issue.title, length: 60), [@project, issue] = link_to_gfm truncate(issue.title, length: 60), [@project, issue]
%br
.span6 .span6
%table %table.milestone-merge-requests-filter
%thead %thead
%th Participants %th
- @users.each do |user| %ul.nav.nav-pills
%tr %li.active= link_to('Open Merge Requests', '#')
%li=link_to('All Merge Requests', '#')
- @merge_requests.each do |merge_request|
%tr{data: {closed: merge_request.closed}}
%td %td
= image_tag gravatar_icon(user.email, 24), width: "24" = link_to [@project, merge_request] do
&nbsp; %span.badge.badge-info ##{merge_request.id}
= user.name &ndash;
= link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request]
%hr
%h6 Participants:
%div
- @users.each do |user|
= link_to tm_path(user.tm_of(@project)), class: 'float-link' do
= user.avatar_image
= user.name
.clearfix

View file

@ -8,7 +8,7 @@
= f.hidden_field :noteable_id = f.hidden_field :noteable_id
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
= f.text_area :note, size: 255, class: 'note-text gfm-input' = f.text_area :note, size: 255, class: 'note-text js-gfm-input'
#preview-note.preview_note.hide #preview-note.preview_note.hide
.hint .hint
.right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.

View file

@ -13,7 +13,7 @@
= f.hidden_field :noteable_id = f.hidden_field :noteable_id
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
= f.hidden_field :line_code = f.hidden_field :line_code
= f.text_area :note, size: 255, class: 'line-note-text gfm-input' = f.text_area :note, size: 255, class: 'line-note-text js-gfm-input'
.note_actions .note_actions
.buttons .buttons
= f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note" = f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note"

View file

@ -4,7 +4,7 @@
%td{style: "font-size: 1px; line-height: 1px;", width: "21"} %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
%td{align: "left", style: "padding: 20px 0 0;"} %td{align: "left", style: "padding: 20px 0 0;"}
%h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
= "You got granted #{@users_project.project_access_human} access to project" = "You have been granted #{@users_project.project_access_human} access to project"
%td{style: "font-size: 1px; line-height: 1px;", width: "21"} %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
%tr %tr
%td{style: "font-size: 1px; line-height: 1px;", width: "21"} %td{style: "font-size: 1px; line-height: 1px;", width: "21"}

View file

@ -14,7 +14,7 @@
%h3.page_title %h3.page_title
Private token Private token
%span.cred.right %span.cred.right
keep it in secret! keep it secret!
.padded .padded
= form_for @user, url: profile_reset_private_token_path, method: :put do |f| = form_for @user, url: profile_reset_private_token_path, method: :put do |f|
.data .data

Some files were not shown because too many files have changed in this diff Show more