Commit 319f0c30 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' into stable

Conflicts:
	doc/install/installation.md
parents e469084c ced242a2
...@@ -3,8 +3,11 @@ env: ...@@ -3,8 +3,11 @@ env:
- DB=mysql - DB=mysql
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 - wget -P /tmp http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-i686.tar.bz2
- gem install charlock_holmes -v="0.6.8" - tar -xf /tmp/phantomjs-1.7.0-linux-i686.tar.bz2 -C /tmp/
- sudo rm -rf /usr/local/phantomjs
- sudo mv /tmp/phantomjs-1.7.0-linux-i686 /usr/local/phantomjs
- gem install charlock_holmes -v="0.6.9"
branches: branches:
only: only:
- 'master' - 'master'
......
v 3.1.0
- Updated gems
- Services: Gitlab CI integration
- Events filter on dashboard
- Own namespace for redis/resque
- Optimized commit diff views
- add alphabetical order for projects admin page
- Improved web editor
- Commit stats page
- Documentation split and cleanup
- Link to commit authors everywhere
- Restyled milestones list
- added Milestone to Merge Request
- Restyled Top panel
- Refactored Satellite Code
- Added file line links
- moved from capybara-webkit to poltergeist + phantomjs
v 3.0.3 v 3.0.3
- Fixed bug with issues list in Chrome - Fixed bug with issues list in Chrome
- New Feature: Import team from another project - New Feature: Import team from another project
...@@ -28,7 +46,7 @@ v 3.0.0 ...@@ -28,7 +46,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
......
## 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: ...@@ -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).
## Running tests ## Installation
To run the specs for GitLab, you need to run seeds for test db.
cd gitlabhq 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.
rake db:seed_fu RAILS_ENV=test
Then you can run the test suite with rake: ## Running tests
rake gitlab:test
For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
...@@ -8,34 +8,35 @@ def linux_only(require_as) ...@@ -8,34 +8,35 @@ def linux_only(require_as)
RUBY_PLATFORM.include?('linux') && require_as RUBY_PLATFORM.include?('linux') && require_as
end end
gem "rails", "3.2.8" gem "rails", "3.2.9"
# 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"
gem 'omniauth' gem 'omniauth', "~> 1.1.1"
gem 'omniauth-google-oauth2' gem 'omniauth-google-oauth2'
gem 'omniauth-twitter' 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'
# Syntax highlighter # Syntax highlighter
gem "pygments.rb", "0.3.1" gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", ref: '4db80c599067e2d5f23c5c243bf85b8ca0368ad4'
# 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"
...@@ -45,13 +46,13 @@ gem "grape", "~> 0.2.1" ...@@ -45,13 +46,13 @@ gem "grape", "~> 0.2.1"
gem "stamp" gem "stamp"
# Pagination # Pagination
gem "kaminari" gem "kaminari", "~> 0.14.1"
# HAML # HAML
gem "haml-rails" gem "haml-rails", "~> 0.3.5"
# Files attachments # Files attachments
gem "carrierwave" gem "carrierwave", "~> 0.7.1"
# Authorization # Authorization
gem "six" gem "six"
...@@ -63,59 +64,57 @@ gem "ffaker" ...@@ -63,59 +64,57 @@ gem "ffaker"
gem "seed-fu" gem "seed-fu"
# Markdown to HTML # Markdown to HTML
gem "redcarpet", "~> 2.1.1" gem "redcarpet", "~> 2.2.2"
gem "github-markup", "~> 0.7.4", require: 'github/markup' gem "github-markup", "~> 0.7.4", require: 'github/markup'
# Servers # Servers
gem "thin" gem "thin", '~> 1.5.0'
gem "unicorn" gem "unicorn", "~> 4.4.0"
# Issue tags # Issue tags
gem "acts-as-taggable-on", "2.3.1" gem "acts-as-taggable-on", "2.3.3"
# Decorators # Decorators
gem "draper" gem "draper", "~> 0.18.0"
# Background jobs # Background jobs
gem "resque", "~> 1.20.0" gem "resque", "~> 1.23.0"
gem 'resque_mailer' 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"
# GITLAB settings # GitLab settings
gem 'settingslogic' gem 'settingslogic'
# Misc # Misc
gem "foreman" gem "foreman"
gem 'gemoji', require: 'emoji/railtie'
gem "git" gem "git"
group :assets do group :assets do
gem "sass-rails", "3.2.5" gem "sass-rails", "~> 3.2.5"
gem "coffee-rails", "3.2.2" gem "coffee-rails", "~> 3.2.2"
gem "uglifier", "1.0.3" gem "uglifier", "~> 1.3.0"
gem "therubyracer" gem "therubyracer"
gem 'chosen-rails' gem 'chosen-rails', "0.9.8"
gem 'jquery-atwho-rails', '0.1.6' gem 'jquery-atwho-rails', "0.1.6"
gem "jquery-rails", "2.0.2" gem "jquery-rails", "2.1.3"
gem "jquery-ui-rails", "0.5.0" gem "jquery-ui-rails", "2.0.2"
gem "modernizr", "2.5.3" gem "modernizr", "2.6.2"
gem "raphael-rails", "1.5.2" gem "raphael-rails", "2.1.0"
gem 'bootstrap-sass', "2.0.4" gem 'bootstrap-sass', "2.2.1.1"
gem "font-awesome-sass-rails", "~> 2.0.0" gem "font-awesome-sass-rails", "~> 2.0.0"
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
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
...@@ -124,8 +123,6 @@ group :development, :test do ...@@ -124,8 +123,6 @@ group :development, :test do
gem 'spinach-rails' gem 'spinach-rails'
gem "rspec-rails" gem "rspec-rails"
gem "capybara" gem "capybara"
gem "capybara-webkit"
gem "headless"
gem "pry" gem "pry"
gem "awesome_print" gem "awesome_print"
gem "database_cleaner" gem "database_cleaner"
...@@ -137,14 +134,17 @@ group :development, :test do ...@@ -137,14 +134,17 @@ 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')
# PhantomJS driver for Capybara
gem 'poltergeist'
end end
group :test do group :test do
gem "simplecov", :require => false gem "simplecov", require: false
gem "shoulda-matchers" gem "shoulda-matchers", "1.3.0"
gem 'email_spec' gem 'email_spec'
gem 'resque_spec' gem 'resque_spec'
gem "webmock" gem "webmock"
...@@ -152,5 +152,5 @@ group :test do ...@@ -152,5 +152,5 @@ group :test do
end end
group :production do group :production do
gem "gitlab_meta", '3.0' gem "gitlab_meta", '3.1'
end end
This diff is collapsed.
web: bundle exec rails s -p $PORT -e production
worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=*
...@@ -13,7 +13,7 @@ GitLab is a free project and repository management application ...@@ -13,7 +13,7 @@ GitLab is a free project and repository management application
* Ubuntu/Debian * Ubuntu/Debian
* ruby 1.9.3+ * ruby 1.9.3+
* mysql or sqlite * MySQL
* git * git
* gitolite * gitolite
* redis * redis
......
## GitLab Roadmap
### Common
* Help page for service tasks like repos import, backup etc
* Hide last push widget after following link
* Add comment events
* gitolite namespaces for projects per user/group. It will allow us same project names for different users
### Issues
* labels autocomplete via jquery autocomplete
* Import/Export issues
* Form: Assign to me link right to the selectbox
### Merge Request
* Save code fragments with MR comments
### Services
* Campfire integration service
* Hipchat integration service
* Travis CI integration service
* Jenkins CI integration service
app/assets/images/logo_dark.png

2.79 KB | W: | H:

app/assets/images/logo_dark.png

2.53 KB | W: | H:

app/assets/images/logo_dark.png
app/assets/images/logo_dark.png
app/assets/images/logo_dark.png
app/assets/images/logo_dark.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/logo_white.png

1.64 KB | W: | H:

app/assets/images/logo_white.png

1.48 KB | W: | H:

