Commit 93f0a8c9 authored by David Barri's avatar David Barri

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

Conflicts:
	doc/install/installation.md
parents 944d3823 3c7806c3
......@@ -4,7 +4,7 @@ env:
before_install:
- sudo apt-get install libicu-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:
only:
- 'master'
......
......@@ -28,7 +28,7 @@ v 3.0.0
- Reject ssh keys that break gitolite
- [API] list one 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] add user creation
......
## Contribute to GitLab
## Contribute to GitLab
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
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 can be merged w/o problems
* Your code can be merged w/o problems
* It won't break existing functionality
* It's quality code
* 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).
## Running tests
To run the specs for GitLab, you need to run seeds for test db.
## Installation
cd gitlabhq
rake db:seed_fu RAILS_ENV=test
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.
Then you can run the test suite with rake:
rake gitlab:test
## Running tests
For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
......@@ -11,9 +11,9 @@ end
gem "rails", "3.2.8"
# Supported DBs
gem "sqlite3", :group => :sqlite
gem "mysql2", :group => :mysql
gem "pg", :group => :postgres
gem "sqlite3", group: :sqlite
gem "mysql2", group: :mysql
gem "pg", group: :postgres
# Auth
gem "devise", "~> 2.1.0"
......@@ -23,10 +23,11 @@ gem 'omniauth-twitter'
gem 'omniauth-github'
# GITLAB patched libs
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 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
gem 'grack', :git => "https://github.com/gitlabhq/grack.git"
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 'yaml_db', git: "https://github.com/gitlabhq/yaml_db.git", ref: '98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd'
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)
gem "gitolite", '1.1.0'
......@@ -35,7 +36,7 @@ gem "gitolite", '1.1.0'
gem "pygments.rb", "0.3.1"
# Language detection
gem "github-linguist", "~> 2.3.4" , :require => "linguist"
gem "github-linguist", "~> 2.3.4" , require: "linguist"
# API
gem "grape", "~> 0.2.1"
......@@ -83,9 +84,6 @@ gem 'resque_mailer'
# HTTP requests
gem "httparty"
# Handle encodings
gem "charlock_holmes"
# Colored output to console
gem "colored"
......@@ -114,8 +112,9 @@ group :assets do
end
group :development do
gem "annotate", git: "https://github.com/ctran/annotate_models.git"
gem "letter_opener"
gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
gem 'quiet_assets', '1.0.1'
gem 'rack-mini-profiler'
end
......@@ -137,13 +136,13 @@ group :development, :test do
gem 'guard-spinach'
# Notification
gem 'rb-fsevent', :require => darwin_only('rb-fsevent')
gem 'growl', :require => darwin_only('growl')
gem 'rb-inotify', :require => linux_only('rb-inotify')
gem 'rb-fsevent', require: darwin_only('rb-fsevent')
gem 'growl', require: darwin_only('growl')
gem 'rb-inotify', require: linux_only('rb-inotify')
end
group :test do
gem "simplecov", :require => false
gem "simplecov", require: false
gem "shoulda-matchers"
gem 'email_spec'
gem 'resque_spec'
......
......@@ -7,6 +7,7 @@ GIT
GIT
remote: https://github.com/gitlabhq/grack.git
revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
specs:
grack (1.0.0)
rack (~> 1.4.1)
......@@ -21,6 +22,14 @@ GIT
mime-types (~> 1.15)
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
remote: https://github.com/gitlabhq/omniauth-ldap.git
revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
......@@ -35,6 +44,7 @@ GIT
GIT
remote: https://github.com/gitlabhq/yaml_db.git
revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
ref: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
specs:
yaml_db (0.2.2)
......@@ -90,7 +100,7 @@ GEM
carrierwave (0.6.2)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
charlock_holmes (0.6.8)
charlock_holmes (0.6.9)
childprocess (0.3.2)
ffi (~> 1.0.6)
chosen-rails (0.9.8.3)
......@@ -260,6 +270,8 @@ GEM
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.1)
railties (~> 3.1)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
......@@ -411,7 +423,6 @@ DEPENDENCIES
capybara
capybara-webkit
carrierwave
charlock_holmes
chosen-rails
coffee-rails (= 3.2.2)
colored
......@@ -432,6 +443,7 @@ DEPENDENCIES
grack!
grape (~> 0.2.1)
grit!
grit_ext!
growl
guard-rspec
guard-spinach
......@@ -454,6 +466,7 @@ DEPENDENCIES
pg
pry
pygments.rb (= 0.3.1)
quiet_assets (= 1.0.1)
rack-mini-profiler
rails (= 3.2.8)
rails-dev-tweaks
......
web: bundle exec rails s -p $PORT -e production
worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=*
## 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
......@@ -17,6 +17,8 @@
//= require modernizr
//= require chosen-jquery
//= require raphael
//= require g.raphael-min
//= require g.bar-min
//= require branch-graph
//= require ace-src-noconflict/ace
//= require_tree .
# Creates the variables for setting up GFM auto-completion
###
Creates the variables for setting up GFM auto-completion
###
# Emoji
window.autocompleteEmojiData = [];
window.autocompleteEmojiTemplate = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>";
data = []
template = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"
window.autocompleteEmoji = {data, template}
# Team Members
window.autocompleteMembersUrl = "";
window.autocompleteMembersParams =
private_token: ""
page: 1
window.autocompleteMembersData = [];
url = '';
params = {private_token: '', page: 1}
window.autocompleteMembers = {data, url, params}
# Add GFM auto-completion to all input fields, that accept GFM input.
window.setupGfmAutoComplete = ->
$input = $('.js-gfm-input')
# Emoji
$input.atWho ':',
data: autocompleteEmoji.data,
tpl: autocompleteEmoji.template
###
Add GFM auto-completion to all input fields, that accept GFM input.
###
window.setupGfmAutoComplete = ->
###
Emoji
###
$('.gfm-input').atWho ':',
data: autocompleteEmojiData,
tpl: autocompleteEmojiTemplate
###
Team Members
###
$('.gfm-input').atWho '@', (query, callback) ->
# Team Members
$input.atWho '@', (query, callback) ->
(getMoreMembers = ->
$.getJSON(autocompleteMembersUrl, autocompleteMembersParams)
.success (members) ->
# pick the data we need
newMembersData = $.map members, (m) -> m.name
# add the new page of data to the rest
$.merge autocompleteMembersData, newMembersData
# show the pop-up with a copy of the current data
callback autocompleteMembersData[..]
# are we past the last page?
if newMembersData.length == 0
# set static data and stop callbacks
$('.gfm-input').atWho '@',
data: autocompleteMembersData
callback: null
else
# get next page
getMoreMembers()
$.getJSON(autocompleteMembers.url, autocompleteMembers.params).success (members) ->
# pick the data we need
newMembersData = $.map members, (m) -> m.name
# add the new page of data to the rest
$.merge autocompleteMembers.data, newMembersData
# show the pop-up with a copy of the current data
callback autocompleteMembers.data[..]
# are we past the last page?
if newMembersData.length is 0
# set static data and stop callbacks
$input.atWho '@',
data: autocompleteMembers.data
callback: null
else
# get next page
getMoreMembers()
# so the next request gets the next page
autocompleteMembersParams.page += 1;
).call();
\ No newline at end of file
autocompleteMembers.params.page += 1
).call()
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
function switchToNewIssue(form){
function switchToNewIssue(){
$(".issues_content").hide("fade", { direction: "left" }, 150, function(){
$(".issues_content").after(form);
$('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen();
$("#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").after(form);
$('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
......@@ -33,8 +31,8 @@ function switchFromEditIssue(){
function backToIssues(){
$("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){
$(".issues_content").show("fade", { direction: "left" }, 150, function() {
$("#edit_issue_dialog").remove();
$("#new_issue_dialog").remove();
$("#edit_issue_dialog").html("");
$("#new_issue_dialog").html("");
$('.add_new').show();
});
});
......
Loader =
html: (width) ->
$('<img>').attr src: '/assets/ajax-loader.gif', width: width
window.Loader = Loader
......@@ -7,29 +7,32 @@ window.slugify = (text) ->
window.ajaxGet = (url) ->
$.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) ->
field = $(field_selector)
closest_submit = field.closest("form").find(button_selector)
closest_submit.disable() if field.val() is ""
field.on "keyup", ->
if $(this).val() is ""
field.on "input", ->
if $(@).val() is ""
closest_submit.disable()
else
closest_submit.enable()
$ ->
# 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
$('select.chosen').chosen()
# Initialize tooltips
$('.has_tooltip').tooltip()
# Disable form buttons while a form is submitting
$('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
buttons = $('[type="submit"]', this)
buttons = $('[type="submit"]', @)
switch e.type
when 'ajax:beforeSend', 'submit'
......@@ -38,7 +41,7 @@ $ ->
buttons.enable()
# 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
$(document).keypress (e) ->
......@@ -52,22 +55,22 @@ $ ->
# Commit show suppressed diff
$(".supp_diff_link").bind "click", ->
$(this).next('table').show()
$(this).remove()
$(@).next('table').show()
$(@).remove()
# Note markdown preview
$(document).on 'click', '#preview-link', (e) ->
$('#preview-note').text('Loading...')
$('#preview-note').text 'Loading...'
previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview'
$(this).text(previewLinkText)
previewLinkText = if $(@).text() is 'Preview' then 'Edit' else 'Preview'
$(@).text previewLinkText
note = $('#note_note').val()
if note.trim().length == 0
$('#preview-note').text("Nothing to preview.")
if note.trim().length is 0
$('#preview-note').text 'Nothing to preview.'
else
$.post $(this).attr('href'), {note: note}, (data) ->
$.post $(@).attr('href'), {note: note}, (data) ->
$('#preview-note').html(data)
$('#preview-note, #note_note').toggle()
......@@ -79,14 +82,14 @@ $ ->
$.fn.extend chosen: (options) ->
default_options = search_contains: "true"
$.extend default_options, options
_chosen.apply this, [default_options]
_chosen.apply @, [default_options]
# Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: ->
$(this).attr('disabled', 'disabled').addClass('disabled')
$(@).attr('disabled', 'disabled').addClass('disabled')
# Enable an element and remove the 'disabled' Bootstrap class
$.fn.extend enable: ->
$(this).removeAttr('disabled').removeClass('disabled')
$(@).removeAttr('disabled').removeClass('disabled')
)(jQuery)
......@@ -115,4 +115,15 @@ var MergeRequest = {
$(".merge_in_progress").hide();
$(".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();
});
}
......@@ -5,3 +5,10 @@ $ ->
$('.milestone-issue-filter li').toggleClass('active')
$('.milestone-issue-filter tr[data-closed]').toggleClass('hide')
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
......@@ -22,3 +22,10 @@ $ ->
# Ref switcher
$('.project-refs-select').on 'change', ->
$(@).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
$ ->
$('#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
......@@ -17,23 +17,21 @@ $ ->
"ajax:beforeSend": -> $('.tree_progress').addClass("loading")
"ajax:complete": -> $('.tree_progress').removeClass("loading")
# Maintain forward/back history while browsing the file tree
((window) ->
History = window.History
$ = window.jQuery
document = window.document
# Check to see if History.js is enabled for our Browser
unless History.enabled
return false
$ ->
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
History.pushState(null, null, $(@).attr('href'))
return false
History.Adapter.bind window, 'statechange', ->
state = History.getState()
window.ajaxGet(state.url)
)(window)
# Maintain forward/back history while browsing the file tree
((window) ->
History = window.History
$ = window.jQuery
document = window.document
# Check to see if History.js is enabled for our Browser
unless History.enabled
return false
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
History.pushState(null, null, $(@).attr('href'))
return false
History.Adapter.bind window, 'statechange', ->
state = History.getState()
window.ajaxGet(state.url)
)(window)
......@@ -670,3 +670,16 @@ pre {
padding:0;
}
}
.milestone .progress {
margin-bottom: 0;
margin-top:4px;
}
.float-link {
float:left;
margin-right:15px;
.s16 {
margin-right:5px;
}
}
......@@ -26,8 +26,10 @@
.underlined { border-bottom: 1px solid #CCC; }
.no-borders { border:none; }
.vlink { color: $link_color !important; }
.underlined_link { text-decoration: underline; }
.borders { border: 1px solid #ccc; @include shade; }
.hint { font-style: italic; color: #999; }
.light { color: #888 }
/** PILLS & TABS**/
.nav-pills a:hover { background-color:#888; }
......@@ -66,10 +68,10 @@
.alert-message.error { @extend .alert-error; }
/** AVATARS **/
img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; }
img.avatar.s16 { width:16px; height:16px; }
img.avatar.s24 { width:24px; height:24px; }
img.avatar.s32 { width:32px; height:32px; }
img.avatar { float:left; margin-right:12px; width:40px; border:1px solid #ddd; padding:1px; }
img.avatar.s16 { width:16px; height:16px; margin-right:6px; }
img.avatar.s24 { width:24px; height:24px; margin-right:8px; }
img.avatar.s32 { width:32px; height:32px; margin-right:10px; }
img.lil_av { padding-left: 4px; padding-right:3px; }
/** HELPERS **/
......
......@@ -157,10 +157,15 @@
font-size:12px !important;
}
table.highlighttable .linenodiv pre {
text-align: right;
padding-right: 4px;
color:#666;
table.highlighttable .linenodiv {
a {
color: #666;
}
pre {
text-align: right;
padding-right: 4px;
color:#666;
}
}
}
}
......
......@@ -21,7 +21,7 @@ ul {
.author { color: #999; }
p {
padding-top:5px;
padding-top: 1px;
margin:0;
color:#222;
img {
......@@ -31,3 +31,11 @@ ul {
}
}
}
ol, ul {
&.styled {
li {
padding:2px;
}
}
}
......@@ -34,6 +34,11 @@ table {
border-color:#f1f1f1;
line-height:28px;
.s16 {
margin-top: 5px;
margin-right: 5px;
}
&:first-child {
border-left:1px solid #bbb;
}
......
......@@ -3,10 +3,11 @@
@import 'font-awesome';
/** GitLab colors **/
$link_color:#3A89A3;
$blue_link: #2fa0bb;
$style_color: #474d57;
$link_color: #3A89A3;
$blue_link: #2FA0BB;
$style_color: #474D57;
$hover: #D9EDF7;
$hover_border: #ADF;
/** GitLab Fonts **/
@font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); }
......@@ -19,9 +20,9 @@ $hover: #D9EDF7;
}
@mixin solid_shade {
-moz-box-shadow: 0 0 0 3px #eee;
-webkit-box-shadow: 0 0 0 3px #eee;
box-shadow: 0 0 0 3px #eee;
-moz-box-shadow: 0 0 0 3px #f1f1f1;
-webkit-box-shadow: 0 0 0 3px #f1f1f1;
box-shadow: 0 0 0 3px #f1f1f1;
}
@mixin border-radius($radius) {
......@@ -64,6 +65,14 @@ $hover: #D9EDF7;
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 {
background:#eee;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
......
......@@ -19,31 +19,66 @@
margin-right: 10px;
.chzn-drop {
margin:7px 0;
min-width: 400px;
border: 2px solid $blue_link;
@include border-radius(4px);
.chzn-results {
max-height:300px;
}
.chzn-search input {
min-width:365px;
}
}
}
/** Fix for Search Dropdown Border **/
.chzn-container {
.chzn-search {
input:focus {
-webkit-box-shadow: none;
-moz-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: $blue_link;
color: $style_color;
border-bottom: 1px solid #EEE;
padding: 8px;
}
.active-result {
border-radius: 0;
&.highlighted {
background: $blue_link;
background: $hover;
color: $style_color;
}
&.result-selected {
background: #EEE;
border-left: 4px solid #CCC;
}
}
}
.chzn-search input {
min-width:365px;
.chzn-search {
@include bg-gray-gradient;
input {
min-width:165px;
border-color: #CCC;
}
}
}
.chzn-single {
@include bg-gray-gradient;
@include bg-light-gray-gradient;
div {
background:transparent;
......@@ -55,14 +90,3 @@
}
}
}
/** Fix for Search Dropdown Border **/
.chzn-container {
.chzn-search {
input:focus {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
}
}
......@@ -47,12 +47,15 @@
padding-left: 32px;
}
.author,
.committer {
.author a,
.committer a {
font-size:14px;
line-height:22px;
text-shadow:0 1px 1px #fff;
color:#777;
&:hover {
color: #999;
}
}
.avatar {
......@@ -227,6 +230,9 @@
.commit-author-name {
color: #777;
&:hover {
color: #999;
}
}
}
......
......@@ -43,6 +43,7 @@
.event-body {
p {
color:#555;
padding-top: 5px;
}
.event-info {
color:#666;
......@@ -115,3 +116,29 @@
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;
}
}
}
......@@ -44,7 +44,7 @@
img.avatar {
width:32px;
margin-top:4px;
margin-top:1px;
}
}
}
......
......@@ -71,7 +71,7 @@ li.merge_request {
padding:7px 10px;
img.avatar {
width: 32px;
margin-top: 4px;
margin-top: 1px;
}
p {
padding: 0px;
......@@ -121,3 +121,20 @@ li.merge_request {
.mr_direction_tip {
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;
}
}
}
......@@ -57,10 +57,7 @@
padding-right: 8px;
img.avatar {
border: 0 none;
float: none;
margin-right: 0;
padding: 0;
margin-top: 0;
width: 16px;
}
}
......@@ -75,6 +72,15 @@
}
}
}
.blame {
img.avatar {
border: 0 none;
float: none;
margin: 0;
padding: 0;
}
}
}
.tree-btn-group {
......
......@@ -37,9 +37,6 @@
background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0;
color:#fff;
i {
@extend .icon-white;
}
}
border: 1px solid #31363E;
......
......@@ -70,9 +70,6 @@
color:#ccc;
&:hover {
color:#fff;
i {
@extend .icon-white;
}
}
border: none;
box-shadow:none;
......
......@@ -21,7 +21,7 @@ class CommitLoadContext < BaseContext
result[:notes_count] = line_notes.count + project.commit_notes(commit).count
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
result[:suppress_diff] = true
result[:status] = :huge_commit
......
# Build collection of Merge Requests
# based on filtering passed via params for @project
class MergeRequestsLoadContext < BaseContext
def execute
type = params[:f]
......@@ -9,8 +11,21 @@ class MergeRequestsLoadContext < BaseContext
when 'closed' then merge_requests.closed
when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
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
......@@ -13,6 +13,7 @@ class SearchContext
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[: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
end
......@@ -20,7 +21,8 @@ class SearchContext
@result ||= {
projects: [],
merge_requests: [],
issues: []
issues: [],
wiki_pages: []
}
end
end
......
......@@ -9,19 +9,28 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?
rescue_from Gitlab::Gitolite::AccessDenied do |exception|
log_exception(exception)
render "errors/gitolite", layout: "errors", status: 500
end
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
render "errors/encoding", layout: "errors", status: 500
end
rescue_from ActiveRecord::RecordNotFound do |exception|
log_exception(exception)
render "errors/not_found", layout: "errors", status: 404
end
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!
if current_user && current_user.blocked
sign_out current_user
......
# Controller for viewing a file's blame
class BlobController < ProjectResourceController
include ExtractsPath
include Gitlab::Encode
# Authorize
before_filter :authorize_read_project!
......@@ -12,16 +11,9 @@ class BlobController < ProjectResourceController
def show
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(
@tree.data,
type: mime_type,
type: @tree.mime_type,
disposition: 'inline',
filename: @tree.name
)
......
class DashboardController < ApplicationController
respond_to :html
before_filter :event_filter, only: :index
def index
@groups = Group.where(id: current_user.projects.pluck(:group_id))
@projects = current_user.projects_with_events
@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
respond_to do |format|
......@@ -34,4 +39,8 @@ class DashboardController < ApplicationController
format.atom { render layout: false }
end
end
def event_filter
@event_filter ||= EventFilter.new(params[:event_filter])
end
end
......@@ -31,7 +31,8 @@ class MilestonesController < ProjectResourceController
def show
@issues = @milestone.issues
@users = @milestone.participants
@users = UserDecorator.decorate(@milestone.participants)
@merge_requests = @milestone.merge_requests
respond_to do |format|
format.html
......
......@@ -22,7 +22,7 @@ class ProfileController < ApplicationController
flash[:notice] = "Password was successfully updated. Please login with it"
redirect_to new_user_session_path
else
render action: "password"
render 'account'
end
end
......
require Rails.root.join('lib', 'gitlab', 'graph_commit')
require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder')
class ProjectsController < ProjectResourceController
skip_before_filter :project, only: [:new, :create]
......@@ -79,7 +79,9 @@ class ProjectsController < ProjectResourceController
end
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
def destroy
......
class RefsController < ProjectResourceController
include Gitlab::Encode
# Authorize
before_filter :authorize_read_project!
......
......@@ -16,9 +16,14 @@ class RepositoriesController < ProjectResourceController
@tags = @project.tags
end
def stats
@stats = Gitlab::GitStats.new(@project.repo, @project.root_ref)
@graph = @stats.graph
end
def archive
unless can?(current_user, :download_code, @project)
render_404 and return
render_404 and return
end
......
......@@ -5,5 +5,6 @@ class SearchController < ApplicationController
@projects = result[:projects]
@merge_requests = result[:merge_requests]
@issues = result[:issues]
@wiki_pages = result[:wiki_pages]
end
end
......@@ -26,15 +26,14 @@ class TreeController < ProjectResourceController
end
def update
file_editor = Gitlab::FileEditor.new(current_user, @project, @ref)
update_status = file_editor.update(
@path,
edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
updated_successfully = edit_file_action.commit!(
params[:content],
params[:commit_message],
params[:last_commit]
)
if update_status
if updated_successfully
redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited"
else
flash[:notice] = "Your changes could not be commited, because the file has been changed"
......
......@@ -47,21 +47,15 @@ class CommitDecorator < ApplicationDecorator
# Otherwise it will link to the author email as specified in the commit.
#
# options:
# avatar: true will prepend avatar image
def author_link(options)
text = if options[:avatar]
avatar = h.image_tag h.gravatar_icon(author_email), class: "avatar", width: 16
"#{avatar} #{author_name}"
else
author_name
end
team_member = @project.try(:team_member_by_name_or_email, author_name, author_email)
# avatar: true will prepend the avatar image
# size: size of the avatar image in px
def author_link(options = {})
person_link(options.merge source: :author)
end
if team_member.nil?
h.mail_to author_email, text.html_safe, class: "commit-author-link"
else
h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-author-link"
end
# Just like #author_link but for the committer.
def committer_link(options = {})
person_link(options.merge source: :committer)
end
protected
......@@ -69,4 +63,30 @@ class CommitDecorator < ApplicationDecorator
def no_commit_message
"--no commit message"
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
......@@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator
#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|
part_path = File.join(part_path, part) unless part_path.empty?
part_path = part if part_path.empty?
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
......
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
......@@ -36,7 +36,7 @@ module ApplicationHelper
else
gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
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
......
......@@ -65,4 +65,9 @@ module CommitsHelper
end
end
def commit_to_html commit
if commit.model
escape_javascript(render 'commits/commit', commit: commit)
end
end
end
......@@ -33,4 +33,22 @@ module EventsHelper
image_tag event_image_path
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
......@@ -10,5 +10,9 @@ module ProjectsHelper
def link_to_project project
link_to project.name, project
end
def tm_path team_member
project_team_member_path(@project, team_member)
end
end
......@@ -67,4 +67,29 @@ module TreeHelper
can?(current_user, :push_code, @project)
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
class Commit
include ActiveModel::Conversion
include Gitlab::Encode
include StaticModel
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
delegate :message, :authored_date, :committed_date, :parents, :sha,
......@@ -107,7 +111,7 @@ class Commit
end
def safe_message
@safe_message ||= utf8 message
@safe_message ||= message
end
def created_at
......@@ -119,7 +123,7 @@ class Commit
end
def author_name
utf8 author.name
author.name
end
# Was this commit committed by a different person than the original author?
......@@ -128,7 +132,7 @@ class Commit
end
def committer_name
utf8 committer.name
committer.name
end
def committer_email
......
......@@ -7,8 +7,6 @@ class Issue < ActiveRecord::Base
acts_as_taggable_on :labels
belongs_to :milestone
validates :description, length: { within: 0..2000 }
def self.open_for(user)
......
require Rails.root.join("app/models/commit")
require Rails.root.join("app/roles/static_model")
class MergeRequest < ActiveRecord::Base
include IssueCommonality
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
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)
end
def self.find_all_by_milestone(milestone)
where("milestone_id = :milestone_id", milestone_id: milestone)
end
def human_state
states = {
CAN_BE_MERGED => "can_be_merged",
......@@ -60,7 +65,7 @@ class MergeRequest < ActiveRecord::Base
end
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
else
CANNOT_BE_MERGED
......@@ -167,7 +172,7 @@ class MergeRequest < ActiveRecord::Base
end
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)
true
end
......@@ -212,5 +217,6 @@ end
# st_diffs :text(4294967295
# merged :boolean default(FALSE), not null
# state :integer default(1), not null
# milestone_id :integer
#
......@@ -3,6 +3,7 @@ class Milestone < ActiveRecord::Base
belongs_to :project
has_many :issues
has_many :merge_requests
validates :title, presence: true
validates :project, presence: true
......@@ -15,8 +16,20 @@ class Milestone < ActiveRecord::Base
User.where(id: issues.pluck(:assignee_id))
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
((self.issues.closed.count * 100) / self.issues.count).abs
((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError
100
end
......
......@@ -23,13 +23,13 @@ class Note < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
# Scopes
scope :common, where(noteable_id: nil)
scope :today, where("created_at >= :date", date: Date.today)
scope :last_week, where("created_at >= :date", date: (Date.today - 7.days))
scope :common, ->{ where(noteable_id: nil) }
scope :today, ->{ where("created_at >= :date", date: Date.today) }
scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) }
scope :since, ->(day) { where("created_at >= :date", date: (day)) }
scope :fresh, order("created_at ASC, id ASC")
scope :inc_author_project, includes(:project, :author)
scope :inc_author, includes(:author)
scope :fresh, ->{ order("created_at ASC, id ASC") }
scope :inc_author_project, ->{ includes(:project, :author) }
scope :inc_author, ->{ includes(:author) }
def self.create_status_change_note(noteable, author, status)
create({
......
......@@ -104,8 +104,10 @@ class Project < ActiveRecord::Base
end
def repo_name
if path == "gitolite-admin"
errors.add(:path, " like 'gitolite-admin' is not allowed")
denied_paths = %w(gitolite-admin groups projects dashboard)
if denied_paths.include?(path)
errors.add(:path, "like #{path} is not allowed")
end
end
......
......@@ -8,7 +8,7 @@ class Tree
def initialize(raw_tree, project, ref = nil, path = nil)
@project, @ref, @path = project, ref, path
@tree = if path.present?
raw_tree / path.dup.force_encoding('ascii-8bit')
raw_tree / path
else
raw_tree
end
......
......@@ -15,6 +15,12 @@ class Wiki < ActiveRecord::Base
slug
end
class << self
def search(query)
where("title like :query OR content like :query", query: "%#{query}%")
end
end
protected
def self.regenerate_from wiki
......
......@@ -6,6 +6,7 @@ module IssueCommonality
belongs_to :project
belongs_to :author, class_name: "User"
belongs_to :assignee, class_name: "User"
belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy
validates :project, presence: true
......
......@@ -41,7 +41,7 @@ module Repository
end
def satellite
@satellite ||= Gitlab::Satellite.new(self)
@satellite ||= Gitlab::Satellite::Satellite.new(self)
end
def has_post_receive_file?
......
......@@ -43,7 +43,7 @@
%b
Owner:
%td
= @admin_project.owner.name
= @admin_project.owner_name || '(deleted)'
%tr
%td
%b
......
%h3.page_title Resque
%br
.ui-box
%iframe{src: resque_url, width: '100%', height: 600, style: "border: none"}
%iframe{src: resque_path, width: '100%', height: 600, style: "border: none"}
......@@ -4,7 +4,4 @@
= nav_link(controller: :refs) do
= link_to 'Source', project_tree_path(@project, @ref)
%li.right
.input-prepend.project_clone_holder
%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"
= render "shared/clone_panel"
......@@ -15,7 +15,7 @@
.file_title
%i.icon-file
%span.file_name
= @tree.name.force_encoding('utf-8')
= @tree.name
%small= number_to_human_size @tree.size
%span.options= render "tree/blob_actions"
.file_content.blame
......@@ -24,9 +24,7 @@
- commit = Commit.new(commit)
- commit = CommitDecorator.decorate(commit)
%tr
%td.author
= image_tag gravatar_icon(commit.author_email, 16)
= commit.author_name
%td.author= commit.author_link avatar: true, size: 16
%td.blame_commit
&nbsp;
%code= link_to commit.short_id, project_commit_path(@project, commit)
......@@ -34,4 +32,4 @@
%td.lines
= preserve do
%pre
= Gitlab::Encode.utf8 lines.join("\n")
= lines.join("\n")
......@@ -4,9 +4,8 @@
%strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
%p
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
%strong.commit-author-name= commit.author_name
%span.dash &ndash;
= image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
= commit.author_link avatar: true, size: 24
&nbsp;
= link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
%span.committed_ago
......
......@@ -18,16 +18,15 @@
.commit-info
.row
.span5
= image_tag gravatar_icon(@commit.author_email, 40), class: "avatar"
.author
%strong= @commit.author_name
%strong= @commit.author_link avatar: true, size: 40
authored
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.authored_date)} ago
- if @commit.different_committer?
.committer
&rarr;
%strong= @commit.committer_name
%strong= @commit.committer_link
committed
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.committed_date)} ago
......
- if @suppress_diff
.alert-message.block-message
%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
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
Showing #{pluralize(diffs.count, "changed file")}
......@@ -35,10 +35,10 @@
- if file.text?
= render "commits/text_file", diff: diff, index: i
- 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
%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)
.diff_file_content_image.img_compared
%img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"}
......
......@@ -16,6 +16,11 @@
Tags
%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
%li.right
%span.rss-icon
......
......@@ -2,14 +2,7 @@
- if @path.present?
%ul.breadcrumb
%li
%span.arrow
= link_to project_commits_path(@project) do
= @project.name
%span.divider
\/
%li
%a{href: "#"}= @path.split("/").join(" / ")
= breadcrumbs
%div{id: dom_id(@project)}
#commits_list= render "commits"
......
......@@ -3,10 +3,17 @@
.activities.span8
= render "events/event_last_push", event: @last_push
= 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?
.content_list= render @events
- else
%h4.nothing_here_message Projects activity will be displayed here
%p.nothing_here_message Projects activity will be displayed here
.loading.hide
.side
- if @groups.present?
......
......@@ -14,8 +14,9 @@
= f.submit "Sign in", :class => "primary btn wide"
.right
= render :partial => "devise/shared/links"
- if devise_mapping.omniauthable?
%hr/
- resource_class.omniauth_providers.each do |provider|
%span
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
.clearfix
- if devise_mapping.omniauthable? && resource_class.omniauth_providers.present?
%div
- resource_class.omniauth_providers.each do |provider|
%span
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
......@@ -5,9 +5,10 @@
%hr
%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
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
%h5 Hooks request example:
= render "admin/hooks/data_ex"
......@@ -12,7 +12,7 @@
= f.label :title do
%strong= "Subject *"
.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_assignee
= f.label :assignee_id do
......@@ -37,7 +37,7 @@
.clearfix
= f.label :description, "Details"
.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'}.
......
:plain
var edit_issue_dialog = $("<div id='edit_issue_dialog'></div>");
edit_issue_dialog.html("#{escape_javascript(render('form'))}");
switchToEditIssue(edit_issue_dialog);
$("#edit_issue_dialog").html("#{escape_javascript(render('form'))}");
switchToEditIssue();
......@@ -58,6 +58,8 @@
%ul#issues-table.unstyled.issues_table
= render "issues"
#new_issue_dialog
#edit_issue_dialog
:javascript
$(function(){
......
:plain
var new_issue_dialog = $("<div id='new_issue_dialog'></div>");
new_issue_dialog.html("#{escape_javascript(render('form'))}");
switchToNewIssue(new_issue_dialog);
$("#new_issue_dialog").html("#{escape_javascript(render('form'))}");
switchToNewIssue();
......@@ -8,9 +8,7 @@
GITLAB
%span.separator
%h1.project_name= title
.search
= form_tag search_path, method: :get do |f|
= text_field_tag "search", nil, placeholder: "Search", class: "search-input"
= render "layouts/search"
.fbtn
- if current_user.is_admin?
= 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
= render "layouts/init_auto_complete"
:javascript
$(function(){
$("#search").autocomplete({
source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url }
});
});
:javascript
$(function() {
autocompleteMembersUrl = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
autocompleteMembersParams.private_token = "#{current_user.authentication_token}";
autocompleteMembers.url = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
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
autocompleteEmojiData = $.map(autocompleteEmojiData, function(value) {
autocompleteEmoji.data = $.map(autocompleteEmoji.data, function(value) {
return {
name: value,
insert: value+':',
......
.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 }
});
});
......@@ -28,16 +28,22 @@
%h4.cdark 2. Fill info
.clearfix
.main_box
.merge_requests_form_box
.top_box_content
= f.label :title do
= f.label :title do
%strong= "Title *"
.input= f.text_field :title, class: "input-xxlarge pad gfm-input", maxlength: 255, rows: 5
.middle_box_content
= f.label :assignee_id do
%i.icon-user
Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
.input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5
.merge_requests_middle_box
.merge_requests_assignee
= f.label :assignee_id do
%i.icon-user
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
......
......@@ -10,6 +10,10 @@
%span.btn.small.disabled.grouped
%i.icon-comment
= 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
= merge_request.source_branch
&rarr;
......
:plain
$(".mr_source_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}");
$(".mr_source_commit").html("#{commit_to_html(@commit)}");
:plain
$(".mr_target_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}");
$(".mr_target_commit").html("#{commit_to_html(@commit)}");
......@@ -9,19 +9,26 @@
.ui-box
.title
%ul.nav.nav-pills
%li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
= link_to project_merge_requests_path(@project, f: 'open') do
Open
%li{class: ("active" if params[:f] == "closed")}
= link_to project_merge_requests_path(@project, f: "closed") do
Closed
%li{class: ("active" if params[:f] == 'assigned-to-me')}
= link_to project_merge_requests_path(@project, f: 'assigned-to-me') do
To Me
%li{class: ("active" if params[:f] == 'all')}
= link_to project_merge_requests_path(@project, f: 'all') do
All
.left
%ul.nav.nav-pills
%li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
= link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do
Open
%li{class: ("active" if params[:f] == "closed")}
= link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do
Closed
%li{class: ("active" if params[:f] == 'assigned-to-me')}
= link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do
To Me
%li{class: ("active" if params[:f] == '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
= render @merge_requests
......@@ -35,3 +42,7 @@
.span4.right
%span.cgray.right #{@merge_requests.total_count} merge requests for this filter
:javascript
$(function() {
merge_requestsPage();
})
......@@ -14,9 +14,13 @@
%strong.author= link_to_merge_request_author(@merge_request)
- 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"
%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
......
%li{class: "milestone", id: dom_id(milestone) }
.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
= 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
= 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
= milestone.expires_at
%br
.progress.progress-success.span3
.bar{style: "width: #{milestone.percent_complete}%;"}
&nbsp;
.row
.span4
.progress.progress-info
.bar{style: "width: #{milestone.percent_complete}%;"}
.span6
= 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
......@@ -31,10 +31,10 @@
%h5
Progress:
%small
#{@milestone.issues.closed.count} closed
#{@milestone.closed_items_count} closed
&ndash;
#{@milestone.issues.opened.count} open
.progress.progress-success
#{@milestone.open_items_count} open
.progress.progress-info
.bar{style: "width: #{@milestone.percent_complete}%;"}
......@@ -58,15 +58,28 @@
%span.badge.badge-info ##{issue.id}
&ndash;
= link_to_gfm truncate(issue.title, length: 60), [@project, issue]
%br
.span6
%table
%table.milestone-merge-requests-filter
%thead
%th Participants
- @users.each do |user|
%tr
%th
%ul.nav.nav-pills
%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
= image_tag gravatar_icon(user.email, 24), width: "24"
&nbsp;
= user.name
= link_to [@project, merge_request] do
%span.badge.badge-info ##{merge_request.id}
&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
......@@ -8,7 +8,7 @@
= f.hidden_field :noteable_id
= 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
.hint
.right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
......
......@@ -13,7 +13,7 @@
= f.hidden_field :noteable_id
= f.hidden_field :noteable_type
= 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
.buttons
= f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note"
......
......@@ -4,7 +4,7 @@
%td{style: "font-size: 1px; line-height: 1px;", width: "21"}
%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; "}
= "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"}
%tr
%td{style: "font-size: 1px; line-height: 1px;", width: "21"}
......
......@@ -14,7 +14,7 @@
%h3.page_title
Private token
%span.cred.right
keep it in secret!
keep it secret!
.padded
= form_for @user, url: profile_reset_private_token_path, method: :put do |f|
.data
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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