app/assets/images/logo_white.png
app/assets/images/logo_white.png
app/assets/images/logo_white.png
app/assets/images/logo_white.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -13,10 +13,13 @@ ...@@ -13,10 +13,13 @@
//= require jquery.history //= require jquery.history
//= require jquery.waitforimages //= require jquery.waitforimages
//= require jquery.atwho //= require jquery.atwho
//= require jquery.scrollto
//= require bootstrap //= require bootstrap
//= 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 .
# Creates the variables for setting up GFM auto-completion
window.GitLab ?= {}
GitLab.GfmAutoComplete ?= {}
###
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>"
GitLab.GfmAutoComplete.Emoji = {data, template}
# Team Members # Team Members
window.autocompleteMembersUrl = ""; data = []
window.autocompleteMembersParams = url = '';
private_token: "" params = {private_token: '', page: 1}
page: 1 GitLab.GfmAutoComplete.Members = {data, url, params}
window.autocompleteMembersData = [];
# Add GFM auto-completion to all input fields, that accept GFM input.
GitLab.GfmAutoComplete.setup = ->
input = $('.js-gfm-input')
###
Add GFM auto-completion to all input fields, that accept GFM input. # Emoji
### input.atWho ':',
window.setupGfmAutoComplete = -> data: GitLab.GfmAutoComplete.Emoji.data,
### tpl: GitLab.GfmAutoComplete.Emoji.template
Emoji
### # Team Members
$('.gfm-input').atWho ':', input.atWho '@', (query, callback) ->
data: autocompleteEmojiData,
tpl: autocompleteEmojiTemplate
###
Team Members
###
$('.gfm-input').atWho '@', (query, callback) ->
(getMoreMembers = -> (getMoreMembers = ->
$.getJSON(autocompleteMembersUrl, autocompleteMembersParams) $.getJSON(GitLab.GfmAutoComplete.Members.url, GitLab.GfmAutoComplete.Members.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(GitLab.GfmAutoComplete.Members.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(GitLab.GfmAutoComplete.Members.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: GitLab.GfmAutoComplete.Members.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; GitLab.GfmAutoComplete.Members.params.page += 1
).call(); ).call()
\ No newline at end of file
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").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);
$('.top-tabs .add_new').hide(); $('.top-tabs .add_new').hide();
disableButtonIfEmptyField("#issue_title", ".save-btn"); disableButtonIfEmptyField("#issue_title", ".save-btn");
setupGfmAutoComplete(); GitLab.GfmAutoComplete.setup();
}); });
} }
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);
$('.add_new').hide(); $('.add_new').hide();
disableButtonIfEmptyField("#issue_title", ".save-btn"); disableButtonIfEmptyField("#issue_title", ".save-btn");
setupGfmAutoComplete(); GitLab.GfmAutoComplete.setup();
}); });
} }
...@@ -33,18 +31,18 @@ function switchFromEditIssue(){ ...@@ -33,18 +31,18 @@ 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();
}); });
}); });
} }
function initIssuesSearch() { function initIssuesSearch() {
var href = $('.issue_search').parent().attr('action'); var href = $('#issue_search_form').attr('action');
var last_terms = ''; var last_terms = '';
$('.issue_search').keyup(function() { $('#issue_search').keyup(function() {
var terms = $(this).val(); var terms = $(this).val();
var milestone_id = $('#milestone_id').val(); var milestone_id = $('#milestone_id').val();
var status = $('#status').val(); var status = $('#status').val();
...@@ -59,10 +57,6 @@ function initIssuesSearch() { ...@@ -59,10 +57,6 @@ function initIssuesSearch() {
} }
} }
}); });
$('.delete-issue').live('ajax:success', function() {
$(this).closest('tr').fadeOut(); updatePage();
});
} }
/** /**
......
Loader =
html: (width) ->
$('<img>').attr src: '/assets/ajax-loader.gif', width: width
window.Loader = Loader
...@@ -7,29 +7,36 @@ window.slugify = (text) -> ...@@ -7,29 +7,36 @@ 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()
# Bottom tooltip
$('.has_bottom_tooltip').tooltip(placement: 'bottom')
# 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 +45,7 @@ $ -> ...@@ -38,7 +45,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,41 +59,22 @@ $ -> ...@@ -52,41 +59,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
$(document).on 'click', '#preview-link', (e) ->
$('#preview-note').text('Loading...')
previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview'
$(this).text(previewLinkText)
note = $('#note_note').val()
if note.trim().length == 0
$('#preview-note').text("Nothing to preview.")
else
$.post $(this).attr('href'), {note: note}, (data) ->
$('#preview-note').html(data)
$('#preview-note, #note_note').toggle()
e.preventDefault()
false
(($) -> (($) ->
_chosen = $.fn.chosen _chosen = $.fn.chosen
$.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)
...@@ -115,4 +115,15 @@ var MergeRequest = { ...@@ -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();
});
} }
...@@ -5,3 +5,10 @@ $ -> ...@@ -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
...@@ -14,8 +14,8 @@ var NoteList = { ...@@ -14,8 +14,8 @@ var NoteList = {
this.notes_path = path + ".js"; this.notes_path = path + ".js";
this.target_id = tid; this.target_id = tid;
this.target_type = tt; this.target_type = tt;
this.reversed = $("#notes-list").hasClass("reversed"); this.reversed = $("#notes-list").is(".reversed");
this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; this.target_params = "target_type=" + this.target_type + "&target_id=" + this.target_id;
// get initial set of notes // get initial set of notes
this.getContent(); this.getContent();
...@@ -33,6 +33,8 @@ var NoteList = { ...@@ -33,6 +33,8 @@ var NoteList = {
$(".note-form-holder").on("ajax:complete", function(){ $(".note-form-holder").on("ajax:complete", function(){
$(".submit_note").enable(); $(".submit_note").enable();
$('#preview-note').hide();
$('#note_note').show();
}) })
disableButtonIfEmptyField(".note-text", ".submit_note"); disableButtonIfEmptyField(".note-text", ".submit_note");
...@@ -52,6 +54,26 @@ var NoteList = { ...@@ -52,6 +54,26 @@ var NoteList = {
$('.note_advanced_opts').show(); $('.note_advanced_opts').show();
}); });
} }
// Setup note preview
$(document).on('click', '#preview-link', function(e) {
$('#preview-note').text('Loading...');
$(this).text($(this).text() === "Edit" ? "Preview" : "Edit");
var note_text = $('#note_note').val();
if(note_text.trim().length === 0) {
$('#preview-note').text('Nothing to preview.');
} else {
$.post($(this).attr('href'), {note: note_text}).success(function(data) {
$('#preview-note').html(data);
});
}
$('#preview-note, #note_note').toggle();
e.preventDefault();
});
}, },
...@@ -69,7 +91,7 @@ var NoteList = { ...@@ -69,7 +91,7 @@ var NoteList = {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "?" + this.target_params, data: this.target_params,
complete: function(){ $('.notes-status').removeClass("loading")}, complete: function(){ $('.notes-status').removeClass("loading")},
beforeSend: function() { $('.notes-status').addClass("loading") }, beforeSend: function() { $('.notes-status').addClass("loading") },
dataType: "script"}); dataType: "script"});
...@@ -131,7 +153,7 @@ var NoteList = { ...@@ -131,7 +153,7 @@ var NoteList = {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "loading_more=1&" + (this.reversed ? "before_id" : "after_id") + "=" + this.bottom_id + this.target_params, data: this.target_params + "&loading_more=1&" + (this.reversed ? "before_id" : "after_id") + "=" + this.bottom_id,
complete: function(){ $('.notes-status').removeClass("loading")}, complete: function(){ $('.notes-status').removeClass("loading")},
beforeSend: function() { $('.notes-status').addClass("loading") }, beforeSend: function() { $('.notes-status').addClass("loading") },
dataType: "script"}); dataType: "script"});
...@@ -192,7 +214,7 @@ var NoteList = { ...@@ -192,7 +214,7 @@ var NoteList = {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "loading_new=1&after_id=" + (this.reversed ? this.top_id : this.bottom_id) + this.target_params, data: this.target_params + "&loading_new=1&after_id=" + (this.reversed ? this.top_id : this.bottom_id),
dataType: "script"}); dataType: "script"});
}, },
...@@ -264,7 +286,7 @@ var PerLineNotes = { ...@@ -264,7 +286,7 @@ var PerLineNotes = {
$(this).closest("tr").after(form); $(this).closest("tr").after(form);
form.find("#note_line_code").val($(this).data("lineCode")); form.find("#note_line_code").val($(this).data("lineCode"));
form.show(); form.show();
return false; e.preventDefault();
}); });
disableButtonIfEmptyField(".line-note-text", ".submit_inline_note"); disableButtonIfEmptyField(".line-note-text", ".submit_inline_note");
...@@ -285,7 +307,7 @@ var PerLineNotes = { ...@@ -285,7 +307,7 @@ var PerLineNotes = {
// elements must really be removed for this to work reliably // elements must really be removed for this to work reliably
var trLine = trNote.prev(); var trLine = trNote.prev();
var trRpl = trNote.next(); var trRpl = trNote.next();
if (trLine.hasClass("line_holder") && trRpl.hasClass("reply")) { if (trLine.is(".line_holder") && trRpl.is(".reply")) {
trRpl.fadeOut(function() { $(this).remove(); }); trRpl.fadeOut(function() { $(this).remove(); });
} }
}); });
......
$ ->
$('.edit_user .application-theme input, .edit_user .code-preview-theme input').click ->
# Hide any previous submission feedback
$('.edit_user .update-feedback').hide()
# Submit the form
$('.edit_user').submit()
# Go up the hierarchy and show the corresponding submission feedback element
$(@).closest('fieldset').find('.update-feedback').show('highlight', {color: '#DFF0D8'}, 500)
...@@ -22,3 +22,10 @@ $ -> ...@@ -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
$ ->
$('#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,40 @@ $ -> ...@@ -17,23 +17,40 @@ $ ->
"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) ->
((window) -> History = window.History
History = window.History $ = window.jQuery
$ = window.jQuery document = window.document
document = window.document
# Check to see if History.js is enabled for our Browser
# Check to see if History.js is enabled for our Browser unless History.enabled
unless History.enabled return false
return false
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
$ -> History.pushState(null, null, $(@).attr('href'))
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) -> return false
History.pushState(null, null, $(@).attr('href'))
return false History.Adapter.bind window, 'statechange', ->
state = History.getState()
History.Adapter.bind window, 'statechange', -> window.ajaxGet(state.url)
state = History.getState() )(window)
window.ajaxGet(state.url)
)(window) # See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = ->
if window.location.hash isnt ""
matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/)
first_line = parseInt(matches?[1])
last_line = parseInt(matches?[3])
unless isNaN first_line
last_line = first_line if isNaN(last_line)
$("#tree-content-holder .highlight .line").removeClass("hll")
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
$("#L#{first_line}").ScrollTo()
# Highlight the correct lines on load
highlightBlobLines()
# Highlight the correct lines when the hash part of the URL changes
$(window).on 'hashchange', highlightBlobLines
...@@ -20,18 +20,6 @@ body { ...@@ -20,18 +20,6 @@ body {
float:right; float:right;
} }
.profile_avatar_holder {
float:left;
width:60px;
height:60px;
margin-right:20px;
img {
width:60px;
height:60px;
background:#eee;
}
}
.visible_link, .visible_link,
.author_link { .author_link {
...@@ -596,25 +584,6 @@ li.note { ...@@ -596,25 +584,6 @@ li.note {
} }
} }
.themes_opts {
padding-left:20px;
label {
width:175px;
margin-right:40px;
.prev {
@extend .thumbnail;
height:120px;
width:175px;
margin-bottom:10px;
img {
width:180px;
}
}
}
}
.git_error_tips { .git_error_tips {
@extend .span6; @extend .span6;
text-align:left; text-align:left;
...@@ -628,10 +597,11 @@ li.note { ...@@ -628,10 +597,11 @@ li.note {
.error_message { .error_message {
@extend .cred; @extend .cred;
border-bottom: 1px solid #D21; border-left: 4px solid #E99;
padding-bottom:20px; padding: 10px;
text-align:center; margin-bottom: 10px;
margin-bottom:10px; background: #FEE;
padding-left: 20px;
} }
.oauth_select_holder { .oauth_select_holder {
...@@ -670,3 +640,16 @@ pre { ...@@ -670,3 +640,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;
}
}
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
&.very_small { &.very_small {
font-size:11px; font-size:11px;
padding:2px 6px; padding:2px 6px;
line-height: 16px;
margin:2px; margin:2px;
} }
......
...@@ -26,8 +26,10 @@ ...@@ -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; }
...@@ -38,6 +40,7 @@ ...@@ -38,6 +40,7 @@
> a { > a {
padding:8px 20px; padding:8px 20px;
margin-right: 7px; margin-right: 7px;
line-height: 19px;
border-color: #EEE; border-color: #EEE;
color:#888; color:#888;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
...@@ -66,11 +69,12 @@ ...@@ -66,11 +69,12 @@
.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; }
img.small { width: 80px; }
/** HELPERS **/ /** HELPERS **/
.nothing_here_message { text-align:center; padding:20px; color:#777; } .nothing_here_message { text-align:center; padding:20px; color:#777; }
...@@ -85,3 +89,5 @@ input[type='search'].search-text-input { ...@@ -85,3 +89,5 @@ input[type='search'].search-text-input {
@include border-radius(4px); @include border-radius(4px);
border:1px solid #ccc; border:1px solid #ccc;
} }
fieldset legend { font-size: 17px; }
...@@ -132,35 +132,74 @@ ...@@ -132,35 +132,74 @@
* Code file * Code file
*/ */
&.code { &.code {
padding:0; padding: 0;
td.code {
width: 100%;
.highlight {
margin-left: 55px;
overflow:auto;
overflow-y:hidden;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable { table.lines {
border: none; border: none;
} box-shadow: none;
body.project-page table.highlighttable td { border: none } margin: 0px;
table.highlighttable tr:hover { background:none;} padding: 0px;
table-layout: fixed;
table.highlighttable pre{ pre {
line-height:16px !important; background: none;
font-size:12px !important; border: none;
} font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
font-size: 12px !important;
line-height: 16px !important;
margin: 0;
padding: 10px 0;
}
td {
border: none;
margin: 0;
padding: 0;
vertical-align: top;
&:first-child {
background: #eee;
width: 50px;
}
&:last-child {
}
}
tr:hover {
background: none;
}
pre.line_numbers {
color: #666;
padding: 10px 6px 10px 0;
text-align: right;
a {
color: #666;
i {
display: none;
font-size: 14px;
line-height: 14px;
}
&:hover i {
display: inherit;
}
}
}
table.highlighttable .linenodiv pre { .highlight {
text-align: right; border-left: 1px solid #DEE2E3;
padding-right: 4px; overflow: auto;
color:#666; overflow-y: hidden;
pre {
white-space: pre;
word-wrap: normal;
.line {
padding: 0 10px;
}
}
}
} }
} }
} }
......
...@@ -21,7 +21,7 @@ ul { ...@@ -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 { ...@@ -31,3 +31,11 @@ ul {
} }
} }
} }
ol, ul {
&.styled {
li {
padding:2px;
}
}
}
...@@ -34,6 +34,11 @@ table { ...@@ -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;
} }
......
...@@ -2,8 +2,11 @@ ...@@ -2,8 +2,11 @@
* Headers * Headers
* *
*/ */
h1, h2, h3, h4, h5, h6 { margin: 0; }
h3, h4, h5, h6 { line-height: 36px; } h3, h4, h5, h6 { line-height: 36px; }
h5 { font-size:14px; } h5 { font-size:14px; }
h3.page_title { h3.page_title {
color:#456; color:#456;
font-size:20px; font-size:20px;
...@@ -11,6 +14,11 @@ h3.page_title { ...@@ -11,6 +14,11 @@ h3.page_title {
line-height: 28px; line-height: 28px;
} }
h6 {
color: #888;
text-transform: uppercase;
}
/** CODE **/ /** CODE **/
pre { pre {
font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
......
.black .highlighttable { .black .lines .highlight {
td.linenos { border:none; } background: #333;
pre { color: #eee } pre { color: #eee; }
.highlight { background: #333; border-left:1px solid #555; }
.hll { background-color: #ffffff } .hll { display: block; background-color: darken($hover, 65%) }
.c { color: #888888; font-style: italic } /* Comment */ .c { color: #888888; font-style: italic } /* Comment */
.err { color: #a61717; background-color: #e3d2d2 } /* Error */ .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.k { color: #CDA869; font-weight: bold } /* Keyword */ .k { color: #CDA869; font-weight: bold } /* Keyword */
...@@ -22,43 +21,43 @@ ...@@ -22,43 +21,43 @@
.gs { font-weight: bold } /* Generic.Strong */ .gs { font-weight: bold } /* Generic.Strong */
.gu { color: #606060 } /* Generic.Subheading */ .gu { color: #606060 } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */ .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc{font-weight:bold;} /* Keyword.Constant */ .kc{font-weight:bold;} /* Keyword.Constant */
.highlight .kd{font-weight:bold;} /* Keyword.Declaration */ .kd{font-weight:bold;} /* Keyword.Declaration */
.highlight .kn{font-weight:bold;} /* Keyword.Namespace */ .kn{font-weight:bold;} /* Keyword.Namespace */
.highlight .kp{font-weight:bold;} /* Keyword.Pseudo */ .kp{font-weight:bold;} /* Keyword.Pseudo */
.highlight .kr{font-weight:bold;} /* Keyword.Reserved */ .kr{font-weight:bold;} /* Keyword.Reserved */
.highlight .kt{color:#458;font-weight:bold;} /* Keyword.Type */ .kt{color:#458;font-weight:bold;} /* Keyword.Type */
.m { color: #0000DD; font-weight: bold } /* Literal.Number */ .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.p { color: #eee; } .p { color: #eee; }
.s { color: #0AD; background-color: transparent } /* Literal.String */ .s { color: #0AD; background-color: transparent } /* Literal.String */
.highlight .na{color:#008080;} /* Name.Attribute */ .na{color:#008080;} /* Name.Attribute */
.highlight .nb{color:#0086B3;} /* Name.Builtin */ .nb{color:#0086B3;} /* Name.Builtin */
.highlight .nc{color:#ccc;font-weight:bold;} /* Name.Class */ .nc{color:#ccc;font-weight:bold;} /* Name.Class */
.highlight .no{color:turquoise;} /* Name.Constant */ .no{color:turquoise;} /* Name.Constant */
.highlight .ni{color:#800080;} .ni{color:#800080;}
.highlight .ne{color:#900;font-weight:bold;} /* Name.Exception */ .ne{color:#900;font-weight:bold;} /* Name.Exception */
.highlight .nf{color:#ccc;font-weight:bold;} /* Name.Function */ .nf{color:#ccc;font-weight:bold;} /* Name.Function */
.highlight .nn{color:#79C3E0;font-weight:bold;} /* Name.Namespace */ .nn{color:#79C3E0;font-weight:bold;} /* Name.Namespace */
.highlight .nt{color:#fc5;} /* Name.Tag */ .nt{color:#fc5;} /* Name.Tag */
.highlight .nv{color:#FA4;} /* Name.Variable */ .nv{color:#FA4;} /* Name.Variable */
.py { color: #336699; font-weight: bold } /* Name.Property */ .py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */ .ow { color: #008800 } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */ .w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */ .mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */
.mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */ .mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi {color:#099;} /* Literal.Number.Integer */ .mi {color:#099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */ .sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */
.highlight .sc{color:#d14;} /* Literal.String.Char */ .sc{color:#d14;} /* Literal.String.Char */
.sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */ .sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */
.highlight .s2{color:orange;} /* Literal.String.Double */ .s2{color:orange;} /* Literal.String.Double */
.highlight .se{color:orange;} /* Literal.String.Escape */ .se{color:orange;} /* Literal.String.Escape */
.highlight .sh{color:orange;} /* Literal.String.Heredoc */ .sh{color:orange;} /* Literal.String.Heredoc */
.highlight .si{color:orange;} /* Literal.String.Interpol */ .si{color:orange;} /* Literal.String.Interpol */
.highlight .sx{color:orange;} /* Literal.String.Other */ .sx{color:orange;} /* Literal.String.Other */
.highlight .sr{color:orange;} /* Literal.String.Regex */ .sr{color:orange;} /* Literal.String.Regex */
.highlight .s1{color:orange;} /* Literal.String.Single */ .s1{color:orange;} /* Literal.String.Single */
.highlight .ss{color:orange;} /* Literal.String.Symbol */ .ss{color:orange;} /* Literal.String.Symbol */
.bp { color: #D58 } /* Name.Builtin.Pseudo */ .bp { color: #D58 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */ .vc { color: #336699 } /* Name.Variable.Class */
.vg { color: #dd7700 } /* Name.Variable.Global */ .vg { color: #dd7700 } /* Name.Variable.Global */
......
table.highlighttable { .white .lines .highlight {
margin:0px;
padding:0px;
font-size:12px;
table-layout:fixed;
background: #EEE;
box-shadow: none;
border: none;
td.linenos {
background:#eee;
border-left:none;
}
td.code {
border-right:none;
}
}
td.code,
td.linenos{
padding:0;
margin:0;
border-top:0;
vertical-align:top;
}
.highlighttable .highlight{
background:none;
padding:10px 0px 0px 10px;
margin-left:0px;
border-left: 1px solid #DEE2E3;
background: white; background: white;
} pre { color: #333; }
.linenodiv pre,
.highlighttable .highlight pre{
margin:0;
padding:0;
background:none;
border:none;
}
.linenodiv pre { .hll { display: block; background-color: $hover }
white-space:pre-line; .c { color: #888888; font-style: italic } /* Comment */
.err { color: #a61717; background-color: #e3d2d2 } /* Error */
.k { color: #000000; font-weight: bold } /* Keyword */
.cm { color: #888888 } /* Comment.Multiline */
.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.c1 { color: #888888 } /* Comment.Single */
.cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #aa0000 } /* Generic.Error */
.gh { color: #303030 } /* Generic.Heading */
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.go { color: #888888 } /* Generic.Output */
.gp { color: #555555 } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #606060 } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */
.kc{font-weight:bold;} /* Keyword.Constant */
.kd{font-weight:bold;} /* Keyword.Declaration */
.kn{font-weight:bold;} /* Keyword.Namespace */
.kp{font-weight:bold;} /* Keyword.Pseudo */
.kr{font-weight:bold;} /* Keyword.Reserved */
.kt{color:#458;font-weight:bold;} /* Keyword.Type */
.m { color: #0000DD; font-weight: bold } /* Literal.Number */
.s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.na{color:#008080;} /* Name.Attribute */
.nb{color:#0086B3;} /* Name.Builtin */
.nc{color:#458;font-weight:bold;} /* Name.Class */
.no{color:#008080;} /* Name.Constant */
.ni{color:#800080;}
.ne{color:#900;font-weight:bold;} /* Name.Exception */
.nf{color:#900;font-weight:bold;} /* Name.Function */
.nn{color:#005;font-weight:bold;} /* Name.Namespace */
.nt{color:#000080;} /* Name.Tag */
.nv{color:#008080;} /* Name.Variable */
.py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.mi {color:#099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.sc{color:#d14;} /* Literal.String.Char */
.sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.s2{color:#d14;} /* Literal.String.Double */
.se{color:#d14;} /* Literal.String.Escape */
.sh{color:#d14;} /* Literal.String.Heredoc */
.si{color:#d14;} /* Literal.String.Interpol */
.sx{color:#d14;} /* Literal.String.Other */
.sr{color:#d14;} /* Literal.String.Regex */
.s1{color:#d14;} /* Literal.String.Single */
.ss{color:#d14;} /* Literal.String.Symbol */
.bp { color: #003388 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */
.vg { color: #dd7700 } /* Name.Variable.Global */
.vi { color: #3333bb }
} }
td.linenos { .shadow {
/*background:#F7F7F7;*/
color:#666;
padding:10px 0px 0px 10px;
float:left;
width:45px;
border-right: 1px solid #ccc;
}
td.code .highlight {
overflow: auto;
}
table.highlighttable pre{
padding:0;
margin:0;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
color: #333;
text-align:left;
}
.git-empty .highlight {
pre{
padding:15px;
line-height:2.0;
margin:0;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
color: #333;
text-align:left;}
}
.shadow{
-webkit-box-shadow:0 5px 15px #000; -webkit-box-shadow:0 5px 15px #000;
-moz-box-shadow:0 5px 15px #000; -moz-box-shadow:0 5px 15px #000;
box-shadow:0 5px 15px #000; box-shadow:0 5px 15px #000;
} }
.hll { background-color: #ffffff }
.c { color: #888888; font-style: italic } /* Comment */
.err { color: #a61717; background-color: #e3d2d2 } /* Error */
.k { color: #000000; font-weight: bold } /* Keyword */
.cm { color: #888888 } /* Comment.Multiline */
.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.c1 { color: #888888 } /* Comment.Single */
.cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #aa0000 } /* Generic.Error */
.gh { color: #303030 } /* Generic.Heading */
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.go { color: #888888 } /* Generic.Output */
.gp { color: #555555 } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #606060 } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc{font-weight:bold;} /* Keyword.Constant */
.highlight .kd{font-weight:bold;} /* Keyword.Declaration */
.highlight .kn{font-weight:bold;} /* Keyword.Namespace */
.highlight .kp{font-weight:bold;} /* Keyword.Pseudo */
.highlight .kr{font-weight:bold;} /* Keyword.Reserved */
.highlight .kt{color:#458;font-weight:bold;} /* Keyword.Type */
.m { color: #0000DD; font-weight: bold } /* Literal.Number */
.s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na{color:#008080;} /* Name.Attribute */
.highlight .nb{color:#0086B3;} /* Name.Builtin */
.highlight .nc{color:#458;font-weight:bold;} /* Name.Class */
.highlight .no{color:#008080;} /* Name.Constant */
.highlight .ni{color:#800080;}
.highlight .ne{color:#900;font-weight:bold;} /* Name.Exception */
.highlight .nf{color:#900;font-weight:bold;} /* Name.Function */
.highlight .nn{color:#005;font-weight:bold;} /* Name.Namespace */
.highlight .nt{color:#000080;} /* Name.Tag */
.highlight .nv{color:#008080;} /* Name.Variable */
.py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi {color:#099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc{color:#d14;} /* Literal.String.Char */
.sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2{color:#d14;} /* Literal.String.Double */
.highlight .se{color:#d14;} /* Literal.String.Escape */
.highlight .sh{color:#d14;} /* Literal.String.Heredoc */
.highlight .si{color:#d14;} /* Literal.String.Interpol */
.highlight .sx{color:#d14;} /* Literal.String.Other */
.highlight .sr{color:#d14;} /* Literal.String.Regex */
.highlight .s1{color:#d14;} /* Literal.String.Single */
.highlight .ss{color:#d14;} /* Literal.String.Symbol */
.bp { color: #003388 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */
.vg { color: #dd7700 } /* Name.Variable.Global */
.vi { color: #3333bb }
/** Override bootstrap variables **/
$baseFontSize: 13px !default;
$baseLineHeight: 18px !default;
@import "bootstrap"; @import "bootstrap";
@import "bootstrap-responsive"; @import "bootstrap-responsive";
@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'); }
$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
/** MIXINS **/ /** MIXINS **/
@mixin shade { @mixin shade {
...@@ -19,9 +25,9 @@ $hover: #D9EDF7; ...@@ -19,9 +25,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 +70,14 @@ $hover: #D9EDF7; ...@@ -64,6 +70,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));
...@@ -104,14 +118,12 @@ $hover: #D9EDF7; ...@@ -104,14 +118,12 @@ $hover: #D9EDF7;
@import "themes/ui_basic.scss"; @import "themes/ui_basic.scss";
/** /**
* UI mars theme * UI themes:
*/ */
@import "themes/ui_mars.scss"; @import "themes/ui_mars.scss";
/**
* UI Modern theme
*/
@import "themes/ui_modern.scss"; @import "themes/ui_modern.scss";
@import "themes/ui_gray.scss";
@import "themes/ui_color.scss";
/** /**
* GitLab bootstrap. * GitLab bootstrap.
...@@ -145,6 +157,7 @@ $hover: #D9EDF7; ...@@ -145,6 +157,7 @@ $hover: #D9EDF7;
@import "sections/merge_requests.scss"; @import "sections/merge_requests.scss";
@import "sections/graph.scss"; @import "sections/graph.scss";
@import "sections/events.scss"; @import "sections/events.scss";
@import "sections/themes.scss";
/** /**
* This scss file redefine chozen selectbox styles for * This scss file redefine chozen selectbox styles for
......
...@@ -19,31 +19,66 @@ ...@@ -19,31 +19,66 @@
margin-right: 10px; margin-right: 10px;
.chzn-drop { .chzn-drop {
margin:7px 0;
min-width: 400px; min-width: 400px;
border: 2px solid $blue_link; .chzn-results {
@include border-radius(4px); 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 { .chzn-results {
margin-top: 5px;
max-height:300px; max-height:300px;
.group-result { .group-result {
color: $blue_link; color: $style_color;
border-bottom: 1px solid #EEE;
padding: 8px;
} }
.active-result { .active-result {
border-radius: 0;
&.highlighted { &.highlighted {
background: $blue_link; background: $hover;
color: $style_color;
}
&.result-selected {
background: #EEE;
border-left: 4px solid #CCC;
} }
} }
} }
.chzn-search input { .chzn-search {
min-width:365px; @include bg-gray-gradient;
input {
min-width:165px;
border-color: #CCC;
}
} }
} }
.chzn-single { .chzn-single {
@include bg-gray-gradient; @include bg-light-gray-gradient;
div { div {
background:transparent; background:transparent;
...@@ -55,14 +90,3 @@ ...@@ -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 @@ ...@@ -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 {
...@@ -71,7 +74,9 @@ ...@@ -71,7 +74,9 @@
margin-bottom:1em; margin-bottom:1em;
.diff_file_header { .diff_file_header {
padding:7px 5px; @extend .clearfix;
padding: 5px 5px 5px 10px;
color: #555;
border-bottom:1px solid #CCC; border-bottom:1px solid #CCC;
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));
...@@ -79,8 +84,23 @@ ...@@ -79,8 +84,23 @@
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
span { > span {
font-family: $monospace;
font-size:14px; font-size:14px;
line-height: 30px;
}
a.view-commit{
font-weight: bold;
}
.commit-short-id{
font-family: $monospace;
font-size: smaller;
}
.file-mode{
font-family: $monospace;
} }
} }
.diff_file_content { .diff_file_content {
...@@ -89,7 +109,7 @@ ...@@ -89,7 +109,7 @@
background:#fff; background:#fff;
color:#333; color:#333;
font-size: 12px; font-size: 12px;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; font-family: $monospace;
.old{ .old{
span.idiff{ span.idiff{
background-color:#FAA; background-color:#FAA;
...@@ -110,22 +130,34 @@ ...@@ -110,22 +130,34 @@
.diff_file_content_image { .diff_file_content_image {
background:#eee; background:#eee;
text-align:center; text-align:center;
img { .image {
display: inline-block;
margin:50px; margin:50px;
padding:1px;
max-width:400px; max-width:400px;
&.diff_image_removed { img{
border: 1px solid #C00; background: url('trans_bg.gif');
}
&.diff_removed {
img{
border: 1px solid #C00;
}
}
&.diff_added {
img{
border: 1px solid #0C0;
}
} }
&.diff_image_added { .image-info{
border: 1px solid #0C0;; margin: 5px 0 0 0;
} }
} }
&.img_compared { &.img_compared {
img { .image {
max-width:300px; max-width:300px;
} }
} }
...@@ -222,26 +254,41 @@ ...@@ -222,26 +254,41 @@
float:left; float:left;
@extend .lined; @extend .lined;
min-width:65px; min-width:65px;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; font-family: $monospace;
} }
.commit-author-name { .commit-author-name {
color: #777; color: #777;
&:hover {
color: #999;
}
} }
} }
.diff_file_header a, .diff_file_header a,
.file_stats a { .file-stats a {
color:$style_color; color: $style_color;
} }
.file_stats { .file-stats {
span { .new-file{
img { i{
width:14px; color: #1BCF00;
float:left; }
margin-right:6px; }
padding:2px 0; .renamed-file{
i{
color: #FE9300;
}
}
.deleted-file{
i{
color: #FF0000;
}
}
.edit-file{
i{
color: #555;
} }
} }
} }
...@@ -253,5 +300,5 @@ ...@@ -253,5 +300,5 @@
font-size:13px; font-size:13px;
background: #474D57; background: #474D57;
color:#fff; color:#fff;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; font-family: $monospace;
} }
.file-editor { .file-editor {
#editor{ #editor{
border: none;
border-radius: 0;
height: 500px; height: 500px;
width: 100%; margin: 0;
padding: 0;
position: relative; position: relative;
width: 100%;
} }
.editor-commit-comment {
padding-top:20px; .cancel-btn {
color: #B94A48;
&:hover {
color: #B94A48;
}
}
.commit-button-annotation {
@extend .alert;
@extend .alert-info;
display: inline-block;
margin: 0;
padding: 2px;
> * {
float: left;
}
.commit-btn {
@extend .save-btn;
}
.message {
display: inline-block;
margin: 5px 8px 0 8px;
}
}
.commit_message-group {
margin-top: 20px;
label {
font-size: 16px;
line-height: 20px;
}
textarea { textarea {
width: 50%; @extend .span8;
margin-left: 20px;
} }
} }
} }
...@@ -43,6 +43,7 @@ ...@@ -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 @@ ...@@ -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;
}
}
}
...@@ -3,18 +3,29 @@ ...@@ -3,18 +3,29 @@
* *
*/ */
header { header {
width:100%; &.navbar-gitlab {
padding:0; .navbar-inner {
margin:0; height:45px;
top:1px; padding: 5px;
left:0; background: #F1F1F1;
background: #F1F1F1; /* for non-css3 browsers */
border-bottom: 1px solid #ccc; .nav > li > a {
box-shadow: 0 -1px 0 white inset; color: $style_color;
-moz-box-shadow: 0 -1px 0 white inset; text-shadow: 0 1px 0 #fff;
-webkit-box-shadow: 0 -1px 0 white inset; font-size: 18px;
padding: 11px;
}
/** NAV block with links and profile **/
.nav {
float: right;
margin-right: 0;
}
}
}
z-index:10; z-index:10;
height:60px; /*height:60px;*/
/** /**
* *
...@@ -22,45 +33,26 @@ header { ...@@ -22,45 +33,26 @@ header {
* *
*/ */
.app_logo { .app_logo {
width:200px; width:170px;
float:left; float:left;
position:relative;
top:-5px;
a { a {
float:left; float:left;
padding: 0px;
h1 { h1 {
padding-top: 5px;
width:90px; width:90px;
background: url('logo_dark.png') no-repeat 0px -3px; background: url('logo_dark.png') no-repeat 0px 2px;
float:left; float:left;
margin-left:5px; margin-left:2px;
font-size:36px; font-size:30px;
line-height:36px; line-height:48px;
font-weight:normal; font-weight:normal;
color:$style_color; color:$style_color;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
padding-left:50px; padding-left:45px;
height:40px; height:40px;
font-family: 'Korolev', sans-serif; font-family: 'Korolev', sans-serif;
} }
}
.separator {
margin-left:20px;
float: left;
height: 60px;
width: 1px;
background: white;
border-left: 1px solid #DDD;
margin-top: -10px;
}
}
.container {
.top_panel_content {
margin:auto;
position:relative;
padding:15px 0;
} }
} }
...@@ -74,33 +66,23 @@ header { ...@@ -74,33 +66,23 @@ header {
float:left; float:left;
margin:0; margin:0;
margin-right:30px; margin-right:30px;
font-size:36px; font-size:30px;
line-height:36px; line-height:48px;
font-weight:normal; font-weight:normal;
color:$style_color; color:$style_color;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
font-family: 'Korolev', sans-serif; font-family: 'Korolev', sans-serif;
} }
.fbtn {
float: right;
margin-right:10px;
.btn {
margin-left:7px;
background: #F1F1F1;
border: 1px solid #CCC;
}
}
/** /**
* *
* Search box * Search box
* *
*/ */
.search { .search {
float: right;
margin-right: 45px; margin-right: 45px;
margin-left:10px;
margin-top: 2px;
.search-input { .search-input {
@extend .span2; @extend .span2;
...@@ -108,8 +90,13 @@ header { ...@@ -108,8 +90,13 @@ header {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 10px; background-position: 10px;
padding-left:25px; padding-left:25px;
@include border-radius(5px); font-size: 13px;
border:1px solid #ccc; @include border-radius(3px);
border:1px solid #c6c6c6;
box-shadow:none;
&:focus {
@extend .span3;
}
} }
} }
...@@ -121,7 +108,7 @@ header { ...@@ -121,7 +108,7 @@ header {
.account-box { .account-box {
position: absolute; position: absolute;
right: 0; right: 0;
top: 13px; top: 6px;
z-index: 10000; z-index: 10000;
width: 128px; width: 128px;
font-size: 11px; font-size: 11px;
...@@ -129,13 +116,13 @@ header { ...@@ -129,13 +116,13 @@ header {
display: block; display: block;
cursor: pointer; cursor: pointer;
img { img {
@include border-radius(4px); @include border-radius(3px);
right: 5px; right: 5px;
position: absolute; position: absolute;
width: 28px; width: 28px;
height: 28px; height: 28px;
display: block; display: block;
top: 2px; top:1px;
&:after { &:after {
content: " "; content: " ";
display: block; display: block;
...@@ -162,12 +149,7 @@ header { ...@@ -162,12 +149,7 @@ header {
display: block; } } display: block; } }
.account-links { .account-links {
background: #79C3E0;
display: none;
border-radius: 5px; border-radius: 5px;
width: 100px;
margin-top: 0;
float: right;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
position: relative; position: relative;
&:before { &:before {
...@@ -177,32 +159,33 @@ header { ...@@ -177,32 +159,33 @@ header {
position: absolute; position: absolute;
border: 5px solid transparent; border: 5px solid transparent;
border-color: rgba(255, 255, 255, 0); border-color: rgba(255, 255, 255, 0);
border-bottom-color: #333; border-bottom-color: #555;
text-indent: -9999px; text-indent: -9999px;
top: -10px; top: -10px;
line-height: 0; line-height: 0;
right: 10px; right: 10px;
z-index: 10; } z-index: 10; }
background: #333; background: #555;
display: none; display: none;
z-index: 100000; z-index: 100000;
border-radius: 5px; @include border-radius(4px);
width: 100px; width: 100px;
position: absolute; position: absolute;
right: 10px; right: 5px;
top: 42px; top: 38px;
margin-top: 0; margin-top: 0;
float: right; float: right;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
a { a {
color: #EEE; color: #fff;
padding: 6px 10px; padding: 7px 10px;
display: block; display: block;
text-shadow: none; text-shadow: none;
border-bottom: 1px solid #555; border-bottom: 1px solid #666;
font-size: 12px;
&:hover { &:hover {
color:#eee; color:#fff;
background: #444; background: #333;
} }
} }
} }
...@@ -228,5 +211,52 @@ header { ...@@ -228,5 +211,52 @@ header {
border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
border-bottom: 0; } } border-bottom: 0; } }
/*
* Dark header
*
*/
&.header-dark {
&.navbar-gitlab {
.navbar-inner {
background: #708090;
border-bottom: 1px solid #AAA;
.nav > li > a {
color: #fff;
text-shadow: 0 1px 0 #111;
}
}
}
.search {
.search-input {
background-color: #D2D5DA;
background-color: rgba(255, 255, 255, 0.5);
&:focus {
background-color: white;
}
}
}
.search-input::-webkit-input-placeholder {
color: #666;
}
.app_logo {
a {
h1 {
background: url('logo_white.png') no-repeat 0px 2px;
color:#fff;
text-shadow: 0 1px 1px #111;
}
}
}
.project_name {
color:#fff;
text-shadow: 0 1px 1px #111;
}
}
} }
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
img.avatar { img.avatar {
width:32px; width:32px;
margin-top:4px; margin-top:1px;
} }
} }
} }
......
...@@ -71,7 +71,7 @@ li.merge_request { ...@@ -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,25 @@ li.merge_request { ...@@ -121,3 +121,25 @@ 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;
}
}
}
.status-badge {
height: 32px;
width: 100%;
@include border-radius(5px);
}
...@@ -6,7 +6,7 @@ ul.main_menu { ...@@ -6,7 +6,7 @@ ul.main_menu {
border-radius: 4px; border-radius: 4px;
margin: auto; margin: auto;
margin:30px 0; margin:30px 0;
border:1px solid #AAA; border:1px solid #BBB;
height:37px; height:37px;
@include bg-gray-gradient; @include bg-gray-gradient;
position:relative; position:relative;
......
...@@ -6,3 +6,17 @@ ...@@ -6,3 +6,17 @@
} }
} }
} }
.profile_avatar_holder {
float:left;
width:60px;
height:60px;
margin-right:20px;
img {
width:60px;
height:60px;
background:#fff;
padding: 1px;
border: 1px solid #ddd;
}
}
...@@ -85,9 +85,18 @@ ...@@ -85,9 +85,18 @@
} }
.project_clone_holder { .project_clone_holder {
input[type="text"],
.btn {
font-size:12px;
line-height: 18px;
margin: 0;
padding: 3px 10px;
}
input[type="text"] { input[type="text"] {
border: 1px solid #BBB; border: 1px solid #BBB;
box-shadow: none; box-shadow: none;
margin-left: -1px;
} }
} }
......
.application-theme, .code-preview-theme {
.update-feedback {
color: #468847;
float: right;
}
}
.themes_opts {
padding-left:20px;
label {
width:175px;
margin-right:40px;
.prev {
@extend .thumbnail;
height:30px;
width:175px;
margin-bottom:10px;
&.classic {
background: #31363e;
}
&.default {
background: #f1f1f1;
}
&.modern {
background: #567;
}
&.gray {
background: #708090;
}
&.violet {
background: #657;
}
}
}
}
.code_highlight_opts {
padding-left:20px;
label {
width:220px;
margin-right:40px;
.prev {
@extend .thumbnail;
height:151px;
width:220px;
margin-bottom:10px;
}
}
}
...@@ -57,10 +57,7 @@ ...@@ -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 @@ ...@@ -75,6 +72,15 @@
} }
} }
} }
.blame {
img.avatar {
border: 0 none;
float: none;
margin: 0;
padding: 0;
}
}
} }
.tree-btn-group { .tree-btn-group {
......
...@@ -16,35 +16,21 @@ ...@@ -16,35 +16,21 @@
} }
} }
header { .app_logo {
.fbtn { .separator {
.btn { margin-left: 0;
background-color: #F8F8F8; margin-right: 0;
background-image: -webkit-gradient(linear,left top,left bottom,from(#F8F8F8),to(#ECECEC));
background-image: -webkit-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -moz-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -ms-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -o-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: linear-gradient(top,#F8F8F8,#ECECEC);
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');
border-color: #C6C6C6;
margin-left:7px;
@include border-radius(3px);
box-shadow:none;
color:#666;
}
}
.search {
.search-input {
@include border-radius(3px);
border-color: #C6C6C6;
box-shadow:none;
}
}
.pic {
img {
@include border-radius(3px);
}
} }
} }
.separator {
float: left;
height: 60px;
width: 1px;
background: white;
border-left: 1px solid #DDD;
margin-top: -10px;
margin-left: 10px;
margin-right: 10px;
}
} }
/**
* This file represent some UI that can be changed
* during web app restyle or theme select.
*
* Next items should be placed there
* - link colors
* - header restyles
*
*/
.ui_color {
/*
* Application Header
*
*/
header {
@extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
background: #657;
}
}
}
}
/**
* This file represent some UI that can be changed
* during web app restyle or theme select.
*
* Next items should be placed there
* - link colors
* - header restyles
*
*/
.ui_gray {
/*
* Application Header
*
*/
header {
@extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
background: #708090;
}
}
}
}
...@@ -14,45 +14,24 @@ ...@@ -14,45 +14,24 @@
* *
*/ */
header { header {
background: #474D57 url('bg-header.png') repeat-x bottom;
box-shadow:none;
border-bottom: 1px solid #444;
.fbtn { &.navbar-gitlab {
.btn { .navbar-inner {
i { background: #474D57 url('bg-header.png') repeat-x bottom;
position: relative; border-bottom: 1px solid #444;
top: 1px;
}
margin-left:8px;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
background-image: -moz-linear-gradient(#595D63 6.6%, #31363E);
background-image: -o-linear-gradient(#595D63 6.6%, #31363E);
font-size: 12px;
&:hover {
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#2C2F35));
background-image: -webkit-linear-gradient(#595D63 6.6%, #2C2F35);
background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0;
color:#fff;
i {
@extend .icon-white;
}
}
border: 1px solid #31363E; .nav > li > a {
color:#D6DADF; color: #eee;
text-shadow: 0 -1px 0 #000000; text-shadow: 0 1px 0 #444;
}
} }
} }
.search { .search {
float: right; float: right;
margin-right: 45px; margin-right: 45px;
.search-input { .search-input {
border: 1px solid rgba(0, 0, 0, 0.7); border: 1px solid rgba(0, 0, 0, 0.7);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 2px 2px rgba(0, 0, 0, 0.4) inset;
background-color: #D2D5DA; background-color: #D2D5DA;
background-color: rgba(255, 255, 255, 0.5); background-color: rgba(255, 255, 255, 0.5);
...@@ -67,8 +46,8 @@ ...@@ -67,8 +46,8 @@
.app_logo { .app_logo {
a { a {
h1 { h1 {
background: url('logo_white.png') no-repeat 0px -3px; background: url('logo_white.png') no-repeat 0px 2px;
color:#fff; color:#eee;
text-shadow: 0 1px 1px #111; text-shadow: 0 1px 1px #111;
} }
} }
...@@ -78,7 +57,7 @@ ...@@ -78,7 +57,7 @@
} }
.project_name { .project_name {
color:#fff; color:#eee;
text-shadow: 0 1px 1px #111; text-shadow: 0 1px 1px #111;
} }
} }
......
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
* *
* Next items should be placed there * Next items should be placed there
* - link colors * - link colors
* - header styles * - header restyles
* - main menu styles
* *
*/ */
.ui_modern { .ui_modern {
...@@ -14,120 +13,10 @@ ...@@ -14,120 +13,10 @@
* *
*/ */
header { header {
height:40px; @extend .header-dark;
background-image: -moz-linear-gradient(top, #333, #222); &.navbar-gitlab {
background-image: -ms-linear-gradient(top, #333, #222); .navbar-inner {
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333), to(#222)); background: #567;
background-image: -webkit-linear-gradient(top, #333, #222);
background-image: -o-linear-gradient(top, #333, #222);
background-image: linear-gradient(top, #333, #222);
background-repeat: repeat-x;
background-repeat: repeat-x;
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
.container .top_panel_content { padding: 5px 0; }
/**
*
* Logo holder
*
*/
.app_logo {
width:160px;
a {
h1 {
background: none;
color:#DDD;
font-size:30px;
text-shadow: 0 1px 1px #111;
padding-left: 0;
}
}
.separator {
width: 1px;
height: 40px;
margin: 0 10px;
overflow: hidden;
background: #222;
border-left: 1px solid #333;
}
}
.fbtn {
.btn {
i {
position: relative;
top: 2px;
}
background:none;
margin-left:8px;
font-size: 13px;
line-height: 19px;
color:#ccc;
&:hover {
color:#fff;
i {
@extend .icon-white;
}
}
border: none;
box-shadow:none;
text-shadow: 0 -1px 0 #000000;
border-left: 1px solid #333;
}
}
/**
*
* Search box
*
*/
.search {
float: right;
margin-right: 45px;
.search-input {
border: 1px solid rgba(0, 0, 0, 0.7);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 2px 2px rgba(0, 0, 0, 0.4) inset;
background-color: #D2D5DA;
background-color: rgba(255, 255, 255, 0.5);
&:focus {
background-color: white;
}
}
.search-input::-webkit-input-placeholder {
color: #666;
}
}
/**
*
* Project / Area name
*
*/
.project_name {
line-height:36px;
font-size:30px;
color:#DDD;
text-shadow: 0 1px 1px #111;
}
/**
*
* Account box
*
*/
.account-box {
top:6px;
img {
top:1px;
right: 5px;
width: 26px;
height: 26px;
} }
} }
} }
......
...@@ -21,7 +21,7 @@ class CommitLoadContext < BaseContext ...@@ -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
......
# 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 ...@@ -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
...@@ -13,6 +13,7 @@ class SearchContext ...@@ -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 ...@@ -20,7 +21,8 @@ class SearchContext
@result ||= { @result ||= {
projects: [], projects: [],
merge_requests: [], merge_requests: [],
issues: [] issues: [],
wiki_pages: []
} }
end end
end end
......
class Admin::DashboardController < AdminController class Admin::DashboardController < AdminController
def index def index
@workers = Resque.workers
@pending_jobs = Resque.size(:post_receive)
@projects = Project.order("created_at DESC").limit(10) @projects = Project.order("created_at DESC").limit(10)
@users = User.order("created_at DESC").limit(10) @users = User.order("created_at DESC").limit(10)
@resque_accessible = true
@workers = Resque.workers
@pending_jobs = Resque.size(:post_receive)
rescue Redis::InheritedError
@resque_accessible = false
end end
end end
...@@ -4,7 +4,7 @@ class Admin::ProjectsController < AdminController ...@@ -4,7 +4,7 @@ class Admin::ProjectsController < AdminController
def index def index
@admin_projects = Project.scoped @admin_projects = Project.scoped
@admin_projects = @admin_projects.search(params[:name]) if params[:name].present? @admin_projects = @admin_projects.search(params[:name]) if params[:name].present?
@admin_projects = @admin_projects.page(params[:page]).per(20) @admin_projects = @admin_projects.order("name ASC").page(params[:page]).per(20)
end end
def show def show
......
...@@ -98,6 +98,9 @@ class Admin::UsersController < AdminController ...@@ -98,6 +98,9 @@ class Admin::UsersController < AdminController
def destroy def destroy
@admin_user = User.find(params[:id]) @admin_user = User.find(params[:id])
if @admin_user.my_own_projects.count > 0
redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return
end
@admin_user.destroy @admin_user.destroy
respond_to do |format| respond_to do |format|
......
...@@ -9,19 +9,28 @@ class ApplicationController < ActionController::Base ...@@ -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
......
# 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 ...@@ -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
) )
......
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_sorted_by_activity
@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 ...@@ -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
...@@ -54,7 +54,7 @@ class GroupsController < ApplicationController ...@@ -54,7 +54,7 @@ class GroupsController < ApplicationController
end end
def projects def projects
@projects ||= current_user.projects_with_events.where(group_id: @group.id) @projects ||= current_user.projects_sorted_by_activity.where(group_id: @group.id)
end end
def project_ids def project_ids
......
...@@ -31,7 +31,8 @@ class MilestonesController < ProjectResourceController ...@@ -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
......
...@@ -9,7 +9,11 @@ class ProfileController < ApplicationController ...@@ -9,7 +9,11 @@ class ProfileController < ApplicationController
def update def update
@user.update_attributes(params[:user]) @user.update_attributes(params[:user])
redirect_to :back
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end end
def token def token
...@@ -22,7 +26,7 @@ class ProfileController < ApplicationController ...@@ -22,7 +26,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
......
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]
...@@ -21,9 +21,10 @@ class ProjectsController < ProjectResourceController ...@@ -21,9 +21,10 @@ class ProjectsController < ProjectResourceController
@project = Project.create_by_user(params[:project], current_user) @project = Project.create_by_user(params[:project], current_user)
respond_to do |format| respond_to do |format|
flash[:notice] = 'Project was successfully created.' if @project.saved?
format.html do format.html do
if @project.saved? if @project.saved?
redirect_to(@project, notice: 'Project was successfully created.') redirect_to @project
else else
render action: "new" render action: "new"
end end
...@@ -79,7 +80,9 @@ class ProjectsController < ProjectResourceController ...@@ -79,7 +80,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
......
class RefsController < ProjectResourceController class RefsController < ProjectResourceController
include Gitlab::Encode
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
......
...@@ -16,9 +16,14 @@ class RepositoriesController < ProjectResourceController ...@@ -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
......
...@@ -5,5 +5,6 @@ class SearchController < ApplicationController ...@@ -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
class ServicesController < ProjectResourceController
# Authorize
before_filter :authorize_admin_project!
respond_to :html
def index
@gitlab_ci_service = @project.gitlab_ci_service
end
def edit
@service = @project.gitlab_ci_service
# Create if missing
@service = @project.create_gitlab_ci_service unless @service
end
def update
@service = @project.gitlab_ci_service
if @service.update_attributes(params[:service])
redirect_to edit_project_service_path(@project, :gitlab_ci)
else
render 'edit'
end
end
def test
commits = project.commits(project.default_branch, nil, 3)
data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
@service = project.gitlab_ci_service
@service.execute(data)
redirect_to :back
end
end
...@@ -26,15 +26,14 @@ class TreeController < ProjectResourceController ...@@ -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"
......
...@@ -47,21 +47,15 @@ class CommitDecorator < ApplicationDecorator ...@@ -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 ...@@ -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
...@@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator ...@@ -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
......
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 ...@@ -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
......
...@@ -57,12 +57,17 @@ module CommitsHelper ...@@ -57,12 +57,17 @@ module CommitsHelper
def image_diff_class(diff) def image_diff_class(diff)
if diff.deleted_file if diff.deleted_file
"diff_image_removed" "diff_removed"
elsif diff.new_file elsif diff.new_file
"diff_image_added" "diff_added"
else else
nil nil
end end
end end
def commit_to_html commit
if commit.model
escape_javascript(render 'commits/commit', commit: commit)
end
end
end end
...@@ -33,4 +33,22 @@ module EventsHelper ...@@ -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
...@@ -38,4 +38,8 @@ module MergeRequestsHelper ...@@ -38,4 +38,8 @@ module MergeRequestsHelper
classes << " merged" if mr.merged? classes << " merged" if mr.merged?
classes classes
end end
def ci_status_path
@project.gitlab_ci_service.commit_badge_path(@merge_request.last_commit.sha)
end
end end
...@@ -10,5 +10,9 @@ module ProjectsHelper ...@@ -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
...@@ -67,4 +67,29 @@ module TreeHelper ...@@ -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
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 ...@@ -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 ...@@ -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 ...@@ -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
......
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# target_type :string(255)
# target_id :integer
# title :string(255)
# data :text
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# action :integer
# author_id :integer
#
class Event < ActiveRecord::Base class Event < ActiveRecord::Base
include PushEvent include PushEvent
...@@ -144,20 +160,3 @@ class Event < ActiveRecord::Base ...@@ -144,20 +160,3 @@ class Event < ActiveRecord::Base
end end
end end
end end
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# target_type :string(255)
# target_id :integer
# title :string(255)
# data :text
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# action :integer
# author_id :integer
#
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
#
class GitlabCiService < Service
attr_accessible :project_url
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
delegate :execute, to: :service_hook, prefix: nil
after_save :compose_service_hook, if: :activated?
def activated?
active
end
def compose_service_hook
hook = service_hook || build_service_hook
hook.url = [project_url, "/build", "?token=#{token}"].join("")
hook.save
end
def commit_badge_path sha
project_url + "/status?sha=#{sha}"
end
end
# == Schema Information
#
# Table name: groups
#
# id :integer not null, primary key
# name :string(255) not null
# code :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Group < ActiveRecord::Base class Group < ActiveRecord::Base
attr_accessible :code, :name, :owner_id attr_accessible :code, :name, :owner_id
...@@ -22,16 +34,3 @@ class Group < ActiveRecord::Base ...@@ -22,16 +34,3 @@ class Group < ActiveRecord::Base
User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq
end end
end end
# == Schema Information
#
# Table name: groups
#
# id :integer not null, primary key
# name :string(255) not null
# code :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# title :string(255)
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# closed :boolean default(FALSE), not null
# position :integer default(0)
# branch_name :string(255)
# description :text
# milestone_id :integer
#
class Issue < ActiveRecord::Base class Issue < ActiveRecord::Base
include IssueCommonality include IssueCommonality
include Votes include Votes
...@@ -7,30 +25,9 @@ class Issue < ActiveRecord::Base ...@@ -7,30 +25,9 @@ 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)
opened.assigned(user) opened.assigned(user)
end end
end end
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# title :string(255)
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# closed :boolean default(FALSE), not null
# position :integer default(0)
# branch_name :string(255)
# description :text
# milestone_id :integer
#
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# key :text
# title :string(255)
# identifier :string(255)
# project_id :integer
#
require 'digest/md5' require 'digest/md5'
class Key < ActiveRecord::Base class Key < ActiveRecord::Base
...@@ -67,18 +81,3 @@ class Key < ActiveRecord::Base ...@@ -67,18 +81,3 @@ class Key < ActiveRecord::Base
Key.where(identifier: identifier).count == 0 Key.where(identifier: identifier).count == 0
end end
end end
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# key :text
# title :string(255)
# identifier :string(255)
# project_id :integer
#
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
# st_commits :text(2147483647)
# st_diffs :text(2147483647)
# merged :boolean default(FALSE), not null
# state :integer default(1), not null
# milestone_id :integer
#
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 +48,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -26,6 +48,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 +86,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -60,7 +86,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 +193,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -167,7 +193,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
...@@ -193,24 +219,3 @@ class MergeRequest < ActiveRecord::Base ...@@ -193,24 +219,3 @@ class MergeRequest < ActiveRecord::Base
Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND noteable_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND noteable_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids)
end end
end end
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
# st_commits :text(4294967295
# st_diffs :text(4294967295
# merged :boolean default(FALSE), not null
# state :integer default(1), not null
#
# == Schema Information
#
# Table name: milestones
#
# id :integer not null, primary key
# title :string(255) not null
# project_id :integer not null
# description :text
# due_date :date
# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Milestone < ActiveRecord::Base class Milestone < ActiveRecord::Base
attr_accessible :title, :description, :due_date, :closed attr_accessible :title, :description, :due_date, :closed
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
validates :closed, inclusion: { in: [true, false] }
def self.active def self.active
where("due_date > ? OR due_date IS NULL", Date.today) where("due_date > ? OR due_date IS NULL", Date.today)
...@@ -15,8 +31,20 @@ class Milestone < ActiveRecord::Base ...@@ -15,8 +31,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
...@@ -25,18 +53,3 @@ class Milestone < ActiveRecord::Base ...@@ -25,18 +53,3 @@ class Milestone < ActiveRecord::Base
"expires at #{due_date.stamp("Aug 21, 2011")}" if due_date "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date
end end
end end
# == Schema Information
#
# Table name: milestones
#
# id :integer not null, primary key
# title :string(255) not null
# project_id :integer not null
# description :text
# due_date :date
# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
#
# == Schema Information
#
# Table name: notes
#
# id :integer not null, primary key
# note :text
# noteable_id :string(255)
# noteable_type :string(255)
# author_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# project_id :integer
# attachment :string(255)
# line_code :string(255)
#
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
require 'file_size_validator' require 'file_size_validator'
...@@ -23,13 +39,13 @@ class Note < ActiveRecord::Base ...@@ -23,13 +39,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({
...@@ -107,20 +123,3 @@ class Note < ActiveRecord::Base ...@@ -107,20 +123,3 @@ class Note < ActiveRecord::Base
note.start_with?('-1') || note.start_with?(':-1:') note.start_with?('-1') || note.start_with?(':-1:')
end end
end end
# == Schema Information
#
# Table name: notes
#
# id :integer not null, primary key
# note :text
# noteable_id :string(255)
# noteable_type :string(255)
# author_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# project_id :integer
# attachment :string(255)
# line_code :string(255)
#
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# path :string(255)
# description :text
# created_at :datetime not null
# updated_at :datetime not null
# private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer
# default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# group_id :integer
#
require "grit" require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
...@@ -26,6 +47,7 @@ class Project < ActiveRecord::Base ...@@ -26,6 +47,7 @@ class Project < ActiveRecord::Base
has_many :wikis, dependent: :destroy has_many :wikis, dependent: :destroy
has_many :protected_branches, dependent: :destroy has_many :protected_branches, dependent: :destroy
has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id'
has_one :gitlab_ci_service, dependent: :destroy
delegate :name, to: :owner, allow_nil: true, prefix: true delegate :name, to: :owner, allow_nil: true, prefix: true
...@@ -104,8 +126,10 @@ class Project < ActiveRecord::Base ...@@ -104,8 +126,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
...@@ -160,26 +184,12 @@ class Project < ActiveRecord::Base ...@@ -160,26 +184,12 @@ class Project < ActiveRecord::Base
def issues_labels def issues_labels
issues.tag_counts_on(:labels) issues.tag_counts_on(:labels)
end end
end
# == Schema Information def services
# [gitlab_ci_service].compact
# Table name: projects end
#
# id :integer not null, primary key
# name :string(255)
# path :string(255)
# description :text
# created_at :datetime not null
# updated_at :datetime not null
# private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer
# default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# group_id :integer
#
def gitlab_ci?
gitlab_ci_service && gitlab_ci_service.active
end
end
class ProjectHook < WebHook
belongs_to :project
end
# == Schema Information # == Schema Information
# #
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer
# #
class ProjectHook < WebHook
belongs_to :project
end
# == Schema Information
#
# Table name: protected_branches
#
# id :integer not null, primary key
# project_id :integer not null
# name :string(255) not null
# created_at :datetime not null
# updated_at :datetime not null
#
class ProtectedBranch < ActiveRecord::Base class ProtectedBranch < ActiveRecord::Base
include GitHost include GitHost
...@@ -18,15 +29,3 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -18,15 +29,3 @@ class ProtectedBranch < ActiveRecord::Base
project.commit(self.name) project.commit(self.name)
end end
end end
# == Schema Information
#
# Table name: protected_branches
#
# id :integer not null, primary key
# project_id :integer not null
# name :string(255) not null
# created_at :datetime not null
# updated_at :datetime not null
#
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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